From a588df64cace156db8ab3a0324b0a47a5d4a2cf8 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Wed, 15 Oct 2025 17:18:44 +0100 Subject: [PATCH 1/4] Update rustdocs for the Hidden RPC client The hidden module had a copy-paste error and stated it was for the generating section. Update the documentation to state that the methods are hidden and not shown in the COre API docs. --- client/src/client_sync/v21/hidden.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/client_sync/v21/hidden.rs b/client/src/client_sync/v21/hidden.rs index fc867510..e7601632 100644 --- a/client/src/client_sync/v21/hidden.rs +++ b/client/src/client_sync/v21/hidden.rs @@ -2,7 +2,7 @@ //! Macros for implementing JSON-RPC methods on a client. //! -//! Specifically this is methods found under the `== Generating ==` section of the +//! Specifically this is `== Hidden ==` methods that are not listed in the //! API docs of Bitcoin Core `v0.21`. //! //! All macros require `Client` to be in scope. From ffd8051c5289926becc859ba957efe36941f3998 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Wed, 15 Oct 2025 18:28:48 +0100 Subject: [PATCH 2/4] Remove redundant test blockchain__get_tx_out_proof__modelled is identical to blockchain__verify_tx_out_proof__modelled, and the method gettxoutproof is tested above in blockchain__get_tx_out_proof. Remove the redundant test. --- integration_test/tests/blockchain.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/integration_test/tests/blockchain.rs b/integration_test/tests/blockchain.rs index 3a820e86..10d05194 100644 --- a/integration_test/tests/blockchain.rs +++ b/integration_test/tests/blockchain.rs @@ -512,13 +512,6 @@ fn blockchain__verify_tx_out_proof__modelled() { verify_tx_out_proof(&node).unwrap(); } -#[test] -fn blockchain__get_tx_out_proof__modelled() { - let node = Node::with_wallet(Wallet::Default, &[]); - node.fund_wallet(); - verify_tx_out_proof(&node).unwrap(); -} - #[test] fn blockchain__verify_chain() { let node = Node::with_wallet(Wallet::None, &[]); From cf0d46f6755f6f1411f49a83cca619cc9e276076 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Thu, 16 Oct 2025 07:57:03 +0100 Subject: [PATCH 3/4] Move test code into test function The model part of the verify_tx_out_proof test was in it's own function that the test function called. Other tests all check the model in the same test. Combine them into one function. Place it in the correct location. Remove associated import. --- integration_test/tests/blockchain.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/integration_test/tests/blockchain.rs b/integration_test/tests/blockchain.rs index 10d05194..a76c960c 100644 --- a/integration_test/tests/blockchain.rs +++ b/integration_test/tests/blockchain.rs @@ -7,7 +7,6 @@ use bitcoin::consensus::encode; use bitcoin::hex; use integration_test::{Node, NodeExt as _, Wallet}; -use node::client::client_sync; use node::vtype::*; // All the version specific types. use node::{mtype, Input, Output}; @@ -505,13 +504,6 @@ fn blockchain__scan_blocks_modelled() { let _: ScanBlocksAbort = node.client.scan_blocks_abort().expect("scanblocks abort"); } -#[test] -fn blockchain__verify_tx_out_proof__modelled() { - let node = Node::with_wallet(Wallet::Default, &[]); - node.fund_wallet(); - verify_tx_out_proof(&node).unwrap(); -} - #[test] fn blockchain__verify_chain() { let node = Node::with_wallet(Wallet::None, &[]); @@ -519,20 +511,22 @@ fn blockchain__verify_chain() { let _: Result = node.client.verify_chain(); } -fn verify_tx_out_proof(node: &Node) -> Result<(), client_sync::Error> { +#[test] +fn blockchain__verify_tx_out_proof__modelled() { + let node = Node::with_wallet(Wallet::Default, &[]); + node.fund_wallet(); + let (_address, tx) = node.create_mined_transaction(); let txid = tx.compute_txid(); - let proof = node.client.get_tx_out_proof(&[txid])?; + let proof = node.client.get_tx_out_proof(&[txid]).expect("gettxoutproof"); - let json: VerifyTxOutProof = node.client.verify_tx_out_proof(&proof)?; + let json: VerifyTxOutProof = node.client.verify_tx_out_proof(&proof).expect("verifytxoutproof"); let model: Result = json.into_model(); let txids = model.unwrap(); // sanity check assert_eq!(txids.0.len(), 1); - - Ok(()) } /// Create and broadcast a child transaction spending vout 0 of the given parent mempool txid. From 6a684dc01842c4adf37aa5651dee7de5ada9047a Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Wed, 15 Oct 2025 15:34:24 +0100 Subject: [PATCH 4/4] Add new waitforX RPCs Add waitforblock, waitforblockheight and waitfornewblock methods to v17. They are hidden until v30 with no changes. --- client/src/client_sync/v17/hidden.rs | 46 ++++++++++++ client/src/client_sync/v17/mod.rs | 6 ++ client/src/client_sync/v18/mod.rs | 5 ++ client/src/client_sync/v19/mod.rs | 5 ++ client/src/client_sync/v20/mod.rs | 5 ++ client/src/client_sync/v21/mod.rs | 3 + client/src/client_sync/v22/mod.rs | 3 + client/src/client_sync/v23/mod.rs | 3 + client/src/client_sync/v24/mod.rs | 3 + client/src/client_sync/v25/mod.rs | 3 + client/src/client_sync/v26/mod.rs | 3 + client/src/client_sync/v27/mod.rs | 3 + client/src/client_sync/v28/mod.rs | 3 + client/src/client_sync/v29/mod.rs | 3 + client/src/client_sync/v30/mod.rs | 3 + integration_test/tests/blockchain.rs | 55 ++++++++++++++ types/src/model/blockchain.rs | 27 +++++++ types/src/model/mod.rs | 3 +- types/src/v17/hidden/error.rs | 104 +++++++++++++++++++++++++++ types/src/v17/hidden/into.rs | 42 +++++++++++ types/src/v17/hidden/mod.rs | 65 +++++++++++++++++ types/src/v17/mod.rs | 5 ++ types/src/v18/mod.rs | 5 +- types/src/v19/mod.rs | 5 +- types/src/v20/mod.rs | 6 +- types/src/v21/mod.rs | 5 +- types/src/v22/mod.rs | 5 +- types/src/v23/mod.rs | 5 +- types/src/v24/mod.rs | 5 +- types/src/v25/mod.rs | 5 +- types/src/v26/mod.rs | 5 +- types/src/v27/mod.rs | 5 +- types/src/v28/mod.rs | 5 +- types/src/v29/mod.rs | 4 +- types/src/v30/mod.rs | 10 +-- 35 files changed, 440 insertions(+), 28 deletions(-) create mode 100644 client/src/client_sync/v17/hidden.rs create mode 100644 types/src/v17/hidden/error.rs create mode 100644 types/src/v17/hidden/into.rs create mode 100644 types/src/v17/hidden/mod.rs diff --git a/client/src/client_sync/v17/hidden.rs b/client/src/client_sync/v17/hidden.rs new file mode 100644 index 00000000..decb5cc9 --- /dev/null +++ b/client/src/client_sync/v17/hidden.rs @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Macros for implementing JSON-RPC methods on a client. +//! +//! Specifically this is `== Hidden ==` methods that are not listed in the +//! API docs of Bitcoin Core `v0.17`. +//! +//! All macros require `Client` to be in scope. +//! +//! See or use the `define_jsonrpc_minreq_client!` macro to define a `Client`. + +/// Implements Bitcoin Core JSON-RPC API method `waitforblock`. +#[macro_export] +macro_rules! impl_client_v17__wait_for_block { + () => { + impl Client { + pub fn wait_for_block(&self, hash: &bitcoin::BlockHash) -> Result { + self.call("waitforblock", &[into_json(hash)?]) + } + } + }; +} + +/// Implements Bitcoin Core JSON-RPC API method `waitforblockheight`. +#[macro_export] +macro_rules! impl_client_v17__wait_for_block_height { + () => { + impl Client { + pub fn wait_for_block_height(&self, height: u64) -> Result { + self.call("waitforblockheight", &[into_json(height)?]) + } + } + }; +} + +/// Implements Bitcoin Core JSON-RPC API method `waitfornewblock`. +#[macro_export] +macro_rules! impl_client_v17__wait_for_new_block { + () => { + impl Client { + pub fn wait_for_new_block(&self) -> Result { + self.call("waitfornewblock", &[]) + } + } + }; +} diff --git a/client/src/client_sync/v17/mod.rs b/client/src/client_sync/v17/mod.rs index 58215d5c..26613dd8 100644 --- a/client/src/client_sync/v17/mod.rs +++ b/client/src/client_sync/v17/mod.rs @@ -7,6 +7,7 @@ pub mod blockchain; pub mod control; pub mod generating; +pub mod hidden; pub mod mining; pub mod network; pub mod raw_transactions; @@ -64,6 +65,11 @@ crate::impl_client_v17__generate_to_address!(); crate::impl_client_v17__generate!(); crate::impl_client_v17__invalidate_block!(); +// == Hidden == +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); + // == Mining == crate::impl_client_v17__get_block_template!(); crate::impl_client_v17__get_mining_info!(); diff --git a/client/src/client_sync/v18/mod.rs b/client/src/client_sync/v18/mod.rs index 7a806ccd..572b03c7 100644 --- a/client/src/client_sync/v18/mod.rs +++ b/client/src/client_sync/v18/mod.rs @@ -70,6 +70,11 @@ crate::impl_client_v17__generate_to_address!(); crate::impl_client_v17__generate!(); crate::impl_client_v17__invalidate_block!(); +// == Hidden == +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); + // == Mining == crate::impl_client_v17__get_block_template!(); crate::impl_client_v17__get_mining_info!(); diff --git a/client/src/client_sync/v19/mod.rs b/client/src/client_sync/v19/mod.rs index 7cf1d16e..aa72f9bc 100644 --- a/client/src/client_sync/v19/mod.rs +++ b/client/src/client_sync/v19/mod.rs @@ -65,6 +65,11 @@ crate::impl_client_v17__uptime!(); crate::impl_client_v17__generate_to_address!(); crate::impl_client_v17__invalidate_block!(); +// == Hidden == +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); + // == Mining == crate::impl_client_v17__get_block_template!(); crate::impl_client_v17__get_mining_info!(); diff --git a/client/src/client_sync/v20/mod.rs b/client/src/client_sync/v20/mod.rs index 21424320..83b4488f 100644 --- a/client/src/client_sync/v20/mod.rs +++ b/client/src/client_sync/v20/mod.rs @@ -65,6 +65,11 @@ crate::impl_client_v17__generate_to_address!(); crate::impl_client_v20__generate_to_descriptor!(); crate::impl_client_v17__invalidate_block!(); +// == Hidden == +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); + // == Mining == crate::impl_client_v17__get_block_template!(); crate::impl_client_v17__get_mining_info!(); diff --git a/client/src/client_sync/v21/mod.rs b/client/src/client_sync/v21/mod.rs index 58b9d0a8..0a93c795 100644 --- a/client/src/client_sync/v21/mod.rs +++ b/client/src/client_sync/v21/mod.rs @@ -72,6 +72,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v22/mod.rs b/client/src/client_sync/v22/mod.rs index 6d32b66f..59a52477 100644 --- a/client/src/client_sync/v22/mod.rs +++ b/client/src/client_sync/v22/mod.rs @@ -70,6 +70,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v23/mod.rs b/client/src/client_sync/v23/mod.rs index 8cc0102e..761fd16c 100644 --- a/client/src/client_sync/v23/mod.rs +++ b/client/src/client_sync/v23/mod.rs @@ -73,6 +73,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v24/mod.rs b/client/src/client_sync/v24/mod.rs index 49f4a804..41ed19fd 100644 --- a/client/src/client_sync/v24/mod.rs +++ b/client/src/client_sync/v24/mod.rs @@ -74,6 +74,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v25/mod.rs b/client/src/client_sync/v25/mod.rs index 36ecc2cc..393f0c55 100644 --- a/client/src/client_sync/v25/mod.rs +++ b/client/src/client_sync/v25/mod.rs @@ -75,6 +75,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v26/mod.rs b/client/src/client_sync/v26/mod.rs index f7fd02f2..888ac4fd 100644 --- a/client/src/client_sync/v26/mod.rs +++ b/client/src/client_sync/v26/mod.rs @@ -81,6 +81,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v27/mod.rs b/client/src/client_sync/v27/mod.rs index a4c9f449..56ff9d68 100644 --- a/client/src/client_sync/v27/mod.rs +++ b/client/src/client_sync/v27/mod.rs @@ -75,6 +75,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v28/mod.rs b/client/src/client_sync/v28/mod.rs index 5c2c24bf..e7bac8ea 100644 --- a/client/src/client_sync/v28/mod.rs +++ b/client/src/client_sync/v28/mod.rs @@ -78,6 +78,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v29/mod.rs b/client/src/client_sync/v29/mod.rs index d8754589..7a6a5b81 100644 --- a/client/src/client_sync/v29/mod.rs +++ b/client/src/client_sync/v29/mod.rs @@ -78,6 +78,9 @@ crate::impl_client_v17__invalidate_block!(); // == Hidden == crate::impl_client_v21__add_peer_address!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Mining == crate::impl_client_v17__get_block_template!(); diff --git a/client/src/client_sync/v30/mod.rs b/client/src/client_sync/v30/mod.rs index e62fa86c..73a2d9ca 100644 --- a/client/src/client_sync/v30/mod.rs +++ b/client/src/client_sync/v30/mod.rs @@ -58,6 +58,9 @@ crate::impl_client_v23__save_mempool!(); crate::impl_client_v25__scan_blocks!(); crate::impl_client_v17__verify_chain!(); crate::impl_client_v17__verify_tx_out_proof!(); +crate::impl_client_v17__wait_for_block!(); +crate::impl_client_v17__wait_for_block_height!(); +crate::impl_client_v17__wait_for_new_block!(); // == Control == crate::impl_client_v17__get_memory_info!(); diff --git a/integration_test/tests/blockchain.rs b/integration_test/tests/blockchain.rs index a76c960c..2564d6a9 100644 --- a/integration_test/tests/blockchain.rs +++ b/integration_test/tests/blockchain.rs @@ -529,6 +529,61 @@ fn blockchain__verify_tx_out_proof__modelled() { assert_eq!(txids.0.len(), 1); } +#[test] +fn blockchain__wait_for_block__modelled() { + let node = Node::with_wallet(Wallet::Default, &[]); + node.fund_wallet(); + let (_address, _tx) = node.create_mined_transaction(); + let block_hash = node.client.best_block_hash().expect("bestblockhash"); + + let json: WaitForBlock = node.client.wait_for_block(&block_hash).expect("waitforblock"); + let model: Result = json.into_model(); + let block = model.unwrap(); + assert_eq!(block.hash, block_hash); +} + +#[test] +fn blockchain__wait_for_block_height__modelled() { + let node = Node::with_wallet(Wallet::Default, &[]); + node.fund_wallet(); + let (_address, _tx) = node.create_mined_transaction(); + let height = node.client.get_block_count().expect("getblockcount").0; + let block_hash = node.client.best_block_hash().expect("bestblockhash"); + let target_height = height; + + let json: WaitForBlockHeight = + node.client.wait_for_block_height(target_height).expect("waitforblockheight"); + let model: Result = json.into_model(); + let block = model.unwrap(); + assert_eq!(block.height, target_height as u32); + assert_eq!(block.hash, block_hash); +} + +#[test] +fn blockchain__wait_for_new_block__modelled() { + let (node1, node2, _node3) = integration_test::three_node_network(); + node1.fund_wallet(); + node1.mine_a_block(); + + let prev_hash = node1.client.best_block_hash().expect("bestblockhash"); + let prev_height = node1.client.get_block_count().expect("getblockcount").0; + + // Start waiting for a new block on node1 in a separate thread. + let handle = std::thread::spawn(move || { + let json: WaitForNewBlock = node1.client.wait_for_new_block().expect("waitfornewblock"); + let model: Result = json.into_model(); + model.unwrap() + }); + std::thread::sleep(std::time::Duration::from_millis(200)); + + // Trigger a new block on node2. + node2.mine_a_block(); + + let block = handle.join().expect("waitfornewblock thread panicked"); + assert_eq!(block.height, (prev_height + 1) as u32); + assert_ne!(block.hash, prev_hash); +} + /// Create and broadcast a child transaction spending vout 0 of the given parent mempool txid. /// Returns the child's txid. fn create_child_spending_parent(node: &Node, parent_txid: bitcoin::Txid) -> bitcoin::Txid { diff --git a/types/src/model/blockchain.rs b/types/src/model/blockchain.rs index 1c43b219..87e18e59 100644 --- a/types/src/model/blockchain.rs +++ b/types/src/model/blockchain.rs @@ -739,3 +739,30 @@ pub struct ScanBlocksStart { /// Models the result of JSON-RPC method `verifytxoutproof`. #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct VerifyTxOutProof(pub Vec); + +/// Models the result of JSON-RPC method `waitforblock`. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct WaitForBlock { + /// The blockhash. + pub hash: BlockHash, + /// Block height. + pub height: u32, +} + +/// Models the result of JSON-RPC method `waitforblockheight`. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct WaitForBlockHeight { + /// The blockhash. + pub hash: BlockHash, + /// Block height. + pub height: u32, +} + +/// Models the result of JSON-RPC method `waitfornewblock`. +#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub struct WaitForNewBlock { + /// The blockhash. + pub hash: BlockHash, + /// Block height. + pub height: u32, +} diff --git a/types/src/model/mod.rs b/types/src/model/mod.rs index c414822b..189b4ca2 100644 --- a/types/src/model/mod.rs +++ b/types/src/model/mod.rs @@ -34,7 +34,8 @@ pub use self::{ GetMempoolDescendants, GetMempoolDescendantsVerbose, GetMempoolEntry, GetMempoolInfo, GetRawMempool, GetRawMempoolVerbose, GetTxOut, GetTxOutSetInfo, GetTxSpendingPrevout, GetTxSpendingPrevoutItem, LoadTxOutSet, MempoolEntry, MempoolEntryFees, ReceiveActivity, - ScanBlocksStart, Softfork, SoftforkType, SpendActivity, VerifyTxOutProof, + ScanBlocksStart, Softfork, SoftforkType, SpendActivity, VerifyTxOutProof, WaitForBlock, + WaitForBlockHeight, WaitForNewBlock, }, generating::{Generate, GenerateBlock, GenerateToAddress, GenerateToDescriptor}, mining::{ diff --git a/types/src/v17/hidden/error.rs b/types/src/v17/hidden/error.rs new file mode 100644 index 00000000..f326b6df --- /dev/null +++ b/types/src/v17/hidden/error.rs @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: CC0-1.0 + +use core::fmt; + +use bitcoin::hex; + +use crate::error::write_err; +use crate::NumericError; + +/// Error when converting a `WaitForBlock` type into the model type. +#[derive(Debug)] +pub enum WaitForBlockError { + /// Conversion of numeric type to expected type failed. + Numeric(NumericError), + /// Conversion of the `hash` field failed. + Hash(hex::HexToArrayError), +} + +impl fmt::Display for WaitForBlockError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Numeric(ref e) => write_err!(f, "numeric"; e), + Self::Hash(ref e) => write_err!(f, "conversion of the `hash` field failed"; e), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for WaitForBlockError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + Self::Numeric(ref e) => Some(e), + Self::Hash(ref e) => Some(e), + } + } +} + +impl From for WaitForBlockError { + fn from(e: NumericError) -> Self { Self::Numeric(e) } +} + +/// Error when converting a `WaitForBlockHeight` type into the model type. +#[derive(Debug)] +pub enum WaitForBlockHeightError { + /// Conversion of numeric type to expected type failed. + Numeric(NumericError), + /// Conversion of the `hash` field failed. + Hash(hex::HexToArrayError), +} + +impl fmt::Display for WaitForBlockHeightError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Numeric(ref e) => write_err!(f, "numeric"; e), + Self::Hash(ref e) => write_err!(f, "conversion of the `hash` field failed"; e), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for WaitForBlockHeightError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + Self::Numeric(ref e) => Some(e), + Self::Hash(ref e) => Some(e), + } + } +} + +impl From for WaitForBlockHeightError { + fn from(e: NumericError) -> Self { Self::Numeric(e) } +} + +/// Error when converting a `WaitForNewBlock` type into the model type. +#[derive(Debug)] +pub enum WaitForNewBlockError { + /// Conversion of numeric type to expected type failed. + Numeric(NumericError), + /// Conversion of the `hash` field failed. + Hash(hex::HexToArrayError), +} + +impl fmt::Display for WaitForNewBlockError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Self::Numeric(ref e) => write_err!(f, "numeric"; e), + Self::Hash(ref e) => write_err!(f, "conversion of the `hash` field failed"; e), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for WaitForNewBlockError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match *self { + Self::Numeric(ref e) => Some(e), + Self::Hash(ref e) => Some(e), + } + } +} + +impl From for WaitForNewBlockError { + fn from(e: NumericError) -> Self { Self::Numeric(e) } +} diff --git a/types/src/v17/hidden/into.rs b/types/src/v17/hidden/into.rs new file mode 100644 index 00000000..9027bf4a --- /dev/null +++ b/types/src/v17/hidden/into.rs @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: CC0-1.0 + +use bitcoin::BlockHash; + +use super::{ + WaitForBlock, WaitForBlockError, WaitForBlockHeight, WaitForBlockHeightError, WaitForNewBlock, + WaitForNewBlockError, +}; +use crate::model; + +impl WaitForBlock { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + use WaitForBlockError as E; + + let hash = self.hash.parse::().map_err(E::Hash)?; + + Ok(model::WaitForBlock { hash, height: crate::to_u32(self.height, "height")? }) + } +} + +impl WaitForBlockHeight { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + use WaitForBlockHeightError as E; + + let hash = self.hash.parse::().map_err(E::Hash)?; + + Ok(model::WaitForBlockHeight { hash, height: crate::to_u32(self.height, "height")? }) + } +} + +impl WaitForNewBlock { + /// Converts version specific type to a version nonspecific, more strongly typed type. + pub fn into_model(self) -> Result { + use WaitForNewBlockError as E; + + let hash = self.hash.parse::().map_err(E::Hash)?; + + Ok(model::WaitForNewBlock { hash, height: crate::to_u32(self.height, "height")? }) + } +} diff --git a/types/src/v17/hidden/mod.rs b/types/src/v17/hidden/mod.rs new file mode 100644 index 00000000..2001c0d3 --- /dev/null +++ b/types/src/v17/hidden/mod.rs @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! The JSON-RPC API for Bitcoin Core `v0.17` - hidden. +//! +//! Types for methods that are excluded from the API docs by default. + +mod error; +mod into; + +use serde::{Deserialize, Serialize}; + +pub use self::error::{WaitForBlockError, WaitForBlockHeightError, WaitForNewBlockError}; + +/// Result of JSON-RPC method `waitforblock`. +/// +/// > waitforblock "blockhash" ( timeout ) +/// > +/// > Waits for a specific new block and returns useful info about it. +/// > +/// > Returns the current block on timeout or exit. +/// > +/// > Arguments: +/// > 1. "blockhash" (string, required) Block hash to wait for. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[cfg_attr(feature = "serde-deny-unknown-fields", serde(deny_unknown_fields))] +pub struct WaitForBlock { + /// The blockhash. + pub hash: String, + /// Block height. + pub height: i64, +} + +/// Result of JSON-RPC method `waitforblockheight`. +/// +/// > waitforblockheight "height" ( timeout ) +/// > +/// > Waits for (at least) block height and returns the height and hash +/// > of the current tip. +/// > +/// > Arguments: +/// > 1. "blockhash" (string, required) Block hash to wait for +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[cfg_attr(feature = "serde-deny-unknown-fields", serde(deny_unknown_fields))] +pub struct WaitForBlockHeight { + /// The blockhash. + pub hash: String, + /// Block height. + pub height: i64, +} + +/// Result of JSON-RPC method `waitfornewblock`. +/// +/// > waitfornewblock ( timeout "current_tip" ) +/// > +/// > Waits for any new block and returns useful info about it. +/// > +/// > Returns the current block on timeout or exit. +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +#[cfg_attr(feature = "serde-deny-unknown-fields", serde(deny_unknown_fields))] +pub struct WaitForNewBlock { + /// The blockhash. + pub hash: String, + /// Block height. + pub height: i64, +} diff --git a/types/src/v17/mod.rs b/types/src/v17/mod.rs index 44125f64..f6bfed6b 100644 --- a/types/src/v17/mod.rs +++ b/types/src/v17/mod.rs @@ -224,6 +224,7 @@ mod blockchain; mod control; mod generating; +mod hidden; mod mining; mod network; pub(crate) mod raw_transactions; @@ -248,6 +249,10 @@ pub use self::{ }, control::{GetMemoryInfoStats, Locked, Logging}, generating::{Generate, GenerateToAddress}, + hidden::{ + WaitForBlock, WaitForBlockError, WaitForBlockHeight, WaitForBlockHeightError, + WaitForNewBlock, WaitForNewBlockError, + }, mining::{ BlockTemplateTransaction, BlockTemplateTransactionError, GetBlockTemplate, GetBlockTemplateError, GetMiningInfo, diff --git a/types/src/v18/mod.rs b/types/src/v18/mod.rs index 24cc75fe..e5a744ee 100644 --- a/types/src/v18/mod.rs +++ b/types/src/v18/mod.rs @@ -284,6 +284,7 @@ pub use crate::v17::{ SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, Softfork, SoftforkReject, TestMempoolAccept, TransactionCategory, TransactionItem, TransactionItemError, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, VerifyMessage, - VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, WalletProcessPsbt, - WitnessUtxo, + VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, WaitForBlockHeightError, + WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, + WalletProcessPsbt, WitnessUtxo, }; diff --git a/types/src/v19/mod.rs b/types/src/v19/mod.rs index fbeeb23a..ef29b3ac 100644 --- a/types/src/v19/mod.rs +++ b/types/src/v19/mod.rs @@ -278,8 +278,9 @@ pub use crate::v17::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TestMempoolAccept, TransactionCategory, TransactionItem, TransactionItemError, UploadTarget, ValidateAddress, ValidateAddressError, - VerifyChain, VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, - WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, + VerifyChain, VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, + WaitForBlockHeight, WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, + WalletCreateFundedPsbt, WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, }; #[doc(inline)] pub use crate::v18::{ diff --git a/types/src/v20/mod.rs b/types/src/v20/mod.rs index 38236039..db28df34 100644 --- a/types/src/v20/mod.rs +++ b/types/src/v20/mod.rs @@ -272,8 +272,10 @@ pub use crate::{ SetNetworkActive, SetTxFee, SignMessage, SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TestMempoolAccept, TransactionCategory, UploadTarget, ValidateAddress, - ValidateAddressError, VerifyChain, VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, - WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, + ValidateAddressError, VerifyChain, VerifyMessage, VerifyTxOutProof, WaitForBlock, + WaitForBlockError, WaitForBlockHeight, WaitForBlockHeightError, WaitForNewBlock, + WaitForNewBlockError, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, + WalletProcessPsbt, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v21/mod.rs b/types/src/v21/mod.rs index a03aa47c..b81beb20 100644 --- a/types/src/v21/mod.rs +++ b/types/src/v21/mod.rs @@ -288,8 +288,9 @@ pub use crate::{ SetTxFee, SignMessage, SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WalletProcessPsbt, WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v22/mod.rs b/types/src/v22/mod.rs index 512189fd..140082ee 100644 --- a/types/src/v22/mod.rs +++ b/types/src/v22/mod.rs @@ -290,8 +290,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WalletProcessPsbt, WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v23/mod.rs b/types/src/v23/mod.rs index 2be1b0a9..0797658e 100644 --- a/types/src/v23/mod.rs +++ b/types/src/v23/mod.rs @@ -292,8 +292,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WalletProcessPsbt, WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v24/mod.rs b/types/src/v24/mod.rs index 8728519c..50be7bbe 100644 --- a/types/src/v24/mod.rs +++ b/types/src/v24/mod.rs @@ -290,8 +290,9 @@ pub use crate::{ SetTxFee, SignMessage, SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WalletProcessPsbt, WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v25/mod.rs b/types/src/v25/mod.rs index d186e22d..24132b7d 100644 --- a/types/src/v25/mod.rs +++ b/types/src/v25/mod.rs @@ -285,8 +285,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WalletProcessPsbt, WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WalletProcessPsbt, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v26/mod.rs b/types/src/v26/mod.rs index f2588ab3..be48a17f 100644 --- a/types/src/v26/mod.rs +++ b/types/src/v26/mod.rs @@ -303,8 +303,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v27/mod.rs b/types/src/v27/mod.rs index 45e4b723..7a80045b 100644 --- a/types/src/v27/mod.rs +++ b/types/src/v27/mod.rs @@ -279,8 +279,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v28/mod.rs b/types/src/v28/mod.rs index 50b96b80..302784e8 100644 --- a/types/src/v28/mod.rs +++ b/types/src/v28/mod.rs @@ -300,8 +300,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, SoftforkReject, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, - VerifyMessage, VerifyTxOutProof, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, - WitnessUtxo, + VerifyMessage, VerifyTxOutProof, WaitForBlock, WaitForBlockError, WaitForBlockHeight, + WaitForBlockHeightError, WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, + WalletCreateFundedPsbtError, WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v29/mod.rs b/types/src/v29/mod.rs index b5be8c28..a2e5a6ca 100644 --- a/types/src/v29/mod.rs +++ b/types/src/v29/mod.rs @@ -293,7 +293,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, VerifyMessage, VerifyTxOutProof, - WalletCreateFundedPsbt, WalletCreateFundedPsbtError, WitnessUtxo, + WaitForBlock, WaitForBlockError, WaitForBlockHeight, WaitForBlockHeightError, + WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, + WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing, diff --git a/types/src/v30/mod.rs b/types/src/v30/mod.rs index 1442de44..cd73423e 100644 --- a/types/src/v30/mod.rs +++ b/types/src/v30/mod.rs @@ -60,9 +60,9 @@ //! | scantxoutset | omitted | API marked as experimental | //! | verifychain | version | | //! | verifytxoutproof | version + model | | -//! | waitforblock | version + model | TODO | -//! | waitforblockheight | version + model | TODO | -//! | waitfornewblock | version + model | TODO | +//! | waitforblock | version + model | | +//! | waitforblockheight | version + model | | +//! | waitfornewblock | version + model | | //! //! //! @@ -265,7 +265,9 @@ pub use crate::{ SignMessageWithPrivKey, SignRawTransaction, SignRawTransactionError, SignRawTransactionWithKey, SignRawTransactionWithWallet, TransactionCategory, UploadTarget, ValidateAddress, ValidateAddressError, VerifyChain, VerifyMessage, VerifyTxOutProof, - WalletCreateFundedPsbt, WalletCreateFundedPsbtError, WitnessUtxo, + WaitForBlock, WaitForBlockError, WaitForBlockHeight, WaitForBlockHeightError, + WaitForNewBlock, WaitForNewBlockError, WalletCreateFundedPsbt, WalletCreateFundedPsbtError, + WitnessUtxo, }, v18::{ ActiveCommand, AnalyzePsbt, AnalyzePsbtError, AnalyzePsbtInput, AnalyzePsbtInputMissing,