Skip to content

Commit fef1b64

Browse files
authored
Merge pull request #241 from RCasatta/hex_reader
Deserialize hexes without allocating intermediate `Vec<u8>`
2 parents 64c4e19 + 46d9970 commit fef1b64

File tree

2 files changed

+17
-9
lines changed

2 files changed

+17
-9
lines changed

client/src/client.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::iter::FromIterator;
1414
use std::path::PathBuf;
1515
use std::{fmt, result};
1616

17-
use crate::bitcoin;
17+
use crate::{bitcoin, deserialize_hex};
1818
use jsonrpc;
1919
use serde;
2020
use serde_json;
@@ -327,8 +327,7 @@ pub trait RpcApi: Sized {
327327

328328
fn get_block(&self, hash: &bitcoin::BlockHash) -> Result<Block> {
329329
let hex: String = self.call("getblock", &[into_json(hash)?, 0.into()])?;
330-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
331-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
330+
deserialize_hex(&hex)
332331
}
333332

334333
fn get_block_hex(&self, hash: &bitcoin::BlockHash) -> Result<String> {
@@ -342,8 +341,7 @@ pub trait RpcApi: Sized {
342341

343342
fn get_block_header(&self, hash: &bitcoin::BlockHash) -> Result<BlockHeader> {
344343
let hex: String = self.call("getblockheader", &[into_json(hash)?, false.into()])?;
345-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
346-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
344+
deserialize_hex(&hex)
347345
}
348346

349347
fn get_block_header_info(
@@ -487,8 +485,7 @@ pub trait RpcApi: Sized {
487485
) -> Result<Transaction> {
488486
let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
489487
let hex: String = self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))?;
490-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
491-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
488+
deserialize_hex(&hex)
492489
}
493490

494491
fn get_raw_transaction_hex(
@@ -756,8 +753,7 @@ pub trait RpcApi: Sized {
756753
replaceable: Option<bool>,
757754
) -> Result<Transaction> {
758755
let hex: String = self.create_raw_transaction_hex(utxos, outs, locktime, replaceable)?;
759-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
760-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
756+
deserialize_hex(&hex)
761757
}
762758

763759
fn fund_raw_transaction<R: RawTx>(

client/src/lib.rs

+12
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub extern crate jsonrpc;
2727
pub extern crate bitcoincore_rpc_json;
2828
pub use crate::json::bitcoin;
2929
pub use bitcoincore_rpc_json as json;
30+
use json::bitcoin::consensus::{Decodable, ReadExt};
31+
use json::bitcoin::hashes::hex::HexIterator;
3032

3133
mod client;
3234
mod error;
@@ -35,3 +37,13 @@ mod queryable;
3537
pub use crate::client::*;
3638
pub use crate::error::Error;
3739
pub use crate::queryable::*;
40+
41+
fn deserialize_hex<T: Decodable>(hex: &str) -> Result<T> {
42+
let mut reader = HexIterator::new(&hex)?;
43+
let object = Decodable::consensus_decode(&mut reader)?;
44+
if reader.read_u8().is_ok() {
45+
Err(Error::BitcoinSerialization(bitcoin::consensus::encode::Error::ParseFailed("data not consumed entirely when explicitly deserializing")))
46+
} else {
47+
Ok(object)
48+
}
49+
}

0 commit comments

Comments
 (0)