diff --git a/itest/README.md b/itest/README.md index c6cbf3f..78fb787 100644 --- a/itest/README.md +++ b/itest/README.md @@ -11,15 +11,17 @@ around the network). The network is set up as follows: ``` - Alice ◄──► Bob ◄──► Charlie ◄──► Dave + Alice ◄──► Bob ◄──► Charlie ◄──► Dave* └───────►└──► Rusty ◄──┘ - | Nifty ◄──┘ | - └► Snyke ◄─────────────┘ + |────► Nifty ◄──┘ | + └► Snyke* ◄────────────┘ ``` - Channel **Alice** - **Bob**: Remains open, used by `runZombieRecoveryLndLnd`. - Channel **Alice** - **Rusty**: Is force closed by Alice, used by `runSweepRemoteClosedCln`. +- Channel **Alice** - **Nifty**: Is force closed by Alice, used by + `runForceClose`. - Channel **Alice** - **Snyke**: Remains open, used by `runTriggerForceCloseCln`. - Channel **Bob** - **Charlie**: Is force closed by Bob, used by @@ -32,6 +34,7 @@ The network is set up as follows: `runZombieRecoveryClnLnd`. - Channel **Rusty** - **Nifty**: Remains open, used by `runZombieRecoveryClnCln`. +- `*`: Node is kept running after initial test setup. All nodes except for Dave and Snyke are stopped before the integration tests are run. diff --git a/itest/cmd_forceclose_test.go b/itest/cmd_forceclose_test.go new file mode 100644 index 0000000..a93a96e --- /dev/null +++ b/itest/cmd_forceclose_test.go @@ -0,0 +1,30 @@ +package itest + +import ( + "fmt" + "testing" + + "github.com/lightningnetwork/lnd/lnrpc" + "github.com/stretchr/testify/require" +) + +func runForceClose(t *testing.T) { + aliceChannels := readChannelsJSON(t, "alice") + niftyIdentity := getNodeIdentityKeyCln(t, "nifty") + + var aliceNiftyChannel *lnrpc.Channel + for _, c := range aliceChannels { + if c.RemotePubkey == niftyIdentity { + aliceNiftyChannel = c + } + } + require.NotNil(t, aliceNiftyChannel, "alice-nifty channel not found") + + channelDB := fmt.Sprintf(channelDBFilePattern, "alice") + txHex, _ := getForceClose( + t, "alice", tempDir, channelDB, aliceNiftyChannel.ChannelPoint, + ) + + backend := connectBitcoind(t) + publishTx(t, txHex, backend) +} diff --git a/itest/docker/setup-test-network.sh b/itest/docker/setup-test-network.sh index f518a68..7942803 100755 --- a/itest/docker/setup-test-network.sh +++ b/itest/docker/setup-test-network.sh @@ -34,7 +34,7 @@ wait_for_nodes alice bob charlie dave rusty nifty snyke do_for fund_node alice bob charlie dave rusty nifty snyke # Alice, Bob and Charlie will open more than one channel each. -do_for fund_node alice alice bob charlie charlie +do_for fund_node alice alice alice bob charlie charlie mine 6 @@ -54,6 +54,7 @@ connect_nodes rusty nifty open_channel alice bob open_channel alice rusty +open_channel alice nifty open_channel bob charlie open_channel charlie dave open_channel bob rusty @@ -64,15 +65,15 @@ open_channel alice snyke echo "🔗 Set up network:" cat << EOF - Alice ◄──► Bob ◄──► Charlie ◄──► Dave + Alice ◄──► Bob ◄──► Charlie ◄──► Dave* └───────►└──► Rusty ◄──┘ - | Nifty ◄──┘ | - └► Snyke ◄─────────────┘ + |────► Nifty ◄──┘ | + └► Snyke* ◄────────────┘ EOF mine 12 -num_channels=9 +num_channels=10 wait_graph_sync alice $num_channels wait_graph_sync bob $num_channels @@ -84,15 +85,17 @@ send_payment bob dave send_payment dave bob send_payment alice dave send_payment alice rusty +send_payment alice nifty send_payment dave rusty send_payment alice snyke send_payment charlie snyke -# Repeat the basic tests. +# Repeat the basic sends. send_payment bob dave send_payment dave bob send_payment alice dave send_payment alice rusty +send_payment alice nifty send_payment dave rusty send_payment alice snyke send_payment charlie snyke diff --git a/itest/helpers.go b/itest/helpers.go index f5278c0..15f693d 100644 --- a/itest/helpers.go +++ b/itest/helpers.go @@ -30,8 +30,10 @@ const ( ) const ( - channelsFilePattern = "docker/node-data/chantools/%s-channels.json" - walletFilePattern = "docker/node-data/%s/data/chain/bitcoin/" + + channelsFilePattern = "docker/node-data/chantools/%s-channels.json" + channelDBFilePattern = "docker/node-data/%s/data/graph/regtest/" + + "channel.db" + walletFilePattern = "docker/node-data/%s/data/chain/bitcoin/" + "regtest/wallet.db" scbFilePattern = "docker/node-data/%s/data/chain/bitcoin/" + "regtest/channel.backup" @@ -354,6 +356,32 @@ func invokeCmdScbForceClose(t *testing.T, walletPassword *string, return output } +func invokeCmdForceClose(t *testing.T, walletPassword *string, + resultsDir string, args ...string) string { + + t.Helper() + + fullArgs := append([]string{ + "--regtest", "--resultsdir", resultsDir, "forceclose", + }, args...) + proc := StartChantools(t, fullArgs...) + defer proc.Wait(t) + + if walletPassword != nil { + pwPrompt := proc.ReadAvailableOutput(t, readTimeout) + + require.Contains(t, pwPrompt, "Input wallet password:") + proc.WriteInput(t, *walletPassword+"\n") + + proc.AssertNoStderr(t) + } + + proc.AssertNoStderr(t) + + output := proc.ReadAvailableOutput(t, longTimeout) + return output +} + func getNodeIdentityKey(t *testing.T, node string) string { t.Helper() @@ -553,3 +581,20 @@ func getScbForceClose(t *testing.T, node, tempDir, multiBackup, return txHex, cmdOutput } + +func getForceClose(t *testing.T, node, tempDir, channelDB, + channelPoint string) (string, string) { + + t.Helper() + + walletDbPath := fmt.Sprintf(walletFilePattern, node) + cmdOutput := invokeCmdForceClose( + t, &emptyPassword, tempDir, + "--channelpoint", channelPoint, "--walletdb", walletDbPath, + "--channeldb", channelDB, + ) + txHex := extractRowContent(cmdOutput, rowRawTransaction) + require.Contains(t, txHex, transactionHexIdent) + + return txHex, cmdOutput +} diff --git a/itest/integration_test.go b/itest/integration_test.go index aa24c4e..bad924d 100644 --- a/itest/integration_test.go +++ b/itest/integration_test.go @@ -46,6 +46,10 @@ var testCases = []testCase{ name: "scb force close", fn: runScbForceClose, }, + { + name: "force close", + fn: runForceClose, + }, } // TestIntegration runs all integration test cases.