Skip to content

Commit df393f8

Browse files
ValuedMammaltvpeter
authored andcommitted
feat(client): Add v28 module
1 parent b0731c1 commit df393f8

File tree

6 files changed

+163
-29
lines changed

6 files changed

+163
-29
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ corepc-types = { version = "0.11.0", features = ["default"]}
1616
jsonrpc = { version = "0.18.0", features = ["simple_http", "simple_tcp", "minreq_http", "simple_uds", "proxy"] }
1717

1818
[features]
19+
default = ["30_0"]
1920
30_0 = []
21+
29_0 = []
22+
28_0 = []

src/client.rs

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,26 @@ use std::{
66

77
use crate::error::Error;
88
use crate::jsonrpc::minreq_http::Builder;
9+
#[cfg(not(feature = "29_0"))]
10+
use corepc_types::v30::GetBlockFilter;
911
use corepc_types::{
1012
bitcoin::{
1113
block::Header, consensus::encode::deserialize_hex, Block, BlockHash, Transaction, Txid,
1214
},
13-
model::{GetBlockCount, GetBlockFilter, GetBlockVerboseOne, GetRawMempool},
15+
model::{GetBlockCount, GetRawMempool},
1416
};
1517
use jsonrpc::{
1618
serde,
1719
serde_json::{self, json},
1820
Transport,
1921
};
2022

23+
#[cfg(feature = "28_0")]
24+
pub mod v28;
25+
26+
#[cfg(feature = "29_0")]
27+
pub mod v29;
28+
2129
/// Client authentication methods for the Bitcoin Core JSON-RPC server
2230
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
2331
pub enum Auth {
@@ -34,6 +42,7 @@ impl Auth {
3442
/// required by JSON-RPC client transport.
3543
///
3644
/// # Errors
45+
///
3746
/// Returns an error if the `CookieFile` cannot be read or invalid
3847
pub fn get_user_pass(self) -> Result<(Option<String>, Option<String>), Error> {
3948
match self {
@@ -65,11 +74,14 @@ impl Client {
6574
///
6675
/// Requires authentication via username/password or cookie file.
6776
/// For connections without authentication, use `with_transport` instead.
77+
///
6878
/// # Arguments
79+
///
6980
/// * `url` - URL of the RPC server
7081
/// * `auth` - authentication method (`UserPass` or `CookieFile`).
7182
///
7283
/// # Errors
84+
///
7385
/// * Returns `Error::MissingAuthentication` if `Auth::None` is provided.
7486
/// * Returns `Error::InvalidResponse` if the URL is invalid.
7587
/// * Returns errors related to reading the cookie file.
@@ -132,34 +144,22 @@ impl Client {
132144
/// Retrieves the raw block data for a given block hash (verbosity 0)
133145
///
134146
/// # Arguments
147+
///
135148
/// * `block_hash`: The hash of the block to retrieve.
136149
///
137150
/// # Returns
151+
///
138152
/// The deserialized `Block` struct.
139153
pub fn get_block(&self, block_hash: &BlockHash) -> Result<Block, Error> {
140154
let block_string: String = self.call("getblock", &[json!(block_hash), json!(0)])?;
141155
let block = deserialize_hex(&block_string)?;
142156
Ok(block)
143157
}
144158

145-
/// Retrieves the verbose JSON representation of a block (verbosity 1)
146-
///
147-
/// # Arguments
148-
/// * `block_hash`: The hash of the block to retrieve.
149-
///
150-
/// # Returns
151-
/// The verbose block data as a `GetBlockVerboseOne` struct.
152-
pub fn get_block_verbose(&self, block_hash: &BlockHash) -> Result<GetBlockVerboseOne, Error> {
153-
let block: corepc_types::v30::GetBlockVerboseOne =
154-
self.call("getblock", &[json!(block_hash), json!(1)])?;
155-
let block_model = block.into_model()?;
156-
157-
Ok(block_model)
158-
}
159-
160159
/// Retrieves the hash of the tip of the best block chain.
161160
///
162161
/// # Returns
162+
///
163163
/// The `BlockHash` of the chain tip.
164164
pub fn get_best_block_hash(&self) -> Result<BlockHash, Error> {
165165
let best_block_hash: String = self.call("getbestblockhash", &[])?;
@@ -169,6 +169,7 @@ impl Client {
169169
/// Retrieves the number of blocks in the longest chain
170170
///
171171
/// # Returns
172+
///
172173
/// The block count as a `u32`
173174
pub fn get_block_count(&self) -> Result<u32, Error> {
174175
let block_count: GetBlockCount = self.call("getblockcount", &[])?;
@@ -180,22 +181,27 @@ impl Client {
180181
/// Retrieves the block hash at a given height
181182
///
182183
/// # Arguments
184+
///
183185
/// * `height`: The block height
184186
///
185187
/// # Returns
188+
///
186189
/// The `BlockHash` for the given height
187190
pub fn get_block_hash(&self, height: u32) -> Result<BlockHash, Error> {
188191
let block_hash: String = self.call("getblockhash", &[json!(height)])?;
189192
Ok(block_hash.parse()?)
190193
}
191194

192-
/// Retrieves the compact block filter for a given block
195+
/// Retrieve the `basic` BIP 157 content filter for a particular block
193196
///
194197
/// # Arguments
198+
///
195199
/// * `block_hash`: The hash of the block whose filter is requested
196200
///
197201
/// # Returns
202+
///
198203
/// The `GetBlockFilter` structure containing the filter data
204+
#[cfg(not(feature = "29_0"))]
199205
pub fn get_block_filter(&self, block_hash: &BlockHash) -> Result<GetBlockFilter, Error> {
200206
let block_filter: GetBlockFilter = self.call("getblockfilter", &[json!(block_hash)])?;
201207
Ok(block_filter)
@@ -204,9 +210,11 @@ impl Client {
204210
/// Retrieves the raw block header for a given block hash.
205211
///
206212
/// # Arguments
213+
///
207214
/// * `block_hash`: The hash of the block whose header is requested.
208215
///
209216
/// # Returns
217+
///
210218
/// The deserialized `Header` struct
211219
pub fn get_block_header(&self, block_hash: &BlockHash) -> Result<Header, Error> {
212220
let header_string: String =
@@ -218,6 +226,7 @@ impl Client {
218226
/// Retrieves the transaction IDs of all transactions currently in the mempool
219227
///
220228
/// # Returns
229+
///
221230
/// A vector of `Txid`s in the raw mempool
222231
pub fn get_raw_mempool(&self) -> Result<Vec<Txid>, Error> {
223232
let txids: GetRawMempool = self.call("getrawmempool", &[])?;
@@ -227,9 +236,11 @@ impl Client {
227236
/// Retrieves the raw transaction data for a given transaction ID
228237
///
229238
/// # Arguments
239+
///
230240
/// * `txid`: The transaction ID to retrieve.
231241
///
232242
/// # Returns
243+
///
233244
/// The deserialized `Transaction` struct
234245
pub fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction, Error> {
235246
let hex_string: String = self.call("getrawtransaction", &[json!(txid)])?;
@@ -238,6 +249,52 @@ impl Client {
238249
}
239250
}
240251

252+
#[cfg(not(feature = "28_0"))]
253+
use corepc_types::{
254+
model::{GetBlockHeaderVerbose, GetBlockVerboseOne},
255+
v30,
256+
};
257+
258+
#[cfg(not(feature = "28_0"))]
259+
impl Client {
260+
/// Retrieves the verbose JSON representation of a block header (verbosity 1).
261+
///
262+
/// # Arguments
263+
///
264+
/// * `block_hash`: The hash of the block to retrieve.
265+
///
266+
/// # Returns
267+
///
268+
/// The verbose header as a `GetBlockHeaderVerbose` struct.
269+
pub fn get_block_header_verbose(
270+
&self,
271+
hash: &BlockHash,
272+
) -> Result<GetBlockHeaderVerbose, Error> {
273+
let header_info: v30::GetBlockHeaderVerbose =
274+
self.call("getblockheader", &[json!(hash)])?;
275+
header_info
276+
.into_model()
277+
.map_err(Error::GetBlockHeaderVerboseError)
278+
}
279+
280+
/// Retrieves the verbose JSON representation of a block (verbosity 1).
281+
///
282+
/// # Arguments
283+
///
284+
/// * `block_hash`: The hash of the block to retrieve.
285+
///
286+
/// # Returns
287+
///
288+
/// The verbose block data as a `GetBlockVerboseOne` struct.
289+
pub fn get_block_verbose(&self, hash: &BlockHash) -> Result<GetBlockVerboseOne, Error> {
290+
let block_info: v30::GetBlockVerboseOne =
291+
self.call("getblock", &[json!(hash), json!(1)])?;
292+
block_info
293+
.into_model()
294+
.map_err(Error::GetBlockVerboseOneError)
295+
}
296+
}
297+
241298
#[cfg(test)]
242299
mod test_auth {
243300
use super::*;

src/client/v28.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use bitcoin::BlockHash;
2+
use corepc_types::{
3+
bitcoin,
4+
model::{GetBlockHeaderVerbose, GetBlockVerboseOne},
5+
v28,
6+
};
7+
8+
use jsonrpc::serde_json::json;
9+
10+
use crate::{Client, Error};
11+
12+
impl Client {
13+
/// Retrieves the verbose JSON representation of a block header (verbosity 1).
14+
///
15+
/// # Arguments
16+
///
17+
/// * `block_hash`: The hash of the block to retrieve.
18+
///
19+
/// # Returns
20+
///
21+
/// The verbose header as a `GetBlockHeaderVerbose` struct.
22+
pub fn get_block_header_verbose(
23+
&self,
24+
hash: &BlockHash,
25+
) -> Result<GetBlockHeaderVerbose, Error> {
26+
let header_info: v28::GetBlockHeaderVerbose =
27+
self.call("getblockheader", &[json!(hash)])?;
28+
header_info
29+
.into_model()
30+
.map_err(Error::GetBlockHeaderVerboseError)
31+
}
32+
33+
/// Retrieves the verbose JSON representation of a block (verbosity 1).
34+
///
35+
/// # Arguments
36+
///
37+
/// * `block_hash`: The hash of the block to retrieve.
38+
///
39+
/// # Returns
40+
///
41+
/// The verbose block data as a `GetBlockVerboseOne` struct.
42+
pub fn get_block_verbose(&self, hash: &BlockHash) -> Result<GetBlockVerboseOne, Error> {
43+
let block_info: v28::GetBlockVerboseOne =
44+
self.call("getblock", &[json!(hash), json!(1)])?;
45+
block_info
46+
.into_model()
47+
.map_err(Error::GetBlockVerboseOneError)
48+
}
49+
}

src/client/v29.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use corepc_types::{bitcoin::BlockHash, v29::GetBlockFilter};
2+
3+
use jsonrpc::serde_json::json;
4+
5+
use crate::{Client, Error};
6+
7+
impl Client {
8+
/// Retrieve the `basic` BIP 157 content filter for a particular block
9+
///
10+
/// # Arguments
11+
///
12+
/// * `block_hash`: The hash of the block whose filter is requested
13+
///
14+
/// # Returns
15+
///
16+
/// The `GetBlockFilter` structure containing the filter data
17+
pub fn get_block_filter(&self, block_hash: &BlockHash) -> Result<GetBlockFilter, Error> {
18+
let block_filter: GetBlockFilter = self.call("getblockfilter", &[json!(block_hash)])?;
19+
Ok(block_filter)
20+
}
21+
}

src/error.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
//! Error types for the Bitcoin RPC client.
22
3-
use std::{fmt, io, num::TryFromIntError};
4-
5-
use corepc_types::{
6-
bitcoin::{
7-
consensus::{self, encode::FromHexError},
8-
hex::{HexToArrayError, HexToBytesError},
9-
},
10-
v30::GetBlockVerboseOneError,
3+
use bitcoin::{
4+
consensus::encode::FromHexError,
5+
hex::{HexToArrayError, HexToBytesError},
116
};
7+
use corepc_types::bitcoin;
8+
#[cfg(feature = "28_0")]
9+
use corepc_types::v17::{GetBlockHeaderVerboseError, GetBlockVerboseOneError};
10+
#[cfg(not(feature = "28_0"))]
11+
use corepc_types::v30::{GetBlockHeaderVerboseError, GetBlockVerboseOneError};
1212
use jsonrpc::serde_json;
13+
use std::{fmt, io, num::TryFromIntError};
1314

1415
/// Result type alias for the RPC client.
1516
pub type Result<T> = std::result::Result<T, Error>;
@@ -18,11 +19,14 @@ pub type Result<T> = std::result::Result<T, Error>;
1819
#[derive(Debug)]
1920
pub enum Error {
2021
/// Hex deserialization error
21-
DecodeHex(consensus::encode::FromHexError),
22+
DecodeHex(FromHexError),
2223

2324
/// Error converting `GetBlockVersboseOne` type into the model type
2425
GetBlockVerboseOneError(GetBlockVerboseOneError),
2526

27+
/// Error modeling [`GetBlockHeaderVerbose`](corepc_types::model::GetBlockHeaderVerbose).
28+
GetBlockHeaderVerboseError(GetBlockHeaderVerboseError),
29+
2630
/// Missing authentication credentials.
2731
MissingAuthentication,
2832

@@ -65,6 +69,7 @@ impl fmt::Display for Error {
6569
Error::Json(e) => write!(f, "JSON error: {e}"),
6670
Error::Io(e) => write!(f, "I/O error: {e}"),
6771
Error::DecodeHex(e) => write!(f, "Hex deserialization error: {e}"),
72+
Error::GetBlockHeaderVerboseError(e) => write!(f, "{e}"),
6873
Error::GetBlockVerboseOneError(e) => {
6974
write!(f, "Error converting getblockverboseone: {e}")
7075
}

tests/test_rpc_client.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,10 @@ fn test_get_block_hash_invalid_height() {
169169
fn test_get_best_block_hash() {
170170
let client = test_client();
171171

172-
let best_hash = client
172+
let best_block_hash = client
173173
.get_best_block_hash()
174174
.expect("failed to get best block hash");
175-
176-
assert_eq!(best_hash.to_string().len(), 64);
175+
assert_eq!(best_block_hash.to_string().len(), 64);
177176
}
178177

179178
#[test]

0 commit comments

Comments
 (0)