Skip to content

Commit

Permalink
Merge pull request #29 from jp1ac4/feerate-round-up-vbytes
Browse files Browse the repository at this point in the history
Calculate transaction fee by applying fee rate to rounded-up vbytes
  • Loading branch information
LLFourn authored Oct 30, 2024
2 parents 7bfb3d3 + 4eae611 commit c22b30b
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 16 deletions.
5 changes: 4 additions & 1 deletion src/coin_selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,10 @@ impl<'a> CoinSelector<'a> {
}

fn implied_fee_from_feerate(&self, target: Target, drain_weights: DrainWeights) -> u64 {
(self.weight(target.outputs, drain_weights) as f32 * target.fee.rate.spwu()).ceil() as u64
target
.fee
.rate
.implied_fee(self.weight(target.outputs, drain_weights))
}

/// The actual fee the selection would pay if it was used in a transaction that had
Expand Down
6 changes: 6 additions & 0 deletions src/feerate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ impl FeeRate {
pub fn spwu(&self) -> f32 {
self.0 .0
}

/// The fee that the transaction with weight `tx_weight` should pay in order to satisfy the fee rate given by `self`.
pub fn implied_fee(&self, tx_weight: u64) -> u64 {
// The fee rate is applied to the rounded-up vbytes.
((tx_weight as f32 / 4.0).ceil() * self.as_sat_vb()).ceil() as u64
}
}

impl Add<FeeRate> for FeeRate {
Expand Down
7 changes: 4 additions & 3 deletions src/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ impl Replace {
///
/// [RBF rule 4]: https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy
pub fn min_fee_to_do_replacement(&self, replacing_tx_weight: u64) -> u64 {
let min_fee_increment =
(replacing_tx_weight as f32 * self.incremental_relay_feerate.spwu()).ceil() as u64;
self.fee + min_fee_increment
self.fee
+ self
.incremental_relay_feerate
.implied_fee(replacing_tx_weight)
}
}
37 changes: 25 additions & 12 deletions tests/rbf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,78 @@ fn run_bitcoin_core_rbf_tests() {
// see rbf_tests.cpp
//
// https://github.com/bitcoin/bitcoin/blob/e69796c79c0aa202087a13ba62d9fbcc1c8754d4/src/test/rbf_tests.cpp#L151
const CENT: u64 = 100_000; // no clue why this would be called CENT 😕
const CENT: u64 = 1_000_000;
let low_fee = CENT / 100;
let _normal_fee = CENT / 10;
let high_fee = CENT;
let incremental_relay_feerate = FeeRate::DEFUALT_RBF_INCREMENTAL_RELAY;
let higher_relay_feerate = FeeRate::from_sat_per_vb(2.0);
let very_high_relay_feerate = FeeRate::from_sat_per_vb(10.0);

assert!(pays_for_rbf(high_fee, high_fee, 1, FeeRate::ZERO));
assert!(!pays_for_rbf(high_fee, high_fee - 1, 1, FeeRate::ZERO));
assert!(!pays_for_rbf(high_fee + 1, high_fee, 1, FeeRate::ZERO));
assert!(pays_for_rbf(high_fee, high_fee, 4, FeeRate::ZERO));
assert!(!pays_for_rbf(high_fee, high_fee - 1, 4, FeeRate::ZERO));
assert!(!pays_for_rbf(high_fee + 1, high_fee, 4, FeeRate::ZERO));
assert!(!pays_for_rbf(
high_fee,
high_fee + 1,
2,
8,
incremental_relay_feerate
));
assert!(pays_for_rbf(
high_fee,
high_fee + 2,
2,
8,
incremental_relay_feerate
));
assert!(!pays_for_rbf(
high_fee,
high_fee + 2,
2,
8,
higher_relay_feerate
));
assert!(pays_for_rbf(
high_fee,
high_fee + 4,
2,
8,
higher_relay_feerate
));
assert!(!pays_for_rbf(
low_fee,
high_fee,
99999999,
99999999 * 4,
incremental_relay_feerate
));
assert!(pays_for_rbf(
low_fee,
high_fee + 99999999,
99999999,
99999999 * 4,
incremental_relay_feerate
));
assert!(!pays_for_rbf(
low_fee,
low_fee + 29,
8 + 1,
very_high_relay_feerate
));
assert!(pays_for_rbf(
low_fee,
low_fee + 30, // 30 = (10 * (9/4).ceil())
8 + 1,
very_high_relay_feerate
));
}

fn pays_for_rbf(
original_fees: u64,
replacement_fees: u64,
replacement_vsize: u64,
replacement_weight: u64,
relay_fee: FeeRate,
) -> bool {
let min_fee = Replace {
fee: original_fees,
incremental_relay_feerate: relay_fee,
}
.min_fee_to_do_replacement(replacement_vsize * 4);
.min_fee_to_do_replacement(replacement_weight);

replacement_fees >= min_fee
}

0 comments on commit c22b30b

Please sign in to comment.