Skip to content

Commit a25827b

Browse files
committed
feat: Add optional EstimationMode parameter to estimate_fee
Add support for the optional `mode` argument to `blockchain.estimatefee` which was added in protocol v1.6. The mode is passed to bitcoind's `estimatesmartfee` RPC as the `estimate_mode` parameter. - Add `EstimationMode` enum with `Conservative` and `Economical` variants - Update `estimate_fee` to take `Option<EstimationMode>` as second parameter - Update `Batch::estimate_fee` to support the mode parameter - `batch_estimate_fee` currently always uses `None` for mode This is a breaking change as the `estimate_fee` signature has changed. Co-Authored-By: Claude Code AI
1 parent 6ad0cb0 commit a25827b

File tree

5 files changed

+62
-13
lines changed

5 files changed

+62
-13
lines changed

src/api.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ where
4242
(**self).block_headers(start_height, count)
4343
}
4444

45-
fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
46-
(**self).estimate_fee(number)
45+
fn estimate_fee(&self, number: usize, mode: Option<EstimationMode>) -> Result<f64, Error> {
46+
(**self).estimate_fee(number, mode)
4747
}
4848

4949
fn relay_fee(&self) -> Result<f64, Error> {
@@ -272,7 +272,10 @@ pub trait ElectrumApi {
272272
fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
273273

274274
/// Estimates the fee required in **Bitcoin per kilobyte** to confirm a transaction in `number` blocks.
275-
fn estimate_fee(&self, number: usize) -> Result<f64, Error>;
275+
///
276+
/// Optionally takes an [`EstimationMode`] parameter to specify the fee estimation mode.
277+
/// This parameter was added in protocol v1.6.
278+
fn estimate_fee(&self, number: usize, mode: Option<EstimationMode>) -> Result<f64, Error>;
276279

277280
/// Returns the minimum accepted fee by the server's node in **Bitcoin, not Satoshi**.
278281
fn relay_fee(&self) -> Result<f64, Error>;
@@ -459,7 +462,11 @@ mod test {
459462
unreachable!()
460463
}
461464

462-
fn estimate_fee(&self, _: usize) -> Result<f64, super::Error> {
465+
fn estimate_fee(
466+
&self,
467+
_: usize,
468+
_: Option<super::EstimationMode>,
469+
) -> Result<f64, super::Error> {
463470
unreachable!()
464471
}
465472

src/batch.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use bitcoin::{Script, Txid};
66

7-
use crate::types::{Call, Param, ToElectrumScriptHash};
7+
use crate::types::{Call, EstimationMode, Param, ToElectrumScriptHash};
88

99
/// Helper structure that caches all the requests before they are actually sent to the server.
1010
///
@@ -74,8 +74,11 @@ impl Batch {
7474
}
7575

7676
/// Add one `blockchain.estimatefee` request to the batch queue
77-
pub fn estimate_fee(&mut self, number: usize) {
78-
let params = vec![Param::Usize(number)];
77+
pub fn estimate_fee(&mut self, number: usize, mode: Option<EstimationMode>) {
78+
let mut params = vec![Param::Usize(number)];
79+
if let Some(mode) = mode {
80+
params.push(Param::String(mode.to_string()));
81+
}
7982
self.calls
8083
.push((String::from("blockchain.estimatefee"), params));
8184
}

src/client.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ impl ElectrumApi for Client {
207207
}
208208

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

214214
#[inline]

src/raw_client.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -938,11 +938,15 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
938938
Ok(deserialized)
939939
}
940940

941-
fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
941+
fn estimate_fee(&self, number: usize, mode: Option<EstimationMode>) -> Result<f64, Error> {
942+
let mut params = vec![Param::Usize(number)];
943+
if let Some(mode) = mode {
944+
params.push(Param::String(mode.to_string()));
945+
}
942946
let req = Request::new_id(
943947
self.last_id.fetch_add(1, Ordering::SeqCst),
944948
"blockchain.estimatefee",
945-
vec![Param::Usize(number)],
949+
params,
946950
);
947951
let result = self.call(req)?;
948952

@@ -1147,7 +1151,19 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
11471151
I: IntoIterator + Clone,
11481152
I::Item: Borrow<usize>,
11491153
{
1150-
impl_batch_call!(self, numbers, estimate_fee, apply_deref)
1154+
let mut batch = Batch::default();
1155+
for i in numbers {
1156+
batch.estimate_fee(*i.borrow(), None);
1157+
}
1158+
1159+
let resp = self.batch_call(&batch)?;
1160+
let mut answer = Vec::new();
1161+
1162+
for x in resp {
1163+
answer.push(serde_json::from_value(x)?);
1164+
}
1165+
1166+
Ok(answer)
11511167
}
11521168

11531169
fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
@@ -1328,7 +1344,7 @@ mod test {
13281344
fn test_estimate_fee() {
13291345
let client = get_test_client();
13301346

1331-
let resp = client.estimate_fee(10).unwrap();
1347+
let resp = client.estimate_fee(10, None).unwrap();
13321348
assert!(resp > 0.0);
13331349
}
13341350

src/types.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,29 @@ pub enum Param {
3737
StringVec(Vec<String>),
3838
}
3939

40+
/// Fee estimation mode for [`estimate_fee`](../api/trait.ElectrumApi.html#method.estimate_fee).
41+
///
42+
/// This parameter was added in protocol v1.6 and is passed to bitcoind's
43+
/// `estimatesmartfee` RPC as the `estimate_mode` parameter.
44+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45+
pub enum EstimationMode {
46+
/// A conservative estimate potentially returns a higher feerate and is more likely to be
47+
/// sufficient for the desired target, but is not as responsive to short term drops in the
48+
/// prevailing fee market.
49+
Conservative,
50+
/// Economical fee estimate - potentially lower fees but may take longer to confirm.
51+
Economical,
52+
}
53+
54+
impl Display for EstimationMode {
55+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
56+
match self {
57+
EstimationMode::Conservative => write!(f, "CONSERVATIVE"),
58+
EstimationMode::Economical => write!(f, "ECONOMICAL"),
59+
}
60+
}
61+
}
62+
4063
#[derive(Serialize, Clone)]
4164
/// A request that can be sent to the server
4265
pub struct Request<'a> {

0 commit comments

Comments
 (0)