@@ -8,13 +8,15 @@ import (
88 "testing"
99 "time"
1010
11+ "github.com/btcsuite/btcd/btcec/v2"
1112 "github.com/btcsuite/btcd/btcutil"
1213 "github.com/btcsuite/btcd/chaincfg/chainhash"
1314 "github.com/btcsuite/btcd/wire"
1415 "github.com/lightninglabs/loop/loopdb"
1516 "github.com/lightninglabs/loop/test"
1617 "github.com/lightninglabs/loop/utils"
1718 "github.com/lightningnetwork/lnd/chainntnfs"
19+ "github.com/lightningnetwork/lnd/keychain"
1820 "github.com/lightningnetwork/lnd/lntypes"
1921 "github.com/stretchr/testify/require"
2022)
@@ -42,6 +44,20 @@ var destAddr = func() btcutil.Address {
4244 return addr
4345}()
4446
47+ var senderKey , receiverKey [33 ]byte
48+
49+ func init () {
50+ // Generate keys.
51+ _ , senderPubKey := test .CreateKey (1 )
52+ copy (senderKey [:], senderPubKey .SerializeCompressed ())
53+ _ , receiverPubKey := test .CreateKey (2 )
54+ copy (receiverKey [:], receiverPubKey .SerializeCompressed ())
55+ }
56+
57+ func testVerifySchnorrSig (pubKey * btcec.PublicKey , hash , sig []byte ) error {
58+ return nil
59+ }
60+
4561func testMuSig2SignSweep (ctx context.Context ,
4662 protocolVersion loopdb.ProtocolVersion , swapHash lntypes.Hash ,
4763 paymentAddr [32 ]byte , nonce []byte , sweepTxPsbt []byte ,
@@ -245,6 +261,103 @@ func testSweepBatcherBatchCreation(t *testing.T, store testStore,
245261 require .True (t , batcherStore .AssertSweepStored (sweepReq3 .SwapHash ))
246262}
247263
264+ // testFeeBumping tests that sweep is RBFed with slightly higher fee rate after
265+ // each block unless WithNoBumping is passed.
266+ func testFeeBumping (t * testing.T , store testStore ,
267+ batcherStore testBatcherStore , noFeeBumping bool ) {
268+
269+ defer test .Guard (t )()
270+
271+ lnd := test .NewMockLnd ()
272+ ctx , cancel := context .WithCancel (context .Background ())
273+ defer cancel ()
274+
275+ sweepStore , err := NewSweepFetcherFromSwapStore (store , lnd .ChainParams )
276+ require .NoError (t , err )
277+
278+ // Disable fee bumping, if requested.
279+ var opts []BatcherOption
280+ if noFeeBumping {
281+ opts = append (opts , WithNoBumping ())
282+ }
283+
284+ batcher := NewBatcher (lnd .WalletKit , lnd .ChainNotifier , lnd .Signer ,
285+ testMuSig2SignSweep , testVerifySchnorrSig , lnd .ChainParams ,
286+ batcherStore , sweepStore , opts ... )
287+ go func () {
288+ err := batcher .Run (ctx )
289+ checkBatcherError (t , err )
290+ }()
291+
292+ // Create a sweep request.
293+ sweepReq1 := SweepRequest {
294+ SwapHash : lntypes.Hash {1 , 1 , 1 },
295+ Value : 1_000_000 ,
296+ Outpoint : wire.OutPoint {
297+ Hash : chainhash.Hash {1 , 1 },
298+ Index : 1 ,
299+ },
300+ Notifier : & SpendNotifier {
301+ SpendChan : make (chan * SpendDetail , ntfnBufferSize ),
302+ SpendErrChan : make (chan error , ntfnBufferSize ),
303+ QuitChan : make (chan bool , ntfnBufferSize ),
304+ },
305+ }
306+
307+ swap1 := & loopdb.LoopOutContract {
308+ SwapContract : loopdb.SwapContract {
309+ CltvExpiry : 111 ,
310+ AmountRequested : 1_000_000 ,
311+ ProtocolVersion : loopdb .ProtocolVersionMuSig2 ,
312+ HtlcKeys : loopdb.HtlcKeys {
313+ SenderScriptKey : senderKey ,
314+ ReceiverScriptKey : receiverKey ,
315+ SenderInternalPubKey : senderKey ,
316+ ReceiverInternalPubKey : receiverKey ,
317+ ClientScriptKeyLocator : keychain.KeyLocator {
318+ Family : 1 ,
319+ Index : 2 ,
320+ },
321+ },
322+ },
323+
324+ DestAddr : destAddr ,
325+ SwapInvoice : swapInvoice ,
326+ SweepConfTarget : 111 ,
327+ }
328+
329+ err = store .CreateLoopOut (ctx , sweepReq1 .SwapHash , swap1 )
330+ require .NoError (t , err )
331+ store .AssertLoopOutStored ()
332+
333+ // Deliver sweep request to batcher.
334+ require .NoError (t , batcher .AddSweep (& sweepReq1 ))
335+
336+ // Since a batch was created we check that it registered for its primary
337+ // sweep's spend.
338+ <- lnd .RegisterSpendChannel
339+
340+ // Wait for tx to be published.
341+ tx1 := <- lnd .TxPublishChannel
342+ out1 := tx1 .TxOut [0 ].Value
343+
344+ // Tick tock next block.
345+ err = lnd .NotifyHeight (601 )
346+ require .NoError (t , err )
347+
348+ // Wait for another sweep tx to be published.
349+ tx2 := <- lnd .TxPublishChannel
350+ out2 := tx2 .TxOut [0 ].Value
351+
352+ if noFeeBumping {
353+ // Expect output to stay the same.
354+ require .Equal (t , out1 , out2 , "expected out to stay the same" )
355+ } else {
356+ // Expect output to drop.
357+ require .Greater (t , out1 , out2 , "expected out to drop" )
358+ }
359+ }
360+
248361// testSweepBatcherSimpleLifecycle tests the simple lifecycle of the batches
249362// that are created and run by the batcher.
250363func testSweepBatcherSimpleLifecycle (t * testing.T , store testStore ,
@@ -1837,6 +1950,26 @@ func TestSweepBatcherBatchCreation(t *testing.T) {
18371950 runTests (t , testSweepBatcherBatchCreation )
18381951}
18391952
1953+ // TestFeeBumping tests that sweep is RBFed with slightly higher fee rate after
1954+ // each block unless WithNoBumping is passed.
1955+ func TestFeeBumping (t * testing.T ) {
1956+ t .Run ("regular" , func (t * testing.T ) {
1957+ runTests (t , func (t * testing.T , store testStore ,
1958+ batcherStore testBatcherStore ) {
1959+
1960+ testFeeBumping (t , store , batcherStore , false )
1961+ })
1962+ })
1963+
1964+ t .Run ("WithNoBumping" , func (t * testing.T ) {
1965+ runTests (t , func (t * testing.T , store testStore ,
1966+ batcherStore testBatcherStore ) {
1967+
1968+ testFeeBumping (t , store , batcherStore , true )
1969+ })
1970+ })
1971+ }
1972+
18401973// TestSweepBatcherSimpleLifecycle tests the simple lifecycle of the batches
18411974// that are created and run by the batcher.
18421975func TestSweepBatcherSimpleLifecycle (t * testing.T ) {
0 commit comments