@@ -3698,6 +3698,180 @@ func testWithMixedBatchCoopFailedOnly(t *testing.T, store testStore,
3698
3698
wantWeight , wantWitnessSizes )
3699
3699
}
3700
3700
3701
+ // testFeeRateGrows tests that fee rate of a batch does not decrease and is at
3702
+ // least as high as the highest fee rate of sweeps.
3703
+ func testFeeRateGrows (t * testing.T , store testStore ,
3704
+ batcherStore testBatcherStore ) {
3705
+
3706
+ defer test .Guard (t )()
3707
+
3708
+ lnd := test .NewMockLnd ()
3709
+ ctx , cancel := context .WithCancel (context .Background ())
3710
+ defer cancel ()
3711
+
3712
+ sweepStore , err := NewSweepFetcherFromSwapStore (store , lnd .ChainParams )
3713
+ require .NoError (t , err )
3714
+
3715
+ // Create a map to store fee rates.
3716
+ swap2feeRate := map [lntypes.Hash ]chainfee.SatPerKWeight {}
3717
+ var swap2feeRateMu sync.Mutex
3718
+ setFeeRate := func (swapHash lntypes.Hash , rate chainfee.SatPerKWeight ) {
3719
+ swap2feeRateMu .Lock ()
3720
+ defer swap2feeRateMu .Unlock ()
3721
+
3722
+ swap2feeRate [swapHash ] = rate
3723
+ }
3724
+
3725
+ customFeeRate := func (ctx context.Context ,
3726
+ swapHash lntypes.Hash ) (chainfee.SatPerKWeight , error ) {
3727
+
3728
+ swap2feeRateMu .Lock ()
3729
+ defer swap2feeRateMu .Unlock ()
3730
+
3731
+ return swap2feeRate [swapHash ], nil
3732
+ }
3733
+
3734
+ const (
3735
+ feeRateLow = chainfee .SatPerKWeight (10_000 )
3736
+ feeRateMedium = chainfee .SatPerKWeight (30_000 )
3737
+ feeRateHigh = chainfee .SatPerKWeight (50_000 )
3738
+ )
3739
+
3740
+ batcher := NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
3741
+ testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
3742
+ batcherStore , sweepStore , WithCustomFeeRate (customFeeRate ))
3743
+
3744
+ go func () {
3745
+ err := batcher .Run (ctx )
3746
+ checkBatcherError (t , err )
3747
+ }()
3748
+
3749
+ // Create the first sweep.
3750
+ swapHash1 := lntypes.Hash {1 , 1 , 1 }
3751
+ setFeeRate (swapHash1 , feeRateMedium )
3752
+ sweepReq1 := SweepRequest {
3753
+ SwapHash : swapHash1 ,
3754
+ Value : 1_000_000 ,
3755
+ Outpoint : wire.OutPoint {
3756
+ Hash : chainhash.Hash {1 , 1 },
3757
+ Index : 1 ,
3758
+ },
3759
+ Notifier : & dummyNotifier ,
3760
+ }
3761
+
3762
+ swap1 := & loopdb.LoopOutContract {
3763
+ SwapContract : loopdb.SwapContract {
3764
+ CltvExpiry : 111 ,
3765
+ AmountRequested : 1_000_000 ,
3766
+ ProtocolVersion : loopdb .ProtocolVersionMuSig2 ,
3767
+ HtlcKeys : htlcKeys ,
3768
+
3769
+ // Make preimage unique to pass SQL constraints.
3770
+ Preimage : lntypes.Preimage {1 },
3771
+ },
3772
+
3773
+ DestAddr : destAddr ,
3774
+ SwapInvoice : swapInvoice ,
3775
+ SweepConfTarget : 111 ,
3776
+ }
3777
+
3778
+ err = store .CreateLoopOut (ctx , swapHash1 , swap1 )
3779
+ require .NoError (t , err )
3780
+ store .AssertLoopOutStored ()
3781
+
3782
+ // Deliver sweep request to batcher.
3783
+ require .NoError (t , batcher .AddSweep (& sweepReq1 ))
3784
+
3785
+ // Since a batch was created we check that it registered for its primary
3786
+ // sweep's spend.
3787
+ <- lnd .RegisterSpendChannel
3788
+
3789
+ // Wait for tx to be published.
3790
+ <- lnd .TxPublishChannel
3791
+
3792
+ // Make sure the fee rate is feeRateMedium.
3793
+ batch := getOnlyBatch (batcher )
3794
+ require .Len (t , batch .sweeps , 1 )
3795
+ require .Equal (t , feeRateMedium , batch .rbfCache .FeeRate )
3796
+
3797
+ // Now decrease the fee of sweep1.
3798
+ setFeeRate (swapHash1 , feeRateLow )
3799
+ require .NoError (t , batcher .AddSweep (& sweepReq1 ))
3800
+
3801
+ // Tick tock next block.
3802
+ err = lnd .NotifyHeight (601 )
3803
+ require .NoError (t , err )
3804
+
3805
+ // Wait for tx to be published.
3806
+ <- lnd .TxPublishChannel
3807
+
3808
+ // Make sure the fee rate is still feeRateMedium.
3809
+ require .Equal (t , feeRateMedium , batch .rbfCache .FeeRate )
3810
+
3811
+ // Add sweep2, with feeRateMedium.
3812
+ swapHash2 := lntypes.Hash {2 , 2 , 2 }
3813
+ setFeeRate (swapHash2 , feeRateMedium )
3814
+ sweepReq2 := SweepRequest {
3815
+ SwapHash : swapHash2 ,
3816
+ Value : 1_000_000 ,
3817
+ Outpoint : wire.OutPoint {
3818
+ Hash : chainhash.Hash {2 , 2 },
3819
+ Index : 1 ,
3820
+ },
3821
+ Notifier : & dummyNotifier ,
3822
+ }
3823
+
3824
+ swap2 := & loopdb.LoopOutContract {
3825
+ SwapContract : loopdb.SwapContract {
3826
+ CltvExpiry : 111 ,
3827
+ AmountRequested : 1_000_000 ,
3828
+ ProtocolVersion : loopdb .ProtocolVersionMuSig2 ,
3829
+ HtlcKeys : htlcKeys ,
3830
+
3831
+ // Make preimage unique to pass SQL constraints.
3832
+ Preimage : lntypes.Preimage {2 },
3833
+ },
3834
+
3835
+ DestAddr : destAddr ,
3836
+ SwapInvoice : swapInvoice ,
3837
+ SweepConfTarget : 111 ,
3838
+ }
3839
+
3840
+ err = store .CreateLoopOut (ctx , swapHash2 , swap2 )
3841
+ require .NoError (t , err )
3842
+ store .AssertLoopOutStored ()
3843
+
3844
+ // Deliver sweep request to batcher.
3845
+ require .NoError (t , batcher .AddSweep (& sweepReq2 ))
3846
+
3847
+ // Tick tock next block.
3848
+ err = lnd .NotifyHeight (602 )
3849
+ require .NoError (t , err )
3850
+
3851
+ // Wait for tx to be published.
3852
+ <- lnd .TxPublishChannel
3853
+
3854
+ // Make sure the fee rate is still feeRateMedium.
3855
+ require .Len (t , batch .sweeps , 2 )
3856
+ require .Equal (t , feeRateMedium , batch .rbfCache .FeeRate )
3857
+
3858
+ // Now update fee rate of second sweep (which is not primary) to
3859
+ // feeRateHigh. Fee rate of sweep 1 is still feeRateLow.
3860
+ setFeeRate (swapHash2 , feeRateHigh )
3861
+ require .NoError (t , batcher .AddSweep (& sweepReq1 ))
3862
+ require .NoError (t , batcher .AddSweep (& sweepReq2 ))
3863
+
3864
+ // Tick tock next block.
3865
+ err = lnd .NotifyHeight (603 )
3866
+ require .NoError (t , err )
3867
+
3868
+ // Wait for tx to be published.
3869
+ <- lnd .TxPublishChannel
3870
+
3871
+ // Make sure the fee rate increased to feeRateHigh.
3872
+ require .Equal (t , feeRateHigh , batch .rbfCache .FeeRate )
3873
+ }
3874
+
3701
3875
// TestSweepBatcherBatchCreation tests that sweep requests enter the expected
3702
3876
// batch based on their timeout distance.
3703
3877
func TestSweepBatcherBatchCreation (t * testing.T ) {
@@ -3839,6 +4013,12 @@ func TestWithMixedBatchCoopFailedOnly(t *testing.T) {
3839
4013
runTests (t , testWithMixedBatchCoopFailedOnly )
3840
4014
}
3841
4015
4016
+ // TestFeeRateGrows tests that fee rate of a batch does not decrease and is at
4017
+ // least as high as the highest fee rate of sweeps.
4018
+ func TestFeeRateGrows (t * testing.T ) {
4019
+ runTests (t , testFeeRateGrows )
4020
+ }
4021
+
3842
4022
// testBatcherStore is BatcherStore used in tests.
3843
4023
type testBatcherStore interface {
3844
4024
BatcherStore
0 commit comments