lntest/itest: resolve mempool flake in multi-hop htlc local timeout test

The test assumed that transactions would be broadcast and confirmed at
incorrect heights. Due to timing issues, it was possible for the test to
still succeed, resulting in a flake.

The test assumes that Bob will sweep a pending outgoing HTLC and commit
output back to their wallet. This commit ensures that these operations
are done when expected, i.e.:

1. Bob force closes the channel due to the HTLC timing out.
2. Once the channel is confirmed, Bob broadcasts their HTLC timeout
transaction.
3. Bob broadcasts their commit output sweep transaction once its CSV
expires.
4. Bob broadcasts their second layer sweep transaction for the timed out
HTLC once its CSV expires.
This commit is contained in:
Wilmer Paulino 2019-08-26 18:17:30 -07:00
parent 06206f09b5
commit 578df81fb2
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F

@ -10153,6 +10153,10 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
if err != nil { if err != nil {
t.Fatalf("unable to get txid: %v", err) t.Fatalf("unable to get txid: %v", err)
} }
closeTxid, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
if err != nil {
t.Fatalf("unable to find closing txid: %v", err)
}
assertSpendingTxInMempool( assertSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{ t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{
Hash: *bobFundingTxid, Hash: *bobFundingTxid,
@ -10179,24 +10183,22 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("htlc mismatch: %v", predErr) t.Fatalf("htlc mismatch: %v", predErr)
} }
// We'll mine defaultCSV blocks in order to generate the sweep // With the closing transaction confirmed, we should expect Bob's HTLC
// transaction of Bob's funding output. This will also bring us to the // timeout transaction to be broadcast due to the expiry being reached.
// maturity height of the htlc tx output. htlcTimeout, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
if _, err := net.Miner.Node.Generate(defaultCSV); err != nil { if err != nil {
t.Fatalf("unable to generate blocks: %v", err) t.Fatalf("unable to find bob's htlc timeout tx: %v", err)
} }
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) // We'll mine the remaining blocks in order to generate the sweep
if err != nil { // transaction of Bob's commitment output.
t.Fatalf("unable to find bob's funding output sweep tx: %v", err) mineBlocks(t, net, defaultCSV, 1)
} assertSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{
// The second layer HTLC timeout transaction should now have been Hash: *closeTxid,
// broadcast on-chain. Index: 1,
secondLayerHash, err := waitForTxInMempool(net.Miner.Node, minerMempoolTimeout) },
if err != nil { )
t.Fatalf("unable to find bob's second layer transaction")
}
// Bob's pending channel report should show that he has a commitment // Bob's pending channel report should show that he has a commitment
// output awaiting sweeping, and also that there's an outgoing HTLC // output awaiting sweeping, and also that there's an outgoing HTLC
@ -10220,14 +10222,20 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("bob should have pending htlc but doesn't") t.Fatalf("bob should have pending htlc but doesn't")
} }
// Now we'll mine an additional block, which should include the second // Now we'll mine an additional block, which should confirm Bob's commit
// layer sweep tx. // sweep. This block should also prompt Bob to broadcast their second
block := mineBlocks(t, net, 1, 1)[0] // layer sweep due to the CSV on the HTLC timeout output.
mineBlocks(t, net, 1, 1)
assertSpendingTxInMempool(
t, net.Miner.Node, minerMempoolTimeout, wire.OutPoint{
Hash: *htlcTimeout,
Index: 0,
},
)
// The block should have confirmed Bob's second layer sweeping // The block should have confirmed Bob's HTLC timeout transaction.
// transaction. Therefore, at this point, there should be no active // Therefore, at this point, there should be no active HTLC's on the
// HTLC's on the commitment transaction from Alice -> Bob. // commitment transaction from Alice -> Bob.
assertTxInBlock(t, block, secondLayerHash)
nodes = []*lntest.HarnessNode{net.Alice} nodes = []*lntest.HarnessNode{net.Alice}
err = lntest.WaitPredicate(func() bool { err = lntest.WaitPredicate(func() bool {
predErr = assertNumActiveHtlcs(nodes, 0) predErr = assertNumActiveHtlcs(nodes, 0)
@ -10252,16 +10260,6 @@ func testMultiHopHtlcLocalTimeout(net *lntest.NetworkHarness, t *harnessTest) {
t.Fatalf("bob's htlc should have advanced to the second stage: %v", err) t.Fatalf("bob's htlc should have advanced to the second stage: %v", err)
} }
// We'll now mine four more blocks. After the 4th block, a transaction
// sweeping the HTLC output should be broadcast.
if _, err := net.Miner.Node.Generate(4); err != nil {
t.Fatalf("unable to generate blocks: %v", err)
}
_, err = waitForTxInMempool(net.Miner.Node, minerMempoolTimeout)
if err != nil {
t.Fatalf("unable to find bob's sweeping transaction: %v", err)
}
// Next, we'll mine a final block that should confirm the second-layer // Next, we'll mine a final block that should confirm the second-layer
// sweeping transaction. // sweeping transaction.
if _, err := net.Miner.Node.Generate(1); err != nil { if _, err := net.Miner.Node.Generate(1); err != nil {