package itest import ( "time" "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntest" "github.com/stretchr/testify/require" ) // testResHandoff tests that the contractcourt is able to properly hand-off // resolution messages to the switch. func testResHandoff(ht *lntest.HarnessTest) { const ( chanAmt = btcutil.Amount(1000000) paymentAmt = 50000 ) alice, bob := ht.Alice, ht.Bob // First we'll create a channel between Alice and Bob. ht.EnsureConnected(alice, bob) params := lntest.OpenChannelParams{Amt: chanAmt} chanPointAlice := ht.OpenChannel(alice, bob, params) // Create a new node Carol that will be in hodl mode. This is used to // trigger the behavior of checkRemoteDanglingActions in the // contractcourt. This will cause Bob to fail the HTLC back to Alice. carol := ht.NewNode("Carol", []string{"--hodl.commit"}) // Connect Bob to Carol. ht.ConnectNodes(bob, carol) // Open a channel between Bob and Carol. chanPointCarol := ht.OpenChannel(bob, carol, params) // Wait for Alice to see the channel edge in the graph. ht.AssertTopologyChannelOpen(alice, chanPointCarol) // We'll create an invoice for Carol that Alice will attempt to pay. // Since Carol is in hodl.commit mode, she won't send back any commit // sigs. carolPayReqs, _, _ := ht.CreatePayReqs(carol, paymentAmt, 1) // Alice will now attempt to fulfill the invoice. ht.CompletePaymentRequestsNoWait(alice, carolPayReqs, chanPointAlice) // Wait until Carol has received the Add, CommitSig from Bob, and has // responded with a RevokeAndAck. We expect NumUpdates to be 1 meaning // Carol's CommitHeight is 1. ht.AssertChannelCommitHeight(carol, chanPointCarol, 1) // Before we shutdown Alice, we'll assert that she only has 1 update. ht.AssertChannelCommitHeight(alice, chanPointAlice, 1) // We'll shutdown Alice so that Bob can't connect to her. restartAlice := ht.SuspendNode(alice) // Bob will now force close his channel with Carol such that resolution // messages are created and forwarded backwards to Alice. ht.CloseChannelAssertPending(bob, chanPointCarol, true) // The channel should be listed in the PendingChannels result. ht.AssertNumWaitingClose(bob, 1) // Mine a block to confirm the closing tx. ht.MineBlocks(1) // We sleep here so we can be sure that the hand-off has occurred from // Bob's contractcourt to Bob's htlcswitch. This sleep could be removed // if there was some feedback (i.e. API in switch) that allowed for // querying the state of resolution messages. time.Sleep(10 * time.Second) // Mine blocks until Bob has no waiting close channels. This tests that // the circuit-deletion logic is skipped if a resolution message // exists. ht.CleanupForceClose(bob) // We will now restart Bob so that we can test whether the resolution // messages are re-forwarded on start-up. ht.RestartNode(bob) // We'll now also restart Alice and connect her with Bob. require.NoError(ht, restartAlice()) ht.EnsureConnected(alice, bob) // We'll assert that Alice has received the failure resolution message. ht.AssertChannelCommitHeight(alice, chanPointAlice, 2) // Assert that Alice's payment failed. ht.AssertFirstHTLCError(alice, lnrpc.Failure_PERMANENT_CHANNEL_FAILURE) ht.CloseChannel(alice, chanPointAlice) }