Skip to content

Commit 901bf21

Browse files
committed
Implement scantxoutset method and test
1 parent 1aabd27 commit 901bf21

File tree

31 files changed

+454
-38
lines changed

31 files changed

+454
-38
lines changed

client/src/client_sync/v17/blockchain.rs

+24
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,30 @@ macro_rules! impl_client_v17__savemempool {
318318
};
319319
}
320320

321+
/// Implements Bitcoin Core JSON-RPC API method `scantxoutset`
322+
#[macro_export]
323+
macro_rules! impl_client_v17__scantxoutset {
324+
() => {
325+
impl Client {
326+
pub fn scan_tx_out_set(
327+
&self,
328+
action: ScanAction,
329+
scan_objects: &[ScanObject],
330+
) -> Result<ScanTxOutSet> {
331+
let params = match action {
332+
ScanAction::Start => {
333+
vec![into_json(action)?, into_json(scan_objects)?]
334+
}
335+
ScanAction::Abort | ScanAction::Status => {
336+
vec![into_json(action)?]
337+
}
338+
};
339+
self.call("scantxoutset", &params)
340+
}
341+
}
342+
};
343+
}
344+
321345
/// Implements Bitcoin Core JSON-RPC API method `verifychain`
322346
#[macro_export]
323347
macro_rules! impl_client_v17__verifychain {

client/src/client_sync/v17/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4848
crate::impl_client_v17__preciousblock!();
4949
crate::impl_client_v17__pruneblockchain!();
5050
crate::impl_client_v17__savemempool!();
51+
crate::impl_client_v17__scantxoutset!();
5152
crate::impl_client_v17__verifychain!();
5253
crate::impl_client_v17__verifytxoutproof!();
5354

@@ -214,3 +215,24 @@ pub struct WalletCreateFundedPsbtInput {
214215
txid: Txid,
215216
vout: u32,
216217
}
218+
219+
/// Args for the `scantxoutset`
220+
///
221+
/// Represents the action for the `scantxoutset` RPC call.
222+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
223+
#[serde(rename_all = "lowercase")]
224+
pub enum ScanAction {
225+
Start,
226+
Abort,
227+
Status,
228+
}
229+
230+
/// Represents a scan object for scantxoutset (descriptor string or object).
231+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
232+
#[serde(untagged)]
233+
pub enum ScanObject {
234+
/// Plain descriptor string
235+
Descriptor(String),
236+
/// Object containing descriptor and optional range
237+
WithDesc { desc: String },
238+
}

client/src/client_sync/v18/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ use crate::types::v18::*;
1919

2020
#[rustfmt::skip] // Keep public re-exports separate.
2121
pub use crate::client_sync::{
22-
v17::{AddressType, Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
22+
v17::{
23+
AddressType, Input, Output, ScanAction, ScanObject, TemplateRequest,
24+
TemplateRules, WalletCreateFundedPsbtInput
25+
},
2326
};
2427

2528
// This publicly re-exports `Client`.
@@ -48,6 +51,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4851
crate::impl_client_v17__preciousblock!();
4952
crate::impl_client_v17__pruneblockchain!();
5053
crate::impl_client_v17__savemempool!();
54+
crate::impl_client_v17__scantxoutset!();
5155
crate::impl_client_v17__verifychain!();
5256
crate::impl_client_v17__verifytxoutproof!();
5357

client/src/client_sync/v19/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ use crate::types::v19::*;
1818

1919
#[rustfmt::skip] // Keep public re-exports separate.
2020
pub use crate::client_sync::{
21-
v17::{AddressType, Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
21+
v17::{
22+
AddressType, Input, Output, ScanAction, ScanObject, TemplateRequest,
23+
TemplateRules, WalletCreateFundedPsbtInput
24+
},
2225
};
2326

2427
crate::define_jsonrpc_minreq_client!("v19");
@@ -47,6 +50,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4750
crate::impl_client_v17__preciousblock!();
4851
crate::impl_client_v17__pruneblockchain!();
4952
crate::impl_client_v17__savemempool!();
53+
crate::impl_client_v17__scantxoutset!();
5054
crate::impl_client_v17__verifychain!();
5155
crate::impl_client_v17__verifytxoutproof!();
5256

client/src/client_sync/v20.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use crate::types::v20::*;
1515

1616
#[rustfmt::skip] // Keep public re-exports separate.
1717
pub use crate::client_sync::{
18-
v17::{AddressType, Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
18+
v17::{
19+
AddressType, Input, Output, ScanAction, ScanObject, TemplateRequest,
20+
TemplateRules, WalletCreateFundedPsbtInput
21+
},
1922
};
2023

2124
crate::define_jsonrpc_minreq_client!("v20");
@@ -44,6 +47,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4447
crate::impl_client_v17__preciousblock!();
4548
crate::impl_client_v17__pruneblockchain!();
4649
crate::impl_client_v17__savemempool!();
50+
crate::impl_client_v17__scantxoutset!();
4751
crate::impl_client_v17__verifychain!();
4852
crate::impl_client_v17__verifytxoutproof!();
4953

client/src/client_sync/v21/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use crate::types::v21::*;
1717

1818
#[rustfmt::skip] // Keep public re-exports separate.
1919
pub use crate::client_sync::{
20-
v17::{AddressType, Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
20+
v17::{
21+
AddressType, Input, Output, ScanAction, ScanObject, TemplateRequest,
22+
TemplateRules, WalletCreateFundedPsbtInput
23+
},
2124
};
2225

2326
crate::define_jsonrpc_minreq_client!("v21");
@@ -46,6 +49,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4649
crate::impl_client_v17__preciousblock!();
4750
crate::impl_client_v17__pruneblockchain!();
4851
crate::impl_client_v17__savemempool!();
52+
crate::impl_client_v17__scantxoutset!();
4953
crate::impl_client_v17__verifychain!();
5054
crate::impl_client_v17__verifytxoutproof!();
5155

client/src/client_sync/v22/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use crate::types::v22::*;
1717

1818
#[rustfmt::skip] // Keep public re-exports separate.
1919
pub use crate::client_sync::{
20-
v17::{AddressType, Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
20+
v17::{
21+
AddressType, Input, Output, ScanAction, ScanObject, TemplateRequest,
22+
TemplateRules, WalletCreateFundedPsbtInput
23+
},
2124
};
2225

2326
crate::define_jsonrpc_minreq_client!("v22");
@@ -46,6 +49,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4649
crate::impl_client_v17__preciousblock!();
4750
crate::impl_client_v17__pruneblockchain!();
4851
crate::impl_client_v17__savemempool!();
52+
crate::impl_client_v17__scantxoutset!();
4953
crate::impl_client_v17__verifychain!();
5054
crate::impl_client_v17__verifytxoutproof!();
5155

client/src/client_sync/v23/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ use crate::types::v23::*;
1919

2020
#[rustfmt::skip] // Keep public re-exports separate.
2121
pub use crate::client_sync::{
22-
v17::{Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
22+
v17::{
23+
Input, Output, ScanAction, ScanObject, TemplateRequest,
24+
TemplateRules, WalletCreateFundedPsbtInput
25+
},
2326
};
2427

2528
crate::define_jsonrpc_minreq_client!("v23");
@@ -48,6 +51,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4851
crate::impl_client_v17__preciousblock!();
4952
crate::impl_client_v17__pruneblockchain!();
5053
crate::impl_client_v23__savemempool!();
54+
crate::impl_client_v17__scantxoutset!();
5155
crate::impl_client_v17__verifychain!();
5256
crate::impl_client_v17__verifytxoutproof!();
5357

client/src/client_sync/v24.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use crate::types::v24::*;
1515

1616
#[rustfmt::skip] // Keep public re-exports separate.
1717
pub use crate::client_sync::{
18-
v17::{Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
18+
v17::{
19+
Input, Output, ScanAction, ScanObject, TemplateRequest, TemplateRules,
20+
WalletCreateFundedPsbtInput
21+
},
1922
v23::AddressType,
2023
};
2124

@@ -45,6 +48,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4548
crate::impl_client_v17__preciousblock!();
4649
crate::impl_client_v17__pruneblockchain!();
4750
crate::impl_client_v23__savemempool!();
51+
crate::impl_client_v17__scantxoutset!();
4852
crate::impl_client_v17__verifychain!();
4953
crate::impl_client_v17__verifytxoutproof!();
5054

client/src/client_sync/v25.rs renamed to client/src/client_sync/v25/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use crate::types::v25::*;
1515

1616
#[rustfmt::skip] // Keep public re-exports separate.
1717
pub use crate::client_sync::{
18-
v17::{Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
18+
v17::{
19+
Input, Output, ScanAction, ScanObject, TemplateRequest, TemplateRules,
20+
WalletCreateFundedPsbtInput
21+
},
1922
v23::AddressType,
2023
};
2124

@@ -45,6 +48,7 @@ crate::impl_client_v17__gettxoutsetinfo!();
4548
crate::impl_client_v17__preciousblock!();
4649
crate::impl_client_v17__pruneblockchain!();
4750
crate::impl_client_v23__savemempool!();
51+
crate::impl_client_v17__scantxoutset!();
4852
crate::impl_client_v17__verifychain!();
4953
crate::impl_client_v17__verifytxoutproof!();
5054

client/src/client_sync/v26/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ use crate::types::v26::*;
1919

2020
#[rustfmt::skip] // Keep public re-exports separate.
2121
pub use crate::client_sync::{
22-
v17::{Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
22+
v17::{
23+
Input, Output, ScanAction, ScanObject, TemplateRequest,
24+
TemplateRules, WalletCreateFundedPsbtInput
25+
},
2326
v23::AddressType,
2427
};
2528

@@ -49,6 +52,7 @@ crate::impl_client_v26__gettxoutsetinfo!();
4952
crate::impl_client_v17__preciousblock!();
5053
crate::impl_client_v17__pruneblockchain!();
5154
crate::impl_client_v23__savemempool!();
55+
crate::impl_client_v17__scantxoutset!();
5256
crate::impl_client_v17__verifychain!();
5357
crate::impl_client_v17__verifytxoutproof!();
5458

client/src/client_sync/v27.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use crate::types::v27::*;
1515

1616
#[rustfmt::skip] // Keep public re-exports separate.
1717
pub use crate::client_sync::{
18-
v17::{Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
18+
v17::{
19+
Input, Output, ScanAction, ScanObject, TemplateRequest, TemplateRules,
20+
WalletCreateFundedPsbtInput
21+
},
1922
v23::AddressType,
2023
};
2124

@@ -45,6 +48,7 @@ crate::impl_client_v26__gettxoutsetinfo!();
4548
crate::impl_client_v17__preciousblock!();
4649
crate::impl_client_v17__pruneblockchain!();
4750
crate::impl_client_v23__savemempool!();
51+
crate::impl_client_v17__scantxoutset!();
4852
crate::impl_client_v17__verifychain!();
4953
crate::impl_client_v17__verifytxoutproof!();
5054

client/src/client_sync/v28/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ use crate::types::v28::*;
1717

1818
#[rustfmt::skip] // Keep public re-exports separate.
1919
pub use crate::client_sync::{
20-
v17::{Input, Output, TemplateRequest, TemplateRules, WalletCreateFundedPsbtInput},
20+
v17::{
21+
Input, Output, ScanAction, ScanObject, TemplateRequest,
22+
TemplateRules, WalletCreateFundedPsbtInput
23+
},
2124
v23::AddressType,
2225
};
2326

@@ -47,6 +50,7 @@ crate::impl_client_v26__gettxoutsetinfo!();
4750
crate::impl_client_v17__preciousblock!();
4851
crate::impl_client_v17__pruneblockchain!();
4952
crate::impl_client_v23__savemempool!();
53+
crate::impl_client_v17__scantxoutset!();
5054
crate::impl_client_v17__verifychain!();
5155
crate::impl_client_v17__verifytxoutproof!();
5256

integration_test/tests/blockchain.rs

+29
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,35 @@ fn blockchain__savemempool() {
307307
}
308308
}
309309

310+
#[test]
311+
fn blockchain__scan_tx_out_set_modelled() {
312+
#[cfg(any(
313+
feature = "v17",
314+
feature = "v18",
315+
feature = "v19",
316+
feature = "v20",
317+
feature = "v21"
318+
))]
319+
let node = Node::with_wallet(Wallet::None, &[]);
320+
321+
#[cfg(not(any(
322+
feature = "v17",
323+
feature = "v18",
324+
feature = "v19",
325+
feature = "v20",
326+
feature = "v21"
327+
)))]
328+
let node = Node::with_wallet(Wallet::None, &["-coinstatsindex=1"]);
329+
330+
let dummy_pubkey_hex = "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798";
331+
let scan_desc = format!("pkh({})", dummy_pubkey_hex);
332+
333+
let scan_objects: node::ScanObject = node::ScanObject::Descriptor(scan_desc);
334+
let action: node::ScanAction = node::ScanAction::Start;
335+
336+
let _: Result<ScanTxOutSet, _> = node.client.scan_tx_out_set(action, &[scan_objects]);
337+
}
338+
310339
#[test]
311340
fn blockchain__verify_tx_out_proof__modelled() {
312341
let node = Node::with_wallet(Wallet::Default, &[]);

types/src/v17/blockchain/mod.rs

+47
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,53 @@ pub struct PruneBlockchain(
650650
pub i64,
651651
);
652652

653+
/// Result of JSON-RPC method `scantxoutset`.
654+
///
655+
/// > scantxoutset "action" ( [scanobjects,...] )
656+
/// >
657+
/// > Arguments:
658+
/// > 1. "action" (string, required) The action to execute
659+
/// > 2. "scanobjects" (array, required) Array of scan objects
660+
#[derive(Deserialize, Debug, Clone, PartialEq)]
661+
#[serde(untagged)]
662+
pub enum ScanTxOutSet {
663+
/// Returns after scan completes
664+
Start(ScanTxOutSetStart),
665+
/// True (scan will be aborted), False (no scan to abort)
666+
Abort(bool),
667+
/// Scan in progress or Completed
668+
Status(Option<ScanTxOutSetStatus>),
669+
}
670+
671+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
672+
pub struct ScanTxOutSetStart {
673+
/// The unspents
674+
pub unspents: Vec<ScanTxOutSetUnspent>,
675+
/// The total amount of all found unspent outputs in BTC
676+
pub total_amount: f64,
677+
}
678+
679+
#[derive(Deserialize, Debug, Clone, PartialEq)]
680+
pub struct ScanTxOutSetStatus {
681+
/// Approximate percent complete
682+
pub progress: f64,
683+
}
684+
685+
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
686+
pub struct ScanTxOutSetUnspent {
687+
/// The transaction id
688+
pub txid: String,
689+
/// The vout value
690+
pub vout: u32,
691+
/// The script key
692+
#[serde(rename = "scriptPubKey")]
693+
pub script_pubkey: String,
694+
/// The total amount in BTC of unspent output
695+
pub amount: f64,
696+
/// Height of the unspent transaction output
697+
pub height: u64,
698+
}
699+
653700
/// Result of JSON-RPC method `verifychain`.
654701
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
655702
pub struct VerifyChain(pub bool);

types/src/v17/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
//! | preciousblock | returns nothing | |
4848
//! | pruneblockchain | returns numeric | |
4949
//! | savemempool | returns nothing | |
50-
//! | scantxoutset | omitted | API marked as experimental |
50+
//! | scantxoutset | version + model | API marked as experimental |
5151
//! | verifychain | returns boolean | |
5252
//! | verifytxoutproof | version + model | |
5353
//!
@@ -243,8 +243,9 @@ pub use self::{
243243
GetMempoolDescendantsVerbose, GetMempoolEntry, GetMempoolInfo, GetMempoolInfoError,
244244
GetRawMempool, GetRawMempoolVerbose, GetTxOut, GetTxOutError, GetTxOutSetInfo,
245245
GetTxOutSetInfoError, MapMempoolEntryError, MempoolEntry, MempoolEntryError,
246-
MempoolEntryFees, MempoolEntryFeesError, PruneBlockchain, Softfork, SoftforkReject,
247-
VerifyChain, VerifyTxOutProof,
246+
MempoolEntryFees, MempoolEntryFeesError, PruneBlockchain, ScanTxOutSet, ScanTxOutSetStart,
247+
ScanTxOutSetStatus, ScanTxOutSetUnspent, Softfork, SoftforkReject, VerifyChain,
248+
VerifyTxOutProof,
248249
},
249250
control::{GetMemoryInfoStats, Locked, Logging},
250251
generating::{Generate, GenerateToAddress},

0 commit comments

Comments
 (0)