@@ -762,31 +762,42 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
762
762
batcher := NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
763
763
testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
764
764
batcherStore , sweepStore )
765
+ runErrChan := make (chan error )
765
766
go func () {
766
- err := batcher .Run (ctx )
767
- checkBatcherError (t , err )
767
+ runErrChan <- batcher .Run (ctx )
768
768
}()
769
769
770
770
// Create a sweep request.
771
771
op1 := wire.OutPoint {
772
772
Hash : chainhash.Hash {1 , 1 },
773
773
Index : 1 ,
774
774
}
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
+ }
775
786
sweepReq1 := SweepRequest {
776
787
SwapHash : lntypes.Hash {1 , 1 , 1 },
777
788
Inputs : []Input {{
778
- Value : 111 ,
789
+ Value : inputValue ,
779
790
Outpoint : op1 ,
780
791
}},
781
- Notifier : & dummyNotifier ,
792
+ Notifier : notifier ,
782
793
}
783
794
784
795
const initiationHeight = 550
785
796
786
797
swap1 := & loopdb.LoopOutContract {
787
798
SwapContract : loopdb.SwapContract {
788
799
CltvExpiry : 111 ,
789
- AmountRequested : 111 ,
800
+ AmountRequested : inputValue ,
790
801
ProtocolVersion : loopdb .ProtocolVersionMuSig2 ,
791
802
HtlcKeys : htlcKeys ,
792
803
InitiationHeight : initiationHeight ,
@@ -806,48 +817,98 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
806
817
807
818
// When batch is successfully created it will execute it's first step,
808
819
// 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
810
824
811
825
// Eventually request will be consumed and a new batch will spin up.
826
+ var primarySweepID wire.OutPoint
812
827
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
+ }
815
832
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
825
834
826
- require .Eventually (t , func () bool {
827
835
// Batch should have the sweep stored.
828
836
return batch .numSweeps (ctx ) == 1
829
837
}, test .Timeout , eventuallyCheckFrequency )
830
838
831
839
// 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 )
836
841
837
842
err = lnd .NotifyHeight (601 )
838
843
require .NoError (t , err )
839
844
840
845
// After receiving a height notification the batch will step again,
841
846
// leading to a new spend monitoring.
842
847
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 )
844
853
845
854
return batch .currentHeight == 601
846
855
}, test .Timeout , eventuallyCheckFrequency )
847
856
848
857
// Wait for tx to be published.
849
858
<- lnd .TxPublishChannel
850
859
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
+ spendReg = <- 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 (& 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
+
851
912
// Create the spending tx that will trigger the spend monitor of the
852
913
// batch.
853
914
spendingTx := & wire.MsgTx {
@@ -861,6 +922,7 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
861
922
},
862
923
TxOut : []* wire.TxOut {
863
924
{
925
+ Value : outputValue ,
864
926
PkScript : []byte {3 , 2 , 1 },
865
927
},
866
928
},
@@ -879,6 +941,11 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
879
941
// We notify the spend.
880
942
lnd .SpendChannel <- spendDetail
881
943
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
+
882
949
// After receiving the spend, the batch is now monitoring for confs.
883
950
confReg := <- lnd .RegisterConfChannel
884
951
@@ -889,7 +956,84 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
889
956
// The batch should eventually read the spend notification and progress
890
957
// its state to closed.
891
958
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
+ spendReg = <- 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 (& 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 )
893
1037
894
1038
return batch .state == Closed
895
1039
}, test .Timeout , eventuallyCheckFrequency )
@@ -905,8 +1049,60 @@ func testSweepBatcherSimpleLifecycle(t *testing.T, store testStore,
905
1049
// Eventually the batch receives the confirmation notification and
906
1050
// confirms itself.
907
1051
require .Eventually (t , func () bool {
1052
+ batch := tryGetOnlyBatch (ctx , batcher )
1053
+ if batch == nil {
1054
+ return false
1055
+ }
1056
+
908
1057
return batch .isComplete ()
909
1058
}, 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 (& 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 (& 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 )
910
1106
}
911
1107
912
1108
// wrappedLogger implements btclog.Logger, recording last debug message format.
0 commit comments