Skip to content

Commit

Permalink
sweepbatcher: MinFeeRate -> WithCustomFeeRate
Browse files Browse the repository at this point in the history
The reason is because we want to know in advance if fee rates come from
an external source or are determined by sweepbatcher internally.

Also remove WithNoBumping option. It is now a part of WithCustomFeeRate:
if WithCustomFeeRate is passed, automatic fee bumping by sweepbatcher
is disabled.
  • Loading branch information
starius committed Jul 8, 2024
1 parent 663f4d2 commit f9edd53
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 34 deletions.
4 changes: 1 addition & 3 deletions sweepbatcher/sweep_batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,7 @@ type batchConfig struct {
batchPublishDelay time.Duration

// noBumping instructs sweepbatcher not to fee bump itself and rely on
// external source of fee rates (MinFeeRate). To change the fee rate,
// the caller has to update it in the source of SweepInfo (interface
// SweepFetcher) and re-add the sweep by calling AddSweep.
// external source of fee rates (FeeRateProvider).
noBumping bool

// customMuSig2Signer is a custom signer. If it is set, it is used to
Expand Down
60 changes: 37 additions & 23 deletions sweepbatcher/sweep_batcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,6 @@ type SweepInfo struct {

// DestAddr is the destination address of the sweep.
DestAddr btcutil.Address

// MinFeeRate is minimum fee rate that must be used by a batch of
// the sweep. If it is specified, confTarget is ignored.
MinFeeRate chainfee.SatPerKWeight
}

// SweepFetcher is used to get details of a sweep.
Expand All @@ -151,6 +147,11 @@ type SignMuSig2 func(ctx context.Context, muSig2Version input.MuSig2Version,
// signature.
type VerifySchnorrSig func(pubKey *btcec.PublicKey, hash, sig []byte) error

// FeeRateProvider is a function that returns min fee rate of a batch sweeping
// the UTXO of the swap.
type FeeRateProvider func(ctx context.Context,
swapHash lntypes.Hash) (chainfee.SatPerKWeight, error)

// SweepRequest is a request to sweep a specific outpoint.
type SweepRequest struct {
// SwapHash is the hash of the swap that is being swept.
Expand Down Expand Up @@ -247,11 +248,10 @@ type Batcher struct {
// exit.
wg sync.WaitGroup

// noBumping instructs sweepbatcher not to fee bump itself and rely on
// external source of fee rates (MinFeeRate). To change the fee rate,
// the caller has to update it in the source of SweepInfo (interface
// SweepFetcher) and re-add the sweep by calling AddSweep.
noBumping bool
// customFeeRate provides custom min fee rate per swap. The batch uses
// max of the fee rates of its swaps. In this mode confTarget is
// ignored and fee bumping by sweepbatcher is disabled.
customFeeRate FeeRateProvider

// customMuSig2Signer is a custom signer. If it is set, it is used to
// create musig2 signatures instead of musig2SignSweep and signerClient.
Expand All @@ -262,11 +262,10 @@ type Batcher struct {

// BatcherConfig holds batcher configuration.
type BatcherConfig struct {
// noBumping instructs sweepbatcher not to fee bump itself and rely on
// external source of fee rates (MinFeeRate). To change the fee rate,
// the caller has to update it in the source of SweepInfo (interface
// SweepFetcher) and re-add the sweep by calling AddSweep.
noBumping bool
// customFeeRate provides custom min fee rate per swap. The batch uses
// max of the fee rates of its swaps. In this mode confTarget is
// ignored and fee bumping by sweepbatcher is disabled.
customFeeRate FeeRateProvider

// customMuSig2Signer is a custom signer. If it is set, it is used to
// create musig2 signatures instead of musig2SignSweep and signerClient.
Expand All @@ -278,13 +277,12 @@ type BatcherConfig struct {
// BatcherOption configures batcher behaviour.
type BatcherOption func(*BatcherConfig)

// WithNoBumping instructs sweepbatcher not to fee bump itself and
// rely on external source of fee rates (MinFeeRate). To change the
// fee rate, the caller has to update it in the source of SweepInfo
// (interface SweepFetcher) and re-add the sweep by calling AddSweep.
func WithNoBumping() BatcherOption {
// WithCustomFeeRate instructs sweepbatcher not to fee bump itself and rely on
// external source of fee rates (FeeRateProvider). To apply a fee rate change,
// the caller should re-add the sweep by calling AddSweep.
func WithCustomFeeRate(customFeeRate FeeRateProvider) BatcherOption {
return func(cfg *BatcherConfig) {
cfg.noBumping = true
cfg.customFeeRate = customFeeRate
}
}

Expand Down Expand Up @@ -331,7 +329,7 @@ func NewBatcher(wallet lndclient.WalletKitClient,
chainParams: chainparams,
store: store,
sweepStore: sweepStore,
noBumping: cfg.noBumping,
customFeeRate: cfg.customFeeRate,
customMuSig2Signer: cfg.customMuSig2Signer,
}
}
Expand Down Expand Up @@ -848,6 +846,22 @@ func (b *Batcher) loadSweep(ctx context.Context, swapHash lntypes.Hash,
swapHash[:6], err)
}

// minFeeRate is 0 be default. If customFeeRate is not provided, then
// rbfCache.FeeRate is also 0 and method batch.updateRbfRate() updates
// it to current fee rate according to batchConfTarget.
var minFeeRate chainfee.SatPerKWeight
if b.customFeeRate != nil {
minFeeRate, err = b.customFeeRate(ctx, swapHash)
if err != nil {
return nil, fmt.Errorf("failed to fetch min fee rate "+
"for %x: %w", swapHash[:6], err)
}
if minFeeRate < chainfee.AbsoluteFeePerKwFloor {
return nil, fmt.Errorf("min fee rate too low (%v) for "+
"%x", minFeeRate, swapHash[:6])
}
}

return &sweep{
swapHash: swapHash,
outpoint: outpoint,
Expand All @@ -863,15 +877,15 @@ func (b *Batcher) loadSweep(ctx context.Context, swapHash lntypes.Hash,
protocolVersion: s.ProtocolVersion,
isExternalAddr: s.IsExternalAddr,
destAddr: s.DestAddr,
minFeeRate: s.MinFeeRate,
minFeeRate: minFeeRate,
}, nil
}

// newBatchConfig creates new batch config.
func (b *Batcher) newBatchConfig(maxTimeoutDistance int32) batchConfig {
return batchConfig{
maxTimeoutDistance: maxTimeoutDistance,
noBumping: b.noBumping,
noBumping: b.customFeeRate != nil,
customMuSig2Signer: b.customMuSig2Signer,
}
}
Expand Down
28 changes: 20 additions & 8 deletions sweepbatcher/sweep_batcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func testSweepBatcherBatchCreation(t *testing.T, store testStore,
}

// testFeeBumping tests that sweep is RBFed with slightly higher fee rate after
// each block unless WithNoBumping is passed.
// each block unless WithCustomFeeRate is passed.
func testFeeBumping(t *testing.T, store testStore,
batcherStore testBatcherStore, noFeeBumping bool) {

Expand All @@ -324,7 +324,14 @@ func testFeeBumping(t *testing.T, store testStore,
// Disable fee bumping, if requested.
var opts []BatcherOption
if noFeeBumping {
opts = append(opts, WithNoBumping())
customFeeRate := func(ctx context.Context,
swapHash lntypes.Hash) (chainfee.SatPerKWeight, error) {

// Always provide the same value, no bumping.
return test.DefaultMockFee, nil
}

opts = append(opts, WithCustomFeeRate(customFeeRate))
}

batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer,
Expand Down Expand Up @@ -1931,8 +1938,7 @@ func testSweepFetcher(t *testing.T, store testStore,
feeRate := chainfee.SatPerKWeight(30000)
amt := btcutil.Amount(1_000_000)
weight := lntypes.WeightUnit(445) // Weight for 1-to-1 tx.
bumpedFee := feeRate + 100
expectedFee := bumpedFee.FeeForWeight(weight)
expectedFee := feeRate.FeeForWeight(weight)

swap := &loopdb.LoopOutContract{
SwapContract: loopdb.SwapContract{
Expand All @@ -1955,7 +1961,6 @@ func testSweepFetcher(t *testing.T, store testStore,
ConfTarget: 123,
Timeout: 111,
SwapInvoicePaymentAddr: *swapPaymentAddr,
MinFeeRate: feeRate,
ProtocolVersion: loopdb.ProtocolVersionMuSig2,
HTLCKeys: htlcKeys,
HTLC: *htlc,
Expand Down Expand Up @@ -1987,9 +1992,16 @@ func testSweepFetcher(t *testing.T, store testStore,
require.NoError(t, err)
store.AssertLoopOutStored()

customFeeRate := func(ctx context.Context,
swapHash lntypes.Hash) (chainfee.SatPerKWeight, error) {

// Always provide the same value, no bumping.
return feeRate, nil
}

batcher := NewBatcher(lnd.WalletKit, lnd.ChainNotifier, lnd.Signer,
testMuSig2SignSweep, testVerifySchnorrSig, lnd.ChainParams,
batcherStore, sweepFetcher)
batcherStore, sweepFetcher, WithCustomFeeRate(customFeeRate))

var wg sync.WaitGroup
wg.Add(1)
Expand Down Expand Up @@ -2238,7 +2250,7 @@ func TestSweepBatcherBatchCreation(t *testing.T) {
}

// TestFeeBumping tests that sweep is RBFed with slightly higher fee rate after
// each block unless WithNoBumping is passed.
// each block unless WithCustomFeeRate is passed.
func TestFeeBumping(t *testing.T) {
t.Run("regular", func(t *testing.T) {
runTests(t, func(t *testing.T, store testStore,
Expand All @@ -2248,7 +2260,7 @@ func TestFeeBumping(t *testing.T) {
})
})

t.Run("WithNoBumping", func(t *testing.T) {
t.Run("fixed fee rate", func(t *testing.T) {
runTests(t, func(t *testing.T, store testStore,
batcherStore testBatcherStore) {

Expand Down

0 comments on commit f9edd53

Please sign in to comment.