Skip to content

Commit da769ee

Browse files
committed
Consider dust threshold for fee rate determination
Previously, the `feerate_bump` method did not enforce the dust threshold, which could result in us thinking we had raised the fee rate without actually having done so. Instead, `compute_package_output` blindly accepted the updated fee rate while enforcing a non-dust output value, resulting in repeated broadcast attempts of an identical transaction.
1 parent 2aabf78 commit da769ee

File tree

2 files changed

+28
-17
lines changed

2 files changed

+28
-17
lines changed

lightning/src/chain/onchaintx.rs

+1
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ pub(crate) enum OnchainClaim {
215215
}
216216

217217
/// Represents the different feerate strategies a pending request can use when generating a claim.
218+
#[derive(Debug)]
218219
pub(crate) enum FeerateStrategy {
219220
/// We must reuse the most recently used feerate, if any.
220221
RetryPrevious,

lightning/src/chain/package.rs

+27-17
Original file line numberDiff line numberDiff line change
@@ -1117,10 +1117,10 @@ impl PackageTemplate {
11171117
// If old feerate is 0, first iteration of this claim, use normal fee calculation
11181118
if self.feerate_previous != 0 {
11191119
if let Some((new_fee, feerate)) = feerate_bump(
1120-
predicted_weight, input_amounts, self.feerate_previous, feerate_strategy,
1121-
conf_target, fee_estimator, logger,
1120+
predicted_weight, input_amounts, dust_limit_sats, self.feerate_previous,
1121+
feerate_strategy, conf_target, fee_estimator, logger,
11221122
) {
1123-
return Some((cmp::max(input_amounts as i64 - new_fee as i64, dust_limit_sats as i64) as u64, feerate));
1123+
return Some((input_amounts.saturating_sub(new_fee), feerate));
11241124
}
11251125
} else {
11261126
if let Some((new_fee, feerate)) = compute_fee_from_spent_amounts(input_amounts, predicted_weight, conf_target, fee_estimator, logger) {
@@ -1270,16 +1270,20 @@ fn compute_fee_from_spent_amounts<F: Deref, L: Logger>(
12701270
/// respect BIP125 rules 3) and 4) and if required adjust the new fee to meet the RBF policy
12711271
/// requirement.
12721272
fn feerate_bump<F: Deref, L: Logger>(
1273-
predicted_weight: u64, input_amounts: u64, previous_feerate: u64, feerate_strategy: &FeerateStrategy,
1274-
conf_target: ConfirmationTarget, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
1273+
predicted_weight: u64, input_amounts: u64, dust_limit_sats: u64, previous_feerate: u64,
1274+
feerate_strategy: &FeerateStrategy, conf_target: ConfirmationTarget,
1275+
fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L,
12751276
) -> Option<(u64, u64)>
12761277
where
12771278
F::Target: FeeEstimator,
12781279
{
1280+
let previous_fee = previous_feerate * predicted_weight / 1000;
1281+
12791282
// If old feerate inferior to actual one given back by Fee Estimator, use it to compute new fee...
12801283
let (new_fee, new_feerate) = if let Some((new_fee, new_feerate)) =
12811284
compute_fee_from_spent_amounts(input_amounts, predicted_weight, conf_target, fee_estimator, logger)
12821285
{
1286+
log_debug!(logger, "Initiating fee rate bump from {} s/kWU ({} s) to {} s/kWU ({} s) using {:?} strategy", previous_feerate, previous_fee, new_feerate, new_fee, feerate_strategy);
12831287
match feerate_strategy {
12841288
FeerateStrategy::RetryPrevious => {
12851289
let previous_fee = previous_feerate * predicted_weight / 1000;
@@ -1297,15 +1301,12 @@ where
12971301
// ...else just increase the previous feerate by 25% (because that's a nice number)
12981302
let bumped_feerate = previous_feerate + (previous_feerate / 4);
12991303
let bumped_fee = bumped_feerate * predicted_weight / 1000;
1300-
if input_amounts <= bumped_fee {
1301-
log_warn!(logger, "Can't 25% bump new claiming tx, amount {} is too small", input_amounts);
1302-
return None;
1303-
}
1304+
13041305
(bumped_fee, bumped_feerate)
13051306
},
13061307
}
13071308
} else {
1308-
log_warn!(logger, "Can't new-estimation bump new claiming tx, amount {} is too small", input_amounts);
1309+
log_warn!(logger, "Can't bump new claiming tx, input amount {} is too small", input_amounts);
13091310
return None;
13101311
};
13111312

@@ -1316,17 +1317,26 @@ where
13161317
return Some((new_fee, new_feerate));
13171318
}
13181319

1319-
let previous_fee = previous_feerate * predicted_weight / 1000;
13201320
let min_relay_fee = INCREMENTAL_RELAY_FEE_SAT_PER_1000_WEIGHT * predicted_weight / 1000;
13211321
// BIP 125 Opt-in Full Replace-by-Fee Signaling
13221322
// * 3. The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.
13231323
// * 4. The replacement transaction must also pay for its own bandwidth at or above the rate set by the node's minimum relay fee setting.
1324-
let new_fee = if new_fee < previous_fee + min_relay_fee {
1325-
new_fee + previous_fee + min_relay_fee - new_fee
1326-
} else {
1327-
new_fee
1328-
};
1329-
Some((new_fee, new_fee * 1000 / predicted_weight))
1324+
let naive_new_fee = new_fee;
1325+
let new_fee = cmp::max(new_fee, previous_fee + min_relay_fee);
1326+
1327+
if new_fee > naive_new_fee {
1328+
log_debug!(logger, "Naive fee bump of {}s does not meet min relay fee requirements of {}s", naive_new_fee - previous_fee, min_relay_fee);
1329+
}
1330+
1331+
let remaining_output_amount = input_amounts.saturating_sub(new_fee);
1332+
if remaining_output_amount < dust_limit_sats {
1333+
log_warn!(logger, "Can't bump new claiming tx, output amount {} would end up below dust threshold {}", remaining_output_amount, dust_limit_sats);
1334+
return None;
1335+
}
1336+
1337+
let new_feerate = new_fee * 1000 / predicted_weight;
1338+
log_debug!(logger, "Fee rate bumped by {}s from {} s/KWU ({} s) to {} s/KWU ({} s)", new_fee - previous_fee, previous_feerate, previous_fee, new_feerate, new_fee);
1339+
Some((new_fee, new_feerate))
13301340
}
13311341

13321342
#[cfg(test)]

0 commit comments

Comments
 (0)