Skip to content

Commit aa1e80d

Browse files
committed
Use trait methods for RPCs
Use trait methods instead of inherent methods to define the RPCs to better allow downstream clients that define their own RPCs. This helps when different implementations of the ones defined in the client are required.
1 parent 19dab53 commit aa1e80d

5 files changed

Lines changed: 73 additions & 45 deletions

File tree

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use std::fs::File;
1010
use std::io::{BufRead, BufReader};
1111
use std::path::PathBuf;
1212

13-
pub use crate::bdk_client::error::Error;
14-
use crate::bdk_client::error::UnexpectedServerVersionError;
13+
pub use rpcs::BitcoinRpcs;
14+
15+
pub use self::error::Error;
16+
use self::error::UnexpectedServerVersionError;
1517

1618
/// Crate-specific Result type.
1719
///
@@ -51,7 +53,7 @@ pub struct Client {
5153

5254
impl fmt::Debug for Client {
5355
fn fmt(&self, f: &mut fmt::Formatter) -> core::fmt::Result {
54-
write!(f, "corepc_client::bdk_client::Client({:?})", self.inner)
56+
write!(f, "corepc_client::client_async::Client({:?})", self.inner)
5557
}
5658
}
5759

@@ -103,6 +105,19 @@ impl Client {
103105
Ok(resp?.result()?)
104106
}
105107

108+
/// Returns the version integer reported by the server (e.g. `250200` for v25.2.0).
109+
pub async fn server_version(&self) -> Result<usize> {
110+
// Use a minimal type to read only the `version` field; the shape of other fields
111+
// (e.g. `warnings` changed from String to Vec<String> at v28) differs across the
112+
// supported version range.
113+
#[derive(serde::Deserialize)]
114+
struct NetworkVersion {
115+
version: usize,
116+
}
117+
let json: NetworkVersion = self.call("getnetworkinfo", &[]).await?;
118+
Ok(json.version)
119+
}
120+
106121
/// Checks that the JSON-RPC endpoint is for a `bitcoind` instance with the expected version.
107122
///
108123
/// # Parameters
@@ -121,7 +136,7 @@ impl Client {
121136
}
122137

123138
/// Shorthand for converting a variable into a `serde_json::Value`.
124-
pub(crate) fn into_json<T>(val: T) -> Result<serde_json::Value>
139+
pub fn into_json<T>(val: T) -> Result<serde_json::Value>
125140
where
126141
T: serde::ser::Serialize,
127142
{
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,83 @@
11
// SPDX-License-Identifier: CC0-1.0
22

3-
//! RPC set used by BDK.
4-
//! All functions return the version nonspecific, strongly typed types.
3+
//! RPC methods for the async Bitcoin Core client.
54
65
use bitcoin::{block, Block, BlockHash, Transaction, Txid};
76
use serde_json::value::RawValue;
87

9-
use crate::bdk_client::{into_json, Client, Result};
8+
use super::{into_json, Client, Result};
109
use crate::types::model::{GetBlockFilter, GetBlockHeaderVerbose, GetBlockVerboseOne};
1110

12-
impl Client {
11+
/// Bitcoin Core RPC methods (v25 to v30).
12+
///
13+
/// This trait exposes the Bitcoin Core RPC methods available on [`Client`]. Downstream users
14+
/// can define their own extension traits with additional methods without risk of
15+
/// name collision with the methods defined here.
16+
// `async fn` in traits produces non-`Send` futures by default; we suppress this lint because
17+
// `BitcoinRpcs` is intended only for use with concrete types (never `dyn BitcoinRpcs`).
18+
#[allow(async_fn_in_trait)]
19+
pub trait BitcoinRpcs {
1320
/// Gets a block by blockhash.
14-
pub async fn get_block(&self, hash: &BlockHash) -> Result<Block> {
21+
async fn get_block(&self, hash: &BlockHash) -> Result<Block>;
22+
23+
/// Gets the block count.
24+
async fn get_block_count(&self) -> Result<u64>;
25+
26+
/// Gets the block hash for a height.
27+
async fn get_block_hash(&self, height: u32) -> Result<BlockHash>;
28+
29+
/// Gets the hash of the chain tip.
30+
async fn get_best_block_hash(&self) -> Result<BlockHash>;
31+
32+
/// Gets the block header by blockhash.
33+
async fn get_block_header(&self, hash: &BlockHash) -> Result<block::Header>;
34+
35+
/// Gets the block header with verbose output.
36+
async fn get_block_header_verbose(&self, hash: &BlockHash) -> Result<GetBlockHeaderVerbose>;
37+
38+
/// Gets a block by blockhash with verbose set to 1.
39+
async fn get_block_verbose(&self, hash: &BlockHash) -> Result<GetBlockVerboseOne>;
40+
41+
/// Gets the block filter for a blockhash.
42+
async fn get_block_filter(&self, hash: &BlockHash) -> Result<GetBlockFilter>;
43+
44+
/// Gets the transaction IDs currently in the mempool.
45+
async fn get_raw_mempool(&self) -> Result<Vec<Txid>>;
46+
47+
/// Gets the raw transaction by txid.
48+
async fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction>;
49+
}
50+
51+
impl BitcoinRpcs for Client {
52+
async fn get_block(&self, hash: &BlockHash) -> Result<Block> {
1553
let json: crate::types::v25::GetBlockVerboseZero =
1654
self.call("getblock", &[into_json(hash)?, into_json(0)?]).await?;
1755
Ok(json.into_model()?.0)
1856
}
1957

20-
/// Gets the block count.
21-
pub async fn get_block_count(&self) -> Result<u64> {
58+
async fn get_block_count(&self) -> Result<u64> {
2259
let json: crate::types::v25::GetBlockCount = self.call("getblockcount", &[]).await?;
2360
Ok(json.into_model().0)
2461
}
2562

26-
/// Gets the block hash for a height.
27-
pub async fn get_block_hash(&self, height: u32) -> Result<BlockHash> {
63+
async fn get_block_hash(&self, height: u32) -> Result<BlockHash> {
2864
let json: crate::types::v25::GetBlockHash =
2965
self.call("getblockhash", &[into_json(height)?]).await?;
3066
Ok(json.into_model()?.0)
3167
}
3268

33-
/// Gets the hash of the chain tip.
34-
pub async fn get_best_block_hash(&self) -> Result<BlockHash> {
69+
async fn get_best_block_hash(&self) -> Result<BlockHash> {
3570
let json: crate::types::v25::GetBestBlockHash = self.call("getbestblockhash", &[]).await?;
3671
Ok(json.into_model()?.0)
3772
}
3873

39-
/// Gets the block header by blockhash.
40-
pub async fn get_block_header(&self, hash: &BlockHash) -> Result<block::Header> {
74+
async fn get_block_header(&self, hash: &BlockHash) -> Result<block::Header> {
4175
let json: crate::types::v25::GetBlockHeader =
4276
self.call("getblockheader", &[into_json(hash)?, into_json(false)?]).await?;
4377
Ok(json.into_model()?.0)
4478
}
4579

46-
/// Gets the block header with verbose output.
47-
pub async fn get_block_header_verbose(
48-
&self,
49-
hash: &BlockHash,
50-
) -> Result<GetBlockHeaderVerbose> {
80+
async fn get_block_header_verbose(&self, hash: &BlockHash) -> Result<GetBlockHeaderVerbose> {
5181
let raw: Box<RawValue> =
5282
self.call("getblockheader", &[into_json(hash)?, into_json(true)?]).await?;
5383

@@ -61,8 +91,7 @@ impl Client {
6191
}
6292
}
6393

64-
/// Gets a block by blockhash with verbose set to 1.
65-
pub async fn get_block_verbose(&self, hash: &BlockHash) -> Result<GetBlockVerboseOne> {
94+
async fn get_block_verbose(&self, hash: &BlockHash) -> Result<GetBlockVerboseOne> {
6695
let raw: Box<RawValue> = self.call("getblock", &[into_json(hash)?, into_json(1)?]).await?;
6796

6897
if let Ok(json) = serde_json::from_str::<crate::types::v29::GetBlockVerboseOne>(raw.get()) {
@@ -73,36 +102,20 @@ impl Client {
73102
}
74103
}
75104

76-
/// Gets the block filter for a blockhash.
77-
pub async fn get_block_filter(&self, hash: &BlockHash) -> Result<GetBlockFilter> {
105+
async fn get_block_filter(&self, hash: &BlockHash) -> Result<GetBlockFilter> {
78106
let json: crate::types::v25::GetBlockFilter =
79107
self.call("getblockfilter", &[into_json(hash)?]).await?;
80108
Ok(json.into_model()?)
81109
}
82110

83-
/// Gets the transaction IDs currently in the mempool.
84-
pub async fn get_raw_mempool(&self) -> Result<Vec<Txid>> {
111+
async fn get_raw_mempool(&self) -> Result<Vec<Txid>> {
85112
let json: crate::types::v25::GetRawMempool = self.call("getrawmempool", &[]).await?;
86113
Ok(json.into_model()?.0)
87114
}
88115

89-
/// Gets the raw transaction by txid.
90-
pub async fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction> {
116+
async fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction> {
91117
let json: crate::types::v25::GetRawTransaction =
92118
self.call("getrawtransaction", &[into_json(txid)?]).await?;
93119
Ok(json.into_model()?.0)
94120
}
95-
96-
/// Returns the version integer reported by the server (e.g. `250200` for v25.2.0).
97-
pub async fn server_version(&self) -> Result<usize> {
98-
// Use a minimal type to read only the `version` field; the shape of other fields
99-
// (e.g. `warnings` changed from String to Vec<String> at v28) differs across the
100-
// supported version range.
101-
#[derive(serde::Deserialize)]
102-
struct NetworkVersion {
103-
version: usize,
104-
}
105-
let json: NetworkVersion = self.call("getnetworkinfo", &[]).await?;
106-
Ok(json.version)
107-
}
108121
}

client/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ pub(crate) mod error;
1616
pub mod client_sync;
1717

1818
#[cfg(feature = "client-async")]
19-
pub mod bdk_client;
19+
pub mod client_async;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use bitcoin::address::KnownHrp;
99
use bitcoin::{Address, CompressedPublicKey, PrivateKey};
1010
use bitcoind::mtype;
11-
use corepc_client::bdk_client::{Auth, Client, Error as AsyncClientError};
11+
use corepc_client::client_async::{Auth, BitcoinRpcs as _, Client, Error as AsyncClientError};
1212
use integration_test::{BitcoinD, BitcoinDExt as _, Wallet};
1313

1414
fn async_client_for(node: &BitcoinD) -> Client {

0 commit comments

Comments
 (0)