diff --git a/contractcourt/briefcase_test.go b/contractcourt/briefcase_test.go index 59f9bd3b..0cccd5a6 100644 --- a/contractcourt/briefcase_test.go +++ b/contractcourt/briefcase_test.go @@ -161,9 +161,9 @@ func assertResolversEqual(t *testing.T, originalResolver ContractResolver, t.Fatalf("expected %v, got %v", ogRes.broadcastHeight, diskRes.broadcastHeight) } - if ogRes.htlcIndex != diskRes.htlcIndex { - t.Fatalf("expected %v, got %v", ogRes.htlcIndex, - diskRes.htlcIndex) + if ogRes.htlc.HtlcIndex != diskRes.htlc.HtlcIndex { + t.Fatalf("expected %v, got %v", ogRes.htlc.HtlcIndex, + diskRes.htlc.HtlcIndex) } } @@ -184,9 +184,9 @@ func assertResolversEqual(t *testing.T, originalResolver ContractResolver, t.Fatalf("expected %v, got %v", ogRes.broadcastHeight, diskRes.broadcastHeight) } - if ogRes.payHash != diskRes.payHash { - t.Fatalf("expected %v, got %v", ogRes.payHash, - diskRes.payHash) + if ogRes.htlc.RHash != diskRes.htlc.RHash { + t.Fatalf("expected %v, got %v", ogRes.htlc.RHash, + diskRes.htlc.RHash) } } @@ -265,7 +265,9 @@ func TestContractInsertionRetrieval(t *testing.T) { outputIncubating: true, resolved: true, broadcastHeight: 102, - htlcIndex: 12, + htlc: channeldb.HTLC{ + HtlcIndex: 12, + }, } successResolver := htlcSuccessResolver{ htlcResolution: lnwallet.IncomingHtlcResolution{ @@ -278,8 +280,10 @@ func TestContractInsertionRetrieval(t *testing.T) { outputIncubating: true, resolved: true, broadcastHeight: 109, - payHash: testPreimage, - sweepTx: nil, + htlc: channeldb.HTLC{ + RHash: testPreimage, + }, + sweepTx: nil, } resolvers := []ContractResolver{ &timeoutResolver, @@ -395,7 +399,9 @@ func TestContractResolution(t *testing.T) { outputIncubating: true, resolved: true, broadcastHeight: 192, - htlcIndex: 9912, + htlc: channeldb.HTLC{ + HtlcIndex: 9912, + }, } // First, we'll insert the resolver into the database and ensure that @@ -454,7 +460,9 @@ func TestContractSwapping(t *testing.T) { outputIncubating: true, resolved: true, broadcastHeight: 102, - htlcIndex: 12, + htlc: channeldb.HTLC{ + HtlcIndex: 12, + }, } contestResolver := &htlcOutgoingContestResolver{ htlcTimeoutResolver: timeoutResolver, diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index e9001d8e..4d6093d2 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -1647,6 +1647,8 @@ func (c *ChannelArbitrator) prepContractResolutions( // claim the HTLC (second-level or directly), then add the pre case HtlcClaimAction: for _, htlc := range htlcs { + htlc := htlc + htlcOp := wire.OutPoint{ Hash: commitHash, Index: uint32(htlc.OutputIndex), @@ -1662,8 +1664,7 @@ func (c *ChannelArbitrator) prepContractResolutions( } resolver := newSuccessResolver( - resolution, height, - htlc.RHash, htlc.Amt, resolverCfg, + resolution, height, htlc, resolverCfg, ) htlcResolvers = append(htlcResolvers, resolver) } @@ -1673,6 +1674,8 @@ func (c *ChannelArbitrator) prepContractResolutions( // backwards. case HtlcTimeoutAction: for _, htlc := range htlcs { + htlc := htlc + htlcOp := wire.OutPoint{ Hash: commitHash, Index: uint32(htlc.OutputIndex), @@ -1686,8 +1689,7 @@ func (c *ChannelArbitrator) prepContractResolutions( } resolver := newTimeoutResolver( - resolution, height, htlc.HtlcIndex, - htlc.Amt, resolverCfg, + resolution, height, htlc, resolverCfg, ) htlcResolvers = append(htlcResolvers, resolver) } @@ -1697,6 +1699,8 @@ func (c *ChannelArbitrator) prepContractResolutions( // learn of the pre-image, or let the remote party time out. case HtlcIncomingWatchAction: for _, htlc := range htlcs { + htlc := htlc + htlcOp := wire.OutPoint{ Hash: commitHash, Index: uint32(htlc.OutputIndex), @@ -1713,15 +1717,9 @@ func (c *ChannelArbitrator) prepContractResolutions( continue } - circuitKey := channeldb.CircuitKey{ - HtlcID: htlc.HtlcIndex, - ChanID: c.cfg.ShortChanID, - } - resolver := newIncomingContestResolver( - htlc.RefundTimeout, circuitKey, - resolution, height, htlc.RHash, - htlc.Amt, resolverCfg, + resolution, height, htlc, + resolverCfg, ) htlcResolvers = append(htlcResolvers, resolver) } @@ -1731,6 +1729,8 @@ func (c *ChannelArbitrator) prepContractResolutions( // backwards), or just timeout. case HtlcOutgoingWatchAction: for _, htlc := range htlcs { + htlc := htlc + htlcOp := wire.OutPoint{ Hash: commitHash, Index: uint32(htlc.OutputIndex), @@ -1745,8 +1745,7 @@ func (c *ChannelArbitrator) prepContractResolutions( } resolver := newOutgoingContestResolver( - resolution, height, htlc.HtlcIndex, - htlc.Amt, resolverCfg, + resolution, height, htlc, resolverCfg, ) htlcResolvers = append(htlcResolvers, resolver) } diff --git a/contractcourt/channel_arbitrator_test.go b/contractcourt/channel_arbitrator_test.go index 85c76479..3e71c1bb 100644 --- a/contractcourt/channel_arbitrator_test.go +++ b/contractcourt/channel_arbitrator_test.go @@ -858,10 +858,10 @@ func TestChannelArbitratorLocalForceClosePendingHtlc(t *testing.T) { resolver) } - // The resolver should have its htlcAmt field populated as it. - if int64(outgoingResolver.htlcAmt) != int64(htlcAmt) { + // The resolver should have its htlc amt field populated as it. + if int64(outgoingResolver.htlc.Amt) != int64(htlcAmt) { t.Fatalf("wrong htlc amount: expected %v, got %v,", - htlcAmt, int64(outgoingResolver.htlcAmt)) + htlcAmt, int64(outgoingResolver.htlc.Amt)) } // htlcOutgoingContestResolver is now active and waiting for the HTLC to diff --git a/contractcourt/htlc_incoming_contest_resolver.go b/contractcourt/htlc_incoming_contest_resolver.go index 84ed63ea..d2bd3f89 100644 --- a/contractcourt/htlc_incoming_contest_resolver.go +++ b/contractcourt/htlc_incoming_contest_resolver.go @@ -10,7 +10,6 @@ import ( "github.com/lightningnetwork/lnd/invoices" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" - "github.com/lightningnetwork/lnd/lnwire" ) // htlcIncomingContestResolver is a ContractResolver that's able to resolve an @@ -27,28 +26,22 @@ type htlcIncomingContestResolver struct { // successfully. htlcExpiry uint32 - // circuitKey describes the incoming htlc that is being resolved. - circuitKey channeldb.CircuitKey - // htlcSuccessResolver is the inner resolver that may be utilized if we // learn of the preimage. htlcSuccessResolver } // newIncomingContestResolver instantiates a new incoming htlc contest resolver. -func newIncomingContestResolver(htlcExpiry uint32, - circuitKey channeldb.CircuitKey, res lnwallet.IncomingHtlcResolution, - broadcastHeight uint32, payHash lntypes.Hash, - htlcAmt lnwire.MilliSatoshi, - resCfg ResolverConfig) *htlcIncomingContestResolver { +func newIncomingContestResolver( + res lnwallet.IncomingHtlcResolution, broadcastHeight uint32, + htlc channeldb.HTLC, resCfg ResolverConfig) *htlcIncomingContestResolver { success := newSuccessResolver( - res, broadcastHeight, payHash, htlcAmt, resCfg, + res, broadcastHeight, htlc, resCfg, ) return &htlcIncomingContestResolver{ - htlcExpiry: htlcExpiry, - circuitKey: circuitKey, + htlcExpiry: htlc.RefundTimeout, htlcSuccessResolver: *success, } } @@ -119,7 +112,7 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) { applyPreimage := func(preimage lntypes.Preimage) error { // Sanity check to see if this preimage matches our htlc. At // this point it should never happen that it does not match. - if !preimage.Matches(h.payHash) { + if !preimage.Matches(h.htlc.RHash) { return errors.New("preimage does not match hash") } @@ -185,9 +178,14 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) { // on-chain. If this HTLC indeed pays to an existing invoice, the // invoice registry will tell us what to do with the HTLC. This is // identical to HTLC resolution in the link. + circuitKey := channeldb.CircuitKey{ + ChanID: h.ShortChanID, + HtlcID: h.htlc.HtlcIndex, + } + event, err := h.Registry.NotifyExitHopHtlc( - h.payHash, h.htlcAmt, h.htlcExpiry, currentHeight, - h.circuitKey, hodlChan, nil, + h.htlc.RHash, h.htlc.Amt, h.htlcExpiry, currentHeight, + circuitKey, hodlChan, nil, ) switch err { case channeldb.ErrInvoiceNotFound: @@ -204,7 +202,7 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) { // With the epochs and preimage subscriptions initialized, we'll query // to see if we already know the preimage. - preimage, ok := h.PreimageDB.LookupPreimage(h.payHash) + preimage, ok := h.PreimageDB.LookupPreimage(h.htlc.RHash) if ok { // If we do, then this means we can claim the HTLC! However, // we don't know how to ourselves, so we'll return our inner @@ -222,7 +220,7 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) { case preimage := <-preimageSubscription.WitnessUpdates: // We receive all new preimages, so we need to ignore // all except the preimage we are waiting for. - if !preimage.Matches(h.payHash) { + if !preimage.Matches(h.htlc.RHash) { continue } @@ -268,7 +266,7 @@ func (h *htlcIncomingContestResolver) Resolve() (ContractResolver, error) { func (h *htlcIncomingContestResolver) report() *ContractReport { // No locking needed as these values are read-only. - finalAmt := h.htlcAmt.ToSatoshis() + finalAmt := h.htlc.Amt.ToSatoshis() if h.htlcResolution.SignedSuccessTx != nil { finalAmt = btcutil.Amount( h.htlcResolution.SignedSuccessTx.TxOut[0].Value, @@ -343,11 +341,7 @@ func newIncomingContestResolverFromReader(r io.Reader, resCfg ResolverConfig) ( // // NOTE: Part of the htlcContractResolver interface. func (h *htlcIncomingContestResolver) Supplement(htlc channeldb.HTLC) { - h.htlcAmt = htlc.Amt - h.circuitKey = channeldb.CircuitKey{ - ChanID: h.ShortChanID, - HtlcID: htlc.HtlcIndex, - } + h.htlc = htlc } // A compile time assertion to ensure htlcIncomingContestResolver meets the diff --git a/contractcourt/htlc_incoming_resolver_test.go b/contractcourt/htlc_incoming_resolver_test.go index 1f28f0a5..04be1583 100644 --- a/contractcourt/htlc_incoming_resolver_test.go +++ b/contractcourt/htlc_incoming_resolver_test.go @@ -210,7 +210,9 @@ func newIncomingResolverTestContext(t *testing.T) *incomingResolverTestContext { htlcSuccessResolver: htlcSuccessResolver{ contractResolverKit: *newContractResolverKit(cfg), htlcResolution: lnwallet.IncomingHtlcResolution{}, - payHash: testResHash, + htlc: channeldb.HTLC{ + RHash: testResHash, + }, }, htlcExpiry: testHtlcExpiry, } diff --git a/contractcourt/htlc_outgoing_contest_resolver.go b/contractcourt/htlc_outgoing_contest_resolver.go index 12146f2f..93a4adfa 100644 --- a/contractcourt/htlc_outgoing_contest_resolver.go +++ b/contractcourt/htlc_outgoing_contest_resolver.go @@ -5,8 +5,8 @@ import ( "io" "github.com/btcsuite/btcutil" + "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwallet" - "github.com/lightningnetwork/lnd/lnwire" ) // htlcOutgoingContestResolver is a ContractResolver that's able to resolve an @@ -23,11 +23,11 @@ type htlcOutgoingContestResolver struct { // newOutgoingContestResolver instantiates a new outgoing contested htlc // resolver. func newOutgoingContestResolver(res lnwallet.OutgoingHtlcResolution, - broadcastHeight uint32, htlcIndex uint64, htlcAmt lnwire.MilliSatoshi, + broadcastHeight uint32, htlc channeldb.HTLC, resCfg ResolverConfig) *htlcOutgoingContestResolver { timeout := newTimeoutResolver( - res, broadcastHeight, htlcIndex, htlcAmt, resCfg, + res, broadcastHeight, htlc, resCfg, ) return &htlcOutgoingContestResolver{ @@ -157,7 +157,7 @@ func (h *htlcOutgoingContestResolver) Resolve() (ContractResolver, error) { func (h *htlcOutgoingContestResolver) report() *ContractReport { // No locking needed as these values are read-only. - finalAmt := h.htlcAmt.ToSatoshis() + finalAmt := h.htlc.Amt.ToSatoshis() if h.htlcResolution.SignedTimeoutTx != nil { finalAmt = btcutil.Amount( h.htlcResolution.SignedTimeoutTx.TxOut[0].Value, diff --git a/contractcourt/htlc_success_resolver.go b/contractcourt/htlc_success_resolver.go index 01244010..73d37063 100644 --- a/contractcourt/htlc_success_resolver.go +++ b/contractcourt/htlc_success_resolver.go @@ -8,9 +8,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/input" - "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet" - "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/sweep" ) @@ -39,9 +37,6 @@ type htlcSuccessResolver struct { // historical queries to the chain for spends/confirmations. broadcastHeight uint32 - // payHash is the payment hash of the original HTLC extended to us. - payHash lntypes.Hash - // sweepTx will be non-nil if we've already crafted a transaction to // sweep a direct HTLC output. This is only a concern if we're sweeping // from the commitment transaction of the remote party. @@ -49,25 +44,22 @@ type htlcSuccessResolver struct { // TODO(roasbeef): send off to utxobundler sweepTx *wire.MsgTx - // htlcAmt is the original amount of the htlc, not taking into - // account any fees that may have to be paid if it goes on chain. - htlcAmt lnwire.MilliSatoshi + // htlc contains information on the htlc that we are resolving on-chain. + htlc channeldb.HTLC contractResolverKit } // newSuccessResolver instanties a new htlc success resolver. func newSuccessResolver(res lnwallet.IncomingHtlcResolution, - broadcastHeight uint32, payHash lntypes.Hash, - htlcAmt lnwire.MilliSatoshi, + broadcastHeight uint32, htlc channeldb.HTLC, resCfg ResolverConfig) *htlcSuccessResolver { return &htlcSuccessResolver{ contractResolverKit: *newContractResolverKit(resCfg), htlcResolution: res, broadcastHeight: broadcastHeight, - payHash: payHash, - htlcAmt: htlcAmt, + htlc: htlc, } } @@ -115,7 +107,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { if h.sweepTx == nil { log.Infof("%T(%x): crafting sweep tx for "+ "incoming+remote htlc confirmed", h, - h.payHash[:]) + h.htlc.RHash[:]) // Before we can craft out sweeping transaction, we // need to create an input which contains all the items @@ -149,7 +141,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { } log.Infof("%T(%x): crafted sweep tx=%v", h, - h.payHash[:], spew.Sdump(h.sweepTx)) + h.htlc.RHash[:], spew.Sdump(h.sweepTx)) // With the sweep transaction signed, we'll now // Checkpoint our state. @@ -165,7 +157,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { err := h.PublishTx(h.sweepTx) if err != nil { log.Infof("%T(%x): unable to publish tx: %v", - h, h.payHash[:], err) + h, h.htlc.RHash[:], err) return nil, err } @@ -181,7 +173,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { } log.Infof("%T(%x): waiting for sweep tx (txid=%v) to be "+ - "confirmed", h, h.payHash[:], sweepTXID) + "confirmed", h, h.htlc.RHash[:], sweepTXID) select { case _, ok := <-confNtfn.Confirmed: @@ -200,7 +192,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { } log.Infof("%T(%x): broadcasting second-layer transition tx: %v", - h, h.payHash[:], spew.Sdump(h.htlcResolution.SignedSuccessTx)) + h, h.htlc.RHash[:], spew.Sdump(h.htlcResolution.SignedSuccessTx)) // We'll now broadcast the second layer transaction so we can kick off // the claiming process. @@ -216,7 +208,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { // done so. if !h.outputIncubating { log.Infof("%T(%x): incubating incoming htlc output", - h, h.payHash[:]) + h, h.htlc.RHash[:]) err := h.IncubateOutputs( h.ChanPoint, nil, nil, &h.htlcResolution, @@ -246,7 +238,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { } log.Infof("%T(%x): waiting for second-level HTLC output to be spent "+ - "after csv_delay=%v", h, h.payHash[:], h.htlcResolution.CsvDelay) + "after csv_delay=%v", h, h.htlc.RHash[:], h.htlcResolution.CsvDelay) select { case _, ok := <-spendNtfn.Spend: @@ -299,7 +291,7 @@ func (h *htlcSuccessResolver) Encode(w io.Writer) error { if err := binary.Write(w, endian, h.broadcastHeight); err != nil { return err } - if _, err := w.Write(h.payHash[:]); err != nil { + if _, err := w.Write(h.htlc.RHash[:]); err != nil { return err } @@ -332,7 +324,7 @@ func newSuccessResolverFromReader(r io.Reader, resCfg ResolverConfig) ( if err := binary.Read(r, endian, &h.broadcastHeight); err != nil { return nil, err } - if _, err := io.ReadFull(r, h.payHash[:]); err != nil { + if _, err := io.ReadFull(r, h.htlc.RHash[:]); err != nil { return nil, err } @@ -344,7 +336,7 @@ func newSuccessResolverFromReader(r io.Reader, resCfg ResolverConfig) ( // // NOTE: Part of the htlcContractResolver interface. func (h *htlcSuccessResolver) Supplement(htlc channeldb.HTLC) { - h.htlcAmt = htlc.Amt + h.htlc = htlc } // HtlcPoint returns the htlc's outpoint on the commitment tx. diff --git a/contractcourt/htlc_timeout_resolver.go b/contractcourt/htlc_timeout_resolver.go index f36e8292..2469f531 100644 --- a/contractcourt/htlc_timeout_resolver.go +++ b/contractcourt/htlc_timeout_resolver.go @@ -41,29 +41,22 @@ type htlcTimeoutResolver struct { // TODO(roasbeef): wrap above into definite resolution embedding? broadcastHeight uint32 - // htlcIndex is the index of this HTLC within the trace of the - // additional commitment state machine. - htlcIndex uint64 - - // htlcAmt is the original amount of the htlc, not taking into - // account any fees that may have to be paid if it goes on chain. - htlcAmt lnwire.MilliSatoshi + // htlc contains information on the htlc that we are resolving on-chain. + htlc channeldb.HTLC contractResolverKit } // newTimeoutResolver instantiates a new timeout htlc resolver. func newTimeoutResolver(res lnwallet.OutgoingHtlcResolution, - broadcastHeight uint32, htlcIndex uint64, - htlcAmt lnwire.MilliSatoshi, + broadcastHeight uint32, htlc channeldb.HTLC, resCfg ResolverConfig) *htlcTimeoutResolver { return &htlcTimeoutResolver{ contractResolverKit: *newContractResolverKit(resCfg), htlcResolution: res, broadcastHeight: broadcastHeight, - htlcIndex: htlcIndex, - htlcAmt: htlcAmt, + htlc: htlc, } } @@ -158,7 +151,7 @@ func (h *htlcTimeoutResolver) claimCleanUp( // resolved, then exit. if err := h.DeliverResolutionMsg(ResolutionMsg{ SourceChan: h.ShortChanID, - HtlcIndex: h.htlcIndex, + HtlcIndex: h.htlc.HtlcIndex, PreImage: &pre, }); err != nil { return nil, err @@ -353,7 +346,7 @@ func (h *htlcTimeoutResolver) Resolve() (ContractResolver, error) { failureMsg := &lnwire.FailPermanentChannelFailure{} if err := h.DeliverResolutionMsg(ResolutionMsg{ SourceChan: h.ShortChanID, - HtlcIndex: h.htlcIndex, + HtlcIndex: h.htlc.HtlcIndex, Failure: failureMsg, }); err != nil { return nil, err @@ -415,7 +408,7 @@ func (h *htlcTimeoutResolver) Encode(w io.Writer) error { return err } - if err := binary.Write(w, endian, h.htlcIndex); err != nil { + if err := binary.Write(w, endian, h.htlc.HtlcIndex); err != nil { return err } @@ -450,7 +443,7 @@ func newTimeoutResolverFromReader(r io.Reader, resCfg ResolverConfig) ( return nil, err } - if err := binary.Read(r, endian, &h.htlcIndex); err != nil { + if err := binary.Read(r, endian, &h.htlc.HtlcIndex); err != nil { return nil, err } @@ -462,7 +455,7 @@ func newTimeoutResolverFromReader(r io.Reader, resCfg ResolverConfig) ( // // NOTE: Part of the htlcContractResolver interface. func (h *htlcTimeoutResolver) Supplement(htlc channeldb.HTLC) { - h.htlcAmt = htlc.Amt + h.htlc = htlc } // HtlcPoint returns the htlc's outpoint on the commitment tx.