@@ -19,6 +19,7 @@ import (
19
19
"github.com/lightninglabs/loop/loopdb"
20
20
"github.com/lightninglabs/loop/test"
21
21
"github.com/lightninglabs/loop/utils"
22
+ "github.com/lightningnetwork/lnd/build"
22
23
"github.com/lightningnetwork/lnd/chainntnfs"
23
24
"github.com/lightningnetwork/lnd/clock"
24
25
"github.com/lightningnetwork/lnd/input"
@@ -1176,6 +1177,161 @@ func testDelays(t *testing.T, store testStore, batcherStore testBatcherStore) {
1176
1177
checkBatcherError (t , runErr )
1177
1178
}
1178
1179
1180
+ // testMaxSweepsPerBatch tests the limit on max number of sweeps per batch.
1181
+ func testMaxSweepsPerBatch (t * testing.T , store testStore ,
1182
+ batcherStore testBatcherStore ) {
1183
+
1184
+ // Disable logging, because this test is very noisy.
1185
+ oldLogger := log
1186
+ UseLogger (build .NewSubLogger ("SWEEP" , nil ))
1187
+ defer UseLogger (oldLogger )
1188
+
1189
+ defer test .Guard (t , test .WithGuardTimeout (5 * time .Minute ))()
1190
+
1191
+ lnd := test .NewMockLnd ()
1192
+ ctx , cancel := context .WithCancel (context .Background ())
1193
+
1194
+ sweepStore , err := NewSweepFetcherFromSwapStore (store , lnd .ChainParams )
1195
+ require .NoError (t , err )
1196
+
1197
+ startTime := time .Date (2018 , 11 , 1 , 0 , 0 , 0 , 0 , time .UTC )
1198
+ testClock := clock .NewTestClock (startTime )
1199
+
1200
+ // Create muSig2SignSweep failing all sweeps to force non-cooperative
1201
+ // scenario (it increases transaction size).
1202
+ muSig2SignSweep := func (ctx context.Context ,
1203
+ protocolVersion loopdb.ProtocolVersion , swapHash lntypes.Hash ,
1204
+ paymentAddr [32 ]byte , nonce []byte , sweepTxPsbt []byte ,
1205
+ prevoutMap map [wire.OutPoint ]* wire.TxOut ) (
1206
+ []byte , []byte , error ) {
1207
+
1208
+ return nil , nil , fmt .Errorf ("test error" )
1209
+ }
1210
+
1211
+ // Set publish delay.
1212
+ const publishDelay = 3 * time .Second
1213
+
1214
+ batcher := NewBatcher (
1215
+ lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
1216
+ muSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
1217
+ batcherStore , sweepStore , WithPublishDelay (publishDelay ),
1218
+ WithClock (testClock ),
1219
+ )
1220
+
1221
+ var wg sync.WaitGroup
1222
+ wg .Add (1 )
1223
+
1224
+ var runErr error
1225
+ go func () {
1226
+ defer wg .Done ()
1227
+ runErr = batcher .Run (ctx )
1228
+ }()
1229
+
1230
+ // Wait for the batcher to be initialized.
1231
+ <- batcher .initDone
1232
+
1233
+ const swapsNum = MaxSweepsPerBatch + 1
1234
+
1235
+ // Expect 2 batches to be registered.
1236
+ expectedBatches := (swapsNum + MaxSweepsPerBatch - 1 ) /
1237
+ MaxSweepsPerBatch
1238
+
1239
+ for i := 0 ; i < swapsNum ; i ++ {
1240
+ preimage := lntypes.Preimage {2 , byte (i % 256 ), byte (i / 256 )}
1241
+ swapHash := preimage .Hash ()
1242
+
1243
+ // Create a sweep request.
1244
+ sweepReq := SweepRequest {
1245
+ SwapHash : swapHash ,
1246
+ Value : 111 ,
1247
+ Outpoint : wire.OutPoint {
1248
+ Hash : chainhash.Hash {1 , 1 },
1249
+ Index : 1 ,
1250
+ },
1251
+ Notifier : & dummyNotifier ,
1252
+ }
1253
+
1254
+ swap := & loopdb.LoopOutContract {
1255
+ SwapContract : loopdb.SwapContract {
1256
+ CltvExpiry : 1000 ,
1257
+ AmountRequested : 111 ,
1258
+ ProtocolVersion : loopdb .ProtocolVersionMuSig2 ,
1259
+ HtlcKeys : htlcKeys ,
1260
+
1261
+ // Make preimage unique to pass SQL constraints.
1262
+ Preimage : preimage ,
1263
+ },
1264
+
1265
+ DestAddr : destAddr ,
1266
+ SwapInvoice : swapInvoice ,
1267
+ SweepConfTarget : 123 ,
1268
+ }
1269
+
1270
+ err = store .CreateLoopOut (ctx , swapHash , swap )
1271
+ require .NoError (t , err )
1272
+ store .AssertLoopOutStored ()
1273
+
1274
+ // Deliver sweep request to batcher.
1275
+ require .NoError (t , batcher .AddSweep (& sweepReq ))
1276
+
1277
+ // If this is new batch, expect a spend registration.
1278
+ if i % MaxSweepsPerBatch == 0 {
1279
+ <- lnd .RegisterSpendChannel
1280
+ }
1281
+ }
1282
+
1283
+ // Eventually the batches are launched and all the sweeps are added.
1284
+ require .Eventually (t , func () bool {
1285
+ // Make sure all the batches have started.
1286
+ if len (batcher .batches ) != expectedBatches {
1287
+ return false
1288
+ }
1289
+
1290
+ // Make sure all the sweeps were added.
1291
+ sweepsNum := 0
1292
+ for _ , batch := range batcher .batches {
1293
+ sweepsNum += len (batch .sweeps )
1294
+ }
1295
+ return sweepsNum == swapsNum
1296
+ }, test .Timeout , eventuallyCheckFrequency )
1297
+
1298
+ // Advance the clock to publishDelay, so batches are published.
1299
+ now := startTime .Add (publishDelay )
1300
+ testClock .SetTime (now )
1301
+
1302
+ // Expect mockSigner.SignOutputRaw calls to sign non-cooperative
1303
+ // sweeps.
1304
+ for i := 0 ; i < expectedBatches ; i ++ {
1305
+ <- lnd .SignOutputRawChannel
1306
+ }
1307
+
1308
+ // Wait for txs to be published.
1309
+ inputsNum := 0
1310
+ const maxWeight = lntypes .WeightUnit (400_000 )
1311
+ for i := 0 ; i < expectedBatches ; i ++ {
1312
+ tx := <- lnd .TxPublishChannel
1313
+ inputsNum += len (tx .TxIn )
1314
+
1315
+ // Make sure the transaction size is standard.
1316
+ weight := lntypes .WeightUnit (
1317
+ blockchain .GetTransactionWeight (btcutil .NewTx (tx )),
1318
+ )
1319
+ require .Less (t , weight , maxWeight )
1320
+ t .Logf ("tx weight: %v" , weight )
1321
+ }
1322
+
1323
+ // Make sure the number of inputs in batch transactions is equal
1324
+ // to the number of swaps.
1325
+ require .Equal (t , swapsNum , inputsNum )
1326
+
1327
+ // Now make the batcher quit by canceling the context.
1328
+ cancel ()
1329
+ wg .Wait ()
1330
+
1331
+ // Make sure the batcher exited without an error.
1332
+ checkBatcherError (t , runErr )
1333
+ }
1334
+
1179
1335
// testSweepBatcherSweepReentry tests that when an old version of the batch tx
1180
1336
// gets confirmed the sweep leftovers are sent back to the batcher.
1181
1337
func testSweepBatcherSweepReentry (t * testing.T , store testStore ,
@@ -3468,6 +3624,11 @@ func TestDelays(t *testing.T) {
3468
3624
runTests (t , testDelays )
3469
3625
}
3470
3626
3627
+ // TestMaxSweepsPerBatch tests the limit on max number of sweeps per batch.
3628
+ func TestMaxSweepsPerBatch (t * testing.T ) {
3629
+ runTests (t , testMaxSweepsPerBatch )
3630
+ }
3631
+
3471
3632
// TestSweepBatcherSweepReentry tests that when an old version of the batch tx
3472
3633
// gets confirmed the sweep leftovers are sent back to the batcher.
3473
3634
func TestSweepBatcherSweepReentry (t * testing.T ) {
0 commit comments