Skip to content

Commit 6e8a4a8

Browse files
committed
Merge #1216: Migrate to bitcoin::FeeRate
475a772 refactor(bdk)!: Remove trait Vbytes (vmammal) 0d64beb chore: organize some imports (vmammal) 89608dd refactor(bdk): display CreateTxError::FeeRateTooLow in sat/vb (vmammal) 09bd86e test(bdk): initialize all feerates from `u64` (vmammal) 004957d refactor(bdk)!: drop FeeRate from bdk::types (vmammal) Pull request description: ### Description This follows a similar approach to #1141 namely to remove `FeeRate` from `bdk::types` and instead defer to the upstream implementation for all fee rates. The idea is that making the switch allows BDK to benefit from a higher level abstraction, leaving the implementation details largely hidden. As noted in #774, we should avoid extraneous conversions that can result in deviations in estimated transaction size and calculated fee amounts, etc. This would happen for example whenever calling a method like `FeeRate::to_sat_per_vb_ceil`. The only exception I would make is if we must return a fee rate error to the user, we might prefer to display it in the more familiar sats/vb, but this would only be useful if the rate can be expressed as a float. ### Notes to the reviewers `bitcoin::FeeRate` is an integer whose native unit is sats per kilo-weight unit. In order to facilitate the change, a helper method `feerate_unchecked` is added and used only in wallet tests and psbt tests as necessary to convert existing fee rates to the new type. It's "unchecked" in the sense that we're not checking for integer overflow, because it's assumed we're passing a valid fee rate in a unit test. Potential follow-ups can include: - [x] Constructing a proper `FeeRate` from a `u64` in all unit tests, and thus obviating the need for the helper `feerate_unchecked` going forward. - [x] Remove trait `Vbytes`. - Consider adding an extra check that the argument to `TxBuilder::drain_to` is within "standard" size limits. - Consider refactoring `coin_selection::select_sorted_utxos` to be efficient and readable. closes #1136 ### Changelog notice - Removed `FeeRate` type. All fee rates are now rust-bitcoin [`FeeRate`](https://docs.rs/bitcoin/latest/bitcoin/blockdata/fee_rate/struct.FeeRate.html). - Removed trait `Vbytes`. ### 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 ACKs for top commit: evanlinjin: ACK 475a772 Tree-SHA512: 511dab8aa7a65d2b15b160cb4feb96964e8401bb04cda4ef0f0244524bf23a575b3739783a14b90d2dccc984b3f30f5dabfb0a890ffe7c897c2dc23ba301bcaf
2 parents fc637a7 + 475a772 commit 6e8a4a8

File tree

11 files changed

+194
-335
lines changed

11 files changed

+194
-335
lines changed

crates/bdk/src/psbt/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111

1212
//! Additional functions on the `rust-bitcoin` `PartiallySignedTransaction` structure.
1313
14-
use crate::FeeRate;
1514
use alloc::vec::Vec;
1615
use bitcoin::psbt::PartiallySignedTransaction as Psbt;
16+
use bitcoin::Amount;
17+
use bitcoin::FeeRate;
1718
use bitcoin::TxOut;
1819

1920
// TODO upstream the functions here to `rust-bitcoin`?
@@ -65,7 +66,7 @@ impl PsbtUtils for Psbt {
6566
let fee_amount = self.fee_amount();
6667
fee_amount.map(|fee| {
6768
let weight = self.clone().extract_tx().weight();
68-
FeeRate::from_wu(fee, weight)
69+
Amount::from_sat(fee) / weight
6970
})
7071
}
7172
}

crates/bdk/src/types.rs

Lines changed: 1 addition & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111

1212
use alloc::boxed::Box;
1313
use core::convert::AsRef;
14-
use core::ops::Sub;
1514

1615
use bdk_chain::ConfirmationTime;
1716
use bitcoin::blockdata::transaction::{OutPoint, Sequence, TxOut};
18-
use bitcoin::{psbt, Weight};
17+
use bitcoin::psbt;
1918

2019
use serde::{Deserialize, Serialize};
2120

@@ -47,116 +46,6 @@ impl AsRef<[u8]> for KeychainKind {
4746
}
4847
}
4948

50-
/// Fee rate
51-
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
52-
// Internally stored as satoshi/vbyte
53-
pub struct FeeRate(f32);
54-
55-
impl FeeRate {
56-
/// Create a new instance checking the value provided
57-
///
58-
/// ## Panics
59-
///
60-
/// Panics if the value is not [normal](https://doc.rust-lang.org/std/primitive.f32.html#method.is_normal) (except if it's a positive zero) or negative.
61-
fn new_checked(value: f32) -> Self {
62-
assert!(value.is_normal() || value == 0.0);
63-
assert!(value.is_sign_positive());
64-
65-
FeeRate(value)
66-
}
67-
68-
/// Create a new instance of [`FeeRate`] given a float fee rate in sats/kwu
69-
pub fn from_sat_per_kwu(sat_per_kwu: f32) -> Self {
70-
FeeRate::new_checked(sat_per_kwu / 250.0_f32)
71-
}
72-
73-
/// Create a new instance of [`FeeRate`] given a float fee rate in sats/kvb
74-
pub fn from_sat_per_kvb(sat_per_kvb: f32) -> Self {
75-
FeeRate::new_checked(sat_per_kvb / 1000.0_f32)
76-
}
77-
78-
/// Create a new instance of [`FeeRate`] given a float fee rate in btc/kvbytes
79-
///
80-
/// ## Panics
81-
///
82-
/// Panics if the value is not [normal](https://doc.rust-lang.org/std/primitive.f32.html#method.is_normal) (except if it's a positive zero) or negative.
83-
pub fn from_btc_per_kvb(btc_per_kvb: f32) -> Self {
84-
FeeRate::new_checked(btc_per_kvb * 1e5)
85-
}
86-
87-
/// Create a new instance of [`FeeRate`] given a float fee rate in satoshi/vbyte
88-
///
89-
/// ## Panics
90-
///
91-
/// Panics if the value is not [normal](https://doc.rust-lang.org/std/primitive.f32.html#method.is_normal) (except if it's a positive zero) or negative.
92-
pub fn from_sat_per_vb(sat_per_vb: f32) -> Self {
93-
FeeRate::new_checked(sat_per_vb)
94-
}
95-
96-
/// Create a new [`FeeRate`] with the default min relay fee value
97-
pub const fn default_min_relay_fee() -> Self {
98-
FeeRate(1.0)
99-
}
100-
101-
/// Calculate fee rate from `fee` and weight units (`wu`).
102-
pub fn from_wu(fee: u64, wu: Weight) -> FeeRate {
103-
Self::from_vb(fee, wu.to_vbytes_ceil() as usize)
104-
}
105-
106-
/// Calculate fee rate from `fee` and `vbytes`.
107-
pub fn from_vb(fee: u64, vbytes: usize) -> FeeRate {
108-
let rate = fee as f32 / vbytes as f32;
109-
Self::from_sat_per_vb(rate)
110-
}
111-
112-
/// Return the value as satoshi/vbyte
113-
pub fn as_sat_per_vb(&self) -> f32 {
114-
self.0
115-
}
116-
117-
/// Return the value as satoshi/kwu
118-
pub fn sat_per_kwu(&self) -> f32 {
119-
self.0 * 250.0_f32
120-
}
121-
122-
/// Calculate absolute fee in Satoshis using size in weight units.
123-
pub fn fee_wu(&self, wu: Weight) -> u64 {
124-
self.fee_vb(wu.to_vbytes_ceil() as usize)
125-
}
126-
127-
/// Calculate absolute fee in Satoshis using size in virtual bytes.
128-
pub fn fee_vb(&self, vbytes: usize) -> u64 {
129-
(self.as_sat_per_vb() * vbytes as f32).ceil() as u64
130-
}
131-
}
132-
133-
impl Default for FeeRate {
134-
fn default() -> Self {
135-
FeeRate::default_min_relay_fee()
136-
}
137-
}
138-
139-
impl Sub for FeeRate {
140-
type Output = Self;
141-
142-
fn sub(self, other: FeeRate) -> Self::Output {
143-
FeeRate(self.0 - other.0)
144-
}
145-
}
146-
147-
/// Trait implemented by types that can be used to measure weight units.
148-
pub trait Vbytes {
149-
/// Convert weight units to virtual bytes.
150-
fn vbytes(self) -> usize;
151-
}
152-
153-
impl Vbytes for usize {
154-
fn vbytes(self) -> usize {
155-
// ref: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-size-calculations
156-
(self as f32 / 4.0).ceil() as usize
157-
}
158-
}
159-
16049
/// An unspent output owned by a [`Wallet`].
16150
///
16251
/// [`Wallet`]: crate::Wallet
@@ -244,73 +133,3 @@ impl Utxo {
244133
}
245134
}
246135
}
247-
248-
#[cfg(test)]
249-
mod tests {
250-
use super::*;
251-
252-
#[test]
253-
fn can_store_feerate_in_const() {
254-
const _MIN_RELAY: FeeRate = FeeRate::default_min_relay_fee();
255-
}
256-
257-
#[test]
258-
#[should_panic]
259-
fn test_invalid_feerate_neg_zero() {
260-
let _ = FeeRate::from_sat_per_vb(-0.0);
261-
}
262-
263-
#[test]
264-
#[should_panic]
265-
fn test_invalid_feerate_neg_value() {
266-
let _ = FeeRate::from_sat_per_vb(-5.0);
267-
}
268-
269-
#[test]
270-
#[should_panic]
271-
fn test_invalid_feerate_nan() {
272-
let _ = FeeRate::from_sat_per_vb(f32::NAN);
273-
}
274-
275-
#[test]
276-
#[should_panic]
277-
fn test_invalid_feerate_inf() {
278-
let _ = FeeRate::from_sat_per_vb(f32::INFINITY);
279-
}
280-
281-
#[test]
282-
fn test_valid_feerate_pos_zero() {
283-
let _ = FeeRate::from_sat_per_vb(0.0);
284-
}
285-
286-
#[test]
287-
fn test_fee_from_btc_per_kvb() {
288-
let fee = FeeRate::from_btc_per_kvb(1e-5);
289-
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
290-
}
291-
292-
#[test]
293-
fn test_fee_from_sat_per_vbyte() {
294-
let fee = FeeRate::from_sat_per_vb(1.0);
295-
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
296-
}
297-
298-
#[test]
299-
fn test_fee_default_min_relay_fee() {
300-
let fee = FeeRate::default_min_relay_fee();
301-
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
302-
}
303-
304-
#[test]
305-
fn test_fee_from_sat_per_kvb() {
306-
let fee = FeeRate::from_sat_per_kvb(1000.0);
307-
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
308-
}
309-
310-
#[test]
311-
fn test_fee_from_sat_per_kwu() {
312-
let fee = FeeRate::from_sat_per_kwu(250.0);
313-
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
314-
assert_eq!(fee.sat_per_kwu(), 250.0);
315-
}
316-
}

0 commit comments

Comments
 (0)