diff --git a/itest/lnd_channel_backup_test.go b/itest/lnd_channel_backup_test.go index d3daeb1df..f4911a95f 100644 --- a/itest/lnd_channel_backup_test.go +++ b/itest/lnd_channel_backup_test.go @@ -193,7 +193,8 @@ func newChanRestoreScenario(ht *lntest.HarnessTest, ct lnrpc.CommitmentType, // If the commitment type is taproot, then the channel must also be // private. var privateChan bool - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT || + ct == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { privateChan = true } @@ -639,7 +640,8 @@ func runChanRestoreScenarioCommitTypes(ht *lntest.HarnessTest, // If this was a zero conf taproot channel, then since it's private, // we'll need to mine an extra block (framework won't mine extra blocks // otherwise). - if ct == lnrpc.CommitmentType_SIMPLE_TAPROOT && zeroConf { + if (ct == lnrpc.CommitmentType_SIMPLE_TAPROOT || + ct == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL) && zeroConf { ht.MineBlocksAndAssertNumTxes(1, 1) } diff --git a/itest/lnd_channel_force_close_test.go b/itest/lnd_channel_force_close_test.go index 3cb6d30e4..60e2a61d1 100644 --- a/itest/lnd_channel_force_close_test.go +++ b/itest/lnd_channel_force_close_test.go @@ -26,6 +26,10 @@ var channelForceCloseTestCases = []*lntest.TestCase{ Name: "simple taproot", TestFunc: testChannelForceClosureSimpleTaproot, }, + { + Name: "simple taproot final", + TestFunc: testChannelForceClosureSimpleTaprootFinal, + }, { Name: "anchor restart", TestFunc: testChannelForceClosureAnchorRestart, @@ -34,6 +38,10 @@ var channelForceCloseTestCases = []*lntest.TestCase{ Name: "simple taproot restart", TestFunc: testChannelForceClosureSimpleTaprootRestart, }, + { + Name: "simple taproot final restart", + TestFunc: testChannelForceClosureSimpleTaprootFinalRestart, + }, { Name: "wrong preimage", @@ -87,6 +95,31 @@ func testChannelForceClosureSimpleTaproot(ht *lntest.HarnessTest) { runChannelForceClosureTest(ht, cfgs, openChannelParams) } +// testChannelForceClosureSimpleTaprootFinal runs `runChannelForceClosureTest` +// with production simple taproot channels. +func testChannelForceClosureSimpleTaprootFinal(ht *lntest.HarnessTest) { + // Create a simple network: Alice -> Carol, using production simple + // taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + // If the channel is a taproot channel, then we'll need to + // create a private channel. + // + // TODO(roasbeef): lift after G175 + CommitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfgCarol} + + runChannelForceClosureTest(ht, cfgs, openChannelParams) +} + // runChannelForceClosureTest performs a test to exercise the behavior of // "force" closing a channel or unilaterally broadcasting the latest local // commitment state on-chain. The test creates a new channel between Alice and @@ -675,6 +708,31 @@ func testChannelForceClosureSimpleTaprootRestart(ht *lntest.HarnessTest) { runChannelForceClosureTestRestart(ht, cfgs, openChannelParams) } +// testChannelForceClosureSimpleTaprootFinalRestart runs +// `runChannelForceClosureTestRestart` with production simple taproot channels. +func testChannelForceClosureSimpleTaprootFinalRestart(ht *lntest.HarnessTest) { + // Create a simple network: Alice -> Carol, using production simple + // taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + PushAmt: pushAmt, + // If the channel is a taproot channel, then we'll need to + // create a private channel. + // + // TODO(roasbeef): lift after G175 + CommitmentType: lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfgCarol} + + runChannelForceClosureTestRestart(ht, cfgs, openChannelParams) +} + // runChannelForceClosureTestRestart performs a test to exercise the behavior of // "force" closing a channel or unilaterally broadcasting the latest local // commitment state on-chain. The test creates a new channel between Alice and diff --git a/itest/lnd_funding_test.go b/itest/lnd_funding_test.go index 2c1daf53d..04f779859 100644 --- a/itest/lnd_funding_test.go +++ b/itest/lnd_funding_test.go @@ -33,6 +33,10 @@ var basicFundingTestCases = []*lntest.TestCase{ Name: "basic flow simple taproot", TestFunc: testBasicChannelFundingSimpleTaproot, }, + { + Name: "basic flow simple taproot final", + TestFunc: testBasicChannelFundingSimpleTaprootFinal, + }, } // allFundingTypes defines the channel types to test for the basic funding @@ -41,6 +45,7 @@ var allFundingTypes = []lnrpc.CommitmentType{ lnrpc.CommitmentType_STATIC_REMOTE_KEY, lnrpc.CommitmentType_ANCHORS, lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } // testBasicChannelFundingStaticRemote performs a test exercising expected @@ -130,6 +135,35 @@ func testBasicChannelFundingSimpleTaproot(ht *lntest.HarnessTest) { } } +// testBasicChannelFundingSimpleTaprootFinal performs a test exercising expected +// behavior from a basic funding workflow. The test creates a new channel +// between Carol and Dave, with Carol using the production simple taproot +// commitment type, and Dave using allFundingTypes. +func testBasicChannelFundingSimpleTaprootFinal(ht *lntest.HarnessTest) { + carolCommitType := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // We'll test all possible combinations of the feature bit presence + // that both nodes can signal for this new channel type. We'll make a + // new Carol+Dave for each test instance as well. + for _, daveCommitType := range allFundingTypes { + cc := carolCommitType + dc := daveCommitType + + testName := fmt.Sprintf( + "carol_commit=%v,dave_commit=%v", cc, dc, + ) + + success := ht.Run(testName, func(t *testing.T) { + st := ht.Subtest(t) + runBasicFundingTest(st, cc, dc) + }) + + if !success { + break + } + } +} + // runBasicFundingTest is a helper function that takes Carol and Dave's // commitment types and test the funding flow. func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, @@ -158,14 +192,17 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, // private, otherwise it'll be rejected by Dave. // // TODO(roasbeef): lift after gossip 1.75 - if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { privateChan = true } - // If carol wants taproot, but dave wants something else, then we'll - // assert that the channel negotiation attempt fails. + // If carol wants taproot, but dave wants something else (excluding + // SIMPLE_TAPROOT_FINAL which is allowed via cross-type negotiation), + // then we'll assert that the channel negotiation attempt fails. if carolCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT && - daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT { + daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT && + daveCommitType != lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { expectedErr := fmt.Errorf("requested channel type " + "not supported") @@ -181,6 +218,12 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, return } + // NOTE: With both staging and final feature bits advertised by default, + // cross-type negotiation (e.g., Carol wants FINAL, Dave prefers + // STAGING) will succeed because explicit channel_type takes precedence. + // The channel will be created with Carol's requested type (FINAL) since + // Dave advertises support for it. + carolChan, daveChan := basicChannelFundingTest( ht, carol, dave, nil, privateChan, &carolCommitType, ) @@ -196,6 +239,9 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, expType := carolCommitType switch daveCommitType { + // Dave supports production taproot, type will be what Carol supports. + case lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + // Dave supports taproot, type will be what Carol supports. case lnrpc.CommitmentType_SIMPLE_TAPROOT: @@ -206,6 +252,9 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, if expType == lnrpc.CommitmentType_SIMPLE_TAPROOT { expType = lnrpc.CommitmentType_ANCHORS } + if expType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { + expType = lnrpc.CommitmentType_ANCHORS + } // Dave only supports tweakless, channel will be downgraded to this // type if Carol supports anchors. @@ -215,6 +264,8 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY case lnrpc.CommitmentType_SIMPLE_TAPROOT: expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY + case lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + expType = lnrpc.CommitmentType_STATIC_REMOTE_KEY } // Dave only supports legacy type, channel will be downgraded to this @@ -240,6 +291,9 @@ func runBasicFundingTest(ht *lntest.HarnessTest, carolCommitType, case expType == lnrpc.CommitmentType_SIMPLE_TAPROOT && chansCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT: + case expType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL && + chansCommitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + default: ht.Fatalf("expected nodes to signal commit type %v, instead "+ "got %v", expType, chansCommitType) @@ -289,10 +343,13 @@ func basicChannelFundingTest(ht *lntest.HarnessTest, // explicit commitment type. This allows us to continue supporting the // existing min version comparison for implicit negotiation. var commitTypeParam lnrpc.CommitmentType - if commitType != nil && - *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if commitType != nil { + switch *commitType { + case lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: - commitTypeParam = *commitType + commitTypeParam = *commitType + } } // First establish a channel with a capacity of 0.5 BTC between Alice @@ -834,9 +891,38 @@ func runExternalFundingTaproot(ht *lntest.HarnessTest) { // HTLCs. ht.AssertInvoiceSettled(dave, resp.PaymentAddr) + // Mine past the thaw height so the channel can be cooperatively + // closed. With RBF cooperative close (auto-enabled for taproot + // channels), both sides enforce the thaw height check during + // shutdown negotiation. + ht.MineBlocks(int(thawHeight)) + // Next we'll try but this time with Dave (the responder) as the - // initiator. This time the channel should be closed as normal. - ht.CloseChannel(dave, chanPoint2) + // initiator. With RBF close auto-enabled for taproot channels, + // both sides create competing closing txs. Only one makes it + // to the mempool (the other is rejected as a same-fee RBF). + // We skip the mempool check since the local tx may not be the + // one that made it in. + closeStream, _ := ht.CloseChannelAssertPending( + dave, chanPoint2, false, + lntest.WithSkipMempoolCheck(), + ) + + // Mine a block to confirm whichever closing tx is in the mempool. + ht.MineBlocksAndAssertNumTxes(1, 1) + + // Consume updates until we get the final ChanClose event. The + // RBF close protocol may send multiple ClosePending updates + // (one per side's closing tx proposal) before the final close. + for { + event, err := ht.ReceiveCloseChannelUpdate(closeStream) + require.NoError(ht, err) + + //nolint:ll + if _, ok := event.Update.(*lnrpc.CloseStatusUpdate_ChanClose); ok { + break + } + } // Let's make sure we can abandon it. carol.RPC.AbandonChannel(&lnrpc.AbandonChannelRequest{ diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index 02da2e5fd..7e87089de 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -47,6 +47,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local claim outgoing htlc simple taproot zero conf", TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootZeroConf, }, + { + Name: "local claim outgoing htlc simple taproot final", + TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootFinal, + }, + { + Name: "local claim outgoing htlc simple taproot final zero conf", + TestFunc: testLocalClaimOutgoingHTLCSimpleTaprootFinalZeroConf, + }, { Name: "local claim outgoing htlc leased", TestFunc: testLocalClaimOutgoingHTLCLeased, @@ -71,6 +79,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "receiver preimage claim simple taproot zero conf", TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf, }, + { + Name: "receiver preimage claim simple taproot final", + TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootFinal, + }, + { + Name: "receiver preimage claim simple taproot final zero conf", + TestFunc: testMultiHopReceiverPreimageClaimSimpleTaprootFinalZeroConf, + }, { Name: "receiver preimage claim leased", TestFunc: testMultiHopReceiverPreimageClaimLeased, @@ -95,6 +111,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local force close before timeout simple taproot zero conf", TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf, }, + { + Name: "local force close before timeout simple taproot final", + TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootFinal, + }, + { + Name: "local force close before timeout simple taproot final zero conf", + TestFunc: testLocalForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf, + }, { Name: "local force close before timeout leased", TestFunc: testLocalForceCloseBeforeTimeoutLeased, @@ -119,6 +143,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "remote force close before timeout simple taproot zero conf", TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootZeroConf, }, + { + Name: "remote force close before timeout simple taproot final", + TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootFinal, + }, + { + Name: "remote force close before timeout simple taproot final zero conf", + TestFunc: testRemoteForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf, + }, { Name: "remote force close before timeout leased", TestFunc: testRemoteForceCloseBeforeTimeoutLeased, @@ -143,6 +175,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local claim incoming htlc simple taproot zero conf", TestFunc: testLocalClaimIncomingHTLCSimpleTaprootZeroConf, }, + { + Name: "local claim incoming htlc simple taproot final", + TestFunc: testLocalClaimIncomingHTLCSimpleTaprootFinal, + }, + { + Name: "local claim incoming htlc simple taproot final zero conf", + TestFunc: testLocalClaimIncomingHTLCSimpleTaprootFinalZeroConf, + }, { Name: "local claim incoming htlc leased", TestFunc: testLocalClaimIncomingHTLCLeased, @@ -167,6 +207,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "local preimage claim simple taproot zero conf", TestFunc: testLocalPreimageClaimSimpleTaprootZeroConf, }, + { + Name: "local preimage claim simple taproot final", + TestFunc: testLocalPreimageClaimSimpleTaprootFinal, + }, + { + Name: "local preimage claim simple taproot final zero conf", + TestFunc: testLocalPreimageClaimSimpleTaprootFinalZeroConf, + }, { Name: "local preimage claim leased", TestFunc: testLocalPreimageClaimLeased, @@ -191,6 +239,14 @@ var multiHopForceCloseTestCases = []*lntest.TestCase{ Name: "htlc aggregation simple taproot zero conf", TestFunc: testHtlcAggregaitonSimpleTaprootZeroConf, }, + { + Name: "htlc aggregation simple taproot final", + TestFunc: testHtlcAggregationSimpleTaprootFinal, + }, + { + Name: "htlc aggregation simple taproot final zero conf", + TestFunc: testHtlcAggregationSimpleTaprootFinalZeroConf, + }, { Name: "htlc aggregation leased", TestFunc: testHtlcAggregaitonLeased, @@ -285,6 +341,53 @@ func testLocalClaimOutgoingHTLCSimpleTaprootZeroConf(ht *lntest.HarnessTest) { runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) } +// testLocalClaimOutgoingHTLCSimpleTaprootFinal tests +// `runLocalClaimOutgoingHTLC` with production simple taproot channel. +func testLocalClaimOutgoingHTLCSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} + +// testLocalClaimOutgoingHTLCSimpleTaprootFinalZeroConf tests +// `runLocalClaimOutgoingHTLC` with zero-conf production simple taproot channel. +func testLocalClaimOutgoingHTLCSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalClaimOutgoingHTLC(ht, cfgs, openChannelParams) +} + // testLocalClaimOutgoingHTLCLeased tests `runLocalClaimOutgoingHTLC` with // script enforced lease channel. func testLocalClaimOutgoingHTLCLeased(ht *lntest.HarnessTest) { @@ -361,7 +464,8 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -623,6 +727,55 @@ func testMultiHopReceiverPreimageClaimSimpleTaprootZeroConf( runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) } +// testMultiHopReceiverPreimageClaimSimpleTaprootFinal tests +// `runMultiHopReceiverPreimageClaim` with production simple taproot channels. +func testMultiHopReceiverPreimageClaimSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} + +// testMultiHopReceiverPreimageClaimSimpleTaprootFinalZeroConf tests +// `runMultiHopReceiverPreimageClaim` with zero-conf production simple taproot +// channels. +func testMultiHopReceiverPreimageClaimSimpleTaprootFinalZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + openChannelParams := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased + // channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runMultiHopReceiverPreimageClaim(ht, cfgs, openChannelParams) +} + // testMultiHopReceiverPreimageClaimLeased tests // `runMultiHopReceiverPreimageClaim` with script enforce lease channels. func testMultiHopReceiverPreimageClaimLeased(ht *lntest.HarnessTest) { @@ -697,7 +850,8 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -978,6 +1132,56 @@ func testLocalForceCloseBeforeTimeoutSimpleTaprootZeroConf( runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) } +// testLocalForceCloseBeforeTimeoutSimpleTaprootFinal tests +// `runLocalForceCloseBeforeHtlcTimeout` with production simple taproot channel. +func testLocalForceCloseBeforeTimeoutSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + +// testLocalForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf tests +// `runLocalForceCloseBeforeHtlcTimeout` with zero-conf production simple +// taproot channel. +func testLocalForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runLocalForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + // testLocalForceCloseBeforeTimeoutLeased tests // `runLocalForceCloseBeforeHtlcTimeout` with script enforced lease channel. func testLocalForceCloseBeforeTimeoutLeased(ht *lntest.HarnessTest) { @@ -1047,7 +1251,8 @@ func runLocalForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -1317,6 +1522,56 @@ func testRemoteForceCloseBeforeTimeoutSimpleTaproot(ht *lntest.HarnessTest) { runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) } +// testRemoteForceCloseBeforeTimeoutSimpleTaprootFinal tests +// `runRemoteForceCloseBeforeHtlcTimeout` with production simple taproot channel. +func testRemoteForceCloseBeforeTimeoutSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + +// testRemoteForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf tests +// `runRemoteForceCloseBeforeHtlcTimeout` with zero-conf production simple +// taproot channel. +func testRemoteForceCloseBeforeTimeoutSimpleTaprootFinalZeroConf( + ht *lntest.HarnessTest) { + + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgCarol := append([]string{"--hodl.exit-settle"}, cfg...) + cfgs := [][]string{cfg, cfg, cfgCarol} + + runRemoteForceCloseBeforeHtlcTimeout(ht, cfgs, params) +} + // testRemoteForceCloseBeforeTimeoutLeasedZeroConf tests // `runRemoteForceCloseBeforeHtlcTimeout` with zero-conf script enforced lease // channel. @@ -1383,7 +1638,8 @@ func runRemoteForceCloseBeforeHtlcTimeout(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -1614,6 +1870,52 @@ func testLocalClaimIncomingHTLCSimpleTaproot(ht *lntest.HarnessTest) { runLocalClaimIncomingHTLC(ht, cfgs, params) } +// testLocalClaimIncomingHTLCSimpleTaprootFinal tests +// `runLocalClaimIncomingHTLC` with production simple taproot channel. +func testLocalClaimIncomingHTLCSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runLocalClaimIncomingHTLC(ht, cfgs, params) +} + +// testLocalClaimIncomingHTLCSimpleTaprootFinalZeroConf tests +// `runLocalClaimIncomingHTLC` with zero-conf production simple taproot channel. +func testLocalClaimIncomingHTLCSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and simple taproot + // channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runLocalClaimIncomingHTLC(ht, cfgs, params) +} + // runLocalClaimIncomingHTLC tests that in a multi-hop HTLC scenario, if we // force close a channel with an incoming HTLC, and later find out the preimage // via the witness beacon, we properly settle the HTLC on-chain using the HTLC @@ -1639,7 +1941,8 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -2242,6 +2545,51 @@ func testLocalPreimageClaimSimpleTaproot(ht *lntest.HarnessTest) { runLocalPreimageClaim(ht, cfgs, params) } +// testLocalPreimageClaimSimpleTaprootFinal tests `runLocalPreimageClaim` with +// production simple taproot channel. +func testLocalPreimageClaimSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runLocalPreimageClaim(ht, cfgs, params) +} + +// testLocalPreimageClaimSimpleTaprootFinalZeroConf tests +// `runLocalPreimageClaim` with zero-conf production simple taproot channel. +func testLocalPreimageClaimSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runLocalPreimageClaim(ht, cfgs, params) +} + // runLocalPreimageClaim tests that in the multi-hop HTLC scenario, if the // remote party goes to chain while we have an incoming HTLC, then when we // found out the preimage via the witness beacon, we properly settle the HTLC @@ -2268,7 +2616,8 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest, // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. var routeHints []*lnrpc.RouteHint - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { routeHints = makeRouteHints(bob, carol, params.ZeroConf) } @@ -2814,6 +3163,51 @@ func testHtlcAggregaitonSimpleTaproot(ht *lntest.HarnessTest) { runHtlcAggregation(ht, cfgs, params) } +// testHtlcAggregationSimpleTaprootFinal tests `runHtlcAggregation` with +// production simple taproot channel. +func testHtlcAggregationSimpleTaprootFinal(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using production + // simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + Private: true, + } + + cfg := node.CfgSimpleTaproot + cfgs := [][]string{cfg, cfg, cfg} + + runHtlcAggregation(ht, cfgs, params) +} + +// testHtlcAggregationSimpleTaprootFinalZeroConf tests `runHtlcAggregation` +// with zero-conf production simple taproot channel. +func testHtlcAggregationSimpleTaprootFinalZeroConf(ht *lntest.HarnessTest) { + c := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + // Create a three hop network: Alice -> Bob -> Carol, using zero-conf + // production simple taproot channels. + // + // Prepare params. + params := lntest.OpenChannelParams{ + Amt: chanAmt, + ZeroConf: true, + CommitmentType: c, + Private: true, + } + + // Prepare Carol's node config to enable zero-conf and leased channel. + cfg := node.CfgSimpleTaproot + cfg = append(cfg, node.CfgZeroConf...) + cfgs := [][]string{cfg, cfg, cfg} + + runHtlcAggregation(ht, cfgs, params) +} + // testHtlcAggregaitonLeasedZeroConf tests `runHtlcAggregation` with zero-conf // script enforced lease channel. func testHtlcAggregaitonLeasedZeroConf(ht *lntest.HarnessTest) { @@ -2884,7 +3278,8 @@ func runHtlcAggregation(ht *lntest.HarnessTest, aliceRouteHints []*lnrpc.RouteHint ) - if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + params.CommitmentType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { carolRouteHints = makeRouteHints(bob, carol, params.ZeroConf) aliceRouteHints = makeRouteHints(bob, alice, params.ZeroConf) } diff --git a/itest/lnd_payment_test.go b/itest/lnd_payment_test.go index f683cd44a..06c6745ab 100644 --- a/itest/lnd_payment_test.go +++ b/itest/lnd_payment_test.go @@ -709,7 +709,8 @@ func runAsyncPayments(ht *lntest.HarnessTest, alice, bob *node.HarnessNode, if commitType != nil { chanArgs.CommitmentType = *commitType - if *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { chanArgs.Private = true } } diff --git a/itest/lnd_psbt_test.go b/itest/lnd_psbt_test.go index 758aec23b..1dd9dea4a 100644 --- a/itest/lnd_psbt_test.go +++ b/itest/lnd_psbt_test.go @@ -145,7 +145,8 @@ func runPsbtChanFundingWithNodes(ht *lntest.HarnessTest, carol, // If this is a taproot channel, then we'll decode the PSBT to assert // that an internal key is included. - if commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { decodedPSBT, err := psbt.NewFromRawBytes( bytes.NewReader(tempPsbt), false, ) diff --git a/itest/lnd_remote_signer_test.go b/itest/lnd_remote_signer_test.go index eac22828b..5d4545573 100644 --- a/itest/lnd_remote_signer_test.go +++ b/itest/lnd_remote_signer_test.go @@ -47,6 +47,10 @@ var remoteSignerTestCases = []*lntest.TestCase{ Name: "funding async payments taproot", TestFunc: testRemoteSignerAsyncPaymentsTaproot, }, + { + Name: "funding async payments taproot final", + TestFunc: testRemoteSignerAsyncPaymentsTaprootFinal, + }, { Name: "shared key", TestFunc: testRemoteSignerSharedKey, @@ -154,7 +158,8 @@ func prepareRemoteSignerTest(ht *lntest.HarnessTest, tc remoteSignerTestCase) ( } var commitArgs []string - if tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT { + if tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + tc.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL { commitArgs = lntest.NodeArgsForCommitType( tc.commitType, ) @@ -307,6 +312,24 @@ func testRemoteSignerAsyncPaymentsTaproot(ht *lntest.HarnessTest) { tc.fn(ht, watchOnly, carol) } +func testRemoteSignerAsyncPaymentsTaprootFinal(ht *lntest.HarnessTest) { + tc := remoteSignerTestCase{ + name: "async payments taproot final", + sendCoins: true, + fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) { + commitType := lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL + + runAsyncPayments( + tt, wo, carol, &commitType, + ) + }, + commitType: lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, + } + + _, watchOnly, carol := prepareRemoteSignerTest(ht, tc) + tc.fn(ht, watchOnly, carol) +} + func testRemoteSignerSharedKey(ht *lntest.HarnessTest) { tc := remoteSignerTestCase{ name: "shared key", diff --git a/itest/lnd_revocation_test.go b/itest/lnd_revocation_test.go index 54d718f28..304227444 100644 --- a/itest/lnd_revocation_test.go +++ b/itest/lnd_revocation_test.go @@ -52,7 +52,8 @@ func breachRetributionTestCase(ht *lntest.HarnessTest, // In order to test Carol's response to an uncooperative channel // closure by Bob, we'll first open up a channel between them with a // 0.5 BTC value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT + privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL chanPoint := ht.OpenChannel( carol, bob, lntest.OpenChannelParams{ CommitmentType: commitType, @@ -198,6 +199,7 @@ func breachRetributionTestCase(ht *lntest.HarnessTest, func testRevokedCloseRetribution(ht *lntest.HarnessTest) { for _, commitType := range []lnrpc.CommitmentType{ lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } { testName := fmt.Sprintf("%v", commitType.String()) ht.Run(testName, func(t *testing.T) { @@ -248,7 +250,8 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest, // In order to test Dave's response to an uncooperative channel // closure by Carol, we'll first open up a channel between them with a // 0.5 BTC value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT + privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL chanPoint := ht.OpenChannel( dave, carol, lntest.OpenChannelParams{ CommitmentType: commitType, @@ -381,6 +384,7 @@ func revokedCloseRetributionZeroValueRemoteOutputCase(ht *lntest.HarnessTest, func testRevokedCloseRetributionZeroValueRemoteOutput(ht *lntest.HarnessTest) { for _, commitType := range []lnrpc.CommitmentType{ lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } { testName := fmt.Sprintf("%v", commitType.String()) ht.Run(testName, func(t *testing.T) { @@ -435,7 +439,8 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, // In order to test Dave's response to an uncooperative channel closure // by Carol, we'll first open up a channel between them with a // funding.MaxBtcFundingAmount (2^24) satoshis value. - privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT + privateChan := commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL chanPoint := ht.OpenChannel( dave, carol, lntest.OpenChannelParams{ Amt: chanAmt, @@ -704,6 +709,7 @@ func revokedCloseRetributionRemoteHodlCase(ht *lntest.HarnessTest, func testRevokedCloseRetributionRemoteHodl(ht *lntest.HarnessTest) { for _, commitType := range []lnrpc.CommitmentType{ lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL, } { testName := fmt.Sprintf("%v", commitType.String()) ht.Run(testName, func(t *testing.T) { diff --git a/lntest/harness.go b/lntest/harness.go index c848a7b71..08c62a984 100644 --- a/lntest/harness.go +++ b/lntest/harness.go @@ -1730,7 +1730,9 @@ func (h *HarnessTest) OpenChannelPsbt(srcNode, destNode *node.HarnessNode, require.NoError(h, err) switch p.CommitmentType { - case lnrpc.CommitmentType_SIMPLE_TAPROOT: + case lnrpc.CommitmentType_SIMPLE_TAPROOT, + lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL: + require.IsType(h, &btcutil.AddressTaproot{}, fundingAddr) default: @@ -2586,6 +2588,7 @@ func (h *HarnessTest) DeriveFundingShim(alice, bob *node.HarnessNode, ) if commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT || + commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_FINAL || commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY { var carolKey, daveKey *btcec.PublicKey