From 4a7f45b5d44b28a48e5e9c06335f711c3244fbf9 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Thu, 28 Jul 2022 20:15:22 +0800 Subject: [PATCH] itest+lntemp: refactor `testMultiHopHtlcClaims` --- lntest/itest/list_on_test.go | 4 + lntest/itest/lnd_multi-hop_test.go | 307 +++++++++++++++++--------- lntest/itest/lnd_test_list_on_test.go | 4 - 3 files changed, 211 insertions(+), 104 deletions(-) diff --git a/lntest/itest/list_on_test.go b/lntest/itest/list_on_test.go index 939ffc2fa..2e611f222 100644 --- a/lntest/itest/list_on_test.go +++ b/lntest/itest/list_on_test.go @@ -15,6 +15,10 @@ var allTestCasesTemp = []*lntemp.TestCase{ Name: "basic funding flow", TestFunc: testBasicChannelFunding, }, + { + Name: "test multi-hop htlc", + TestFunc: testMultiHopHtlcClaims, + }, { Name: "external channel funding", TestFunc: testExternalFundingChanPoint, diff --git a/lntest/itest/lnd_multi-hop_test.go b/lntest/itest/lnd_multi-hop_test.go index 4ac54b771..1852ff4b3 100644 --- a/lntest/itest/lnd_multi-hop_test.go +++ b/lntest/itest/lnd_multi-hop_test.go @@ -10,63 +10,68 @@ import ( "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" + "github.com/lightningnetwork/lnd/lntemp" + "github.com/lightningnetwork/lnd/lntemp/node" + "github.com/lightningnetwork/lnd/lntemp/rpc" "github.com/lightningnetwork/lnd/lntest" "github.com/lightningnetwork/lnd/lntypes" "github.com/stretchr/testify/require" ) -func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) { +func testMultiHopHtlcClaims(ht *lntemp.HarnessTest) { type testCase struct { name string - test func(net *lntest.NetworkHarness, t *harnessTest, alice, - bob *lntest.HarnessNode, c lnrpc.CommitmentType, - zeroConf bool) + test func(ht *lntemp.HarnessTest, alice, bob *node.HarnessNode, + c lnrpc.CommitmentType, zeroConf bool) + commitType lnrpc.CommitmentType } subTests := []testCase{ - { - // bob: outgoing our commit timeout - // carol: incoming their commit watch and see timeout - name: "local force close immediate expiry", - test: testMultiHopHtlcLocalTimeout, - }, - { - // bob: outgoing watch and see, they sweep on chain - // carol: incoming our commit, know preimage - name: "receiver chain claim", - test: testMultiHopReceiverChainClaim, - }, - { - // bob: outgoing our commit watch and see timeout - // carol: incoming their commit watch and see timeout - name: "local force close on-chain htlc timeout", - test: testMultiHopLocalForceCloseOnChainHtlcTimeout, - }, - { - // bob: outgoing their commit watch and see timeout - // carol: incoming our commit watch and see timeout - name: "remote force close on-chain htlc timeout", - test: testMultiHopRemoteForceCloseOnChainHtlcTimeout, - }, - { - // bob: outgoing our commit watch and see, they sweep on chain - // bob: incoming our commit watch and learn preimage - // carol: incoming their commit know preimage - name: "local chain claim", - test: testMultiHopHtlcLocalChainClaim, - }, - { - // bob: outgoing their commit watch and see, they sweep on chain - // bob: incoming their commit watch and learn preimage - // carol: incoming our commit know preimage - name: "remote chain claim", - test: testMultiHopHtlcRemoteChainClaim, - }, - { - // bob: outgoing and incoming, sweep all on chain - name: "local htlc aggregation", - test: testMultiHopHtlcAggregation, - }, + // { + // // bob: outgoing our commit timeout + // // carol: incoming their commit watch and see timeout + // name: "local force close immediate expiry", + // test: testMultiHopHtlcLocalTimeout, + // }, + // { + // // bob: outgoing watch and see, they sweep on chain + // // carol: incoming our commit, know preimage + // name: "receiver chain claim", + // test: testMultiHopReceiverChainClaim, + // }, + // { + // // bob: outgoing our commit watch and see timeout + // // carol: incoming their commit watch and see timeout + // name: "local force close on-chain htlc timeout", + // test: testMultiHopLocalForceCloseOnChainHtlcTimeout, + // }, + // { + // // bob: outgoing their commit watch and see timeout + // // carol: incoming our commit watch and see timeout + // name: "remote force close on-chain htlc timeout", + // test: testMultiHopRemoteForceCloseOnChainHtlcTimeout, + // }, + // { + // // bob: outgoing our commit watch and see, they sweep + // // on chain + // // bob: incoming our commit watch and learn preimage + // // carol: incoming their commit know preimage + // name: "local chain claim", + // test: testMultiHopHtlcLocalChainClaim, + // }, + // { + // // bob: outgoing their commit watch and see, they sweep + // // on chain + // // bob: incoming their commit watch and learn preimage + // // carol: incoming our commit know preimage + // name: "remote chain claim", + // test: testMultiHopHtlcRemoteChainClaim, + // }, + // { + // // bob: outgoing and incoming, sweep all on chain + // name: "local htlc aggregation", + // test: testMultiHopHtlcAggregation, + // }, } commitWithZeroConf := []struct { @@ -95,63 +100,56 @@ func testMultiHopHtlcClaims(net *lntest.NetworkHarness, t *harnessTest) { }, } - for _, typeAndConf := range commitWithZeroConf { - typeAndConf := typeAndConf - testName := fmt.Sprintf( - "committype=%v zeroconf=%v", - typeAndConf.commitType.String(), typeAndConf.zeroConf, - ) + runTestCase := func(st *lntemp.HarnessTest, name string, tc testCase, + zeroConf bool) { - success := t.t.Run(testName, func(t *testing.T) { - ht := newHarnessTest(t, net) + // Create the nodes here so that separate logs will be created + // for Alice and Bob. + args := nodeArgsForCommitType(tc.commitType) + if zeroConf { + args = append( + args, "--protocol.option-scid-alias", + "--protocol.zero-conf", + ) + } - args := nodeArgsForCommitType(typeAndConf.commitType) + alice := st.NewNode("Alice", args) + bob := st.NewNode("Bob", args) + st.ConnectNodes(alice, bob) - if typeAndConf.zeroConf { - args = append( - args, "--protocol.option-scid-alias", - "--protocol.zero-conf", + // Start each test with the default static fee estimate. + st.SetFeeEstimate(12500) + + // Add test name to the logs. + alice.AddToLogf("Running test case: %s", name) + bob.AddToLogf("Running test case: %s", name) + + tc.test(st, alice, bob, tc.commitType, zeroConf) + } + + for _, subTest := range subTests { + subTest := subTest + + for _, typeAndConf := range commitWithZeroConf { + typeAndConf := typeAndConf + + subTest.commitType = typeAndConf.commitType + + name := fmt.Sprintf("%s/zeroconf=%v/committype=%v", + subTest.name, typeAndConf.zeroConf, + typeAndConf.commitType.String()) + + s := ht.Run(name, func(t1 *testing.T) { + st, cleanup := ht.Subtest(t1) + defer cleanup() + + runTestCase( + st, name, subTest, typeAndConf.zeroConf, ) + }) + if !s { + return } - - alice := net.NewNode(t, "Alice", args) - defer shutdownAndAssert(net, ht, alice) - - bob := net.NewNode(t, "Bob", args) - defer shutdownAndAssert(net, ht, bob) - - net.ConnectNodes(t, alice, bob) - - for _, subTest := range subTests { - subTest := subTest - - logLine := fmt.Sprintf( - "---- multi-hop htlc subtest "+ - "%s/%s ----\n", - testName, subTest.name, - ) - net.Alice.AddToLogf(logLine) - - success := ht.t.Run(subTest.name, func(t *testing.T) { - ht := newHarnessTest(t, net) - - // Start each test with the default - // static fee estimate. - net.SetFeeEstimate(12500) - - subTest.test( - net, ht, alice, bob, - typeAndConf.commitType, - typeAndConf.zeroConf, - ) - }) - if !success { - return - } - } - }) - if !success { - return } } } @@ -239,7 +237,7 @@ func checkPaymentStatus(node *lntest.HarnessNode, preimage lntypes.Preimage, return nil } -// TODO(yy): delete +// TODO(yy): delete. func createThreeHopNetworkOld(t *harnessTest, net *lntest.NetworkHarness, alice, bob *lntest.HarnessNode, carolHodl bool, c lnrpc.CommitmentType, zeroConf bool) ( @@ -396,3 +394,112 @@ func assertAllTxesSpendFrom(t *harnessTest, txes []*wire.MsgTx, } } } + +// createThreeHopNetwork creates a topology of `Alice -> Bob -> Carol`. +func createThreeHopNetwork(ht *lntemp.HarnessTest, + alice, bob *node.HarnessNode, carolHodl bool, c lnrpc.CommitmentType, + zeroConf bool) (*lnrpc.ChannelPoint, + *lnrpc.ChannelPoint, *node.HarnessNode) { + + ht.EnsureConnected(alice, bob) + + // We'll create a new node "carol" and have Bob connect to her. + // If the carolHodl flag is set, we'll make carol always hold onto the + // HTLC, this way it'll force Bob to go to chain to resolve the HTLC. + carolFlags := nodeArgsForCommitType(c) + if carolHodl { + carolFlags = append(carolFlags, "--hodl.exit-settle") + } + + if zeroConf { + carolFlags = append( + carolFlags, "--protocol.option-scid-alias", + "--protocol.zero-conf", + ) + } + carol := ht.NewNode("Carol", carolFlags) + + ht.ConnectNodes(bob, carol) + + // Make sure there are enough utxos for anchoring. Because the anchor + // by itself often doesn't meet the dust limit, a utxo from the wallet + // needs to be attached as an additional input. This can still lead to + // a positively-yielding transaction. + for i := 0; i < 2; i++ { + ht.FundCoins(btcutil.SatoshiPerBitcoin, alice) + ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) + ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) + } + + // We'll start the test by creating a channel between Alice and Bob, + // which will act as the first leg for out multi-hop HTLC. + const chanAmt = 1000000 + var aliceFundingShim *lnrpc.FundingShim + var thawHeight uint32 + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + _, minerHeight := ht.Miner.GetBestBlock() + thawHeight = uint32(minerHeight + 144) + aliceFundingShim, _, _ = deriveFundingShim( + ht, alice, bob, chanAmt, thawHeight, true, + ) + } + + var ( + cancel context.CancelFunc + acceptStream rpc.AcceptorClient + ) + // If a zero-conf channel is being opened, the nodes are signalling the + // zero-conf feature bit. Setup a ChannelAcceptor for the fundee. + if zeroConf { + acceptStream, cancel = bob.RPC.ChannelAcceptor() + go acceptChannel(ht.T, true, acceptStream) + } + + aliceParams := lntemp.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + FundingShim: aliceFundingShim, + ZeroConf: zeroConf, + } + aliceChanPoint := ht.OpenChannel(alice, bob, aliceParams) + + // Remove the ChannelAcceptor for Bob. + if zeroConf { + cancel() + } + + // We'll then create a channel from Bob to Carol. After this channel is + // open, our topology looks like: A -> B -> C. + var bobFundingShim *lnrpc.FundingShim + if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE { + bobFundingShim, _, _ = deriveFundingShim( + ht, bob, carol, chanAmt, thawHeight, true, + ) + } + + // Setup a ChannelAcceptor for Carol if a zero-conf channel open is + // being attempted. + if zeroConf { + acceptStream, cancel = carol.RPC.ChannelAcceptor() + go acceptChannel(ht.T, true, acceptStream) + } + + bobParams := lntemp.OpenChannelParams{ + Amt: chanAmt, + CommitmentType: c, + FundingShim: bobFundingShim, + ZeroConf: zeroConf, + } + bobChanPoint := ht.OpenChannel(bob, carol, bobParams) + + // Remove the ChannelAcceptor for Carol. + if zeroConf { + cancel() + } + + // Make sure alice and carol know each other's channels. + ht.AssertTopologyChannelOpen(alice, bobChanPoint) + ht.AssertTopologyChannelOpen(carol, aliceChanPoint) + + return aliceChanPoint, bobChanPoint, carol +} diff --git a/lntest/itest/lnd_test_list_on_test.go b/lntest/itest/lnd_test_list_on_test.go index a08295122..fe5ac6378 100644 --- a/lntest/itest/lnd_test_list_on_test.go +++ b/lntest/itest/lnd_test_list_on_test.go @@ -4,10 +4,6 @@ package itest var allTestCases = []*testCase{ - { - name: "test multi-hop htlc", - test: testMultiHopHtlcClaims, - }, { name: "sweep coins", test: testSweepAllCoins,