@@ -762,31 +762,42 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
762762 batcher := NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
763763 testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
764764 batcherStore , sweepStore )
765+ runErrChan := make (chan error )
765766 go func () {
766- err := batcher .Run (ctx )
767- checkBatcherError (t , err )
767+ runErrChan <- batcher .Run (ctx )
768768 }()
769769
770770 // Create a sweep request.
771771 op1 := wire.OutPoint {
772772 Hash : chainhash.Hash {1 , 1 },
773773 Index : 1 ,
774774 }
775+ const (
776+ inputValue = 111
777+ outputValue = 50
778+ fee = inputValue - outputValue
779+ )
780+ spendErrChan := make (chan error , 1 )
781+ notifier := & SpendNotifier {
782+ SpendChan : make (chan * SpendDetail , 1 ),
783+ SpendErrChan : spendErrChan ,
784+ QuitChan : make (chan bool , 1 ),
785+ }
775786 sweepReq1 := SweepRequest {
776787 SwapHash : lntypes.Hash {1 , 1 , 1 },
777788 Inputs : []Input {{
778- Value : 111 ,
789+ Value : inputValue ,
779790 Outpoint : op1 ,
780791 }},
781- Notifier : & dummyNotifier ,
792+ Notifier : notifier ,
782793 }
783794
784795 const initiationHeight = 550
785796
786797 swap1 := & loopdb.LoopOutContract {
787798 SwapContract : loopdb.SwapContract {
788799 CltvExpiry : 111 ,
789- AmountRequested : 111 ,
800+ AmountRequested : inputValue ,
790801 ProtocolVersion : loopdb .ProtocolVersionMuSig2 ,
791802 HtlcKeys : htlcKeys ,
792803 InitiationHeight : initiationHeight ,
@@ -806,48 +817,98 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
806817
807818 // When batch is successfully created it will execute it's first step,
808819 // which leads to a spend monitor of the primary sweep.
809- <- lnd .RegisterSpendChannel
820+ spendReg := <- lnd .RegisterSpendChannel
821+
822+ // Wait for tx to be published.
823+ <- lnd .TxPublishChannel
810824
811825 // Eventually request will be consumed and a new batch will spin up.
826+ var primarySweepID wire.OutPoint
812827 require .Eventually (t , func () bool {
813- return batcher .numBatches (ctx ) == 1
814- }, test .Timeout , eventuallyCheckFrequency )
828+ batch := tryGetOnlyBatch (ctx , batcher )
829+ if batch == nil {
830+ return false
831+ }
815832
816- // Find the batch and assign it to a local variable for easier access.
817- batch := & batch {}
818- for _ , btch := range getBatches (ctx , batcher ) {
819- btch .testRunInEventLoop (ctx , func () {
820- if btch .primarySweepID == op1 {
821- batch = btch
822- }
823- })
824- }
833+ primarySweepID = batch .snapshot (ctx ).primarySweepID
825834
826- require .Eventually (t , func () bool {
827835 // Batch should have the sweep stored.
828836 return batch .numSweeps (ctx ) == 1
829837 }, test .Timeout , eventuallyCheckFrequency )
830838
831839 // The primary sweep id should be that of the first inserted sweep.
832- require .Equal (t , batch .primarySweepID , op1 )
833-
834- // Wait for tx to be published.
835- <- lnd .TxPublishChannel
840+ require .Equal (t , primarySweepID , op1 )
836841
837842 err = lnd .NotifyHeight (601 )
838843 require .NoError (t , err )
839844
840845 // After receiving a height notification the batch will step again,
841846 // leading to a new spend monitoring.
842847 require .Eventually (t , func () bool {
843- batch := batch .snapshot (ctx )
848+ batch := tryGetOnlyBatch (ctx , batcher )
849+ if batch == nil {
850+ return false
851+ }
852+ batch = batch .snapshot (ctx )
844853
845854 return batch .currentHeight == 601
846855 }, test .Timeout , eventuallyCheckFrequency )
847856
848857 // Wait for tx to be published.
849858 <- lnd .TxPublishChannel
850859
860+ // Emulate spend error.
861+ testError := errors .New ("test error" )
862+ spendReg .ErrChan <- testError
863+
864+ // Make sure the caller of AddSweep got the spending error.
865+ notifierErr := <- spendErrChan
866+ require .Error (t , notifierErr )
867+ require .ErrorIs (t , notifierErr , testError )
868+
869+ // Wait for the batcher to crash because of the spending error.
870+ runErr := <- runErrChan
871+ require .ErrorIs (t , runErr , testError )
872+
873+ // Now launch the batcher again.
874+ batcher = NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
875+ testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
876+ batcherStore , sweepStore )
877+ go func () {
878+ runErrChan <- batcher .Run (ctx )
879+ }()
880+
881+ // When batch is successfully created it will execute it's first step,
882+ // which leads to a spend monitor of the primary sweep.
883+ <- lnd .RegisterSpendChannel
884+
885+ // Wait for tx to be published.
886+ <- lnd .TxPublishChannel
887+
888+ // Deliver sweep request to batcher.
889+ spendChan := make (chan * SpendDetail , 1 )
890+ notifier = & SpendNotifier {
891+ SpendChan : spendChan ,
892+ SpendErrChan : make (chan error , 1 ),
893+ QuitChan : make (chan bool , 1 ),
894+ }
895+ sweepReq1 .Notifier = notifier
896+ require .NoError (t , batcher .AddSweep (ctx , & sweepReq1 ))
897+
898+ // Wait for the notifier to be installed.
899+ require .Eventually (t , func () bool {
900+ batch := tryGetOnlyBatch (ctx , batcher )
901+ if batch == nil {
902+ return false
903+ }
904+ batch = batch .snapshot (ctx )
905+
906+ sweep := batch .sweeps [batch .primarySweepID ]
907+
908+ return sweep .notifier != nil &&
909+ sweep .notifier .SpendChan == spendChan
910+ }, test .Timeout , eventuallyCheckFrequency )
911+
851912 // Create the spending tx that will trigger the spend monitor of the
852913 // batch.
853914 spendingTx := & wire.MsgTx {
@@ -861,6 +922,7 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
861922 },
862923 TxOut : []* wire.TxOut {
863924 {
925+ Value : outputValue ,
864926 PkScript : []byte {3 , 2 , 1 },
865927 },
866928 },
@@ -879,6 +941,11 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
879941 // We notify the spend.
880942 lnd .SpendChannel <- spendDetail
881943
944+ // Make sure the notifier got a proper spending notification.
945+ spending := <- spendChan
946+ require .Equal (t , spendingTxHash , spending .Tx .TxHash ())
947+ require .Equal (t , btcutil .Amount (fee ), spending .OnChainFeePortion )
948+
882949 // After receiving the spend, the batch is now monitoring for confs.
883950 confReg := <- lnd .RegisterConfChannel
884951
@@ -889,7 +956,84 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
889956 // The batch should eventually read the spend notification and progress
890957 // its state to closed.
891958 require .Eventually (t , func () bool {
892- batch := batch .snapshot (ctx )
959+ batch := tryGetOnlyBatch (ctx , batcher )
960+ if batch == nil {
961+ return false
962+ }
963+ batch = batch .snapshot (ctx )
964+
965+ return batch .state == Closed
966+ }, test .Timeout , eventuallyCheckFrequency )
967+
968+ // Emulate a confirmation error.
969+ confReg .ErrChan <- testError
970+
971+ // Wait for the batcher to crash because of the confirmation error.
972+ runErr = <- runErrChan
973+ require .ErrorIs (t , runErr , testError )
974+
975+ // Now launch the batcher again.
976+ batcher = NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
977+ testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
978+ batcherStore , sweepStore )
979+ go func () {
980+ runErrChan <- batcher .Run (ctx )
981+ }()
982+
983+ // When batch is successfully created it will execute it's first step,
984+ // which leads to a spend monitor of the primary sweep.
985+ <- lnd .RegisterSpendChannel
986+
987+ // Deliver sweep request to batcher.
988+ spendChan = make (chan * SpendDetail , 1 )
989+ notifier = & SpendNotifier {
990+ SpendChan : spendChan ,
991+ SpendErrChan : make (chan error , 1 ),
992+ QuitChan : make (chan bool , 1 ),
993+ }
994+ sweepReq1 .Notifier = notifier
995+ require .NoError (t , batcher .AddSweep (ctx , & sweepReq1 ))
996+
997+ // Wait for tx to be published. A closed batch is stored in DB as Open.
998+ <- lnd .TxPublishChannel
999+
1000+ // Wait for the notifier to be installed.
1001+ require .Eventually (t , func () bool {
1002+ batch := tryGetOnlyBatch (ctx , batcher )
1003+ if batch == nil {
1004+ return false
1005+ }
1006+ batch = batch .snapshot (ctx )
1007+
1008+ sweep := batch .sweeps [batch .primarySweepID ]
1009+
1010+ return sweep .notifier != nil &&
1011+ sweep .notifier .SpendChan == spendChan
1012+ }, test .Timeout , eventuallyCheckFrequency )
1013+
1014+ // We notify the spend.
1015+ lnd .SpendChannel <- spendDetail
1016+
1017+ // Make sure the notifier got a proper spending notification.
1018+ spending = <- spendChan
1019+ require .Equal (t , spendingTxHash , spending .Tx .TxHash ())
1020+ require .Equal (t , btcutil .Amount (fee ), spending .OnChainFeePortion )
1021+
1022+ // After receiving the spend, the batch is now monitoring for confs.
1023+ confReg = <- lnd .RegisterConfChannel
1024+
1025+ // Make sure the confirmation has proper height hint. It should pass
1026+ // the swap initiation height, not the current height.
1027+ require .Equal (t , int32 (initiationHeight ), confReg .HeightHint )
1028+
1029+ // The batch should eventually read the spend notification and progress
1030+ // its state to closed.
1031+ require .Eventually (t , func () bool {
1032+ batch := tryGetOnlyBatch (ctx , batcher )
1033+ if batch == nil {
1034+ return false
1035+ }
1036+ batch = batch .snapshot (ctx )
8931037
8941038 return batch .state == Closed
8951039 }, test .Timeout , eventuallyCheckFrequency )
@@ -905,8 +1049,60 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
9051049 // Eventually the batch receives the confirmation notification and
9061050 // confirms itself.
9071051 require .Eventually (t , func () bool {
1052+ batch := tryGetOnlyBatch (ctx , batcher )
1053+ if batch == nil {
1054+ return false
1055+ }
1056+
9081057 return batch .isComplete ()
9091058 }, test .Timeout , eventuallyCheckFrequency )
1059+
1060+ // Now emulate adding the sweep again after it was fully confirmed.
1061+ // This triggers another code path (monitorSpendAndNotify).
1062+ spendChan = make (chan * SpendDetail , 1 )
1063+ notifier = & SpendNotifier {
1064+ SpendChan : spendChan ,
1065+ SpendErrChan : make (chan error , 1 ),
1066+ QuitChan : make (chan bool , 1 ),
1067+ }
1068+ sweepReq1 .Notifier = notifier
1069+ require .NoError (t , batcher .AddSweep (ctx , & sweepReq1 ))
1070+
1071+ // Expect a spending registration.
1072+ <- lnd .RegisterSpendChannel
1073+
1074+ // We notify the spend.
1075+ lnd .SpendChannel <- spendDetail
1076+
1077+ // Now expect the notifier to produce the spending details.
1078+ spending = <- spendChan
1079+ require .Equal (t , spendingTxHash , spending .Tx .TxHash ())
1080+ require .Equal (t , btcutil .Amount (fee ), spending .OnChainFeePortion )
1081+
1082+ // Now check what happens in case of a spending error.
1083+ spendErrChan = make (chan error , 1 )
1084+ notifier = & SpendNotifier {
1085+ SpendChan : make (chan * SpendDetail , 1 ),
1086+ SpendErrChan : spendErrChan ,
1087+ QuitChan : make (chan bool , 1 ),
1088+ }
1089+ sweepReq1 .Notifier = notifier
1090+ require .NoError (t , batcher .AddSweep (ctx , & sweepReq1 ))
1091+
1092+ // Expect a spending registration.
1093+ spendReg = <- lnd .RegisterSpendChannel
1094+
1095+ // Emulate spend error.
1096+ spendReg .ErrChan <- testError
1097+
1098+ // Make sure the caller of AddSweep got the spending error.
1099+ notifierErr = <- spendErrChan
1100+ require .Error (t , notifierErr )
1101+ require .ErrorIs (t , notifierErr , testError )
1102+
1103+ // Wait for the batcher to crash because of the spending error.
1104+ runErr = <- runErrChan
1105+ require .ErrorIs (t , runErr , testError )
9101106}
9111107
9121108// wrappedLogger implements btclog.Logger, recording last debug message format.
0 commit comments