mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-07 19:30:46 +02:00
multi: merge DetermineFeePerKw
and Estimate
This commit moves `DetermineFeePerKw` into the `Estimate` method on `FeePreference`. A few callsites previously calling `DetermineFeePerKw` without the max fee rate is now also temporarily fixed by forcing them to use `Estimate` with the default sweeper max fee rate.
This commit is contained in:
@@ -27,6 +27,10 @@ var (
|
||||
// ErrNoFeePreference is returned when we attempt to satisfy a sweep
|
||||
// request from a client whom did not specify a fee preference.
|
||||
ErrNoFeePreference = errors.New("no fee preference specified")
|
||||
|
||||
// ErrFeePreferenceConflict is returned when both a fee rate and a conf
|
||||
// target is set for a fee preference.
|
||||
ErrFeePreferenceConflict = errors.New("fee preference conflict")
|
||||
)
|
||||
|
||||
// FeePreference allows callers to express their time value for inclusion of a
|
||||
@@ -50,35 +54,70 @@ func (p FeePreference) String() string {
|
||||
}
|
||||
|
||||
// Estimate returns a fee rate for the given fee preference. It ensures that
|
||||
// the fee rate respects the bounds of the relay fee and the specified max fee
|
||||
// rates.
|
||||
//
|
||||
// TODO(yy): add tests.
|
||||
// the fee rate respects the bounds of the relay fee and the max fee rates, if
|
||||
// specified.
|
||||
func (f FeePreference) Estimate(estimator chainfee.Estimator,
|
||||
maxFeeRate chainfee.SatPerKWeight) (chainfee.SatPerKWeight, error) {
|
||||
|
||||
var (
|
||||
feeRate chainfee.SatPerKWeight
|
||||
err error
|
||||
)
|
||||
|
||||
switch {
|
||||
// Ensure a type of fee preference is specified to prevent using a
|
||||
// default below.
|
||||
case f.FeeRate == 0 && f.ConfTarget == 0:
|
||||
return 0, ErrNoFeePreference
|
||||
|
||||
// If both values are set, then we'll return an error as we require a
|
||||
// strict directive.
|
||||
case f.FeeRate != 0 && f.ConfTarget != 0:
|
||||
return 0, ErrFeePreferenceConflict
|
||||
|
||||
// If the target number of confirmations is set, then we'll use that to
|
||||
// consult our fee estimator for an adequate fee.
|
||||
case f.ConfTarget != 0:
|
||||
feeRate, err = estimator.EstimateFeePerKW((f.ConfTarget))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to query fee "+
|
||||
"estimator: %w", err)
|
||||
}
|
||||
|
||||
// If a manual sat/kw fee rate is set, then we'll use that directly.
|
||||
// We'll need to convert it to sat/kw as this is what we use
|
||||
// internally.
|
||||
case f.FeeRate != 0:
|
||||
feeRate = f.FeeRate
|
||||
|
||||
// Because the user can specify 1 sat/vByte on the RPC
|
||||
// interface, which corresponds to 250 sat/kw, we need to bump
|
||||
// that to the minimum "safe" fee rate which is 253 sat/kw.
|
||||
if feeRate == chainfee.AbsoluteFeePerKwFloor {
|
||||
log.Infof("Manual fee rate input of %d sat/kw is "+
|
||||
"too low, using %d sat/kw instead", feeRate,
|
||||
chainfee.FeePerKwFloor)
|
||||
|
||||
feeRate = chainfee.FeePerKwFloor
|
||||
}
|
||||
}
|
||||
|
||||
// Get the relay fee as the min fee rate.
|
||||
minFeeRate := estimator.RelayFeePerKW()
|
||||
|
||||
// Ensure a type of fee preference is specified to prevent using a
|
||||
// default below.
|
||||
if f.FeeRate == 0 && f.ConfTarget == 0 {
|
||||
return 0, ErrNoFeePreference
|
||||
}
|
||||
|
||||
feeRate, err := DetermineFeePerKw(estimator, f)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// If that bumped fee rate of at least 253 sat/kw is still lower than
|
||||
// the relay fee rate, we return an error to let the user know. Note
|
||||
// that "Relay fee rate" may mean slightly different things depending
|
||||
// on the backend. For bitcoind, it is effectively max(relay fee, min
|
||||
// mempool fee).
|
||||
if feeRate < minFeeRate {
|
||||
return 0, fmt.Errorf("%w: got %v, minimum is %v",
|
||||
ErrFeePreferenceTooLow, feeRate, minFeeRate)
|
||||
}
|
||||
|
||||
// If the estimated fee rate is above the maximum allowed fee rate,
|
||||
// default to the max fee rate.
|
||||
if feeRate > maxFeeRate {
|
||||
// If a maxFeeRate is specified and the estimated fee rate is above the
|
||||
// maximum allowed fee rate, default to the max fee rate.
|
||||
if maxFeeRate != 0 && feeRate > maxFeeRate {
|
||||
log.Warnf("Estimated fee rate %v exceeds max allowed fee "+
|
||||
"rate %v, using max fee rate instead", feeRate,
|
||||
maxFeeRate)
|
||||
@@ -89,80 +128,6 @@ func (f FeePreference) Estimate(estimator chainfee.Estimator,
|
||||
return feeRate, nil
|
||||
}
|
||||
|
||||
// DetermineFeePerKw will determine the fee in sat/kw that should be paid given
|
||||
// an estimator, a confirmation target, and a manual value for sat/byte. A
|
||||
// value is chosen based on the two free parameters as one, or both of them can
|
||||
// be zero.
|
||||
//
|
||||
// TODO(yy): move it into the above `Estimate`.
|
||||
func DetermineFeePerKw(feeEstimator chainfee.Estimator,
|
||||
feePref FeePreference) (chainfee.SatPerKWeight, error) {
|
||||
|
||||
switch {
|
||||
// If both values are set, then we'll return an error as we require a
|
||||
// strict directive.
|
||||
case feePref.FeeRate != 0 && feePref.ConfTarget != 0:
|
||||
return 0, fmt.Errorf("only FeeRate or ConfTarget should " +
|
||||
"be set for FeePreferences")
|
||||
|
||||
// If the target number of confirmations is set, then we'll use that to
|
||||
// consult our fee estimator for an adequate fee.
|
||||
case feePref.ConfTarget != 0:
|
||||
feePerKw, err := feeEstimator.EstimateFeePerKW(
|
||||
uint32(feePref.ConfTarget),
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to query fee "+
|
||||
"estimator: %v", err)
|
||||
}
|
||||
|
||||
return feePerKw, nil
|
||||
|
||||
// If a manual sat/byte fee rate is set, then we'll use that directly.
|
||||
// We'll need to convert it to sat/kw as this is what we use
|
||||
// internally.
|
||||
case feePref.FeeRate != 0:
|
||||
feePerKW := feePref.FeeRate
|
||||
|
||||
// Because the user can specify 1 sat/vByte on the RPC
|
||||
// interface, which corresponds to 250 sat/kw, we need to bump
|
||||
// that to the minimum "safe" fee rate which is 253 sat/kw.
|
||||
if feePerKW == chainfee.AbsoluteFeePerKwFloor {
|
||||
log.Infof("Manual fee rate input of %d sat/kw is "+
|
||||
"too low, using %d sat/kw instead", feePerKW,
|
||||
chainfee.FeePerKwFloor)
|
||||
feePerKW = chainfee.FeePerKwFloor
|
||||
}
|
||||
|
||||
// If that bumped fee rate of at least 253 sat/kw is still lower
|
||||
// than the relay fee rate, we return an error to let the user
|
||||
// know. Note that "Relay fee rate" may mean slightly different
|
||||
// things depending on the backend. For bitcoind, it is
|
||||
// effectively max(relay fee, min mempool fee).
|
||||
minFeePerKW := feeEstimator.RelayFeePerKW()
|
||||
if feePerKW < minFeePerKW {
|
||||
return 0, fmt.Errorf("manual fee rate input of %d "+
|
||||
"sat/kw is too low to be accepted into the "+
|
||||
"mempool or relayed to the network", feePerKW)
|
||||
}
|
||||
|
||||
return feePerKW, nil
|
||||
|
||||
// Otherwise, we'll attempt a relaxed confirmation target for the
|
||||
// transaction
|
||||
default:
|
||||
feePerKw, err := feeEstimator.EstimateFeePerKW(
|
||||
defaultNumBlocksEstimate,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to query fee estimator: "+
|
||||
"%v", err)
|
||||
}
|
||||
|
||||
return feePerKw, nil
|
||||
}
|
||||
}
|
||||
|
||||
// UtxoSource is an interface that allows a caller to access a source of UTXOs
|
||||
// to use when crafting sweep transactions.
|
||||
type UtxoSource interface {
|
||||
|
Reference in New Issue
Block a user