@@ -876,7 +876,7 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture
876876 assert(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED )
877877 }
878878
879- test( " recv INPUT_DISCONNECTED (unsigned rbf attempt) " , Tag ( ChannelStateTestsTags . DualFunding )) { f =>
879+ private def initiateRbf ( f : FixtureParam ) : Unit = {
880880 import f ._
881881
882882 alice ! CMD_BUMP_FUNDING_FEE (TestProbe ().ref, TestConstants .feeratePerKw * 1.1 , fundingFeeBudget = 100_000 .sat, 0 , None )
@@ -900,28 +900,43 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture
900900 alice2bob.forward(bob)
901901 bob2alice.expectMsgType[TxComplete ]
902902 bob2alice.forward(alice)
903- alice2bob.expectMsgType[TxComplete ] // bob doesn't receive alice's tx_complete
904- alice2bob.expectMsgType[CommitSig ] // bob doesn't receive alice's commit_sig
903+ }
905904
906- awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
907- val rbfTx = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.asInstanceOf [DualFundingStatus .RbfWaitingForSigs ].signingSession.fundingTx
908- assert(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfInProgress ])
905+ private def reconnectRbf (f : FixtureParam ): (ChannelReestablish , ChannelReestablish ) = {
906+ import f ._
909907
910908 alice ! INPUT_DISCONNECTED
911909 awaitCond(alice.stateName == OFFLINE )
912- assert(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
913910 bob ! INPUT_DISCONNECTED
914911 awaitCond(bob.stateName == OFFLINE )
915- assert(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
916912
917913 val aliceInit = Init (alice.underlyingActor.nodeParams.features.initFeatures())
918914 val bobInit = Init (bob.underlyingActor.nodeParams.features.initFeatures())
919915 alice ! INPUT_RECONNECTED (bob, aliceInit, bobInit)
920916 bob ! INPUT_RECONNECTED (alice, bobInit, aliceInit)
921- assert( alice2bob.expectMsgType[ChannelReestablish ].nextFundingTxId_opt.contains(rbfTx.txId))
917+ val channelReestablishAlice = alice2bob.expectMsgType[ChannelReestablish ]
922918 alice2bob.forward(bob)
923- assert( bob2alice.expectMsgType[ChannelReestablish ].nextFundingTxId_opt.isEmpty)
919+ val channelReestablishBob = bob2alice.expectMsgType[ChannelReestablish ]
924920 bob2alice.forward(alice)
921+ (channelReestablishAlice, channelReestablishBob)
922+ }
923+
924+ test(" recv INPUT_DISCONNECTED (unsigned rbf attempt)" , Tag (ChannelStateTestsTags .DualFunding )) { f =>
925+ import f ._
926+
927+ initiateRbf(f)
928+ alice2bob.expectMsgType[TxComplete ] // bob doesn't receive alice's tx_complete
929+ alice2bob.expectMsgType[CommitSig ] // bob doesn't receive alice's commit_sig
930+
931+ awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
932+ val rbfTxId = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.asInstanceOf [DualFundingStatus .RbfWaitingForSigs ].signingSession.fundingTx.txId
933+ assert(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfInProgress ])
934+
935+ val (channelReestablishAlice, channelReestablishBob) = reconnectRbf(f)
936+ assert(channelReestablishAlice.nextFundingTxId_opt.contains(rbfTxId))
937+ assert(channelReestablishAlice.nextLocalCommitmentNumber == 1 )
938+ assert(channelReestablishBob.nextFundingTxId_opt.isEmpty)
939+ assert(channelReestablishBob.nextLocalCommitmentNumber == 1 )
925940
926941 // Bob detects that Alice stored an old RBF attempt and tells her to abort.
927942 bob2alice.expectMsgType[TxAbort ]
@@ -934,71 +949,117 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture
934949 bob2alice.expectNoMessage(100 millis)
935950 }
936951
937- test(" recv INPUT_DISCONNECTED (signed rbf attempt )" , Tag (ChannelStateTestsTags .DualFunding )) { f =>
952+ test(" recv INPUT_DISCONNECTED (rbf commit_sig partially received )" , Tag (ChannelStateTestsTags .DualFunding )) { f =>
938953 import f ._
939954
940- val currentFundingTxId = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].latestFundingTx.sharedTx.txId
941- alice ! CMD_BUMP_FUNDING_FEE (TestProbe ().ref, TestConstants .feeratePerKw * 1.1 , fundingFeeBudget = 100_000 .sat, 0 , None )
942- alice2bob.expectMsgType[TxInitRbf ]
955+ initiateRbf(f)
956+ alice2bob.expectMsgType[TxComplete ]
943957 alice2bob.forward(bob)
944- bob2alice.expectMsgType[TxAckRbf ]
945- bob2alice.forward(alice)
946- alice2bob.expectMsgType[TxAddInput ]
958+ alice2bob.expectMsgType[CommitSig ]
947959 alice2bob.forward(bob)
948- bob2alice.expectMsgType[TxAddInput ]
949- bob2alice.forward(alice)
950- alice2bob.expectMsgType[TxAddInput ]
960+ bob2alice.expectMsgType[CommitSig ] // Alice doesn't receive Bob's commit_sig
961+ bob2alice.expectMsgType[TxSignatures ] // Alice doesn't receive Bob's tx_signatures
962+ awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
963+ awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
964+ val rbfTxId = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.asInstanceOf [DualFundingStatus .RbfWaitingForSigs ].signingSession.fundingTx.txId
965+
966+ val (channelReestablishAlice, channelReestablishBob) = reconnectRbf(f)
967+ assert(channelReestablishAlice.nextFundingTxId_opt.contains(rbfTxId))
968+ assert(channelReestablishAlice.nextLocalCommitmentNumber == 1 )
969+ assert(channelReestablishBob.nextFundingTxId_opt.contains(rbfTxId))
970+ assert(channelReestablishBob.nextLocalCommitmentNumber == 1 )
971+
972+ // Alice and Bob exchange signatures and complete the RBF attempt.
973+ alice2bob.expectMsgType[CommitSig ]
951974 alice2bob.forward(bob)
952- bob2alice.expectMsgType[TxAddInput ]
975+ bob2alice.expectMsgType[CommitSig ]
953976 bob2alice.forward(alice)
954- alice2bob.expectMsgType[TxAddOutput ]
955- alice2bob.forward(bob)
956- bob2alice.expectMsgType[TxAddOutput ]
977+ bob2alice.expectMsgType[TxSignatures ]
957978 bob2alice.forward(alice)
958- alice2bob.expectMsgType[TxAddOutput ]
979+ alice2bob.expectMsgType[TxSignatures ]
959980 alice2bob.forward(bob)
960- bob2alice.expectMsgType[TxComplete ]
961- bob2alice.forward(alice)
981+ val nextFundingTx = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].latestFundingTx.sharedTx.asInstanceOf [FullySignedSharedTransaction ]
982+ assert(aliceListener.expectMsgType[TransactionPublished ].tx.txid == nextFundingTx.signedTx.txid)
983+ assert(alice2blockchain.expectMsgType[WatchFundingConfirmed ].txId == nextFundingTx.signedTx.txid)
984+ assert(bobListener.expectMsgType[TransactionPublished ].tx.txid == nextFundingTx.signedTx.txid)
985+ assert(bob2blockchain.expectMsgType[WatchFundingConfirmed ].txId == nextFundingTx.signedTx.txid)
986+ awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
987+ awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
988+ }
989+
990+ test(" recv INPUT_DISCONNECTED (rbf commit_sig received)" , Tag (ChannelStateTestsTags .DualFunding )) { f =>
991+ import f ._
992+
993+ initiateRbf(f)
962994 alice2bob.expectMsgType[TxComplete ]
963995 alice2bob.forward(bob)
964- bob2alice.expectMsgType[CommitSig ] // alice doesn't receive bob's commit_sig
965- alice2bob.expectMsgType[CommitSig ] // bob doesn't receive alice's commit_sig
966-
996+ alice2bob.expectMsgType[CommitSig ]
997+ alice2bob.forward(bob)
998+ bob2alice.expectMsgType[CommitSig ]
999+ bob2alice.forward(alice)
1000+ bob2alice.expectMsgType[TxSignatures ] // Alice doesn't receive Bob's tx_signatures
9671001 awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
968- awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status. isInstanceOf [ DualFundingStatus .RbfWaitingForSigs ] )
1002+ awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
9691003 val rbfTx = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.asInstanceOf [DualFundingStatus .RbfWaitingForSigs ].signingSession.fundingTx
9701004
971- alice ! INPUT_DISCONNECTED
972- awaitCond(alice.stateName == OFFLINE )
973- assert(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
974- bob ! INPUT_DISCONNECTED
975- awaitCond(bob.stateName == OFFLINE )
976- assert(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status.isInstanceOf [DualFundingStatus .RbfWaitingForSigs ])
1005+ val (channelReestablishAlice, channelReestablishBob) = reconnectRbf(f)
1006+ assert(channelReestablishAlice.nextFundingTxId_opt.contains(rbfTx.txId))
1007+ assert(channelReestablishAlice.nextLocalCommitmentNumber == 1 )
1008+ assert(channelReestablishBob.nextFundingTxId_opt.contains(rbfTx.txId))
1009+ assert(channelReestablishBob.nextLocalCommitmentNumber == 1 )
9771010
978- val aliceInit = Init (alice.underlyingActor.nodeParams.features.initFeatures())
979- val bobInit = Init (bob.underlyingActor.nodeParams.features.initFeatures())
980- alice ! INPUT_RECONNECTED (bob, aliceInit, bobInit)
981- bob ! INPUT_RECONNECTED (alice, bobInit, aliceInit)
982- assert(alice2bob.expectMsgType[ChannelReestablish ].nextFundingTxId_opt.contains(rbfTx.txId))
1011+ // Alice and Bob exchange signatures and complete the RBF attempt.
1012+ alice2bob.expectMsgType[CommitSig ]
9831013 alice2bob.forward(bob)
984- assert(bob2alice.expectMsgType[ChannelReestablish ].nextFundingTxId_opt.contains(rbfTx.txId))
1014+ bob2alice.expectMsgType[CommitSig ]
1015+ bob2alice.forward(alice)
1016+ bob2alice.expectMsgType[TxSignatures ]
9851017 bob2alice.forward(alice)
1018+ alice2bob.expectMsgType[TxSignatures ]
1019+ alice2bob.forward(bob)
1020+ val nextFundingTx = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].latestFundingTx.sharedTx.asInstanceOf [FullySignedSharedTransaction ]
1021+ assert(aliceListener.expectMsgType[TransactionPublished ].tx.txid == nextFundingTx.signedTx.txid)
1022+ assert(alice2blockchain.expectMsgType[WatchFundingConfirmed ].txId == nextFundingTx.signedTx.txid)
1023+ assert(bobListener.expectMsgType[TransactionPublished ].tx.txid == nextFundingTx.signedTx.txid)
1024+ assert(bob2blockchain.expectMsgType[WatchFundingConfirmed ].txId == nextFundingTx.signedTx.txid)
1025+ awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
1026+ awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
1027+ }
9861028
987- // Alice and Bob exchange signatures and complete the RBF attempt.
1029+ test(" recv INPUT_DISCONNECTED (rbf tx_signatures partially received)" , Tag (ChannelStateTestsTags .DualFunding )) { f =>
1030+ import f ._
1031+
1032+ val currentFundingTxId = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].latestFundingTx.sharedTx.txId
1033+ initiateRbf(f)
1034+ alice2bob.expectMsgType[TxComplete ]
1035+ alice2bob.forward(bob)
9881036 alice2bob.expectMsgType[CommitSig ]
9891037 alice2bob.forward(bob)
9901038 bob2alice.expectMsgType[CommitSig ]
9911039 bob2alice.forward(alice)
9921040 bob2alice.expectMsgType[TxSignatures ]
9931041 bob2alice.forward(alice)
1042+ alice2bob.expectMsgType[TxSignatures ] // Bob doesn't receive Alice's tx_signatures
1043+ awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
1044+ awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
1045+ val rbfTxId = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].latestFundingTx.sharedTx.txId
1046+ assert(rbfTxId != currentFundingTxId)
1047+
1048+ val (channelReestablishAlice, channelReestablishBob) = reconnectRbf(f)
1049+ assert(channelReestablishAlice.nextFundingTxId_opt.isEmpty)
1050+ assert(channelReestablishAlice.nextLocalCommitmentNumber == 1 )
1051+ assert(channelReestablishBob.nextFundingTxId_opt.contains(rbfTxId))
1052+ assert(channelReestablishBob.nextLocalCommitmentNumber == 1 )
1053+
1054+ // Alice and Bob exchange signatures and complete the RBF attempt.
1055+ bob2alice.expectNoMessage(100 millis)
9941056 alice2bob.expectMsgType[TxSignatures ]
9951057 alice2bob.forward(bob)
9961058 val nextFundingTx = alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].latestFundingTx.sharedTx.asInstanceOf [FullySignedSharedTransaction ]
9971059 assert(aliceListener.expectMsgType[TransactionPublished ].tx.txid == nextFundingTx.signedTx.txid)
9981060 assert(alice2blockchain.expectMsgType[WatchFundingConfirmed ].txId == nextFundingTx.signedTx.txid)
9991061 assert(bobListener.expectMsgType[TransactionPublished ].tx.txid == nextFundingTx.signedTx.txid)
10001062 assert(bob2blockchain.expectMsgType[WatchFundingConfirmed ].txId == nextFundingTx.signedTx.txid)
1001- assert(currentFundingTxId != nextFundingTx.txId)
10021063 awaitCond(alice.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
10031064 awaitCond(bob.stateData.asInstanceOf [DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED ].status == DualFundingStatus .WaitingForConfirmations )
10041065 }
0 commit comments