Skip to content

Commit def6957

Browse files
committed
Implement version specific types
1 parent 9dfed3e commit def6957

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1275
-365
lines changed

client/src/client_sync/mod.rs

+81-3
Original file line numberDiff line numberDiff line change
@@ -300,11 +300,13 @@ pub enum ScanAction {
300300
Status,
301301
}
302302

303-
/// Represents the range for HD descriptor scanning.
303+
/// Represents the range for HD descriptor scanning (handles n or [n, n]).
304304
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
305305
#[serde(untagged)]
306306
pub enum ScanRange {
307+
/// Represents the end index (beginning is 0).
307308
Single(u64),
309+
/// Array represents [begin, end] indexes
308310
Range([u64; 2]),
309311
}
310312

@@ -314,15 +316,91 @@ fn default_scan_range() -> ScanRange {
314316
ScanRange::Single(1000)
315317
}
316318

317-
/// Represents a scan object for scantxoutset, either a descriptor string
318-
/// or an object with descriptor and range.
319+
/// Represents a scan object for scantxoutset (descriptor string or object).
319320
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
320321
#[serde(untagged)]
321322
pub enum ScanObject {
323+
/// Plain descriptor string
322324
Descriptor(String),
325+
/// Object containing descriptor and optional range
323326
WithRange {
324327
desc: String,
325328
#[serde(default = "default_scan_range")]
326329
range: ScanRange,
327330
},
328331
}
332+
333+
/// Args for the `importmulti`
334+
///
335+
/// Represents the scriptPubKey field in an importmulti request.
336+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
337+
#[serde(untagged)]
338+
pub enum ImportMultiScriptPubKey {
339+
/// Script hex string
340+
Script(String),
341+
/// Address object
342+
Address { address: String },
343+
}
344+
345+
/// Represents the timestamp field in an importmulti request.
346+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
347+
#[serde(untagged)]
348+
pub enum ImportMultiTimestamp {
349+
/// Use current blockchain time
350+
Now(String),
351+
/// Specific UNIX epoch time
352+
Time(u64),
353+
}
354+
355+
impl Default for ImportMultiTimestamp {
356+
fn default() -> Self { ImportMultiTimestamp::Now("now".to_string()) }
357+
}
358+
359+
/// Represents a single request object within the importmulti call.
360+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
361+
pub struct ImportMultiRequest {
362+
/// Descriptor to import (optional, mutually exclusive with scriptPubKey/address etc.) (v18+)
363+
#[serde(skip_serializing_if = "Option::is_none")]
364+
pub desc: Option<String>,
365+
/// ScriptPubKey or address object (required unless desc is provided)
366+
#[serde(rename = "scriptPubKey", skip_serializing_if = "Option::is_none")]
367+
pub script_pub_key: Option<ImportMultiScriptPubKey>,
368+
/// Creation time of the key
369+
pub timestamp: ImportMultiTimestamp,
370+
/// Redeem script (P2SH/P2SH-P2WSH only)
371+
#[serde(skip_serializing_if = "Option::is_none")]
372+
pub redeemscript: Option<String>,
373+
/// Witness script (P2WSH/P2SH-P2WSH only) (v18+)
374+
#[serde(skip_serializing_if = "Option::is_none")]
375+
pub witnessscript: Option<String>,
376+
/// Pubkeys to import (cannot be used with descriptor)
377+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
378+
pub pubkeys: Vec<String>,
379+
/// Private keys to import (WIF format)
380+
#[serde(default, skip_serializing_if = "Vec::is_empty")]
381+
pub keys: Vec<String>,
382+
/// Range for ranged descriptors (v18+)
383+
#[serde(skip_serializing_if = "Option::is_none")]
384+
pub range: Option<ScanRange>,
385+
/// Treat matching outputs as change
386+
#[serde(skip_serializing_if = "Option::is_none")]
387+
pub internal: Option<bool>,
388+
/// Treat matching outputs as watchonly
389+
#[serde(skip_serializing_if = "Option::is_none")]
390+
pub watchonly: Option<bool>,
391+
/// Label for address (use "" for default)
392+
#[serde(skip_serializing_if = "Option::is_none")]
393+
pub label: Option<String>,
394+
/// Add pubkeys to keypool (only when private keys disabled) (v18+)
395+
#[serde(skip_serializing_if = "Option::is_none")]
396+
pub keypool: Option<bool>,
397+
}
398+
399+
/// Represents the optional options object for importmulti
400+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
401+
/// Rescan after import (default true)
402+
pub struct ImportMultiOptions {
403+
/// Rescan after import (default true)
404+
#[serde(skip_serializing_if = "Option::is_none")]
405+
pub rescan: Option<bool>,
406+
}

client/src/client_sync/v17/blockchain.rs

+29
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,32 @@ macro_rules! impl_client_v17__verifychain {
370370
}
371371
};
372372
}
373+
374+
/// Implements Bitcoin Core JSON-RPC API method `scantxoutset`
375+
#[macro_export]
376+
macro_rules! impl_client_v17__scantxoutset {
377+
() => {
378+
impl Client {
379+
pub fn scan_tx_out_set(
380+
&self,
381+
action: ScanAction,
382+
scan_objects: Option<&[ScanObject]>,
383+
) -> Result<ScanTxOutSet> {
384+
let params = match action {
385+
ScanAction::Start => match scan_objects {
386+
Some(objects) =>
387+
vec![serde_json::to_value(action)?, serde_json::to_value(objects)?],
388+
None =>
389+
return Err(Error::Returned(
390+
"scan_objects required for 'start'".to_string(),
391+
)),
392+
},
393+
ScanAction::Abort | ScanAction::Status => {
394+
vec![serde_json::to_value(action)?]
395+
}
396+
};
397+
self.call("scantxoutset", &params)
398+
}
399+
}
400+
};
401+
}

client/src/client_sync/v17/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ use bitcoin::address::{Address, NetworkChecked};
1919
use bitcoin::{Amount, Block, BlockHash, PublicKey, Txid};
2020
use serde::{Deserialize, Serialize};
2121

22-
use crate::client_sync::into_json;
23-
use crate::client_sync::{AddNodeCommand, SetBanCommand};
22+
use crate::client_sync::{
23+
into_json, AddNodeCommand, ImportMultiOptions, ImportMultiRequest, ScanAction, ScanObject,
24+
SetBanCommand,
25+
};
2426
use crate::types::v17::*;
2527

2628
#[rustfmt::skip] // Keep public re-exports separate.
@@ -53,6 +55,7 @@ crate::impl_client_v17__verifytxoutproof!();
5355
crate::impl_client_v17__pruneblockchain!();
5456
crate::impl_client_v17__savemempool!();
5557
crate::impl_client_v17__verifychain!();
58+
crate::impl_client_v17__scantxoutset!();
5659

5760
// == Control ==
5861
crate::impl_client_v17__getmemoryinfo!();
@@ -141,6 +144,7 @@ crate::impl_client_v17__settxfee!();
141144
crate::impl_client_v17__walletlock!();
142145
crate::impl_client_v17__walletpassphrase!();
143146
crate::impl_client_v17__walletpassphrasechange!();
147+
crate::impl_client_v17__importmulti!();
144148

145149
/// Argument to the `Client::get_new_address_with_type` function.
146150
///

client/src/client_sync/v17/network.rs

+19-22
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,8 @@ macro_rules! impl_client_v17__addnode {
7070
match self.call("addnode", params) {
7171
Ok(serde_json::Value::Null) => Ok(AddNode),
7272
Ok(ref val) if val.is_null() => Ok(AddNode),
73-
Ok(other) => {
74-
Err(Error::Returned(format!(
75-
"addnode expected null, got: {}", other
76-
)))
77-
},
73+
Ok(other) =>
74+
Err(Error::Returned(format!("addnode expected null, got: {}", other))),
7875
Err(e) => Err(e.into()),
7976
}
8077
}
@@ -91,7 +88,8 @@ macro_rules! impl_client_v17__clearbanned {
9188
match self.call("clearbanned", &[]) {
9289
Ok(serde_json::Value::Null) => Ok(ClearBanned),
9390
Ok(ref val) if val.is_null() => Ok(ClearBanned),
94-
Ok(other) => Err(Error::Returned(format!("clearbanned expected null, got: {}", other))),
91+
Ok(other) =>
92+
Err(Error::Returned(format!("clearbanned expected null, got: {}", other))),
9593
Err(e) => Err(e.into()),
9694
}
9795
}
@@ -111,7 +109,8 @@ macro_rules! impl_client_v17__setban {
111109
bantime: Option<i64>,
112110
absolute: Option<bool>,
113111
) -> Result<SetBan> {
114-
let mut params: Vec<serde_json::Value> = vec![subnet.into(), serde_json::to_value(command)?,];
112+
let mut params: Vec<serde_json::Value> =
113+
vec![subnet.into(), serde_json::to_value(command)?];
115114

116115
if bantime.is_some() || absolute.is_some() {
117116
params.push(bantime.map_or(serde_json::Value::Null, |t| t.into()));
@@ -124,9 +123,8 @@ macro_rules! impl_client_v17__setban {
124123
match self.call("setban", &params) {
125124
Ok(serde_json::Value::Null) => Ok(SetBan),
126125
Ok(ref val) if val.is_null() => Ok(SetBan),
127-
Ok(other) => {
128-
Err(Error::Returned(format!("setban expected null, got: {}", other)))
129-
},
126+
Ok(other) =>
127+
Err(Error::Returned(format!("setban expected null, got: {}", other))),
130128
Err(e) => Err(e.into()),
131129
}
132130
}
@@ -139,9 +137,7 @@ macro_rules! impl_client_v17__setban {
139137
macro_rules! impl_client_v17__listbanned {
140138
() => {
141139
impl Client {
142-
pub fn list_banned(&self) -> Result<ListBanned> {
143-
self.call("listbanned", &[])
144-
}
140+
pub fn list_banned(&self) -> Result<ListBanned> { self.call("listbanned", &[]) }
145141
}
146142
};
147143
}
@@ -174,9 +170,10 @@ macro_rules! impl_client_v17__disconnectnode {
174170
match self.call("disconnectnode", &params) {
175171
Ok(serde_json::Value::Null) => Ok(DisconnectNode),
176172
Ok(ref val) if val.is_null() => Ok(DisconnectNode),
177-
Ok(other) => {
178-
Err(Error::Returned(format!("disconnectnode expected null, got: {}", other)))
179-
}
173+
Ok(other) => Err(Error::Returned(format!(
174+
"disconnectnode expected null, got: {}",
175+
other
176+
))),
180177
Err(e) => Err(e.into()),
181178
}
182179
}
@@ -205,9 +202,8 @@ macro_rules! impl_client_v17__ping {
205202
match self.call("ping", &[]) {
206203
Ok(serde_json::Value::Null) => Ok(Ping),
207204
Ok(ref val) if val.is_null() => Ok(Ping),
208-
Ok(other) => {
209-
Err(Error::Returned(format!("ping expected null, got: {}", other)))
210-
}
205+
Ok(other) =>
206+
Err(Error::Returned(format!("ping expected null, got: {}", other))),
211207
Err(e) => Err(e.into()),
212208
}
213209
}
@@ -224,9 +220,10 @@ macro_rules! impl_client_v17__setnetworkactive {
224220
match self.call("setnetworkactive", &[state.into()]) {
225221
Ok(serde_json::Value::Null) => Ok(SetNetworkActive),
226222
Ok(ref val) if val.is_null() => Ok(SetNetworkActive),
227-
Ok(other) => {
228-
Err(Error::Returned(format!("setnetworkactive expected null, got: {}", other)))
229-
}
223+
Ok(other) => Err(Error::Returned(format!(
224+
"setnetworkactive expected null, got: {}",
225+
other
226+
))),
230227
Err(e) => Err(e.into()),
231228
}
232229
}

0 commit comments

Comments
 (0)