Skip to content

Commit 696ad72

Browse files
committed
feat!: convert fees from BTC/kB to sats/vB
Also changes all fee rates from f64 to proper FeeRate
1 parent 64c77ee commit 696ad72

File tree

4 files changed

+38
-20
lines changed

4 files changed

+38
-20
lines changed

src/api.rs

Lines changed: 4 additions & 4 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 batch::Batch;
1010
use types::*;
@@ -95,10 +95,10 @@ pub trait ElectrumApi {
9595
fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
9696

9797
/// 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>;
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 api::ElectrumApi;
1010
use batch::Batch;
@@ -208,12 +208,12 @@ impl ElectrumApi for Client {
208208
}
209209

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

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

@@ -310,7 +310,7 @@ impl ElectrumApi for Client {
310310
}
311311

312312
#[inline]
313-
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
313+
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
314314
where
315315
I: IntoIterator + Clone,
316316
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};
@@ -34,6 +34,7 @@ use rustls::{
3434

3535
#[cfg(any(feature = "default", feature = "proxy"))]
3636
use crate::socks::{Socks5Stream, TargetAddr, ToTargetAddr};
37+
use crate::utils::convert_fee_rate;
3738

3839
use stream::ClonableStream;
3940

@@ -837,7 +838,7 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
837838
Ok(deserialized)
838839
}
839840

840-
fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
841+
fn estimate_fee(&self, number: usize) -> Result<FeeRate, Error> {
841842
let req = Request::new_id(
842843
self.last_id.fetch_add(1, Ordering::SeqCst),
843844
"blockchain.estimatefee",
@@ -847,10 +848,11 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
847848

848849
result
849850
.as_f64()
851+
.map(convert_fee_rate)
850852
.ok_or_else(|| Error::InvalidResponse(result.clone()))
851853
}
852854

853-
fn relay_fee(&self) -> Result<f64, Error> {
855+
fn relay_fee(&self) -> Result<FeeRate, Error> {
854856
let req = Request::new_id(
855857
self.last_id.fetch_add(1, Ordering::SeqCst),
856858
"blockchain.relayfee",
@@ -860,6 +862,7 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
860862

861863
result
862864
.as_f64()
865+
.map(convert_fee_rate)
863866
.ok_or_else(|| Error::InvalidResponse(result.clone()))
864867
}
865868

@@ -1041,12 +1044,15 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
10411044
.collect()
10421045
}
10431046

1044-
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
1047+
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
10451048
where
10461049
I: IntoIterator + Clone,
10471050
I::Item: Borrow<usize>,
10481051
{
1049-
impl_batch_call!(self, numbers, estimate_fee, apply_deref)
1052+
let fee_rate_num: Result<Vec<f64>, Error> =
1053+
impl_batch_call!(self, numbers, estimate_fee, apply_deref);
1054+
let fee_rate: Vec<FeeRate> = fee_rate_num?.into_iter().map(convert_fee_rate).collect();
1055+
Ok(fee_rate)
10501056
}
10511057

10521058
fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
@@ -1129,20 +1135,21 @@ mod test {
11291135
assert_eq!(resp.hash_function, Some("sha256".into()));
11301136
assert_eq!(resp.pruning, None);
11311137
}
1138+
11321139
#[test]
11331140
fn test_relay_fee() {
11341141
let client = RawClient::new(get_test_server(), None).unwrap();
11351142

1136-
let resp = client.relay_fee().unwrap();
1137-
assert_eq!(resp, 0.00001);
1143+
let resp = client.relay_fee().unwrap().to_sat_per_vb_ceil();
1144+
assert_eq!(resp, 1);
11381145
}
11391146

11401147
#[test]
11411148
fn test_estimate_fee() {
11421149
let client = RawClient::new(get_test_server(), None).unwrap();
11431150

1144-
let resp = client.estimate_fee(10).unwrap();
1145-
assert!(resp > 0.0);
1151+
let resp = client.estimate_fee(10).unwrap().to_sat_per_vb_ceil();
1152+
assert_eq!(resp, 1);
11461153
}
11471154

11481155
#[test]
@@ -1268,8 +1275,8 @@ mod test {
12681275

12691276
let resp = client.batch_estimate_fee(vec![10, 20]).unwrap();
12701277
assert_eq!(resp.len(), 2);
1271-
assert!(resp[0] > 0.0);
1272-
assert!(resp[1] > 0.0);
1278+
assert!(resp[0].to_sat_per_vb_ceil() > 0);
1279+
assert!(resp[1].to_sat_per_vb_ceil() > 0);
12731280
}
12741281

12751282
#[test]

src/utils.rs

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

99
/// Verifies a Merkle inclusion proof as retrieved via [`transaction_get_merkle`] for a transaction with the
@@ -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)