Skip to content

Commit 46d9970

Browse files
committed
Deserialize hexes without allocating intermediate Vec<u8>
Since `HexIterator` is `Read` we can feed him directly to `consensus_decode` without the intermediate step of converting the hex string to `Vec<u8>`
1 parent 400a3c0 commit 46d9970

File tree

2 files changed

+17
-9
lines changed

2 files changed

+17
-9
lines changed

client/src/client.rs

Lines changed: 5 additions & 9 deletions
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;
@@ -321,8 +321,7 @@ pub trait RpcApi: Sized {
321321

322322
fn get_block(&self, hash: &bitcoin::BlockHash) -> Result<Block> {
323323
let hex: String = self.call("getblock", &[into_json(hash)?, 0.into()])?;
324-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
325-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
324+
deserialize_hex(&hex)
326325
}
327326

328327
fn get_block_hex(&self, hash: &bitcoin::BlockHash) -> Result<String> {
@@ -336,8 +335,7 @@ pub trait RpcApi: Sized {
336335

337336
fn get_block_header(&self, hash: &bitcoin::BlockHash) -> Result<BlockHeader> {
338337
let hex: String = self.call("getblockheader", &[into_json(hash)?, false.into()])?;
339-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
340-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
338+
deserialize_hex(&hex)
341339
}
342340

343341
fn get_block_header_info(
@@ -481,8 +479,7 @@ pub trait RpcApi: Sized {
481479
) -> Result<Transaction> {
482480
let mut args = [into_json(txid)?, into_json(false)?, opt_into_json(block_hash)?];
483481
let hex: String = self.call("getrawtransaction", handle_defaults(&mut args, &[null()]))?;
484-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
485-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
482+
deserialize_hex(&hex)
486483
}
487484

488485
fn get_raw_transaction_hex(
@@ -750,8 +747,7 @@ pub trait RpcApi: Sized {
750747
replaceable: Option<bool>,
751748
) -> Result<Transaction> {
752749
let hex: String = self.create_raw_transaction_hex(utxos, outs, locktime, replaceable)?;
753-
let bytes: Vec<u8> = FromHex::from_hex(&hex)?;
754-
Ok(bitcoin::consensus::encode::deserialize(&bytes)?)
750+
deserialize_hex(&hex)
755751
}
756752

757753
fn fund_raw_transaction<R: RawTx>(

client/src/lib.rs

Lines changed: 12 additions & 0 deletions
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)