Skip to content

Commit

Permalink
feat!: convert fees from BTC/kB to sats/vB
Browse files Browse the repository at this point in the history
Also changes all fee rates from f64 to proper FeeRate
  • Loading branch information
storopoli committed Jul 28, 2024
1 parent 64c77ee commit 696ad72
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 20 deletions.
8 changes: 4 additions & 4 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::borrow::Borrow;
use std::convert::TryInto;

use bitcoin::consensus::encode::{deserialize, serialize};
use bitcoin::{block, Script, Transaction, Txid};
use bitcoin::{block, FeeRate, Script, Transaction, Txid};

use batch::Batch;
use types::*;
Expand Down Expand Up @@ -95,10 +95,10 @@ pub trait ElectrumApi {
fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;

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

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

/// Subscribes to notifications for activity on a specific *scriptPubKey*.
///
Expand Down Expand Up @@ -189,7 +189,7 @@ pub trait ElectrumApi {
///
/// Takes a list of `numbers` of blocks and returns a list of fee required in
/// **Satoshis per kilobyte** to confirm a transaction in the given number of blocks.
fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
where
I: IntoIterator + Clone,
I::Item: Borrow<usize>;
Expand Down
8 changes: 4 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{borrow::Borrow, sync::RwLock};

use log::{info, warn};

use bitcoin::{Script, Txid};
use bitcoin::{FeeRate, Script, Txid};

use api::ElectrumApi;
use batch::Batch;
Expand Down Expand Up @@ -208,12 +208,12 @@ impl ElectrumApi for Client {
}

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

#[inline]
fn relay_fee(&self) -> Result<f64, Error> {
fn relay_fee(&self) -> Result<FeeRate, Error> {
impl_inner_call!(self, relay_fee)
}

Expand Down Expand Up @@ -310,7 +310,7 @@ impl ElectrumApi for Client {
}

#[inline]
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
where
I: IntoIterator + Clone,
I::Item: Borrow<usize>,
Expand Down
29 changes: 18 additions & 11 deletions src/raw_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use log::{debug, error, info, trace, warn};

use bitcoin::consensus::encode::deserialize;
use bitcoin::hex::{DisplayHex, FromHex};
use bitcoin::{Script, Txid};
use bitcoin::{FeeRate, Script, Txid};

#[cfg(feature = "use-openssl")]
use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode};
Expand All @@ -34,6 +34,7 @@ use rustls::{

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

use stream::ClonableStream;

Expand Down Expand Up @@ -837,7 +838,7 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
Ok(deserialized)
}

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

result
.as_f64()
.map(convert_fee_rate)
.ok_or_else(|| Error::InvalidResponse(result.clone()))
}

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

result
.as_f64()
.map(convert_fee_rate)
.ok_or_else(|| Error::InvalidResponse(result.clone()))
}

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

fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<FeeRate>, Error>
where
I: IntoIterator + Clone,
I::Item: Borrow<usize>,
{
impl_batch_call!(self, numbers, estimate_fee, apply_deref)
let fee_rate_num: Result<Vec<f64>, Error> =
impl_batch_call!(self, numbers, estimate_fee, apply_deref);
let fee_rate: Vec<FeeRate> = fee_rate_num?.into_iter().map(convert_fee_rate).collect();
Ok(fee_rate)
}

fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
Expand Down Expand Up @@ -1129,20 +1135,21 @@ mod test {
assert_eq!(resp.hash_function, Some("sha256".into()));
assert_eq!(resp.pruning, None);
}

#[test]
fn test_relay_fee() {
let client = RawClient::new(get_test_server(), None).unwrap();

let resp = client.relay_fee().unwrap();
assert_eq!(resp, 0.00001);
let resp = client.relay_fee().unwrap().to_sat_per_vb_ceil();
assert_eq!(resp, 1);
}

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

let resp = client.estimate_fee(10).unwrap();
assert!(resp > 0.0);
let resp = client.estimate_fee(10).unwrap().to_sat_per_vb_ceil();
assert_eq!(resp, 1);
}

#[test]
Expand Down Expand Up @@ -1268,8 +1275,8 @@ mod test {

let resp = client.batch_estimate_fee(vec![10, 20]).unwrap();
assert_eq!(resp.len(), 2);
assert!(resp[0] > 0.0);
assert!(resp[1] > 0.0);
assert!(resp[0].to_sat_per_vb_ceil() > 0);
assert!(resp[1].to_sat_per_vb_ceil() > 0);
}

#[test]
Expand Down
13 changes: 12 additions & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use bitcoin::hash_types::TxMerkleNode;
use bitcoin::hashes::sha256d::Hash as Sha256d;
use bitcoin::hashes::Hash;
use bitcoin::Txid;
use bitcoin::{Amount, FeeRate, Txid};
use types::GetMerkleRes;

/// Verifies a Merkle inclusion proof as retrieved via [`transaction_get_merkle`] for a transaction with the
Expand Down Expand Up @@ -41,3 +41,14 @@ pub fn validate_merkle_proof(

cur == merkle_root.to_raw_hash()
}

/// Converts a fee rate in BTC/kB to sats/vbyte.
///
/// # Note
///
/// If the conversion fails, the function returns a default fee rate of
/// 1 sat/vbyte.
pub(crate) fn convert_fee_rate(fee_rate_kvb: f64) -> FeeRate {
let fee_rate_sat_vb = (Amount::ONE_BTC.to_sat() as f64) * fee_rate_kvb;
FeeRate::from_sat_per_vb(fee_rate_sat_vb as u64).unwrap_or(FeeRate::from_sat_per_vb(1).unwrap())
}

0 comments on commit 696ad72

Please sign in to comment.