Skip to content

Commit 12507c7

Browse files
Merge #678: Implement conversion for Lightning fee rate
de358f8 Implement conversion for Lightning fee rate (Vladimir Fomene) Pull request description: This PR fixes #608. ### Description Lightning denotes transaction fee rate sats / 1000 weight units and sats / 1000 vbytes. Here we add support for creating BDK FeeRate from lightning fee rate. We also move all FeeRate tests to types.rs and rename as_sat_vb to as_sat_per_vb. ### Notes to the reviewers Matt was concerned that we might round down value in fee calculation in such a way that a transaction may not be relayed because it is below Bitcoin Core's min relay fee (1 sat/vbyte). I don't think we need to worry about that because we [round up(ceil)](https://github.com/bitcoindevkit/bdk/blob/master/src/types.rs#L91) during fee calculation, we don't round down. I will love to hear what you think. Is there something I'm missing? @johncantrell97, I will appreciate your review on this one. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: * [x] I've added tests for the new feature * [x] I've added docs for the new feature * [x] I've updated `CHANGELOG.md` #### Bugfixes: * [ ] This pull request breaks the existing API * [ ] I've added tests to reproduce the issue which are now passing * [x] I'm linking the issue being fixed by this PR ACKs for top commit: danielabrozzoni: ACK de358f8 Tree-SHA512: aaa7da8284b668d15ad9c92168c149c4b3ee0f8faee9b7eb159745d23e38835189eaf5c336da14ba9272ee07cd366718eefb8365da9ddf53014e122b6393a087
2 parents 0a3734e + de358f8 commit 12507c7

File tree

5 files changed

+52
-27
lines changed

5 files changed

+52
-27
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
- Add capacity to create FeeRate from sats/kvbytes and sats/kwu.
9+
- Rename `as_sat_vb` to `as_sat_per_vb`. Move all `FeeRate` test to `types.rs`.
810

911
## [v0.21.0] - [v0.20.0]
1012

@@ -19,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1921
- New `RpcBlockchain` implementation with various fixes.
2022
- Return balance in separate categories, namely `confirmed`, `trusted_pending`, `untrusted_pending` & `immature`.
2123

24+
2225
## [v0.20.0] - [v0.19.0]
2326

2427
- New MSRV set to `1.56.1`

src/types.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ impl FeeRate {
6363
FeeRate(value)
6464
}
6565

66+
/// Create a new instance of [`FeeRate`] given a float fee rate in sats/kwu
67+
pub fn from_sat_per_kwu(sat_per_kwu: f32) -> Self {
68+
FeeRate::new_checked(sat_per_kwu / 250.0_f32)
69+
}
70+
71+
/// Create a new instance of [`FeeRate`] given a float fee rate in sats/kvb
72+
pub fn from_sat_per_kvb(sat_per_kvb: f32) -> Self {
73+
FeeRate::new_checked(sat_per_kvb / 1000.0_f32)
74+
}
75+
6676
/// Create a new instance of [`FeeRate`] given a float fee rate in btc/kvbytes
6777
///
6878
/// ## Panics
@@ -98,7 +108,7 @@ impl FeeRate {
98108
}
99109

100110
/// Return the value as satoshi/vbyte
101-
pub fn as_sat_vb(&self) -> f32 {
111+
pub fn as_sat_per_vb(&self) -> f32 {
102112
self.0
103113
}
104114

@@ -109,7 +119,7 @@ impl FeeRate {
109119

110120
/// Calculate absolute fee in Satoshis using size in virtual bytes.
111121
pub fn fee_vb(&self, vbytes: usize) -> u64 {
112-
(self.as_sat_vb() * vbytes as f32).ceil() as u64
122+
(self.as_sat_per_vb() * vbytes as f32).ceil() as u64
113123
}
114124
}
115125

@@ -358,4 +368,34 @@ mod tests {
358368
fn test_valid_feerate_pos_zero() {
359369
let _ = FeeRate::from_sat_per_vb(0.0);
360370
}
371+
372+
#[test]
373+
fn test_fee_from_btc_per_kvb() {
374+
let fee = FeeRate::from_btc_per_kvb(1e-5);
375+
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
376+
}
377+
378+
#[test]
379+
fn test_fee_from_sat_per_vbyte() {
380+
let fee = FeeRate::from_sat_per_vb(1.0);
381+
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
382+
}
383+
384+
#[test]
385+
fn test_fee_default_min_relay_fee() {
386+
let fee = FeeRate::default_min_relay_fee();
387+
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
388+
}
389+
390+
#[test]
391+
fn test_fee_from_sat_per_kvb() {
392+
let fee = FeeRate::from_sat_per_kvb(1000.0);
393+
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
394+
}
395+
396+
#[test]
397+
fn test_fee_from_sat_per_kwu() {
398+
let fee = FeeRate::from_sat_per_kwu(250.0);
399+
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
400+
}
361401
}

src/wallet/coin_selection.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
454454
.iter()
455455
.fold(0, |acc, x| acc + x.effective_value);
456456

457-
let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_vb();
457+
let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_per_vb();
458458

459459
// `curr_value` and `curr_available_value` are both the sum of *effective_values* of
460460
// the UTXOs. For the optional UTXOs (curr_available_value) we filter out UTXOs with
@@ -1360,7 +1360,8 @@ mod test {
13601360
let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
13611361

13621362
let size_of_change = 31;
1363-
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
1363+
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
1364+
13641365
let drain_script = Script::default();
13651366
let target_amount = 20_000 + FEE_AMOUNT;
13661367
BranchAndBoundCoinSelection::new(size_of_change)
@@ -1389,7 +1390,7 @@ mod test {
13891390
let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
13901391

13911392
let size_of_change = 31;
1392-
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
1393+
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
13931394
let target_amount = 20_000 + FEE_AMOUNT;
13941395

13951396
let drain_script = Script::default();
@@ -1413,7 +1414,7 @@ mod test {
14131414
fn test_bnb_function_almost_exact_match_with_fees() {
14141415
let fee_rate = FeeRate::from_sat_per_vb(1.0);
14151416
let size_of_change = 31;
1416-
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
1417+
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
14171418

14181419
let utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
14191420
.into_iter()

src/wallet/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ where
10671067
utxos: original_utxos,
10681068
bumping_fee: Some(tx_builder::PreviousFee {
10691069
absolute: details.fee.ok_or(Error::FeeRateUnavailable)?,
1070-
rate: feerate.as_sat_vb(),
1070+
rate: feerate.as_sat_per_vb(),
10711071
}),
10721072
..Default::default()
10731073
};
@@ -2095,7 +2095,7 @@ pub(crate) mod test {
20952095
let fee_rate = $fee_rate;
20962096

20972097
if !dust_change {
2098-
assert!(tx_fee_rate >= fee_rate && (tx_fee_rate - fee_rate).as_sat_vb().abs() < 0.5, "Expected fee rate of {:?}, the tx has {:?}", fee_rate, tx_fee_rate);
2098+
assert!(tx_fee_rate >= fee_rate && (tx_fee_rate - fee_rate).as_sat_per_vb().abs() < 0.5, "Expected fee rate of {:?}, the tx has {:?}", fee_rate, tx_fee_rate);
20992099
} else {
21002100
assert!(tx_fee_rate >= fee_rate, "Expected fee rate of at least {:?}, the tx has {:?}", fee_rate, tx_fee_rate);
21012101
}

src/wallet/utils.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ mod test {
144144
SEQUENCE_LOCKTIME_TYPE_FLAG,
145145
};
146146
use crate::bitcoin::Address;
147-
use crate::types::FeeRate;
148147
use std::str::FromStr;
149148

150149
#[test]
@@ -164,24 +163,6 @@ mod test {
164163
assert!(!294.is_dust(&script_p2wpkh));
165164
}
166165

167-
#[test]
168-
fn test_fee_from_btc_per_kb() {
169-
let fee = FeeRate::from_btc_per_kvb(1e-5);
170-
assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
171-
}
172-
173-
#[test]
174-
fn test_fee_from_sats_vbyte() {
175-
let fee = FeeRate::from_sat_per_vb(1.0);
176-
assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
177-
}
178-
179-
#[test]
180-
fn test_fee_default_min_relay_fee() {
181-
let fee = FeeRate::default_min_relay_fee();
182-
assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
183-
}
184-
185166
#[test]
186167
fn test_check_nsequence_rbf_msb_set() {
187168
let result = check_nsequence_rbf(0x80000000, 5000);

0 commit comments

Comments
 (0)