itest: add test for ConfirmationsUntilActive and ConfirmationHeight

Signed-off-by: Nishant Bansal <nishant.bansal.282003@gmail.com>
This commit is contained in:
Nishant Bansal committed 2025-09-11 18:27:38 +05:30
1 parent 5fd42ac61d
commit 8f62efb1fa
2 files changed
+238

No files matched your search

+8
View File
@@ -62,6 +62,14 @@ var allTestCases = []*lntest.TestCase{
Name: "funding expiry blocks on pending",
TestFunc: testFundingExpiryBlocksOnPending,
},
{
Name: "pending channel confirmation until active",
TestFunc: testPendingChannelConfirmationUntilActive,
},
{
Name: "pending channel reorg test",
TestFunc: testPendingChannelAfterReorg,
},
{
Name: "list channels",
TestFunc: testListChannels,
+230
View File
@@ -877,6 +877,236 @@ func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) {
ht.MineBlocksAndAssertNumTxes(1, 1)
}
// assertConfirmation is a helper to assert the ConfirmationsUntilActive and
// ConfirmationHeight has been updated to the expected value.
func assertConfirmation(ht *lntest.HarnessTest, hn *node.HarnessNode,
expConfLeft, expConfHeight uint32) {
ht.Helper()
err := wait.NoError(func() error {
// Node should have one pending open channel.
pendingChan := ht.AssertNumPendingOpenChannels(hn, 1)[0]
// Check if the ConfirmationsUntilActive is updated to the
// expected value.
if expConfLeft != pendingChan.ConfirmationsUntilActive {
return fmt.Errorf("remaining confirmations mismatch, "+
"want %v, got %v", expConfLeft,
pendingChan.ConfirmationsUntilActive)
}
// Check if the ConfirmationHeight is updated to the expected
// value.
if expConfHeight != pendingChan.ConfirmationHeight {
return fmt.Errorf("confirmation height mismatch, want "+
"%v, got %v", expConfHeight,
pendingChan.ConfirmationHeight)
}
return nil
}, defaultTimeout)
require.NoError(ht, err)
}
// testPendingChannelConfirmationUntilActive verifies the value for the rpc
// field ConfirmationUntilActive updates correctly as soon as blocks are
// confirmed.
func testPendingChannelConfirmationUntilActive(ht *lntest.HarnessTest) {
var (
numConfs uint32 = 5
chanAmt btcutil.Amount = 100000
)
// Since we want Bob's channels to require more than 1 on-chain
// confirmation before becoming active, we will launch Bob with the
// custom defaultchanconfs flag.
alice := ht.NewNodeWithCoins("Alice", nil)
bob := ht.NewNode("Bob", []string{
fmt.Sprintf("--bitcoin.defaultchanconfs=%v", numConfs),
})
// Ensure Alice and Bob are connected.
ht.EnsureConnected(alice, bob)
// Alice initiates a channel opening to Bob.
param := lntest.OpenChannelParams{Amt: chanAmt}
ht.OpenChannelAssertPending(alice, bob, param)
// Both Alice and Bob have one pending open channel.
ht.AssertNumPendingOpenChannels(alice, 1)
ht.AssertNumPendingOpenChannels(bob, 1)
// Since the funding transaction is not confirmed yet,
// ConfirmationsUntilActive will always be numConfs, and confirmation
// height will be 0.
assertConfirmation(ht, alice, numConfs, 0)
assertConfirmation(ht, bob, numConfs, 0)
// Mine the first block containing the funding transaction, This
// confirms the funding transaction but the channel should still remain
// pending.
ht.MineBlocksAndAssertNumTxes(1, 1)
// Decrement numConfs to reflect that one confirmation has been
// received.
numConfs--
// Since the funding transaction has been mined, the best block height
// corresponds to the confirmation height of the channel's opening tx.
_, expConfHeight := ht.GetBestBlock()
// Channel remains pending after the first confirmation.
ht.AssertNumPendingOpenChannels(alice, 1)
ht.AssertNumPendingOpenChannels(bob, 1)
// Make sure the ConfirmationsUntilActive and ConfirmationHeight
// fields have been updated to the expected values before restarting the
// nodes.
assertConfirmation(ht, alice, numConfs, uint32(expConfHeight))
assertConfirmation(ht, bob, numConfs, uint32(expConfHeight))
// Restart both nodes to test that the appropriate state has been
// persisted and that both nodes recover gracefully.
ht.RestartNode(alice)
ht.RestartNode(bob)
ht.EnsureConnected(alice, bob)
// ConfirmationsUntilActive field should decrease as each block is
// mined until the required number of confirmations is reached. Let's
// mine a few blocks and verify the value of ConfirmationsUntilActive at
// each step.
for i := numConfs; i > 0; i-- {
expConfLeft := i
// Retrieve pending channels for both Alice and Bob and verify
// the remaining confirmations and confirmation height.
assertConfirmation(
ht, alice, expConfLeft, uint32(expConfHeight),
)
assertConfirmation(ht, bob, expConfLeft, uint32(expConfHeight))
// Mine the next block.
ht.MineBlocks(1)
}
// After the required number of confirmations, the channel should be
// marked as active.
ht.AssertNumPendingOpenChannels(alice, 0)
ht.AssertNumPendingOpenChannels(bob, 0)
}
// testPendingChannelAfterReorg verifies the value for the rpc field
// ConfirmationUntilActive updates correctly as blocks are confirmed and after
// chain reorgs.
func testPendingChannelAfterReorg(ht *lntest.HarnessTest) {
// Skip test for neutrino, as we cannot disconnect the miner at will.
if ht.IsNeutrinoBackend() {
ht.Skipf("skipping reorg test for neutrino backend")
}
var numConfs uint32 = 3
// Since we want Bob's channels to require more than 1 on-chain
// confirmation before becoming active, we will launch Bob with the
// custom defaultchanconfs flag.
miner := ht.Miner()
alice := ht.NewNodeWithCoins("Alice", nil)
bob := ht.NewNode("Bob", []string{
fmt.Sprintf("--bitcoin.defaultchanconfs=%v", numConfs),
})
ht.EnsureConnected(alice, bob)
// Spawn a temporary miner to simulate a chain reorg with a longer
// chain.
tempMiner := ht.SpawnTempMiner()
// Alice initiates a channel opening to Bob.
params := lntest.OpenChannelParams{Amt: funding.MaxBtcFundingAmount}
ht.OpenChannelAssertPending(alice, bob, params)
// Mine the first block containing the funding transaction.
ht.MineBlocksAndAssertNumTxes(1, 1)
// Channel remains pending after the first confirmation.
ht.AssertNumPendingOpenChannels(alice, 1)
ht.AssertNumPendingOpenChannels(bob, 1)
// Since the funding transaction has been mined, the best block height
// corresponds to the confirmation height of the channel's opening tx.
_, expConfHeight := ht.GetBestBlock()
// Make sure the ConfirmationsUntilActive and ConfirmationHeight
// fields have been updated to the expected values before reorg.
//
// Decrement numConfs to reflect one confirmation received.
assertConfirmation(ht, alice, numConfs-1, uint32(expConfHeight))
assertConfirmation(ht, bob, numConfs-1, uint32(expConfHeight))
// We now cause a fork, by letting our original miner mine 1 blocks,
// and our new miner mine 3.
_, err := tempMiner.Client.Generate(3)
require.NoError(ht, err, "unable to generate blocks on temp miner")
// Ensure the chain lengths are what we expect, with the temp miner
// being 2 blocks ahead.
miner.AssertMinerBlockHeightDelta(tempMiner, 2)
// Now we disconnect Alice's chain backend from the original miner, and
// connect the two miners together. Since the temporary miner knows
// about a longer chain, both miners should sync to that chain.
ht.DisconnectMiner()
// Connecting to the temporary miner should now cause our original
// chain to be re-orged out.
miner.ConnectMiner(tempMiner)
// Once again they should be on the same chain.
miner.AssertMinerBlockHeightDelta(tempMiner, 0)
// Now we disconnect the two miners, and connect our original miner to
// our chain backend once again.
miner.DisconnectMiner(tempMiner)
ht.ConnectMiner()
// This should have caused a reorg, and Alice should sync to the longer
// chain, where the funding transaction is not confirmed.
_, tempMinerHeight, err := tempMiner.Client.GetBestBlock()
require.NoError(ht, err, "unable to get current blockheight")
ht.WaitForNodeBlockHeight(alice, tempMinerHeight)
// After the reorg, the funding transaction's confirmation is removed,
// so the pending channel should again require the original number of
// confirmations and have a confirmation height of 0.
assertConfirmation(ht, alice, numConfs, 0)
assertConfirmation(ht, bob, numConfs, 0)
// Mine the first block containing the funding transaction again.
ht.MineBlocksAndAssertNumTxes(1, 1)
// Decrement numConfs to reflect one confirmation received.
numConfs--
// Since the funding transaction has been mined, the best block height
// corresponds to the confirmation height of the channel's opening tx.
_, expConfHeight = ht.GetBestBlock()
// Make sure the ConfirmationsUntilActive and ConfirmationHeight
// fields have been updated to the expected values after reorg.
assertConfirmation(ht, alice, numConfs, uint32(expConfHeight))
assertConfirmation(ht, bob, numConfs, uint32(expConfHeight))
// Cleanup by mining the remaining blocks to reach the required number
// of confirmations.
ht.MineBlocks(int(numConfs))
// After the required number of confirmations, the channel should be
// marked as active.
ht.AssertNumPendingOpenChannels(alice, 0)
ht.AssertNumPendingOpenChannels(bob, 0)
}
// testSimpleTaprootChannelActivation ensures that a simple taproot channel is
// active if the initiator disconnects and reconnects in between channel opening
// and channel confirmation.