Skip to content

Commit c22b30b

Browse files
authored
Merge pull request #29 from jp1ac4/feerate-round-up-vbytes
Calculate transaction fee by applying fee rate to rounded-up vbytes
2 parents 7bfb3d3 + 4eae611 commit c22b30b

File tree

4 files changed

+39
-16
lines changed

4 files changed

+39
-16
lines changed

src/coin_selector.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,10 @@ impl<'a> CoinSelector<'a> {
247247
}
248248

249249
fn implied_fee_from_feerate(&self, target: Target, drain_weights: DrainWeights) -> u64 {
250-
(self.weight(target.outputs, drain_weights) as f32 * target.fee.rate.spwu()).ceil() as u64
250+
target
251+
.fee
252+
.rate
253+
.implied_fee(self.weight(target.outputs, drain_weights))
251254
}
252255

253256
/// The actual fee the selection would pay if it was used in a transaction that had

src/feerate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ impl FeeRate {
7878
pub fn spwu(&self) -> f32 {
7979
self.0 .0
8080
}
81+
82+
/// The fee that the transaction with weight `tx_weight` should pay in order to satisfy the fee rate given by `self`.
83+
pub fn implied_fee(&self, tx_weight: u64) -> u64 {
84+
// The fee rate is applied to the rounded-up vbytes.
85+
((tx_weight as f32 / 4.0).ceil() * self.as_sat_vb()).ceil() as u64
86+
}
8187
}
8288

8389
impl Add<FeeRate> for FeeRate {

src/target.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,9 @@ impl Replace {
136136
///
137137
/// [RBF rule 4]: https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy
138138
pub fn min_fee_to_do_replacement(&self, replacing_tx_weight: u64) -> u64 {
139-
let min_fee_increment =
140-
(replacing_tx_weight as f32 * self.incremental_relay_feerate.spwu()).ceil() as u64;
141-
self.fee + min_fee_increment
139+
self.fee
140+
+ self
141+
.incremental_relay_feerate
142+
.implied_fee(replacing_tx_weight)
142143
}
143144
}

tests/rbf.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,78 @@ fn run_bitcoin_core_rbf_tests() {
55
// see rbf_tests.cpp
66
//
77
// https://github.com/bitcoin/bitcoin/blob/e69796c79c0aa202087a13ba62d9fbcc1c8754d4/src/test/rbf_tests.cpp#L151
8-
const CENT: u64 = 100_000; // no clue why this would be called CENT 😕
8+
const CENT: u64 = 1_000_000;
99
let low_fee = CENT / 100;
1010
let _normal_fee = CENT / 10;
1111
let high_fee = CENT;
1212
let incremental_relay_feerate = FeeRate::DEFUALT_RBF_INCREMENTAL_RELAY;
1313
let higher_relay_feerate = FeeRate::from_sat_per_vb(2.0);
14+
let very_high_relay_feerate = FeeRate::from_sat_per_vb(10.0);
1415

15-
assert!(pays_for_rbf(high_fee, high_fee, 1, FeeRate::ZERO));
16-
assert!(!pays_for_rbf(high_fee, high_fee - 1, 1, FeeRate::ZERO));
17-
assert!(!pays_for_rbf(high_fee + 1, high_fee, 1, FeeRate::ZERO));
16+
assert!(pays_for_rbf(high_fee, high_fee, 4, FeeRate::ZERO));
17+
assert!(!pays_for_rbf(high_fee, high_fee - 1, 4, FeeRate::ZERO));
18+
assert!(!pays_for_rbf(high_fee + 1, high_fee, 4, FeeRate::ZERO));
1819
assert!(!pays_for_rbf(
1920
high_fee,
2021
high_fee + 1,
21-
2,
22+
8,
2223
incremental_relay_feerate
2324
));
2425
assert!(pays_for_rbf(
2526
high_fee,
2627
high_fee + 2,
27-
2,
28+
8,
2829
incremental_relay_feerate
2930
));
3031
assert!(!pays_for_rbf(
3132
high_fee,
3233
high_fee + 2,
33-
2,
34+
8,
3435
higher_relay_feerate
3536
));
3637
assert!(pays_for_rbf(
3738
high_fee,
3839
high_fee + 4,
39-
2,
40+
8,
4041
higher_relay_feerate
4142
));
4243
assert!(!pays_for_rbf(
4344
low_fee,
4445
high_fee,
45-
99999999,
46+
99999999 * 4,
4647
incremental_relay_feerate
4748
));
4849
assert!(pays_for_rbf(
4950
low_fee,
5051
high_fee + 99999999,
51-
99999999,
52+
99999999 * 4,
5253
incremental_relay_feerate
5354
));
55+
assert!(!pays_for_rbf(
56+
low_fee,
57+
low_fee + 29,
58+
8 + 1,
59+
very_high_relay_feerate
60+
));
61+
assert!(pays_for_rbf(
62+
low_fee,
63+
low_fee + 30, // 30 = (10 * (9/4).ceil())
64+
8 + 1,
65+
very_high_relay_feerate
66+
));
5467
}
5568

5669
fn pays_for_rbf(
5770
original_fees: u64,
5871
replacement_fees: u64,
59-
replacement_vsize: u64,
72+
replacement_weight: u64,
6073
relay_fee: FeeRate,
6174
) -> bool {
6275
let min_fee = Replace {
6376
fee: original_fees,
6477
incremental_relay_feerate: relay_fee,
6578
}
66-
.min_fee_to_do_replacement(replacement_vsize * 4);
79+
.min_fee_to_do_replacement(replacement_weight);
6780

6881
replacement_fees >= min_fee
6982
}

0 commit comments

Comments
 (0)