Skip to content

Commit 6f95a7f

Browse files
committed
feat(add-blockchain-mthds): add blockchain methods
- getblockcount - getblockhash - getblockfilter - getblockheader - getrawmempool - getrawtransaction
1 parent 956b717 commit 6f95a7f

File tree

2 files changed

+101
-4
lines changed

2 files changed

+101
-4
lines changed

src/client.rs

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,21 @@ use std::{
22
fs::File,
33
io::{BufRead, BufReader},
44
path::PathBuf,
5+
str::FromStr,
56
};
67

78
use crate::error::Error;
89
use crate::jsonrpc::minreq_http::Builder;
9-
use corepc_types::bitcoin::BlockHash;
10-
use jsonrpc::{serde, serde_json, Transport};
10+
use corepc_types::{
11+
bitcoin::{
12+
Block, BlockHash, Transaction, Txid, block::Header, consensus::deserialize, hex::FromHex,
13+
},
14+
model::{GetBlockCount, GetBlockFilter, GetBlockVerboseOne, GetRawMempool},
15+
};
16+
use jsonrpc::{
17+
Transport, serde,
18+
serde_json::{self, json},
19+
};
1120

1221
/// client authentication methods
1322
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
@@ -101,11 +110,94 @@ impl Client {
101110

102111
// `bitcoind` RPC methods
103112
impl Client {
104-
/// Get best block hash.
113+
/// Get block
114+
pub fn get_block(&self, block_hash: &BlockHash) -> Result<Block, Error> {
115+
let hex_string: String = self.call("getblock", &[json!(block_hash), json!(0)])?;
116+
117+
let bytes: Vec<u8> = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;
118+
119+
let block: Block = deserialize(&bytes)
120+
.map_err(|e| Error::InvalidResponse(format!("failed to deserialize block: {e}")))?;
121+
122+
Ok(block)
123+
}
124+
125+
/// Get block verboseone
126+
pub fn get_block_verbose(&self, block_hash: &BlockHash) -> Result<GetBlockVerboseOne, Error> {
127+
let res: GetBlockVerboseOne = self.call("getblock", &[json!(block_hash), json!(1)])?;
128+
Ok(res)
129+
}
130+
131+
/// Get best block hash
105132
pub fn get_best_block_hash(&self) -> Result<BlockHash, Error> {
106133
let res: String = self.call("getbestblockhash", &[])?;
107134
Ok(res.parse()?)
108135
}
136+
137+
/// Get block count
138+
pub fn get_block_count(&self) -> Result<u64, Error> {
139+
let res: GetBlockCount = self.call("getblockcount", &[])?;
140+
Ok(res.0)
141+
}
142+
143+
/// Get block hash
144+
pub fn get_block_hash(&self, height: u32) -> Result<BlockHash, Error> {
145+
let raw: serde_json::Value = self.call("getblockhash", &[json!(height)])?;
146+
147+
let hash_str = match raw {
148+
serde_json::Value::String(s) => s,
149+
serde_json::Value::Object(obj) => obj
150+
.get("hash")
151+
.and_then(|v| v.as_str())
152+
.ok_or_else(|| Error::InvalidResponse("getblockhash: missing 'hash' field".into()))?
153+
.to_string(),
154+
_ => {
155+
return Err(Error::InvalidResponse(
156+
"getblockhash: unexpected response type".into(),
157+
));
158+
}
159+
};
160+
161+
BlockHash::from_str(&hash_str).map_err(Error::HexToArray)
162+
}
163+
164+
/// Get block filter
165+
pub fn get_block_filter(&self, block_hash: BlockHash) -> Result<GetBlockFilter, Error> {
166+
let res: GetBlockFilter = self.call("getblockfilter", &[json!(block_hash)])?;
167+
Ok(res)
168+
}
169+
170+
/// Get block header
171+
pub fn get_block_header(&self, block_hash: &BlockHash) -> Result<Header, Error> {
172+
let hex_string: String = self.call("getblockheader", &[json!(block_hash), json!(false)])?;
173+
174+
let bytes = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;
175+
176+
let header = deserialize(&bytes).map_err(|e| {
177+
Error::InvalidResponse(format!("failed to deserialize block header: {e}"))
178+
})?;
179+
180+
Ok(header)
181+
}
182+
183+
/// Get raw mempool
184+
pub fn get_raw_mempool(&self) -> Result<Vec<Txid>, Error> {
185+
let res: GetRawMempool = self.call("getrawmempool", &[])?;
186+
Ok(res.0)
187+
}
188+
189+
/// Get raw transaction
190+
pub fn get_raw_transaction(&self, txid: &Txid) -> Result<Transaction, Error> {
191+
let hex_string: String = self.call("getrawtransaction", &[json!(txid)])?;
192+
193+
let bytes = Vec::<u8>::from_hex(&hex_string).map_err(Error::HexToBytes)?;
194+
195+
let transaction = deserialize(&bytes).map_err(|e| {
196+
Error::InvalidResponse(format!("transaction deserialization failed: {e}"))
197+
})?;
198+
199+
Ok(transaction)
200+
}
109201
}
110202

111203
#[cfg(test)]

src/error.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{fmt, io};
44

5-
use corepc_types::bitcoin::hex::HexToArrayError;
5+
use corepc_types::bitcoin::hex::{HexToArrayError, HexToBytesError};
66
use jsonrpc::serde_json;
77

88
/// Result type alias for the RPC client.
@@ -23,6 +23,9 @@ pub enum Error {
2323
/// JSON-RPC error from the server.
2424
JsonRpc(jsonrpc::Error),
2525

26+
/// Hex decoding error for byte vectors (used in get_block, etc.)
27+
HexToBytes(HexToBytesError),
28+
2629
/// Hash parsing error.
2730
HexToArray(HexToArrayError),
2831

@@ -41,6 +44,7 @@ impl fmt::Display for Error {
4144
}
4245
Error::InvalidCookieFile => write!(f, "invalid cookie file"),
4346
Error::InvalidResponse(e) => write!(f, "invalid response: {e}"),
47+
Error::HexToBytes(e) => write!(f, "Hex to bytes error: {e}"),
4448
Error::HexToArray(e) => write!(f, "Hash parsing eror: {e}"),
4549
Error::JsonRpc(e) => write!(f, "JSON-RPC error: {e}"),
4650
Error::Json(e) => write!(f, "JSON error: {e}"),
@@ -55,6 +59,7 @@ impl std::error::Error for Error {
5559
Error::JsonRpc(e) => Some(e),
5660
Error::Json(e) => Some(e),
5761
Error::Io(e) => Some(e),
62+
Error::HexToBytes(e) => Some(e),
5863
Error::HexToArray(e) => Some(e),
5964
_ => None,
6065
}

0 commit comments

Comments
 (0)