From a38dc256fdceff16ea9c760dd9280c1436c6b66d Mon Sep 17 00:00:00 2001 From: carla Date: Tue, 7 Jul 2020 19:49:56 +0200 Subject: [PATCH] contractcourt: persist remote outgoing htlc claim outcome on disk When a remote peer claims one of our outgoing htlcs on chain, we do not care whether they claimed with multiple stages. We simply store the claim outgome then forget the resolver. --- channeldb/reports.go | 3 ++ .../htlc_outgoing_contest_resolver_test.go | 48 ++++++++++++++++--- contractcourt/htlc_timeout_resolver.go | 15 +++++- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/channeldb/reports.go b/channeldb/reports.go index ad1e1a83..7e15220b 100644 --- a/channeldb/reports.go +++ b/channeldb/reports.go @@ -52,6 +52,9 @@ const ( // ResolverTypeIncomingHtlc represents resolution of an incoming htlc. ResolverTypeIncomingHtlc ResolverType = 1 + + // ResolverTypeOutgoingHtlc represents resolution of an outgoing htlc. + ResolverTypeOutgoingHtlc ResolverType = 2 ) // ResolverOutcome indicates the outcome for the resolver that that the contract diff --git a/contractcourt/htlc_outgoing_contest_resolver_test.go b/contractcourt/htlc_outgoing_contest_resolver_test.go index c68436db..10d8fbc1 100644 --- a/contractcourt/htlc_outgoing_contest_resolver_test.go +++ b/contractcourt/htlc_outgoing_contest_resolver_test.go @@ -11,6 +11,7 @@ import ( "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwire" ) const ( @@ -47,22 +48,43 @@ func TestHtlcOutgoingResolverRemoteClaim(t *testing.T) { // Setup the resolver with our test resolution and start the resolution // process. ctx := newOutgoingResolverTestContext(t) + + // Replace our mocked checkpoint function with one which will push + // reports into a channel for us to consume. We do so on the resolver + // level because our test context has already created the resolver. + reportChan := make(chan *channeldb.ResolverReport) + ctx.resolver.Checkpoint = func(_ ContractResolver, + reports ...*channeldb.ResolverReport) error { + + // Send all of our reports into the channel. + for _, report := range reports { + reportChan <- report + } + + return nil + } + ctx.resolve() // The remote party sweeps the htlc. Notify our resolver of this event. preimage := lntypes.Preimage{} - ctx.notifier.spendChan <- &chainntnfs.SpendDetail{ - SpendingTx: &wire.MsgTx{ - TxIn: []*wire.TxIn{ - { - Witness: [][]byte{ - {0}, {1}, {2}, preimage[:], - }, + spendTx := &wire.MsgTx{ + TxIn: []*wire.TxIn{ + { + Witness: [][]byte{ + {0}, {1}, {2}, preimage[:], }, }, }, } + spendHash := spendTx.TxHash() + + ctx.notifier.spendChan <- &chainntnfs.SpendDetail{ + SpendingTx: spendTx, + SpenderTxHash: &spendHash, + } + // We expect the extracted preimage to be added to the witness beacon. <-ctx.preimageDB.newPreimages @@ -70,6 +92,17 @@ func TestHtlcOutgoingResolverRemoteClaim(t *testing.T) { // circuit. <-ctx.resolutionChan + // Finally, check that we have a report as expected. + expectedReport := &channeldb.ResolverReport{ + OutPoint: wire.OutPoint{}, + Amount: 0, + ResolverType: channeldb.ResolverTypeOutgoingHtlc, + ResolverOutcome: channeldb.ResolverOutcomeClaimed, + SpendTxID: &spendHash, + } + + assertResolverReport(t, reportChan, expectedReport) + // Assert that the resolver finishes without error. ctx.waitForResult(false) } @@ -147,6 +180,7 @@ func newOutgoingResolverTestContext(t *testing.T) *outgoingResolverTestContext { contractResolverKit: *newContractResolverKit(cfg), htlcResolution: outgoingRes, htlc: channeldb.HTLC{ + Amt: lnwire.MilliSatoshi(testHtlcAmount), RHash: testResHash, OnionBlob: testOnionBlob, }, diff --git a/contractcourt/htlc_timeout_resolver.go b/contractcourt/htlc_timeout_resolver.go index 439babc4..83c33435 100644 --- a/contractcourt/htlc_timeout_resolver.go +++ b/contractcourt/htlc_timeout_resolver.go @@ -6,6 +6,7 @@ import ( "io" "github.com/btcsuite/btcd/wire" + "github.com/btcsuite/btcutil" "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" @@ -157,7 +158,19 @@ func (h *htlcTimeoutResolver) claimCleanUp( return nil, err } h.resolved = true - return nil, h.Checkpoint(h) + + // Checkpoint our resolver with a report which reflects the preimage + // claim by the remote party. + amt := btcutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value) + report := &channeldb.ResolverReport{ + OutPoint: h.htlcResolution.ClaimOutpoint, + Amount: amt, + ResolverType: channeldb.ResolverTypeOutgoingHtlc, + ResolverOutcome: channeldb.ResolverOutcomeClaimed, + SpendTxID: commitSpend.SpenderTxHash, + } + + return nil, h.Checkpoint(h, report) } // chainDetailsToWatch returns the output and script which we use to watch for