Skip to content

Commit 12b34a3

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 79e880d commit 12b34a3

5 files changed

Lines changed: 62 additions & 13 deletions

File tree

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
@@ -889,11 +889,15 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
889889
Ok(deserialized)
890890
}
891891

892-
fn estimate_fee(&self, number: usize) -> Result<f64, Error> {
892+
fn estimate_fee(&self, number: usize, mode: Option<EstimationMode>) -> Result<f64, Error> {
893+
let mut params = vec![Param::Usize(number)];
894+
if let Some(mode) = mode {
895+
params.push(Param::String(mode.to_string()));
896+
}
893897
let req = Request::new_id(
894898
self.last_id.fetch_add(1, Ordering::SeqCst),
895899
"blockchain.estimatefee",
896-
vec![Param::Usize(number)],
900+
params,
897901
);
898902
let result = self.call(req)?;
899903

@@ -1098,7 +1102,19 @@ impl<T: Read + Write> ElectrumApi for RawClient<T> {
10981102
I: IntoIterator + Clone,
10991103
I::Item: Borrow<usize>,
11001104
{
1101-
impl_batch_call!(self, numbers, estimate_fee, apply_deref)
1105+
let mut batch = Batch::default();
1106+
for i in numbers {
1107+
batch.estimate_fee(*i.borrow(), None);
1108+
}
1109+
1110+
let resp = self.batch_call(&batch)?;
1111+
let mut answer = Vec::new();
1112+
1113+
for x in resp {
1114+
answer.push(serde_json::from_value(x)?);
1115+
}
1116+
1117+
Ok(answer)
11021118
}
11031119

11041120
fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error> {
@@ -1279,7 +1295,7 @@ mod test {
12791295
fn test_estimate_fee() {
12801296
let client = get_test_client();
12811297

1282-
let resp = client.estimate_fee(10).unwrap();
1298+
let resp = client.estimate_fee(10, None).unwrap();
12831299
assert!(resp > 0.0);
12841300
}
12851301

src/types.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,29 @@ pub enum Param {
3535
Bytes(Vec<u8>),
3636
}
3737

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

0 commit comments

Comments
 (0)