Implement conversion for Lightning fee rate
Lightning denotes transaction fee rate sats / 1000 weight units and sats / 1000 vbytes. Here we add support for creating BDK fee rate from lightning fee rate. We also move all FeeRate test to types.rs and rename as_sat_vb to as_sat_per_vb.
This commit is contained in:
parent
0a3734ed2b
commit
de358f8cdc
@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
- Add capacity to create FeeRate from sats/kvbytes and sats/kwu.
|
||||||
|
- Rename `as_sat_vb` to `as_sat_per_vb`. Move all `FeeRate` test to `types.rs`.
|
||||||
|
|
||||||
## [v0.21.0] - [v0.20.0]
|
## [v0.21.0] - [v0.20.0]
|
||||||
|
|
||||||
@ -19,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- New `RpcBlockchain` implementation with various fixes.
|
- New `RpcBlockchain` implementation with various fixes.
|
||||||
- Return balance in separate categories, namely `confirmed`, `trusted_pending`, `untrusted_pending` & `immature`.
|
- Return balance in separate categories, namely `confirmed`, `trusted_pending`, `untrusted_pending` & `immature`.
|
||||||
|
|
||||||
|
|
||||||
## [v0.20.0] - [v0.19.0]
|
## [v0.20.0] - [v0.19.0]
|
||||||
|
|
||||||
- New MSRV set to `1.56.1`
|
- New MSRV set to `1.56.1`
|
||||||
|
44
src/types.rs
44
src/types.rs
@ -63,6 +63,16 @@ impl FeeRate {
|
|||||||
FeeRate(value)
|
FeeRate(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new instance of [`FeeRate`] given a float fee rate in sats/kwu
|
||||||
|
pub fn from_sat_per_kwu(sat_per_kwu: f32) -> Self {
|
||||||
|
FeeRate::new_checked(sat_per_kwu / 250.0_f32)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new instance of [`FeeRate`] given a float fee rate in sats/kvb
|
||||||
|
pub fn from_sat_per_kvb(sat_per_kvb: f32) -> Self {
|
||||||
|
FeeRate::new_checked(sat_per_kvb / 1000.0_f32)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new instance of [`FeeRate`] given a float fee rate in btc/kvbytes
|
/// Create a new instance of [`FeeRate`] given a float fee rate in btc/kvbytes
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
@ -98,7 +108,7 @@ impl FeeRate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value as satoshi/vbyte
|
/// Return the value as satoshi/vbyte
|
||||||
pub fn as_sat_vb(&self) -> f32 {
|
pub fn as_sat_per_vb(&self) -> f32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +119,7 @@ impl FeeRate {
|
|||||||
|
|
||||||
/// Calculate absolute fee in Satoshis using size in virtual bytes.
|
/// Calculate absolute fee in Satoshis using size in virtual bytes.
|
||||||
pub fn fee_vb(&self, vbytes: usize) -> u64 {
|
pub fn fee_vb(&self, vbytes: usize) -> u64 {
|
||||||
(self.as_sat_vb() * vbytes as f32).ceil() as u64
|
(self.as_sat_per_vb() * vbytes as f32).ceil() as u64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,4 +368,34 @@ mod tests {
|
|||||||
fn test_valid_feerate_pos_zero() {
|
fn test_valid_feerate_pos_zero() {
|
||||||
let _ = FeeRate::from_sat_per_vb(0.0);
|
let _ = FeeRate::from_sat_per_vb(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fee_from_btc_per_kvb() {
|
||||||
|
let fee = FeeRate::from_btc_per_kvb(1e-5);
|
||||||
|
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fee_from_sat_per_vbyte() {
|
||||||
|
let fee = FeeRate::from_sat_per_vb(1.0);
|
||||||
|
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fee_default_min_relay_fee() {
|
||||||
|
let fee = FeeRate::default_min_relay_fee();
|
||||||
|
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fee_from_sat_per_kvb() {
|
||||||
|
let fee = FeeRate::from_sat_per_kvb(1000.0);
|
||||||
|
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fee_from_sat_per_kwu() {
|
||||||
|
let fee = FeeRate::from_sat_per_kwu(250.0);
|
||||||
|
assert!((fee.as_sat_per_vb() - 1.0).abs() < f32::EPSILON);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
|
|||||||
.iter()
|
.iter()
|
||||||
.fold(0, |acc, x| acc + x.effective_value);
|
.fold(0, |acc, x| acc + x.effective_value);
|
||||||
|
|
||||||
let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_vb();
|
let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_per_vb();
|
||||||
|
|
||||||
// `curr_value` and `curr_available_value` are both the sum of *effective_values* of
|
// `curr_value` and `curr_available_value` are both the sum of *effective_values* of
|
||||||
// the UTXOs. For the optional UTXOs (curr_available_value) we filter out UTXOs with
|
// the UTXOs. For the optional UTXOs (curr_available_value) we filter out UTXOs with
|
||||||
@ -1360,7 +1360,8 @@ mod test {
|
|||||||
let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
|
let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
|
||||||
|
|
||||||
let size_of_change = 31;
|
let size_of_change = 31;
|
||||||
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
|
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
|
||||||
|
|
||||||
let drain_script = Script::default();
|
let drain_script = Script::default();
|
||||||
let target_amount = 20_000 + FEE_AMOUNT;
|
let target_amount = 20_000 + FEE_AMOUNT;
|
||||||
BranchAndBoundCoinSelection::new(size_of_change)
|
BranchAndBoundCoinSelection::new(size_of_change)
|
||||||
@ -1389,7 +1390,7 @@ mod test {
|
|||||||
let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
|
let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
|
||||||
|
|
||||||
let size_of_change = 31;
|
let size_of_change = 31;
|
||||||
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
|
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
|
||||||
let target_amount = 20_000 + FEE_AMOUNT;
|
let target_amount = 20_000 + FEE_AMOUNT;
|
||||||
|
|
||||||
let drain_script = Script::default();
|
let drain_script = Script::default();
|
||||||
@ -1413,7 +1414,7 @@ mod test {
|
|||||||
fn test_bnb_function_almost_exact_match_with_fees() {
|
fn test_bnb_function_almost_exact_match_with_fees() {
|
||||||
let fee_rate = FeeRate::from_sat_per_vb(1.0);
|
let fee_rate = FeeRate::from_sat_per_vb(1.0);
|
||||||
let size_of_change = 31;
|
let size_of_change = 31;
|
||||||
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
|
let cost_of_change = size_of_change as f32 * fee_rate.as_sat_per_vb();
|
||||||
|
|
||||||
let utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
|
let utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1067,7 +1067,7 @@ where
|
|||||||
utxos: original_utxos,
|
utxos: original_utxos,
|
||||||
bumping_fee: Some(tx_builder::PreviousFee {
|
bumping_fee: Some(tx_builder::PreviousFee {
|
||||||
absolute: details.fee.ok_or(Error::FeeRateUnavailable)?,
|
absolute: details.fee.ok_or(Error::FeeRateUnavailable)?,
|
||||||
rate: feerate.as_sat_vb(),
|
rate: feerate.as_sat_per_vb(),
|
||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -2095,7 +2095,7 @@ pub(crate) mod test {
|
|||||||
let fee_rate = $fee_rate;
|
let fee_rate = $fee_rate;
|
||||||
|
|
||||||
if !dust_change {
|
if !dust_change {
|
||||||
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);
|
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);
|
||||||
} else {
|
} else {
|
||||||
assert!(tx_fee_rate >= fee_rate, "Expected fee rate of at least {:?}, the tx has {:?}", fee_rate, tx_fee_rate);
|
assert!(tx_fee_rate >= fee_rate, "Expected fee rate of at least {:?}, the tx has {:?}", fee_rate, tx_fee_rate);
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,6 @@ mod test {
|
|||||||
SEQUENCE_LOCKTIME_TYPE_FLAG,
|
SEQUENCE_LOCKTIME_TYPE_FLAG,
|
||||||
};
|
};
|
||||||
use crate::bitcoin::Address;
|
use crate::bitcoin::Address;
|
||||||
use crate::types::FeeRate;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -164,24 +163,6 @@ mod test {
|
|||||||
assert!(!294.is_dust(&script_p2wpkh));
|
assert!(!294.is_dust(&script_p2wpkh));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fee_from_btc_per_kb() {
|
|
||||||
let fee = FeeRate::from_btc_per_kvb(1e-5);
|
|
||||||
assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fee_from_sats_vbyte() {
|
|
||||||
let fee = FeeRate::from_sat_per_vb(1.0);
|
|
||||||
assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_fee_default_min_relay_fee() {
|
|
||||||
let fee = FeeRate::default_min_relay_fee();
|
|
||||||
assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_nsequence_rbf_msb_set() {
|
fn test_check_nsequence_rbf_msb_set() {
|
||||||
let result = check_nsequence_rbf(0x80000000, 5000);
|
let result = check_nsequence_rbf(0x80000000, 5000);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user