github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_multi-hop_htlc_local_chain_claim_test.go (about)

     1  package itest
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/decred/dcrd/wire"
     8  	"github.com/decred/dcrlnd/lncfg"
     9  	"github.com/decred/dcrlnd/lnrpc"
    10  	"github.com/decred/dcrlnd/lnrpc/invoicesrpc"
    11  	"github.com/decred/dcrlnd/lnrpc/routerrpc"
    12  	"github.com/decred/dcrlnd/lntest"
    13  	"github.com/decred/dcrlnd/lntest/wait"
    14  	"github.com/decred/dcrlnd/lntypes"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  // testMultiHopHtlcLocalChainClaim tests that in a multi-hop HTLC scenario, if
    19  // we force close a channel with an incoming HTLC, and later find out the
    20  // preimage via the witness beacon, we properly settle the HTLC on-chain using
    21  // the HTLC success transaction in order to ensure we don't lose any funds.
    22  func testMultiHopHtlcLocalChainClaim(net *lntest.NetworkHarness, t *harnessTest,
    23  	alice, bob *lntest.HarnessNode, c lnrpc.CommitmentType) {
    24  
    25  	ctxb := context.Background()
    26  
    27  	// First, we'll create a three hop network: Alice -> Bob -> Carol, with
    28  	// Carol refusing to actually settle or directly cancel any HTLC's
    29  	// self.
    30  	aliceChanPoint, bobChanPoint, carol := createThreeHopNetwork(
    31  		t, net, alice, bob, false, c,
    32  	)
    33  
    34  	// Clean up carol's node when the test finishes.
    35  	defer shutdownAndAssert(net, t, carol)
    36  
    37  	// With the network active, we'll now add a new hodl invoice at Carol's
    38  	// end. Make sure the cltv expiry delta is large enough, otherwise Bob
    39  	// won't send out the outgoing htlc.
    40  
    41  	const invoiceAmt = 100000
    42  	preimage := lntypes.Preimage{1, 2, 3}
    43  	payHash := preimage.Hash()
    44  	invoiceReq := &invoicesrpc.AddHoldInvoiceRequest{
    45  		Value:      invoiceAmt,
    46  		CltvExpiry: 40,
    47  		Hash:       payHash[:],
    48  	}
    49  	ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
    50  	defer cancel()
    51  	carolInvoice, err := carol.AddHoldInvoice(ctxt, invoiceReq)
    52  	require.NoError(t.t, err)
    53  
    54  	// Now that we've created the invoice, we'll send a single payment from
    55  	// Alice to Carol. We won't wait for the response however, as Carol
    56  	// will not immediately settle the payment.
    57  	ctx, cancel := context.WithCancel(ctxb)
    58  	defer cancel()
    59  
    60  	_, err = alice.RouterClient.SendPaymentV2(
    61  		ctx, &routerrpc.SendPaymentRequest{
    62  			PaymentRequest: carolInvoice.PaymentRequest,
    63  			TimeoutSeconds: 60,
    64  			FeeLimitMAtoms: noFeeLimitMAtoms,
    65  		},
    66  	)
    67  	require.NoError(t.t, err)
    68  
    69  	// At this point, all 3 nodes should now have an active channel with
    70  	// the created HTLC pending on all of them.
    71  	nodes := []*lntest.HarnessNode{alice, bob, carol}
    72  	err = wait.NoError(func() error {
    73  		return assertActiveHtlcs(nodes, payHash[:])
    74  	}, defaultTimeout)
    75  	require.NoError(t.t, err)
    76  
    77  	// Wait for carol to mark invoice as accepted. There is a small gap to
    78  	// bridge between adding the htlc to the channel and executing the exit
    79  	// hop logic.
    80  	waitForInvoiceAccepted(t, carol, payHash)
    81  
    82  	// Increase the fee estimate so that the following force close tx will
    83  	// be cpfp'ed.
    84  	net.SetFeeEstimate(30000)
    85  
    86  	// At this point, Bob decides that he wants to exit the channel
    87  	// immediately, so he force closes his commitment transaction.
    88  	hasAnchors := commitTypeHasAnchors(c)
    89  	bobForceClose := closeChannelAndAssertType(
    90  		t, net, bob, aliceChanPoint, hasAnchors, true,
    91  	)
    92  
    93  	var expectedTxes int
    94  	switch c {
    95  	// Alice will sweep her commitment output immediately.
    96  	case lnrpc.CommitmentType_LEGACY:
    97  		expectedTxes = 1
    98  
    99  	// Alice will sweep her commitment and anchor output immediately.
   100  	case lnrpc.CommitmentType_ANCHORS:
   101  		expectedTxes = 2
   102  
   103  	// Alice will sweep her anchor output immediately. Her commitment output
   104  	// cannot be swept yet as it has incurred an additional CLTV due to
   105  	// being the initiator of a script-enforced leased channel.
   106  	case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
   107  		expectedTxes = 1
   108  
   109  	default:
   110  		t.Fatalf("unhandled commitment type %v", c)
   111  	}
   112  	_, err = waitForNTxsInMempool(
   113  		net.Miner.Node, expectedTxes, minerMempoolTimeout,
   114  	)
   115  	require.NoError(t.t, err)
   116  
   117  	// Suspend Bob to force Carol to go to chain.
   118  	restartBob, err := net.SuspendNode(bob)
   119  	require.NoError(t.t, err)
   120  
   121  	// Settle invoice. This will just mark the invoice as settled, as there
   122  	// is no link anymore to remove the htlc from the commitment tx. For
   123  	// this test, it is important to actually settle and not leave the
   124  	// invoice in the accepted state, because without a known preimage, the
   125  	// channel arbitrator won't go to chain.
   126  	ctx, cancel = context.WithTimeout(ctxb, defaultTimeout)
   127  	defer cancel()
   128  	_, err = carol.SettleInvoice(ctx, &invoicesrpc.SettleInvoiceMsg{
   129  		Preimage: preimage[:],
   130  	})
   131  	require.NoError(t.t, err)
   132  
   133  	// We'll now mine enough blocks so Carol decides that she needs to go
   134  	// on-chain to claim the HTLC as Bob has been inactive. We mine up to
   135  	// just before the deadline to check the transaction is in the mempool.
   136  	numBlocks := padCLTV(uint32(invoiceReq.CltvExpiry -
   137  		lncfg.DefaultIncomingBroadcastDelta - 1))
   138  	_, err = net.Generate(numBlocks)
   139  	require.NoError(t.t, err)
   140  
   141  	// Carol's commitment transaction should now be in the mempool. If there
   142  	// is an anchor, Carol will sweep that too.
   143  	_, err = waitForNTxsInMempool(
   144  		net.Miner.Node, expectedTxes, minerMempoolTimeout,
   145  	)
   146  	require.NoError(t.t, err)
   147  	bobFundingTxid, err := lnrpc.GetChanPointFundingTxid(bobChanPoint)
   148  	require.NoError(t.t, err)
   149  	carolFundingPoint := wire.OutPoint{
   150  		Hash:  *bobFundingTxid,
   151  		Index: bobChanPoint.OutputIndex,
   152  	}
   153  
   154  	// Look up the closing transaction. It should be spending from the
   155  	// funding transaction,
   156  	closingTx := getSpendingTxInMempool(
   157  		t, net.Miner.Node, minerMempoolTimeout, carolFundingPoint,
   158  	)
   159  	closingTxid := closingTx.TxHash()
   160  
   161  	// Mine a block that should confirm the commit tx, the anchor if present
   162  	// and the coinbase.
   163  	block := mineBlocks(t, net, 1, expectedTxes)[0]
   164  	require.Len(t.t, block.Transactions, expectedTxes+1)
   165  	assertTxInBlock(t, block, &closingTxid)
   166  
   167  	// Restart bob again.
   168  	err = restartBob()
   169  	require.NoError(t.t, err)
   170  
   171  	// After the force close transacion is mined, transactions will be
   172  	// broadcast by both Bob and Carol.
   173  	switch c {
   174  	// Carol will broadcast her second level HTLC transaction and Bob will
   175  	// sweep his commitment output.
   176  	case lnrpc.CommitmentType_LEGACY:
   177  		expectedTxes = 2
   178  
   179  	// Carol will broadcast her second level HTLC transaction and Bob will
   180  	// sweep his commitment and anchor output.
   181  	case lnrpc.CommitmentType_ANCHORS:
   182  		expectedTxes = 3
   183  
   184  	// Carol will broadcast her second level HTLC transaction and anchor
   185  	// sweep, and Bob will sweep his anchor output. Bob can't sweep his
   186  	// commitment output yet as it has incurred an additional CLTV due to
   187  	// being the initiator of a script-enforced leased channel.
   188  	case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
   189  		expectedTxes = 3
   190  
   191  	default:
   192  		t.Fatalf("unhandled commitment type %v", c)
   193  	}
   194  	txes, err := getNTxsFromMempool(
   195  		net.Miner.Node, expectedTxes, minerMempoolTimeout,
   196  	)
   197  	require.NoError(t.t, err)
   198  
   199  	// Both Carol's second level transaction and Bob's sweep should be
   200  	// spending from the commitment transaction.
   201  	assertAllTxesSpendFrom(t, txes, closingTxid)
   202  
   203  	// At this point we suspend Alice to make sure she'll handle the
   204  	// on-chain settle after a restart.
   205  	restartAlice, err := net.SuspendNode(alice)
   206  	require.NoError(t.t, err)
   207  
   208  	// Mine a block to confirm the expected transactions (+ the coinbase).
   209  	block = mineBlocks(t, net, 1, expectedTxes)[0]
   210  	require.Len(t.t, block.Transactions, expectedTxes+1)
   211  
   212  	// For non-anchor channel types, the nursery will handle sweeping the
   213  	// second level output, and it will wait one extra block before
   214  	// sweeping it.
   215  	secondLevelMaturity := uint32(defaultCSV)
   216  
   217  	// If this is a channel of the anchor type, we will subtract one block
   218  	// from the default CSV, as the Sweeper will handle the input, and the
   219  	// Sweeper sweeps the input as soon as the lock expires.
   220  	if hasAnchors {
   221  		secondLevelMaturity = defaultCSV - 1
   222  	}
   223  
   224  	// Keep track of the second level tx maturity.
   225  	carolSecondLevelCSV := secondLevelMaturity
   226  
   227  	// When Bob notices Carol's second level transaction in the block, he
   228  	// will extract the preimage and broadcast a second level tx to claim
   229  	// the HTLC in his (already closed) channel with Alice.
   230  	bobSecondLvlTx, err := waitForTxInMempool(
   231  		net.Miner.Node, minerMempoolTimeout,
   232  	)
   233  	require.NoError(t.t, err)
   234  
   235  	// It should spend from the commitment in the channel with Alice.
   236  	tx, err := net.Miner.Node.GetRawTransaction(context.Background(), bobSecondLvlTx)
   237  	require.NoError(t.t, err)
   238  
   239  	require.Equal(
   240  		t.t, *bobForceClose, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash,
   241  	)
   242  
   243  	// At this point, Bob should have broadcast his second layer success
   244  	// transaction, and should have sent it to the nursery for incubation.
   245  	numPendingChans := 1
   246  	if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE {
   247  		numPendingChans++
   248  	}
   249  	err = waitForNumChannelPendingForceClose(
   250  		bob, numPendingChans, func(c *lnrpcForceCloseChannel) error {
   251  			if c.Channel.LocalBalance != 0 {
   252  				return nil
   253  			}
   254  
   255  			if len(c.PendingHtlcs) != 1 {
   256  				return fmt.Errorf("bob should have pending " +
   257  					"htlc but doesn't")
   258  			}
   259  
   260  			if c.PendingHtlcs[0].Stage != 1 {
   261  				return fmt.Errorf("bob's htlc should have "+
   262  					"advanced to the first stage but was "+
   263  					"stage: %v", c.PendingHtlcs[0].Stage)
   264  			}
   265  
   266  			return nil
   267  		},
   268  	)
   269  	require.NoError(t.t, err)
   270  
   271  	// We'll now mine a block which should confirm Bob's second layer
   272  	// transaction.
   273  	block = mineBlocks(t, net, 1, 1)[0]
   274  	require.Len(t.t, block.Transactions, 2)
   275  	assertTxInBlock(t, block, bobSecondLvlTx)
   276  
   277  	// Keep track of Bob's second level maturity, and decrement our track
   278  	// of Carol's.
   279  	bobSecondLevelCSV := secondLevelMaturity
   280  	carolSecondLevelCSV--
   281  
   282  	// Now that the preimage from Bob has hit the chain, restart Alice to
   283  	// ensure she'll pick it up.
   284  	err = restartAlice()
   285  	require.NoError(t.t, err)
   286  
   287  	// If we then mine 3 additional blocks, Carol's second level tx should
   288  	// mature, and she can pull the funds from it with a sweep tx.
   289  	_, err = net.Generate(carolSecondLevelCSV)
   290  	require.NoError(t.t, err)
   291  	bobSecondLevelCSV -= carolSecondLevelCSV
   292  
   293  	carolSweep, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
   294  	require.NoError(t.t, err)
   295  
   296  	// Mining one additional block, Bob's second level tx is mature, and he
   297  	// can sweep the output.
   298  	block = mineBlocks(t, net, bobSecondLevelCSV, 1)[0]
   299  	assertTxInBlock(t, block, carolSweep)
   300  
   301  	bobSweep, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
   302  	require.NoError(t.t, err)
   303  
   304  	// Make sure it spends from the second level tx.
   305  	tx, err = net.Miner.Node.GetRawTransaction(context.Background(), bobSweep)
   306  	require.NoError(t.t, err)
   307  	require.Equal(
   308  		t.t, *bobSecondLvlTx, tx.MsgTx().TxIn[0].PreviousOutPoint.Hash,
   309  	)
   310  
   311  	// When we mine one additional block, that will confirm Bob's sweep.
   312  	// Now Bob should have no pending channels anymore, as this just
   313  	// resolved it by the confirmation of the sweep transaction.
   314  	block = mineBlocks(t, net, 1, 1)[0]
   315  	assertTxInBlock(t, block, bobSweep)
   316  
   317  	// With the script-enforced lease commitment type, Alice and Bob still
   318  	// haven't been able to sweep their respective commit outputs due to the
   319  	// additional CLTV. We'll need to mine enough blocks for the timelock to
   320  	// expire and prompt their sweep.
   321  	if c == lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE {
   322  		for _, node := range []*lntest.HarnessNode{alice, bob} {
   323  			err = waitForNumChannelPendingForceClose(node, 1, nil)
   324  			require.NoError(t.t, err)
   325  		}
   326  
   327  		// Due to the way the test is set up, Alice and Bob share the
   328  		// same CLTV for their commit outputs even though it's enforced
   329  		// on different channels (Alice-Bob and Bob-Carol).
   330  		ctxt, _ = context.WithTimeout(ctxb, defaultTimeout)
   331  		resp, err := alice.PendingChannels(
   332  			ctxt, &lnrpc.PendingChannelsRequest{},
   333  		)
   334  		require.NoError(t.t, err)
   335  		require.Len(t.t, resp.PendingForceClosingChannels, 1)
   336  		forceCloseChan := resp.PendingForceClosingChannels[0]
   337  		require.Positive(t.t, forceCloseChan.BlocksTilMaturity)
   338  
   339  		// Mine enough blocks for the timelock to expire.
   340  		numBlocks := uint32(forceCloseChan.BlocksTilMaturity)
   341  		_, err = net.Generate(numBlocks)
   342  		require.NoError(t.t, err)
   343  
   344  		// Both Alice and Bob show broadcast their commit sweeps.
   345  		aliceCommitOutpoint := wire.OutPoint{Hash: *bobForceClose, Index: 3}
   346  		aliceCommitSweep := assertSpendingTxInMempool(
   347  			t, net.Miner.Node, minerMempoolTimeout,
   348  			aliceCommitOutpoint,
   349  		)
   350  		bobCommitOutpoint := wire.OutPoint{Hash: closingTxid, Index: 3}
   351  		bobCommitSweep := assertSpendingTxInMempool(
   352  			t, net.Miner.Node, minerMempoolTimeout,
   353  			bobCommitOutpoint,
   354  		)
   355  
   356  		// Confirm their sweeps.
   357  		block := mineBlocks(t, net, 1, 2)[0]
   358  		assertTxInBlock(t, block, &aliceCommitSweep)
   359  		assertTxInBlock(t, block, &bobCommitSweep)
   360  	}
   361  
   362  	// All nodes should show zero pending and open channels.
   363  	for _, node := range []*lntest.HarnessNode{alice, bob, carol} {
   364  		err = waitForNumChannelPendingForceClose(node, 0, nil)
   365  		require.NoError(t.t, err)
   366  		assertNodeNumChannels(t, node, 0)
   367  	}
   368  
   369  	// Finally, check that the Alice's payment is correctly marked
   370  	// succeeded.
   371  	err = checkPaymentStatus(alice, preimage, lnrpc.Payment_SUCCEEDED)
   372  	require.NoError(t.t, err)
   373  }