@@ -159,6 +159,11 @@ func (h *mockPresignedHelper) SignTx(ctx context.Context,
159
159
h .mu .Lock ()
160
160
defer h .mu .Unlock ()
161
161
162
+ if feeRate < minRelayFee {
163
+ return nil , fmt .Errorf ("feeRate (%v) is below minRelayFee (%v)" ,
164
+ feeRate , minRelayFee )
165
+ }
166
+
162
167
// If all the inputs are online and loadOnly is not set, sign this exact
163
168
// transaction.
164
169
if offline := h .offlineInputs (tx ); len (offline ) == 0 && ! loadOnly {
@@ -492,6 +497,118 @@ func testPresigned_input1_offline_then_input2(t *testing.T,
492
497
require .NoError (t , err )
493
498
}
494
499
500
+ // testPresigned_min_relay_fee tests that online and presigned transactions
501
+ // comply with min_relay_fee.
502
+ func testPresigned_min_relay_fee (t * testing.T ,
503
+ batcherStore testBatcherStore ) {
504
+
505
+ defer test .Guard (t )()
506
+
507
+ lnd := test .NewMockLnd ()
508
+ ctx , cancel := context .WithCancel (context .Background ())
509
+ defer cancel ()
510
+
511
+ const inputAmt = 1_000_000
512
+
513
+ customFeeRate := func (_ context.Context , _ lntypes.Hash ,
514
+ _ wire.OutPoint ) (chainfee.SatPerKWeight , error ) {
515
+
516
+ return chainfee .FeePerKwFloor , nil
517
+ }
518
+
519
+ presignedHelper := newMockPresignedHelper ()
520
+
521
+ batcher := NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
522
+ testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
523
+ batcherStore , presignedHelper ,
524
+ WithCustomFeeRate (customFeeRate ),
525
+ WithPresignedHelper (presignedHelper ))
526
+ go func () {
527
+ err := batcher .Run (ctx )
528
+ checkBatcherError (t , err )
529
+ }()
530
+
531
+ // Set high min_relay_fee.
532
+ lnd .SetMinRelayFee (400 )
533
+
534
+ // Create the first sweep.
535
+ swapHash1 := lntypes.Hash {1 , 1 , 1 }
536
+ op1 := wire.OutPoint {
537
+ Hash : chainhash.Hash {1 , 1 },
538
+ Index : 1 ,
539
+ }
540
+ sweepReq1 := SweepRequest {
541
+ SwapHash : swapHash1 ,
542
+ Inputs : []Input {{
543
+ Value : inputAmt ,
544
+ Outpoint : op1 ,
545
+ }},
546
+ Notifier : & dummyNotifier ,
547
+ }
548
+
549
+ // Enable the input and presign.
550
+ presignedHelper .SetOutpointOnline (op1 , true )
551
+ err := batcher .PresignSweepsGroup (
552
+ ctx , []Input {{Outpoint : op1 , Value : inputAmt }},
553
+ sweepTimeout , destAddr ,
554
+ )
555
+ require .NoError (t , err )
556
+
557
+ // Deliver sweep request to batcher.
558
+ require .NoError (t , batcher .AddSweep (ctx , & sweepReq1 ))
559
+
560
+ // Since a batch was created we check that it registered for its primary
561
+ // sweep's spend.
562
+ <- lnd .RegisterSpendChannel
563
+
564
+ // Wait for a transactions to be published.
565
+ tx := <- lnd .TxPublishChannel
566
+ gotFeeRate := presignedHelper .getTxFeerate (tx , inputAmt )
567
+ require .Equal (t , chainfee .SatPerKWeight (402 ), gotFeeRate )
568
+
569
+ // Now decrease min_relay_fee and make sure fee rate doesn't decrease.
570
+ // The only difference of tx2 is a higher lock_time.
571
+ lnd .SetMinRelayFee (300 )
572
+ require .NoError (t , lnd .NotifyHeight (601 ))
573
+ tx2 := <- lnd .TxPublishChannel
574
+ require .Equal (t , tx .TxOut [0 ].Value , tx2 .TxOut [0 ].Value )
575
+ gotFeeRate = presignedHelper .getTxFeerate (tx2 , inputAmt )
576
+ require .Equal (t , chainfee .SatPerKWeight (402 ), gotFeeRate )
577
+ require .Equal (t , uint32 (601 ), tx2 .LockTime )
578
+
579
+ // Set a higher min_relay_fee, turn off the client and try presigned tx.
580
+ lnd .SetMinRelayFee (500 )
581
+ presignedHelper .SetOutpointOnline (op1 , false )
582
+
583
+ // Check fee rate of the presigned tx broadcasted.
584
+ require .NoError (t , lnd .NotifyHeight (602 ))
585
+ tx = <- lnd .TxPublishChannel
586
+ gotFeeRate = presignedHelper .getTxFeerate (tx , inputAmt )
587
+ require .Equal (t , chainfee .SatPerKWeight (523 ), gotFeeRate )
588
+ // LockTime of a presigned tx is 0.
589
+ require .Equal (t , uint32 (0 ), tx .LockTime )
590
+
591
+ // Now decrease min_relay_fee and make sure fee rate doesn't decrease.
592
+ // It should re-broadcast the same presigned tx.
593
+ lnd .SetMinRelayFee (450 )
594
+ require .NoError (t , lnd .NotifyHeight (603 ))
595
+ tx2 = <- lnd .TxPublishChannel
596
+ require .Equal (t , tx .TxHash (), tx2 .TxHash ())
597
+ gotFeeRate = presignedHelper .getTxFeerate (tx2 , inputAmt )
598
+ require .Equal (t , chainfee .SatPerKWeight (523 ), gotFeeRate )
599
+ // LockTime of a presigned tx is 0.
600
+ require .Equal (t , uint32 (0 ), tx2 .LockTime )
601
+
602
+ // Even if the client is back online, fee rate doesn't decrease.
603
+ presignedHelper .SetOutpointOnline (op1 , true )
604
+ require .NoError (t , lnd .NotifyHeight (604 ))
605
+ tx3 := <- lnd .TxPublishChannel
606
+ require .Equal (t , tx2 .TxOut [0 ].Value , tx3 .TxOut [0 ].Value )
607
+ gotFeeRate = presignedHelper .getTxFeerate (tx3 , inputAmt )
608
+ require .Equal (t , chainfee .SatPerKWeight (523 ), gotFeeRate )
609
+ require .Equal (t , uint32 (604 ), tx3 .LockTime )
610
+ }
611
+
495
612
// testPresigned_two_inputs_one_goes_offline tests presigned mode for the
496
613
// following scenario: two online inputs are added, then one of them goes
497
614
// offline, then feerate grows and a presigned transaction is used.
@@ -1690,6 +1807,10 @@ func TestPresigned(t *testing.T) {
1690
1807
testPresigned_input1_offline_then_input2 (t , NewStoreMock ())
1691
1808
})
1692
1809
1810
+ t .Run ("min_relay_fee" , func (t * testing.T ) {
1811
+ testPresigned_min_relay_fee (t , NewStoreMock ())
1812
+ })
1813
+
1693
1814
t .Run ("two_inputs_one_goes_offline" , func (t * testing.T ) {
1694
1815
testPresigned_two_inputs_one_goes_offline (t , NewStoreMock ())
1695
1816
})
0 commit comments