@@ -877,6 +877,236 @@ func testFundingExpiryBlocksOnPending(ht *lntest.HarnessTest) {
877877 ht .MineBlocksAndAssertNumTxes (1 , 1 )
878878}
879879
880+ // assertConfirmation is a helper to assert the ConfirmationsUntilActive and
881+ // ConfirmationHeight has been updated to the expected value.
882+ func assertConfirmation (ht * lntest.HarnessTest , hn * node.HarnessNode ,
883+ expConfLeft , expConfHeight uint32 ) {
884+
885+ ht .Helper ()
886+
887+ err := wait .NoError (func () error {
888+ // Node should have one pending open channel.
889+ pendingChan := ht .AssertNumPendingOpenChannels (hn , 1 )[0 ]
890+
891+ // Check if the ConfirmationsUntilActive is updated to the
892+ // expected value.
893+ if expConfLeft != pendingChan .ConfirmationsUntilActive {
894+ return fmt .Errorf ("remaining confirmations mismatch, " +
895+ "want %v, got %v" , expConfLeft ,
896+ pendingChan .ConfirmationsUntilActive )
897+ }
898+
899+ // Check if the ConfirmationHeight is updated to the expected
900+ // value.
901+ if expConfHeight != pendingChan .ConfirmationHeight {
902+ return fmt .Errorf ("confirmation height mismatch, want " +
903+ "%v, got %v" , expConfHeight ,
904+ pendingChan .ConfirmationHeight )
905+ }
906+
907+ return nil
908+ }, defaultTimeout )
909+
910+ require .NoError (ht , err )
911+ }
912+
913+ // testPendingChannelConfirmationUntilActive verifies the value for the rpc
914+ // field ConfirmationUntilActive updates correctly as soon as blocks are
915+ // confirmed.
916+ func testPendingChannelConfirmationUntilActive (ht * lntest.HarnessTest ) {
917+ var (
918+ numConfs uint32 = 5
919+ chanAmt btcutil.Amount = 100000
920+ )
921+
922+ // Since we want Bob's channels to require more than 1 on-chain
923+ // confirmation before becoming active, we will launch Bob with the
924+ // custom defaultchanconfs flag.
925+ alice := ht .NewNodeWithCoins ("Alice" , nil )
926+ bob := ht .NewNode ("Bob" , []string {
927+ fmt .Sprintf ("--bitcoin.defaultchanconfs=%v" , numConfs ),
928+ })
929+
930+ // Ensure Alice and Bob are connected.
931+ ht .EnsureConnected (alice , bob )
932+
933+ // Alice initiates a channel opening to Bob.
934+ param := lntest.OpenChannelParams {Amt : chanAmt }
935+ ht .OpenChannelAssertPending (alice , bob , param )
936+
937+ // Both Alice and Bob have one pending open channel.
938+ ht .AssertNumPendingOpenChannels (alice , 1 )
939+ ht .AssertNumPendingOpenChannels (bob , 1 )
940+
941+ // Since the funding transaction is not confirmed yet,
942+ // ConfirmationsUntilActive will always be numConfs, and confirmation
943+ // height will be 0.
944+ assertConfirmation (ht , alice , numConfs , 0 )
945+ assertConfirmation (ht , bob , numConfs , 0 )
946+
947+ // Mine the first block containing the funding transaction, This
948+ // confirms the funding transaction but the channel should still remain
949+ // pending.
950+ ht .MineBlocksAndAssertNumTxes (1 , 1 )
951+
952+ // Decrement numConfs to reflect that one confirmation has been
953+ // received.
954+ numConfs --
955+
956+ // Since the funding transaction has been mined, the best block height
957+ // corresponds to the confirmation height of the channel's opening tx.
958+ _ , expConfHeight := ht .GetBestBlock ()
959+
960+ // Channel remains pending after the first confirmation.
961+ ht .AssertNumPendingOpenChannels (alice , 1 )
962+ ht .AssertNumPendingOpenChannels (bob , 1 )
963+
964+ // Make sure the ConfirmationsUntilActive and ConfirmationHeight
965+ // fields have been updated to the expected values before restarting the
966+ // nodes.
967+ assertConfirmation (ht , alice , numConfs , uint32 (expConfHeight ))
968+ assertConfirmation (ht , bob , numConfs , uint32 (expConfHeight ))
969+
970+ // Restart both nodes to test that the appropriate state has been
971+ // persisted and that both nodes recover gracefully.
972+ ht .RestartNode (alice )
973+ ht .RestartNode (bob )
974+ ht .EnsureConnected (alice , bob )
975+
976+ // ConfirmationsUntilActive field should decrease as each block is
977+ // mined until the required number of confirmations is reached. Let's
978+ // mine a few blocks and verify the value of ConfirmationsUntilActive at
979+ // each step.
980+ for i := numConfs ; i > 0 ; i -- {
981+ expConfLeft := i
982+
983+ // Retrieve pending channels for both Alice and Bob and verify
984+ // the remaining confirmations and confirmation height.
985+ assertConfirmation (
986+ ht , alice , expConfLeft , uint32 (expConfHeight ),
987+ )
988+ assertConfirmation (ht , bob , expConfLeft , uint32 (expConfHeight ))
989+
990+ // Mine the next block.
991+ ht .MineBlocks (1 )
992+ }
993+
994+ // After the required number of confirmations, the channel should be
995+ // marked as active.
996+ ht .AssertNumPendingOpenChannels (alice , 0 )
997+ ht .AssertNumPendingOpenChannels (bob , 0 )
998+ }
999+
1000+ // testPendingChannelAfterReorg verifies the value for the rpc field
1001+ // ConfirmationUntilActive updates correctly as blocks are confirmed and after
1002+ // chain reorgs.
1003+ func testPendingChannelAfterReorg (ht * lntest.HarnessTest ) {
1004+ // Skip test for neutrino, as we cannot disconnect the miner at will.
1005+ if ht .IsNeutrinoBackend () {
1006+ ht .Skipf ("skipping reorg test for neutrino backend" )
1007+ }
1008+
1009+ var numConfs uint32 = 3
1010+
1011+ // Since we want Bob's channels to require more than 1 on-chain
1012+ // confirmation before becoming active, we will launch Bob with the
1013+ // custom defaultchanconfs flag.
1014+ miner := ht .Miner ()
1015+ alice := ht .NewNodeWithCoins ("Alice" , nil )
1016+ bob := ht .NewNode ("Bob" , []string {
1017+ fmt .Sprintf ("--bitcoin.defaultchanconfs=%v" , numConfs ),
1018+ })
1019+ ht .EnsureConnected (alice , bob )
1020+
1021+ // Spawn a temporary miner to simulate a chain reorg with a longer
1022+ // chain.
1023+ tempMiner := ht .SpawnTempMiner ()
1024+
1025+ // Alice initiates a channel opening to Bob.
1026+ params := lntest.OpenChannelParams {Amt : funding .MaxBtcFundingAmount }
1027+ ht .OpenChannelAssertPending (alice , bob , params )
1028+
1029+ // Mine the first block containing the funding transaction.
1030+ ht .MineBlocksAndAssertNumTxes (1 , 1 )
1031+
1032+ // Channel remains pending after the first confirmation.
1033+ ht .AssertNumPendingOpenChannels (alice , 1 )
1034+ ht .AssertNumPendingOpenChannels (bob , 1 )
1035+
1036+ // Since the funding transaction has been mined, the best block height
1037+ // corresponds to the confirmation height of the channel's opening tx.
1038+ _ , expConfHeight := ht .GetBestBlock ()
1039+
1040+ // Make sure the ConfirmationsUntilActive and ConfirmationHeight
1041+ // fields have been updated to the expected values before reorg.
1042+ //
1043+ // Decrement numConfs to reflect one confirmation received.
1044+ assertConfirmation (ht , alice , numConfs - 1 , uint32 (expConfHeight ))
1045+ assertConfirmation (ht , bob , numConfs - 1 , uint32 (expConfHeight ))
1046+
1047+ // We now cause a fork, by letting our original miner mine 1 blocks,
1048+ // and our new miner mine 3.
1049+ _ , err := tempMiner .Client .Generate (3 )
1050+ require .NoError (ht , err , "unable to generate blocks on temp miner" )
1051+
1052+ // Ensure the chain lengths are what we expect, with the temp miner
1053+ // being 2 blocks ahead.
1054+ miner .AssertMinerBlockHeightDelta (tempMiner , 2 )
1055+
1056+ // Now we disconnect Alice's chain backend from the original miner, and
1057+ // connect the two miners together. Since the temporary miner knows
1058+ // about a longer chain, both miners should sync to that chain.
1059+ ht .DisconnectMiner ()
1060+
1061+ // Connecting to the temporary miner should now cause our original
1062+ // chain to be re-orged out.
1063+ miner .ConnectMiner (tempMiner )
1064+
1065+ // Once again they should be on the same chain.
1066+ miner .AssertMinerBlockHeightDelta (tempMiner , 0 )
1067+
1068+ // Now we disconnect the two miners, and connect our original miner to
1069+ // our chain backend once again.
1070+ miner .DisconnectMiner (tempMiner )
1071+ ht .ConnectMiner ()
1072+
1073+ // This should have caused a reorg, and Alice should sync to the longer
1074+ // chain, where the funding transaction is not confirmed.
1075+ _ , tempMinerHeight , err := tempMiner .Client .GetBestBlock ()
1076+ require .NoError (ht , err , "unable to get current blockheight" )
1077+ ht .WaitForNodeBlockHeight (alice , tempMinerHeight )
1078+
1079+ // After the reorg, the funding transaction's confirmation is removed,
1080+ // so the pending channel should again require the original number of
1081+ // confirmations and have a confirmation height of 0.
1082+ assertConfirmation (ht , alice , numConfs , 0 )
1083+ assertConfirmation (ht , bob , numConfs , 0 )
1084+
1085+ // Mine the first block containing the funding transaction again.
1086+ ht .MineBlocksAndAssertNumTxes (1 , 1 )
1087+
1088+ // Decrement numConfs to reflect one confirmation received.
1089+ numConfs --
1090+
1091+ // Since the funding transaction has been mined, the best block height
1092+ // corresponds to the confirmation height of the channel's opening tx.
1093+ _ , expConfHeight = ht .GetBestBlock ()
1094+
1095+ // Make sure the ConfirmationsUntilActive and ConfirmationHeight
1096+ // fields have been updated to the expected values after reorg.
1097+ assertConfirmation (ht , alice , numConfs , uint32 (expConfHeight ))
1098+ assertConfirmation (ht , bob , numConfs , uint32 (expConfHeight ))
1099+
1100+ // Cleanup by mining the remaining blocks to reach the required number
1101+ // of confirmations.
1102+ ht .MineBlocks (int (numConfs ))
1103+
1104+ // After the required number of confirmations, the channel should be
1105+ // marked as active.
1106+ ht .AssertNumPendingOpenChannels (alice , 0 )
1107+ ht .AssertNumPendingOpenChannels (bob , 0 )
1108+ }
1109+
8801110// testSimpleTaprootChannelActivation ensures that a simple taproot channel is
8811111// active if the initiator disconnects and reconnects in between channel opening
8821112// and channel confirmation.
0 commit comments