From 4f7bf8bf4b94323ceddfbf30bf384ad080293172 Mon Sep 17 00:00:00 2001 From: Edward Houston Date: Wed, 8 Apr 2026 12:32:38 +0200 Subject: [PATCH 1/2] Use deserialize_hex to avoid intermediate Vec allocation bitcoin 0.32 provides deserialize_hex which parses hex directly into the target type without allocating an intermediate Vec. The elements crate (0.26) doesn't expose this yet, so liquid builds keep the two-step FromHex + deserialize path behind a cfg gate. --- src/daemon.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/daemon.rs b/src/daemon.rs index b4e3cfc10..8c2d80cd9 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -10,13 +10,14 @@ use std::time::Duration; use std::{env, fs, io}; use base64::prelude::{Engine, BASE64_STANDARD}; +#[cfg(feature = "liquid")] use bitcoin::hex::FromHex; use error_chain::ChainedError; use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; use serde_json::{from_str, from_value, Value}; #[cfg(not(feature = "liquid"))] -use bitcoin::consensus::encode::{deserialize, serialize_hex}; +use bitcoin::consensus::encode::{deserialize_hex, serialize_hex}; #[cfg(feature = "liquid")] use elements::encode::{deserialize, serialize_hex}; @@ -63,23 +64,28 @@ fn header_from_value(value: Value) -> Result { let header_hex = value .as_str() .chain_err(|| format!("non-string header: {}", value))?; - let header_bytes = Vec::from_hex(header_hex).chain_err(|| "non-hex header")?; - Ok( - deserialize(&header_bytes) - .chain_err(|| format!("failed to parse header {}", header_hex))?, - ) + deserialize_value(header_hex).chain_err(|| format!("failed to parse header {}", header_hex)) } fn block_from_value(value: Value) -> Result { let block_hex = value.as_str().chain_err(|| "non-string block")?; - let block_bytes = Vec::from_hex(block_hex).chain_err(|| "non-hex block")?; - Ok(deserialize(&block_bytes).chain_err(|| format!("failed to parse block {}", block_hex))?) + deserialize_value(block_hex).chain_err(|| format!("failed to parse block {}", block_hex)) } fn tx_from_value(value: Value) -> Result { let tx_hex = value.as_str().chain_err(|| "non-string tx")?; - let tx_bytes = Vec::from_hex(tx_hex).chain_err(|| "non-hex tx")?; - Ok(deserialize(&tx_bytes).chain_err(|| format!("failed to parse tx {}", tx_hex))?) + deserialize_value(tx_hex).chain_err(|| format!("failed to parse tx {}", tx_hex)) +} + +#[cfg(not(feature = "liquid"))] +fn deserialize_value(hex: &str) -> Result { + Ok(deserialize_hex(hex).chain_err(|| "failed to deserialize hex")?) +} + +#[cfg(feature = "liquid")] +fn deserialize_value(hex: &str) -> Result { + let bytes = Vec::from_hex(hex).chain_err(|| "invalid hex")?; + Ok(deserialize(&bytes).chain_err(|| "failed to deserialize")?) } /// Parse JSONRPC error code, if exists. From 4158fc7b7b3aedf866af17e21f641c18efe29974 Mon Sep 17 00:00:00 2001 From: Edward Houston Date: Wed, 8 Apr 2026 16:25:02 +0200 Subject: [PATCH 2/2] Per review feedback: use std::any::type_name::() so errors identify which type (Block, Transaction, BlockHeader) failed. --- src/daemon.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/daemon.rs b/src/daemon.rs index 8c2d80cd9..bc49d3cb3 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -79,13 +79,15 @@ fn tx_from_value(value: Value) -> Result { #[cfg(not(feature = "liquid"))] fn deserialize_value(hex: &str) -> Result { - Ok(deserialize_hex(hex).chain_err(|| "failed to deserialize hex")?) + Ok(deserialize_hex(hex) + .chain_err(|| format!("failed to deserialize {}", std::any::type_name::()))?) } #[cfg(feature = "liquid")] fn deserialize_value(hex: &str) -> Result { let bytes = Vec::from_hex(hex).chain_err(|| "invalid hex")?; - Ok(deserialize(&bytes).chain_err(|| "failed to deserialize")?) + Ok(deserialize(&bytes) + .chain_err(|| format!("failed to deserialize {}", std::any::type_name::()))?) } /// Parse JSONRPC error code, if exists.