Skip to content

Commit 496479c

Browse files
committed
feat!: convert fees from BTC/kB to sats/vB
Also changes all fee rates from f64 to proper FeeRate
1 parent 0b97659 commit 496479c

File tree

4 files changed

+39
-21
lines changed

4 files changed

+39
-21
lines changed

src/api.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::borrow::Borrow;
44
use std::convert::TryInto;
55

66
use bitcoin::consensus::encode::{deserialize, serialize};
7-
use bitcoin::{block, Script, Transaction, Txid};
7+
use bitcoin::{block, FeeRate, Script, Transaction, Txid};
88

99
use crate::batch::Batch;
1010
use crate::types::*;
@@ -94,11 +94,11 @@ pub trait ElectrumApi {
9494
/// Tries to fetch `count` block headers starting from `start_height`.
9595
fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
9696

97-
/// Estimates the fee required in **Bitcoin per kilobyte** to confirm a transaction in `number` blocks.
98-
fn estimate_fee(&self, number: usize) -> Result<f64, Error>;
97+
/// Estimates the fee required in [`FeeRate`] to confirm a transaction in `number` blocks.
98+
fn estimate_fee(&self, number: usize) -> Result<FeeRate, Error>;
9999

100100
/// Returns the minimum accepted fee by the server's node in **Bitcoin, not Satoshi**.
101-
fn relay_fee(&self) -> Result<f64, Error>;
101+
fn relay_fee(&self) -> Result<FeeRate, Error>;
102102

103103
/// Subscribes to notifications for activity on a specific *scriptPubKey*.
104104
///
@@ -189,7 +189,7 @@ pub trait ElectrumApi {
189189
///
190190
/// Takes a list of `numbers` of blocks and returns a list of fee required in
191191
/// **Satoshis per kilobyte** to confirm a transaction in the given number of blocks.
192-
fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
192+
fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
193193
where
194194
I: IntoIterator + Clone,
195195
I::Item: Borrow<usize>;

src/client.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{borrow::Borrow, sync::RwLock};
44

55
use log::{info, warn};
66

7-
use bitcoin::{Script, Txid};
7+
use bitcoin::{FeeRate, Script, Txid};
88

99
use crate::api::ElectrumApi;
1010
use crate::batch::Batch;
@@ -207,12 +207,12 @@ impl ElectrumApi for Client {
207207
}
208208

209209
#[inline]
210-
fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
210+
fn estimate_fee(&self, number: usize) -> Result<FeeRate, Error> {
211211
impl_inner_call!(self, estimate_fee, number)
212212
}
213213

214214
#[inline]
215-
fn relay_fee(&self) -> Result<f64, Error> {
215+
fn relay_fee(&self) -> Result<FeeRate, Error> {
216216
impl_inner_call!(self, relay_fee)
217217
}
218218

@@ -309,7 +309,7 @@ impl ElectrumApi for Client {
309309
}
310310

311311
#[inline]
312-
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
312+
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
313313
where
314314
I: IntoIterator + Clone,
315315
I::Item: Borrow<usize>,

src/raw_client.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use log::{debug, error, info, trace, warn};
1717

1818
use bitcoin::consensus::encode::deserialize;
1919
use bitcoin::hex::{DisplayHex, FromHex};
20-
use bitcoin::{Script, Txid};
20+
use bitcoin::{FeeRate, Script, Txid};
2121

2222
#[cfg(feature = "use-openssl")]
2323
use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode};
@@ -38,6 +38,7 @@ use rustls::{
3838

3939
#[cfg(any(feature = "default", feature = "proxy"))]
4040
use crate::socks::{Socks5Stream, TargetAddr, ToTargetAddr};
41+
use crate::utils::convert_fee_rate;
4142

4243
use crate::stream::ClonableStream;
4344

@@ -857,7 +858,7 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
857858
Ok(deserialized)
858859
}
859860

860-
fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
861+
fn estimate_fee(&self, number: usize) -> Result<FeeRate, Error> {
861862
let req = Request::new_id(
862863
self.last_id.fetch_add(1, Ordering::SeqCst),
863864
"blockchain.estimatefee",
@@ -867,10 +868,11 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
867868

868869
result
869870
.as_f64()
871+
.map(convert_fee_rate)
870872
.ok_or_else(|| Error::InvalidResponse(result.clone()))
871873
}
872874

873-
fn relay_fee(&self) -> Result<f64, Error> {
875+
fn relay_fee(&self) -> Result<FeeRate, Error> {
874876
let req = Request::new_id(
875877
self.last_id.fetch_add(1, Ordering::SeqCst),
876878
"blockchain.relayfee",
@@ -880,6 +882,7 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
880882

881883
result
882884
.as_f64()
885+
.map(convert_fee_rate)
883886
.ok_or_else(|| Error::InvalidResponse(result.clone()))
884887
}
885888

@@ -1061,12 +1064,15 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
10611064
.collect()
10621065
}
10631066

1064-
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
1067+
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
10651068
where
10661069
I: IntoIterator + Clone,
10671070
I::Item: Borrow<usize>,
10681071
{
1069-
impl_batch_call!(self, numbers, estimate_fee, apply_deref)
1072+
let fee_rate_num: Result<Vec<f64>, Error> =
1073+
impl_batch_call!(self, numbers, estimate_fee, apply_deref);
1074+
let fee_rate: Vec<FeeRate> = fee_rate_num?.into_iter().map(convert_fee_rate).collect();
1075+
Ok(fee_rate)
10701076
}
10711077

10721078
fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
@@ -1149,20 +1155,21 @@ mod test {
11491155
assert_eq!(resp.hash_function, Some("sha256".into()));
11501156
assert_eq!(resp.pruning, None);
11511157
}
1158+
11521159
#[test]
11531160
fn test_relay_fee() {
11541161
let client = RawClient::new(get_test_server(), None).unwrap();
11551162

1156-
let resp = client.relay_fee().unwrap();
1157-
assert_eq!(resp, 0.00001);
1163+
let resp = client.relay_fee().unwrap().to_sat_per_vb_ceil();
1164+
assert!(resp > 0);
11581165
}
11591166

11601167
#[test]
11611168
fn test_estimate_fee() {
11621169
let client = RawClient::new(get_test_server(), None).unwrap();
11631170

1164-
let resp = client.estimate_fee(10).unwrap();
1165-
assert!(resp > 0.0);
1171+
let resp = client.estimate_fee(10).unwrap().to_sat_per_vb_ceil();
1172+
assert!(resp > 0);
11661173
}
11671174

11681175
#[test]
@@ -1288,8 +1295,8 @@ mod test {
12881295

12891296
let resp = client.batch_estimate_fee(vec![10, 20]).unwrap();
12901297
assert_eq!(resp.len(), 2);
1291-
assert!(resp[0] > 0.0);
1292-
assert!(resp[1] > 0.0);
1298+
assert!(resp[0].to_sat_per_vb_ceil() > 0);
1299+
assert!(resp[1].to_sat_per_vb_ceil() > 0);
12931300
}
12941301

12951302
#[test]

src/utils.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::types::GetMerkleRes;
44
use bitcoin::hash_types::TxMerkleNode;
55
use bitcoin::hashes::sha256d::Hash as Sha256d;
66
use bitcoin::hashes::{Hash, HashEngine};
7-
use bitcoin::Txid;
7+
use bitcoin::{Amount, FeeRate, Txid};
88

99
/// Verifies a Merkle inclusion proof as retrieved via [`transaction_get_merkle`] for a transaction with the
1010
/// given `txid` and `merkle_root` as included in the [`BlockHeader`].
@@ -41,3 +41,14 @@ pub fn validate_merkle_proof(
4141

4242
cur == merkle_root.to_raw_hash()
4343
}
44+
45+
/// Converts a fee rate in BTC/kB to sats/vbyte.
46+
///
47+
/// # Note
48+
///
49+
/// If the conversion fails, the function returns a default fee rate of
50+
/// 1 sat/vbyte.
51+
pub(crate) fn convert_fee_rate(fee_rate_kvb: f64) -> FeeRate {
52+
let fee_rate_sat_vb = (Amount::ONE_BTC.to_sat() as f64) * fee_rate_kvb;
53+
FeeRate::from_sat_per_vb(fee_rate_sat_vb as u64).unwrap_or(FeeRate::from_sat_per_vb(1).unwrap())
54+
}

0 commit comments

Comments
 (0)