diff --git a/contractcourt/chain_arbitrator.go b/contractcourt/chain_arbitrator.go index 2d4c37979..d475ef1f1 100644 --- a/contractcourt/chain_arbitrator.go +++ b/contractcourt/chain_arbitrator.go @@ -114,14 +114,15 @@ type ChainArbitratorConfig struct { // returned. IsOurAddress func(btcutil.Address) bool - // IncubateOutput sends either an incoming HTLC, an outgoing HTLC, or + // IncubateOutputs sends either an incoming HTLC, an outgoing HTLC, or // both to the utxo nursery. Once this function returns, the nursery // should have safely persisted the outputs to disk, and should start // the process of incubation. This is used when a resolver wishes to // pass off the output to the nursery as we're only waiting on an // absolute/relative item block. - IncubateOutputs func(wire.OutPoint, *lnwallet.OutgoingHtlcResolution, - *lnwallet.IncomingHtlcResolution, uint32) error + IncubateOutputs func(wire.OutPoint, + fn.Option[lnwallet.OutgoingHtlcResolution], + fn.Option[lnwallet.IncomingHtlcResolution], uint32) error // PreimageDB is a global store of all known pre-images. We'll use this // to decide if we should broadcast a commitment transaction to claim diff --git a/contractcourt/channel_arbitrator_test.go b/contractcourt/channel_arbitrator_test.go index 7bdc75652..6d9ab95e8 100644 --- a/contractcourt/channel_arbitrator_test.go +++ b/contractcourt/channel_arbitrator_test.go @@ -362,8 +362,9 @@ func createTestChannelArbitrator(t *testing.T, log ArbitratorLog, ConfChan: make(chan *chainntnfs.TxConfirmation), }, IncubateOutputs: func(wire.OutPoint, - *lnwallet.OutgoingHtlcResolution, - *lnwallet.IncomingHtlcResolution, uint32) error { + fn.Option[lnwallet.OutgoingHtlcResolution], + fn.Option[lnwallet.IncomingHtlcResolution], + uint32) error { incubateChan <- struct{}{} return nil diff --git a/contractcourt/htlc_success_resolver.go b/contractcourt/htlc_success_resolver.go index fb64faf64..5fb1cc543 100644 --- a/contractcourt/htlc_success_resolver.go +++ b/contractcourt/htlc_success_resolver.go @@ -206,7 +206,8 @@ func (h *htlcSuccessResolver) broadcastSuccessTx() (*wire.OutPoint, error) { h, h.htlc.RHash[:]) err := h.IncubateOutputs( - h.ChanPoint, nil, &h.htlcResolution, + h.ChanPoint, fn.None[lnwallet.OutgoingHtlcResolution](), + fn.Some(h.htlcResolution), h.broadcastHeight, ) if err != nil { diff --git a/contractcourt/htlc_success_resolver_test.go b/contractcourt/htlc_success_resolver_test.go index e18ef3383..39b593e0f 100644 --- a/contractcourt/htlc_success_resolver_test.go +++ b/contractcourt/htlc_success_resolver_test.go @@ -12,6 +12,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/lnmock" @@ -65,8 +66,10 @@ func newHtlcResolverTestContext(t *testing.T, return nil }, Sweeper: newMockSweeper(), - IncubateOutputs: func(wire.OutPoint, *lnwallet.OutgoingHtlcResolution, - *lnwallet.IncomingHtlcResolution, uint32) error { + IncubateOutputs: func(wire.OutPoint, + fn.Option[lnwallet.OutgoingHtlcResolution], + fn.Option[lnwallet.IncomingHtlcResolution], + uint32) error { return nil }, diff --git a/contractcourt/htlc_timeout_resolver.go b/contractcourt/htlc_timeout_resolver.go index c6f98a76d..d99c650c8 100644 --- a/contractcourt/htlc_timeout_resolver.go +++ b/contractcourt/htlc_timeout_resolver.go @@ -545,7 +545,8 @@ func (h *htlcTimeoutResolver) sendSecondLevelTxLegacy() error { h.htlcResolution.ClaimOutpoint) err := h.IncubateOutputs( - h.ChanPoint, &h.htlcResolution, nil, + h.ChanPoint, fn.Some(h.htlcResolution), + fn.None[lnwallet.IncomingHtlcResolution](), h.broadcastHeight, ) if err != nil { diff --git a/contractcourt/htlc_timeout_resolver_test.go b/contractcourt/htlc_timeout_resolver_test.go index f4591281f..1b7bb9243 100644 --- a/contractcourt/htlc_timeout_resolver_test.go +++ b/contractcourt/htlc_timeout_resolver_test.go @@ -14,6 +14,7 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/htlcswitch/hop" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/kvdb" @@ -279,13 +280,14 @@ func TestHtlcTimeoutResolver(t *testing.T) { resolutionChan := make(chan ResolutionMsg, 1) reportChan := make(chan *channeldb.ResolverReport) + //nolint:lll chainCfg := ChannelArbitratorConfig{ ChainArbitratorConfig: ChainArbitratorConfig{ Notifier: notifier, PreimageDB: witnessBeacon, IncubateOutputs: func(wire.OutPoint, - *lnwallet.OutgoingHtlcResolution, - *lnwallet.IncomingHtlcResolution, + fn.Option[lnwallet.OutgoingHtlcResolution], + fn.Option[lnwallet.IncomingHtlcResolution], uint32) error { incubateChan <- struct{}{} diff --git a/contractcourt/utxonursery.go b/contractcourt/utxonursery.go index d823618c8..e558d438d 100644 --- a/contractcourt/utxonursery.go +++ b/contractcourt/utxonursery.go @@ -15,6 +15,7 @@ import ( "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/labels" "github.com/lightningnetwork/lnd/lnwallet" @@ -333,8 +334,8 @@ func (u *UtxoNursery) Stop() error { // they're CLTV absolute time locked, or if they're CSV relative time locked. // Once all outputs reach maturity, they'll be swept back into the wallet. func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, - outgoingHtlcs []lnwallet.OutgoingHtlcResolution, - incomingHtlcs []lnwallet.IncomingHtlcResolution, + outgoingHtlc fn.Option[lnwallet.OutgoingHtlcResolution], + incomingHtlc fn.Option[lnwallet.IncomingHtlcResolution], broadcastHeight uint32) error { // Add to wait group because nursery might shut down during execution of @@ -352,14 +353,13 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, default: } - numHtlcs := len(incomingHtlcs) + len(outgoingHtlcs) var ( // Kid outputs can be swept after an initial confirmation // followed by a maturity period.Baby outputs are two stage and // will need to wait for an absolute time out to reach a // confirmation, then require a relative confirmation delay. - kidOutputs = make([]kidOutput, 0, 1+len(incomingHtlcs)) - babyOutputs = make([]babyOutput, 0, len(outgoingHtlcs)) + kidOutputs = make([]kidOutput, 0) + babyOutputs = make([]babyOutput, 0) ) // 1. Build all the spendable outputs that we will try to incubate. @@ -369,7 +369,7 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, // For each incoming HTLC, we'll register a kid output marked as a // second-layer HTLC output. We effectively skip the baby stage (as the // timelock is zero), and enter the kid stage. - for _, htlcRes := range incomingHtlcs { + incomingHtlc.WhenSome(func(htlcRes lnwallet.IncomingHtlcResolution) { // Based on the input pk script of the sign descriptor, we can // determine if this is a taproot output or not. This'll // determine the witness type we try to set below. @@ -392,13 +392,13 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, if htlcOutput.Amount() > 0 { kidOutputs = append(kidOutputs, htlcOutput) } - } + }) // For each outgoing HTLC, we'll create a baby output. If this is our // commitment transaction, then we'll broadcast a second-layer // transaction to transition to a kid output. Otherwise, we'll directly // spend once the CLTV delay us up. - for _, htlcRes := range outgoingHtlcs { + outgoingHtlc.WhenSome(func(htlcRes lnwallet.OutgoingHtlcResolution) { // If this HTLC is on our commitment transaction, then it'll be // a baby output as we need to go to the second level to sweep // it. @@ -408,7 +408,8 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, if htlcOutput.Amount() > 0 { babyOutputs = append(babyOutputs, htlcOutput) } - continue + + return } // Based on the input pk script of the sign descriptor, we can @@ -435,12 +436,13 @@ func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, witType, &htlcRes.SweepSignDesc, htlcRes.Expiry, ) kidOutputs = append(kidOutputs, htlcOutput) - } + }) // TODO(roasbeef): if want to handle outgoing on remote commit // * need ability to cancel in the case that we learn of pre-image or // remote party pulls + numHtlcs := len(babyOutputs) + len(kidOutputs) utxnLog.Infof("Incubating Channel(%s) num-htlcs=%d", chanPoint, numHtlcs) diff --git a/contractcourt/utxonursery_test.go b/contractcourt/utxonursery_test.go index 59a4de118..e617bbc6f 100644 --- a/contractcourt/utxonursery_test.go +++ b/contractcourt/utxonursery_test.go @@ -16,7 +16,9 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" + "github.com/davecgh/go-spew/spew" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/lntest/mock" "github.com/lightningnetwork/lnd/lnwallet" @@ -627,8 +629,8 @@ func incubateTestOutput(t *testing.T, nursery *UtxoNursery, // Hand off to nursery. err := nursery.IncubateOutputs( testChanPoint, - []lnwallet.OutgoingHtlcResolution{*outgoingRes}, - nil, 0, + fn.Some(*outgoingRes), + fn.None[lnwallet.IncomingHtlcResolution](), 0, ) if err != nil { t.Fatal(err) @@ -709,8 +711,8 @@ func TestRejectedCribTransaction(t *testing.T) { // Hand off to nursery. err := ctx.nursery.IncubateOutputs( testChanPoint, - []lnwallet.OutgoingHtlcResolution{*outgoingRes}, - nil, 0, + fn.Some(*outgoingRes), + fn.None[lnwallet.IncomingHtlcResolution](), 0, ) if test.expectErr { require.ErrorIs(t, err, test.broadcastErr) @@ -758,7 +760,8 @@ func assertNurseryReport(t *testing.T, nursery *UtxoNursery, if len(report.Htlcs) != expectedNofHtlcs { t.Fatalf("expected %v outputs to be reported, but report "+ - "only contains %v", expectedNofHtlcs, len(report.Htlcs)) + "contains %s", expectedNofHtlcs, + spew.Sdump(report.Htlcs)) } if expectedNofHtlcs != 0 { diff --git a/server.go b/server.go index b85505cd4..32aa42a5f 100644 --- a/server.go +++ b/server.go @@ -38,6 +38,7 @@ import ( "github.com/lightningnetwork/lnd/contractcourt" "github.com/lightningnetwork/lnd/discovery" "github.com/lightningnetwork/lnd/feature" + "github.com/lightningnetwork/lnd/fn" "github.com/lightningnetwork/lnd/funding" "github.com/lightningnetwork/lnd/healthcheck" "github.com/lightningnetwork/lnd/htlcswitch" @@ -1148,23 +1149,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr, return nil }, IncubateOutputs: func(chanPoint wire.OutPoint, - outHtlcRes *lnwallet.OutgoingHtlcResolution, - inHtlcRes *lnwallet.IncomingHtlcResolution, + outHtlcRes fn.Option[lnwallet.OutgoingHtlcResolution], + inHtlcRes fn.Option[lnwallet.IncomingHtlcResolution], broadcastHeight uint32) error { - var ( - inRes []lnwallet.IncomingHtlcResolution - outRes []lnwallet.OutgoingHtlcResolution - ) - if inHtlcRes != nil { - inRes = append(inRes, *inHtlcRes) - } - if outHtlcRes != nil { - outRes = append(outRes, *outHtlcRes) - } - return s.utxoNursery.IncubateOutputs( - chanPoint, outRes, inRes, + chanPoint, outHtlcRes, inHtlcRes, broadcastHeight, ) },