From a152b04c9cbd9e4cbccbe552cfae6f8152ccf569 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 15:15:57 +0000 Subject: [PATCH 01/10] bump hex-conservative dependency to 1.1.0 --- Cargo-recent.lock | 9 ++++++--- Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo-recent.lock b/Cargo-recent.lock index a478ed20..3deca569 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -204,7 +204,7 @@ dependencies = [ "bincode", "bitcoin", "getrandom 0.2.16", - "hex-conservative 1.0.0", + "hex-conservative 1.1.0", "rand", "rand_chacha", "secp256k1-zkp", @@ -293,9 +293,12 @@ dependencies = [ [[package]] name = "hex-conservative" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee770c000993d17c185713463d5ebfbd1af9afae4c17cc295640104383bfbf0" +checksum = "a7289f6b628ce69fb1a371d0fdcf8ff38cd93ec00e3010eb055d1e044998c8d1" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" diff --git a/Cargo.toml b/Cargo.toml index 56871adb..35ea72e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ serde_json = { version = "1.0", optional = true } actual-serde = { package = "serde", version = "1.0.103", features = [ "derive", ], optional = true } -hex-conservative = "1.0.0" +hex-conservative = "1.1.0" [target.wasm32-unknown-unknown.dev-dependencies] From b4ab7c3f66ac6cd3d202579b7346c5426fb86004 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 15:55:01 +0000 Subject: [PATCH 02/10] replace Vec::::from_hex with hex-conservative functions These are all very mechanical changes, and only affect tests. No API or behavior changes. Do this replacement across all of src/. There are some examples in examples/ and fuzz/ and elementsd-tests/ but we can't fix these yet because they don't have access to the hex-conservative dep. In a later commit we will delete the hex module and re-export hex-conservative as hex, and then change the other crates. --- src/blind.rs | 52 +++++++++------------------------ src/block.rs | 4 +-- src/dynafed.rs | 5 ++-- src/internal_macros.rs | 2 +- src/pset/elip100.rs | 6 ++-- src/pset/elip102.rs | 11 +++---- src/pset/macros.rs | 2 +- src/pset/mod.rs | 65 +++++++++++++++++++----------------------- src/script.rs | 23 ++++++++------- src/sighash.rs | 12 ++++---- src/transaction.rs | 4 +-- 11 files changed, 77 insertions(+), 109 deletions(-) diff --git a/src/blind.rs b/src/blind.rs index 484ea546..1706a636 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -1381,6 +1381,7 @@ mod tests { use crate::hex::FromHex; use crate::Script; use bitcoin::{PrivateKey, PublicKey}; + use hex_conservative as hex; use rand::thread_rng; use secp256k1_zkp::SECP256K1; use std::str::FromStr; @@ -1388,8 +1389,8 @@ mod tests { #[test] fn test_blind_tx() { // tested with elements 0.20 rebase branch - let tx_hex = "020000000001741498f6da8f47eb438d0fb9de099b7e29c0e011b9ab64c3e0eb097a09a6a9220100000000fdffffff0301230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201000775f04dedb2d102a11e47fd7a0edfb424a43b2d3cf29d700d4b168c92e115709ff7d15070e201dd16001483641e58db3de6067f010d71c9782874572af9fb01230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000f42400206a1039b0fe0d110d2108f2cc49d637f95b6ac18045af5b302b3c14bf8457994160014ad65ebbed8416659141cc788c1b917d6ff3e059901230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f9000000000000"; - let mut tx: Transaction = deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); + const TX_HEX: &str = "020000000001741498f6da8f47eb438d0fb9de099b7e29c0e011b9ab64c3e0eb097a09a6a9220100000000fdffffff0301230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201000775f04dedb2d102a11e47fd7a0edfb424a43b2d3cf29d700d4b168c92e115709ff7d15070e201dd16001483641e58db3de6067f010d71c9782874572af9fb01230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000f42400206a1039b0fe0d110d2108f2cc49d637f95b6ac18045af5b302b3c14bf8457994160014ad65ebbed8416659141cc788c1b917d6ff3e059901230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f9000000000000"; + let mut tx: Transaction = deserialize(&hex::hex!(TX_HEX)).unwrap(); let spent_utxo_secrets = TxOutSecrets { asset: AssetId::from_str( "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23", @@ -1434,24 +1435,15 @@ mod tests { let spent_utxo = TxOut { asset: Asset::from_commitment( - &Vec::::from_hex( - "0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3", - ) - .unwrap(), + &hex::hex!("0baf634b18e1880c96dcf9947b0e0fd2d38d66d723339174df3fd980148c2f0bb3"), ) .unwrap(), value: Value::from_commitment( - &Vec::::from_hex( - "093baba9076190867fbc5e43132cb2f82245caf603b493d7c0da8b7eda7912fa2c", - ) - .unwrap(), + &hex::hex!("093baba9076190867fbc5e43132cb2f82245caf603b493d7c0da8b7eda7912fa2c"), ) .unwrap(), nonce: Nonce::from_commitment( - &Vec::::from_hex( - "02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b", - ) - .unwrap(), + &hex::hex!("02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b"), ) .unwrap(), script_pubkey: Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8") @@ -1571,7 +1563,7 @@ mod tests { let secp = secp256k1_zkp::Secp256k1::new(); let tx_str = include_str!("../tests/data/issue_tx.hex"); - let bytes = Vec::::from_hex(tx_str).unwrap(); + let bytes = hex::decode_to_vec(tx_str).unwrap(); let tx = encode::deserialize::(&bytes).unwrap(); let mut utxos = [ @@ -1582,50 +1574,32 @@ mod tests { ]; { utxos[0].asset = Asset::from_commitment( - &Vec::::from_hex( - "0ae7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e", - ) - .unwrap(), + &hex::hex!("0ae7a52e8e4b07e00548bab151a83e5c9ab2f9a910e10dcee930a1a152a939f99e"), ) .unwrap(); utxos[0].value = Value::Explicit(1); utxos[1].asset = Asset::from_commitment( - &Vec::::from_hex( - "0bc226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a", - ) - .unwrap(), + &hex::hex!("0bc226167e9ee0bb5a86c8f1478ee7d7becb7bfd4d97c26a041e628c5486a8c67a"), ) .unwrap(); utxos[1].value = Value::Explicit(1); utxos[2].asset = Asset::from_commitment( - &Vec::::from_hex( - "0b495dbfc356993c5ac157c3d04fadf6f198a7e35a873df482ad9e4e95daa8aa7e", - ) - .unwrap(), + &hex::hex!("0b495dbfc356993c5ac157c3d04fadf6f198a7e35a873df482ad9e4e95daa8aa7e"), ) .unwrap(); utxos[2].value = Value::from_commitment( - &Vec::::from_hex( - "08e0ac2ab5f3c173d5e0652a2ec209a9a370a4e510178e73c2f22f9e132341abf4", - ) - .unwrap(), + &hex::hex!("08e0ac2ab5f3c173d5e0652a2ec209a9a370a4e510178e73c2f22f9e132341abf4"), ) .unwrap(); utxos[3].asset = Asset::from_commitment( - &Vec::::from_hex( - "0aa0956d60687982d5e73d52f8c5902478754e5f0e2e5ceff5ae53fa9681c12ae1", - ) - .unwrap(), + &hex::hex!("0aa0956d60687982d5e73d52f8c5902478754e5f0e2e5ceff5ae53fa9681c12ae1"), ) .unwrap(); utxos[3].value = Value::from_commitment( - &Vec::::from_hex( - "094b35f1e86b097ccf0b3a826570c089c724ed9cf22620937500b14acdd169e7bf", - ) - .unwrap(), + &hex::hex!("094b35f1e86b097ccf0b3a826570c089c724ed9cf22620937500b14acdd169e7bf"), ) .unwrap(); } diff --git a/src/block.rs b/src/block.rs index f16f790f..a51052fc 100644 --- a/src/block.rs +++ b/src/block.rs @@ -395,7 +395,7 @@ impl Block { #[cfg(test)] mod tests { use crate::Block; - use crate::hex::FromHex; + use hex_conservative as hex; use super::*; @@ -796,7 +796,7 @@ mod tests { fn test_failed_block() { let block_str = include_str!("../tests/data/failedblock.hex"); - let bytes = Vec::::from_hex(block_str).unwrap(); + let bytes = hex::decode_to_vec(block_str).unwrap(); let _block = encode::deserialize::(&bytes).unwrap(); } } diff --git a/src/dynafed.rs b/src/dynafed.rs index c10bf8af..48a9f076 100644 --- a/src/dynafed.rs +++ b/src/dynafed.rs @@ -466,9 +466,8 @@ impl<'de> Deserialize<'de> for Params { } fn visit_str(self, v: &str) -> Result { - use crate::hex::FromHex; - - Ok(HexBytes(FromHex::from_hex(v).map_err(E::custom)?)) + use hex_conservative as hex; + Ok(HexBytes(hex::decode_to_vec(v).map_err(E::custom)?)) } fn visit_bytes(self, v: &[u8]) -> Result { diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 7fb072b6..99e3df34 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -438,7 +438,7 @@ macro_rules! hex_deserialize( #[cfg(test)] macro_rules! hex_script( ($e:expr) => ({ - let v: Vec = crate::hex::FromHex::from_hex($e) + let v: Vec = hex_conservative::decode_to_vec($e) .expect("hex decoding"); crate::Script::from(v) }) diff --git a/src/pset/elip100.rs b/src/pset/elip100.rs index 7b22fe7c..f617c9a6 100644 --- a/src/pset/elip100.rs +++ b/src/pset/elip100.rs @@ -221,8 +221,8 @@ mod test { use crate::encode::serialize; use crate::{OutPoint, Txid}; - use bitcoin::hashes::hex::FromHex; use bitcoin::hashes::Hash; + use hex_conservative as hex; use crate::{ encode::{serialize_hex, Encodable}, @@ -340,7 +340,7 @@ mod test { pset.add_asset_metadata(asset_id, &asset_meta); - let expected_key = Vec::::from_hex(ELIP0100_ASSET_METADATA_RECORD_KEY).unwrap(); + let expected_key = hex::hex!(ELIP0100_ASSET_METADATA_RECORD_KEY); let values: Vec> = pset .global @@ -369,7 +369,7 @@ mod test { pset.add_token_metadata(token_id, &token_meta); - let expected_key = Vec::::from_hex(ELIP0100_TOKEN_METADATA_RECORD_KEY).unwrap(); + let expected_key = hex::hex!(ELIP0100_TOKEN_METADATA_RECORD_KEY); let values: Vec> = pset .global diff --git a/src/pset/elip102.rs b/src/pset/elip102.rs index c1b0df1e..d4f5a0d4 100644 --- a/src/pset/elip102.rs +++ b/src/pset/elip102.rs @@ -69,7 +69,8 @@ mod test { use super::*; use crate::AssetId; use crate::encode::{serialize_hex, Encodable}; - use crate::hex::{FromHex, ToHex}; + use crate::hex::ToHex; + use hex_conservative as hex; // b'\xfc\rpset_liquidex' const ELIP0102_IDENTIFIER: &str = "fc0d707365745f6c69717569646578"; @@ -91,8 +92,8 @@ mod test { #[test] fn set_get_abf() { // An ABF that's different if serialized in reverse or not - let abf_hex = "3311111111111111111111111111111111111111111111111111111111111111"; - let abf_bytes = Vec::::from_hex(abf_hex).unwrap(); + const ABF_HEX: &str = "3311111111111111111111111111111111111111111111111111111111111111"; + let abf_bytes = hex::hex!(ABF_HEX); let abf = AssetBlindingFactor::from_slice(&abf_bytes).unwrap(); let mut input = Input::default(); @@ -101,7 +102,7 @@ mod test { assert_eq!(input.get_abf().unwrap().unwrap(), abf); let input_hex = serialize_hex(&input); assert!(input_hex.contains(ELIP0102_IDENTIFIER)); - assert!(input_hex.contains(abf_hex)); + assert!(input_hex.contains(ABF_HEX)); let mut output = Output::default(); assert!(output.get_abf().is_none()); @@ -109,7 +110,7 @@ mod test { assert_eq!(output.get_abf().unwrap().unwrap(), abf); let output_hex = serialize_hex(&output); assert!(output_hex.contains(ELIP0102_IDENTIFIER)); - assert!(output_hex.contains(abf_hex)); + assert!(output_hex.contains(ABF_HEX)); } #[test] diff --git a/src/pset/macros.rs b/src/pset/macros.rs index 25a04bc3..a6e637ed 100644 --- a/src/pset/macros.rs +++ b/src/pset/macros.rs @@ -16,7 +16,7 @@ macro_rules! hex_pset { ($s:expr) => { $crate::encode::deserialize( - & as $crate::hashes::hex::FromHex>::from_hex($s).unwrap(), + hex_conservative::decode_to_vec($s).unwrap(), ) }; } diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 230369b5..ed14f4fb 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -786,23 +786,24 @@ impl Decodable for PartiallySignedTransaction { mod tests { use super::*; use crate::hex::{FromHex, ToHex}; + use hex_conservative as hex; #[track_caller] fn tx_pset_rtt(tx_hex: &str) { let tx: Transaction = - encode::deserialize(&Vec::::from_hex(tx_hex).unwrap()[..]).unwrap(); + encode::deserialize(&hex::decode_to_vec(tx_hex).unwrap()).unwrap(); let pset = PartiallySignedTransaction::from_tx(tx); let rtt_tx_hex = encode::serialize_hex(&pset.extract_tx().unwrap()); assert_eq!(tx_hex, rtt_tx_hex); let pset_rtt_hex = encode::serialize_hex(&pset); let pset2: PartiallySignedTransaction = - encode::deserialize(&Vec::::from_hex(&pset_rtt_hex).unwrap()[..]).unwrap(); + encode::deserialize(&hex::decode_to_vec(&pset_rtt_hex).unwrap()).unwrap(); assert_eq!(pset, pset2); } fn pset_rtt(pset_hex: &str) { let pset: PartiallySignedTransaction = - encode::deserialize(&Vec::::from_hex(pset_hex).unwrap()[..]).unwrap(); + encode::deserialize(&hex::decode_to_vec(pset_hex).unwrap()[..]).unwrap(); assert_eq!(encode::serialize_hex(&pset), pset_hex); } @@ -832,14 +833,15 @@ mod tests { use serde_json; use std::str::FromStr; + const PSET_HEX: &str = "70736574ff01020402000000010401010105010201fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f0400000000000103088c83b50d0000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657408040000000000010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201040000"; + // Initially secp context and rng global state let secp = secp256k1_zkp::Secp256k1::new(); #[allow(deprecated)] let mut rng = rand::rngs::StdRng::seed_from_u64(0); - let pset_hex = "70736574ff01020402000000010401010105010201fb04020000000001017a0bb9325c276764451bbc2eb82a4c8c4bb6f4007ba803e5a5ba72d0cd7c09848e1a091622d935953bf06e0b7393239c68c6f810a00fe19d11c6ae343cffd3037077da02535fe4ad0fcd675cd0f62bf73b60a554dc1569b80f1f76a2bbfc9f00d439bf4b160014d2cbec8783bd01c9f178348b08500a830a89a7f9010e20805131ba6b37165c026eed9325ac56059ba872fd569e3ed462734098688b4770010f0400000000000103088c83b50d0000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20104220020e5793ad956ee91ebf3543b37d110701118ed4078ffa0d477eacb8885e486ad8507fc047073657406210212bf0ea45b733dfde8ecb5e896306c4165c666c99fc5d1ab887f71393a975cea07fc047073657408040000000000010308f40100000000000007fc04707365740220230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b201040000"; let mut pset: PartiallySignedTransaction = - encode::deserialize(&Vec::::from_hex(pset_hex).unwrap()[..]).unwrap(); + encode::deserialize(&hex::hex!(PSET_HEX)).unwrap(); let btc_txout_secrets_str = r#" { @@ -874,64 +876,55 @@ mod tests { fn basic_pset() { // Invalid psets // Check Global mandatory field - let pset_str = "70736574ff010401000105010001fb040200000000"; let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], + &hex::hex!("70736574ff010401000105010001fb040200000000"), ); pset.expect_err("Missing tx version"); // Check input mandatory field - let pset_str = "70736574ff010204020000000104010001fb040200000000"; let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], + &hex::hex!("70736574ff010204020000000104010001fb040200000000"), ); pset.expect_err("Missing inp count"); - let pset_str = "70736574ff010204020000000105010001fb040200000000"; let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], + &hex::hex!("70736574ff010204020000000105010001fb040200000000"), ); pset.expect_err("Missing out count"); - let pset_str = "70736574ff01020402000000010401000105010000"; let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], + &hex::hex!("70736574ff01020402000000010401000105010000"), ); pset.expect_err("Missing pset version"); // Check inp/out count mismatch - let pset_str = "70736574ff01020402000000010401000105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e6010e208965573f41392a88d8bb106cf13a7bdc69f1ab914cd5e8de11235467b514e5a9010f040100000000"; - let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], - ); + let pset = encode::deserialize::(&hex::hex!( + "70736574ff01020402000000010401000105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e6010e208965573f41392a88d8bb106cf13a7bdc69f1ab914cd5e8de11235467b514e5a9010f040100000000" + )); pset.expect_err("Input count mismatch"); // input mandatory field - let pset_str = "70736574ff01020402000000010401010105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e601010f040100000000"; - let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], - ); + let pset = encode::deserialize::(&hex::hex!( + "70736574ff01020402000000010401010105010001fb04020000000001017a0ad92644e9bf6cb8d0856a8ca713c8a212d3a62142e85454b7865217890e52ec3108a469a9811ec1c1df7a98dbc3a7f71860293e98c6fad8a7ef6828344e9172547302217d344513f0a5ed1a60ebeba01460c505ad63d95b3542fb303aca8f9382777d160014bd5c31aaea2ddc585f317ee589bc6800bc95e7e601010f040100000000" + )); pset.expect_err("Input mandatory field prevtxid"); // output mandatory amount field - let pset_str = "70736574ff01020402000000010401000105010101fb04020000000007fc04707365740220010101010101010101010101010101010101010101010101010101010101010101040000"; - let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], - ); + let pset = encode::deserialize::(&hex::hex!( + "70736574ff01020402000000010401000105010101fb04020000000007fc04707365740220010101010101010101010101010101010101010101010101010101010101010101040000" + )); pset.expect_err("Output non-mandatory field"); - let pset_str = "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574022009090909090909090909090909090909090909090909090909090909090909090100"; - let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], - ); + let pset = encode::deserialize::(&hex::hex!( + "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574022009090909090909090909090909090909090909090909090909090909090909090100" + )); pset.expect_err("Output mandatory field script pubkey"); // Valid Psets // Check both possible conf/explicit values are allowed for pset - let pset_str = "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574012109090909090909090909090909090909090909090909090909090909090909090907fc04707365740220090909090909090909090909090909090909090909090909090909090909090901040000"; - let pset = encode::deserialize::( - &Vec::::from_hex(pset_str).unwrap()[..], - ); + let pset = encode::deserialize::(&hex::hex!( + "70736574ff01020402000000010401000105010101fb040200000000010308170000000000000007fc0470736574012109090909090909090909090909090909090909090909090909090909090909090907fc04707365740220090909090909090909090909090909090909090909090909090909090909090901040000" + )); pset.expect("Both conf/explicit value are allowed be present in map"); // Commented code for quick test vector generation @@ -965,14 +958,14 @@ mod tests { fn pset_from_elements() { let pset_str = include_str!("../../tests/data/pset_swap_tutorial.hex"); - let bytes = Vec::::from_hex(pset_str).unwrap(); + let bytes = hex::decode_to_vec(pset_str).unwrap(); let pset = encode::deserialize::(&bytes).unwrap(); assert_eq!(pset_str.len(), encode::serialize(&pset).to_hex().len()); let back_hex = encode::serialize(&pset).to_hex(); //assert_eq!(pset_str, &back_hex); //TODO this fails, field ordering? - let bytes = Vec::::from_hex(&back_hex).unwrap(); + let bytes = hex::decode_to_vec(&back_hex).unwrap(); let pset = encode::deserialize::(&bytes).unwrap(); assert_eq!(&back_hex, &encode::serialize(&pset).to_hex()); } @@ -981,7 +974,7 @@ mod tests { fn pset_remove_in_out() { let pset_str = include_str!("../../tests/data/pset_swap_tutorial.hex"); - let bytes = Vec::::from_hex(pset_str).unwrap(); + let bytes = hex::decode_to_vec(pset_str).unwrap(); let mut pset = encode::deserialize::(&bytes).unwrap(); let n_inputs = pset.n_inputs(); diff --git a/src/script.rs b/src/script.rs index a1424ed3..b44e66c4 100644 --- a/src/script.rs +++ b/src/script.rs @@ -885,7 +885,6 @@ impl<'de> serde::Deserialize<'de> for Script { D: serde::Deserializer<'de>, { use std::fmt::Formatter; - use crate::hex::FromHex; struct Visitor; impl<'de> serde::de::Visitor<'de> for Visitor { @@ -899,7 +898,7 @@ impl<'de> serde::Deserialize<'de> for Script { where E: serde::de::Error, { - let v = Vec::from_hex(v).map_err(E::custom)?; + let v = hex_conservative::decode_to_vec(v).map_err(E::custom)?; Ok(Script::from(v)) } @@ -953,7 +952,7 @@ impl Decodable for Script { #[cfg(test)] mod test { - use crate::hex::FromHex; + use hex_conservative as hex; use bitcoin::PublicKey; use std::str::FromStr; @@ -965,6 +964,10 @@ mod test { #[test] fn script() { + // Clippy likes these at the top of the method + const KEYSTR_C: &str = "21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"; + const KEYSTR_U: &str = "41042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"; + let mut comp = vec![]; let mut script = Builder::new(); assert_eq!(&script[..], &comp[..]); @@ -987,12 +990,10 @@ mod test { script = script.push_slice(b"NRA4VR"); comp.extend([6u8, 78, 82, 65, 52, 86, 82].iter().copied()); assert_eq!(&script[..], &comp[..]); // keys - let keystr = "21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"; - let key = PublicKey::from_str(&keystr[2..]).unwrap(); - script = script.push_key(&key); comp.extend(Vec::from_hex(keystr).unwrap().iter().copied()); assert_eq!(&script[..], &comp[..]); - let keystr = "41042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"; - let key = PublicKey::from_str(&keystr[2..]).unwrap(); - script = script.push_key(&key); comp.extend(Vec::from_hex(keystr).unwrap().iter().copied()); assert_eq!(&script[..], &comp[..]); + let key = PublicKey::from_str(&KEYSTR_C[2..]).unwrap(); + script = script.push_key(&key); comp.extend(hex::hex!(KEYSTR_C).iter().copied()); assert_eq!(&script[..], &comp[..]); + let key = PublicKey::from_str(&KEYSTR_U[2..]).unwrap(); + script = script.push_key(&key); comp.extend(hex::hex!(KEYSTR_U).iter().copied()); assert_eq!(&script[..], &comp[..]); // opcodes script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]); @@ -1004,7 +1005,7 @@ mod test { // from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test let script = Builder::new().push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&Vec::from_hex("16e1ae70ff0fa102905d4af297f6912bda6cce19").unwrap()) + .push_slice(&hex::hex!("16e1ae70ff0fa102905d4af297f6912bda6cce19")) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_CHECKSIG) .into_script(); @@ -1085,7 +1086,7 @@ mod test { #[test] fn script_serialize() { - let hex_script = Vec::from_hex("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52").unwrap(); + let hex_script = hex::hex!("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52"); let script: Result = deserialize(&hex_script); assert!(script.is_ok()); assert_eq!(serialize(&script.unwrap()), hex_script); diff --git a/src/sighash.rs b/src/sighash.rs index 14461ddc..5d6c26ae 100644 --- a/src/sighash.rs +++ b/src/sighash.rs @@ -969,18 +969,18 @@ impl std::str::FromStr for SchnorrSighashType { mod tests{ use super::*; use crate::encode::deserialize; - use crate::hex::FromHex; + use hex_conservative as hex; use std::str::FromStr; fn test_segwit_sighash(tx: &str, script: &str, input_index: usize, value: &str, hash_type: EcdsaSighashType, expected_result: &str) { - let tx: Transaction = deserialize(&Vec::::from_hex(tx).unwrap()[..]).unwrap(); - let script = Script::from(Vec::::from_hex(script).unwrap()); + let tx: Transaction = deserialize(&hex::decode_to_vec(tx).unwrap()).unwrap(); + let script = Script::from(hex::decode_to_vec(script).unwrap()); // A hack to parse sha256d strings are sha256 so that we don't reverse them... let raw_expected = crate::hashes::sha256::Hash::from_str(expected_result).unwrap(); let expected_result = Sighash::from_slice(&raw_expected[..]).unwrap(); let mut cache = SighashCache::new(&tx); - let value : confidential::Value = deserialize(&Vec::::from_hex(value).unwrap()[..]).unwrap(); + let value : confidential::Value = deserialize(&hex::decode_to_vec(value).unwrap()).unwrap(); let actual_result = cache.segwitv0_sighash(input_index, &script, value, hash_type); assert_eq!(actual_result, expected_result); } @@ -1007,8 +1007,8 @@ mod tests{ fn test_legacy_sighash(tx: &str, script: &str, input_index: usize, hash_type: EcdsaSighashType, expected_result: &str) { - let tx: Transaction = deserialize(&Vec::::from_hex(tx).unwrap()[..]).unwrap(); - let script = Script::from(Vec::::from_hex(script).unwrap()); + let tx: Transaction = deserialize(&hex::decode_to_vec(tx).unwrap()).unwrap(); + let script = Script::from(hex::decode_to_vec(script).unwrap()); // A hack to parse sha256d strings are sha256 so that we don't reverse them... let raw_expected = crate::hashes::sha256::Hash::from_str(expected_result).unwrap(); let expected_result = Sighash::from_slice(&raw_expected[..]).unwrap(); diff --git a/src/transaction.rs b/src/transaction.rs index 03e2b2be..b6c6f105 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1304,7 +1304,7 @@ mod tests { use crate::{encode::serialize, pset::PartiallySignedTransaction}; use crate::confidential; - use crate::hex::FromHex; + use hex_conservative as hex; use secp256k1_zkp::{self, ZERO_TWEAK}; use crate::script; @@ -2404,7 +2404,7 @@ mod tests { #[test] fn superfluous_asset_issuance() { - let tx = Vec::::from_hex("1ae80068000109fee1000000000000000000000000000000000000000000000000000000000000005acf37f60000c7280028a7000000006e000000010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010115190000b9bfb80000000100000000d8d8d8d8d8d8d8d8d8d8d8d8d8d80000000000b8bfb8").unwrap(); + let tx = hex::decode_to_vec("1ae80068000109fee1000000000000000000000000000000000000000000000000000000000000005acf37f60000c7280028a7000000006e000000010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010115190000b9bfb80000000100000000d8d8d8d8d8d8d8d8d8d8d8d8d8d80000000000b8bfb8").unwrap(); assert!(matches!( Transaction::consensus_decode(&tx[..]), Err(encode::Error::ParseFailed("superfluous asset issuance")), From 0b6ef572ec4d62e9b851eef9d1322810fd12b7b6 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 16:09:25 +0000 Subject: [PATCH 03/10] confidential: replace FromHex with FromStr for abf and vbf There are three types in this crate which implement FromHex: AssetBlindingFactor, ValueBlindingFactor, and Script. The first two are straightforward; these types are always encoded as hex and so we should use Display/FromStr rather than hex-specific traits. Script is a bit special because of its length prefix and we will address it in the next commit. --- src/blind.rs | 4 +-- src/confidential.rs | 60 ++++++++++++++++++++------------------------- 2 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/blind.rs b/src/blind.rs index 1706a636..b4e4f478 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -1396,7 +1396,7 @@ mod tests { "b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23", ) .unwrap(), - asset_bf: AssetBlindingFactor::from_hex( + asset_bf: AssetBlindingFactor::from_str( "a5b3d111cdaa5fc111e2723df4caf315864f25fb4610cc737f10d5a55cd4096f", ) .unwrap(), @@ -1406,7 +1406,7 @@ mod tests { ) .unwrap() .to_sat(), - value_bf: ValueBlindingFactor::from_hex( + value_bf: ValueBlindingFactor::from_str( "e36a4de359469f547571d117bc5509fb74fba73c84b0cdd6f4edfa7ff7fa457d", ) .unwrap(), diff --git a/src/confidential.rs b/src/confidential.rs index a6c0779a..3949f208 100644 --- a/src/confidential.rs +++ b/src/confidential.rs @@ -784,6 +784,12 @@ impl AssetBlindingFactor { AssetBlindingFactor(Tweak::new(rng)) } + /// Parse a blinding factor from a 64-character hex string. + #[deprecated(since = "0.27.0", note = "use s.parse() instead")] + pub fn from_hex(s: &str) -> Result { + s.parse() + } + /// Create from bytes. pub fn from_slice(bytes: &[u8]) -> Result { Ok(AssetBlindingFactor(Tweak::from_slice(bytes)?)) @@ -800,18 +806,6 @@ impl AssetBlindingFactor { } } -impl hex::FromHex for AssetBlindingFactor { - type Err = TweakHexDecodeError; - - fn from_hex(s: &str) -> Result { - let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?; - slice.reverse(); - - let inner = Tweak::from_inner(slice)?; - Ok(AssetBlindingFactor(inner)) - } -} - impl fmt::Display for AssetBlindingFactor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex::format_hex_reverse(self.0.as_ref(), f) @@ -828,7 +822,11 @@ impl str::FromStr for AssetBlindingFactor { type Err = encode::Error; fn from_str(s: &str) -> Result { - Ok(hex::FromHex::from_hex(s)?) + let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?; + slice.reverse(); + + let inner = Tweak::from_inner(slice)?; + Ok(AssetBlindingFactor(inner)) } } @@ -846,8 +844,6 @@ impl Serialize for AssetBlindingFactor { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for AssetBlindingFactor { fn deserialize>(d: D) -> Result { - use crate::hex::FromHex; - if d.is_human_readable() { struct HexVisitor; @@ -863,7 +859,7 @@ impl<'de> Deserialize<'de> for AssetBlindingFactor { E: ::serde::de::Error, { if let Ok(hex) = ::std::str::from_utf8(v) { - AssetBlindingFactor::from_hex(hex).map_err(E::custom) + hex.parse().map_err(E::custom) } else { Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) } @@ -873,7 +869,7 @@ impl<'de> Deserialize<'de> for AssetBlindingFactor { where E: ::serde::de::Error, { - AssetBlindingFactor::from_hex(v).map_err(E::custom) + v.parse().map_err(E::custom) } } @@ -919,6 +915,12 @@ impl ValueBlindingFactor { ValueBlindingFactor(Tweak::new(rng)) } + /// Parse a blinding factor from a 64-character hex string. + #[deprecated(since = "0.27.0", note = "use s.parse() instead")] + pub fn from_hex(s: &str) -> Result { + s.parse() + } + /// Create the value blinding factor of the last output of a transaction. pub fn last( secp: &Secp256k1, @@ -1001,18 +1003,6 @@ impl Neg for ValueBlindingFactor { } } -impl hex::FromHex for ValueBlindingFactor { - type Err = TweakHexDecodeError; - - fn from_hex(s: &str) -> Result { - let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?; - slice.reverse(); - - let inner = Tweak::from_inner(slice)?; - Ok(ValueBlindingFactor(inner)) - } -} - impl fmt::Display for ValueBlindingFactor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex::format_hex_reverse(self.0.as_ref(), f) @@ -1029,7 +1019,11 @@ impl str::FromStr for ValueBlindingFactor { type Err = encode::Error; fn from_str(s: &str) -> Result { - Ok(hex::FromHex::from_hex(s)?) + let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?; + slice.reverse(); + + let inner = Tweak::from_inner(slice)?; + Ok(ValueBlindingFactor(inner)) } } @@ -1047,8 +1041,6 @@ impl Serialize for ValueBlindingFactor { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for ValueBlindingFactor { fn deserialize>(d: D) -> Result { - use crate::hex::FromHex; - if d.is_human_readable() { struct HexVisitor; @@ -1064,7 +1056,7 @@ impl<'de> Deserialize<'de> for ValueBlindingFactor { E: ::serde::de::Error, { if let Ok(hex) = ::std::str::from_utf8(v) { - ValueBlindingFactor::from_hex(hex).map_err(E::custom) + hex.parse().map_err(E::custom) } else { Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) } @@ -1074,7 +1066,7 @@ impl<'de> Deserialize<'de> for ValueBlindingFactor { where E: ::serde::de::Error, { - ValueBlindingFactor::from_hex(v).map_err(E::custom) + v.parse().map_err(E::custom) } } From 3a1a2a1d1aa35abbf12f19b062cc5372a780faae Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 16:13:41 +0000 Subject: [PATCH 04/10] script: replace from_hex and from_str with from_hex_no_prefix Scripts are sometimes hex-encoded with a length prefix (in particular, when they are part of a hex-encoding of a transaction, or as a test vector for a signature hash) and sometimes without a length prefix (in particular, in the output of most RPC commands). It is therefore unclear and bug-prone to have a from_hex method which doesn't specify whether a length prefix is expected. In rust-bitcoin we have solved this by splitting from_hex into two methods: from_hex_no_prefix and from_hex_prefixed. Add the former, but not the latter (since it is currently quite annoying to implement, and apparently it's not used anywhere). We will revisit the prefixed version later when we upgrade our consensus encoding traits. Also from Script::from_str. In addition to the length-prefix ambiguity, this is further ambiguous because there are a couple different "opcode dissambly" formats floating around. Better to make the user specify what format they want. --- examples/pset_blind_coinjoin.rs | 2 +- examples/raw_blind.rs | 2 +- src/blind.rs | 3 +-- src/internal_macros.rs | 6 +----- src/pset/mod.rs | 4 ++-- src/script.rs | 30 ++++++++++++------------------ src/taproot.rs | 23 +++++++++++------------ 7 files changed, 29 insertions(+), 41 deletions(-) diff --git a/examples/pset_blind_coinjoin.rs b/examples/pset_blind_coinjoin.rs index 333710f9..e70d610a 100644 --- a/examples/pset_blind_coinjoin.rs +++ b/examples/pset_blind_coinjoin.rs @@ -61,7 +61,7 @@ fn parse_txout(txout_info: &str) -> (TxOut, Secrets, pset::Input) { &Vec::::from_hex(v["commitmentnonce"].as_str().unwrap()).unwrap(), ) .unwrap(), - script_pubkey: Script::from_hex(v["scriptPubKey"].as_str().unwrap()).unwrap(), + script_pubkey: Script::from_hex_no_prefix(v["scriptPubKey"].as_str().unwrap()).unwrap(), witness: TxOutWitness::default(), }; diff --git a/examples/raw_blind.rs b/examples/raw_blind.rs index 0091ceec..d166bc80 100644 --- a/examples/raw_blind.rs +++ b/examples/raw_blind.rs @@ -56,7 +56,7 @@ fn parse_txout(txout_info: &str) -> (TxOut, Secrets, pset::Input) { &Vec::::from_hex(v["commitmentnonce"].as_str().unwrap()).unwrap(), ) .unwrap(), - script_pubkey: Script::from_hex(v["scriptPubKey"].as_str().unwrap()).unwrap(), + script_pubkey: Script::from_hex_no_prefix(v["scriptPubKey"].as_str().unwrap()).unwrap(), witness: TxOutWitness::default(), }; diff --git a/src/blind.rs b/src/blind.rs index b4e4f478..b7304784 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -1378,7 +1378,6 @@ mod tests { use crate::confidential; use crate::encode; use crate::encode::deserialize; - use crate::hex::FromHex; use crate::Script; use bitcoin::{PrivateKey, PublicKey}; use hex_conservative as hex; @@ -1446,7 +1445,7 @@ mod tests { &hex::hex!("02a96a456f4936dcf0afbc325ac3798c4464e7b66dd460d564f3f91882d6089a3b"), ) .unwrap(), - script_pubkey: Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8") + script_pubkey: Script::from_hex_no_prefix("0014d2bcde17e7744f6377466ca1bd35d212954674c8") .unwrap(), witness: TxOutWitness::default(), }; diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 99e3df34..1972a6c8 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -437,9 +437,5 @@ macro_rules! hex_deserialize( #[cfg(test)] macro_rules! hex_script( - ($e:expr) => ({ - let v: Vec = hex_conservative::decode_to_vec($e) - .expect("hex decoding"); - crate::Script::from(v) - }) + ($e:expr) => (crate::Script::from_hex_no_prefix($e).expect("hex decoding")) ); diff --git a/src/pset/mod.rs b/src/pset/mod.rs index ed14f4fb..6c5e9d88 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -785,7 +785,7 @@ impl Decodable for PartiallySignedTransaction { #[cfg(test)] mod tests { use super::*; - use crate::hex::{FromHex, ToHex}; + use crate::hex::ToHex; use hex_conservative as hex; #[track_caller] @@ -995,7 +995,7 @@ mod tests { let policy = crate::AssetId::from_str("5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225").unwrap(); let pk = bitcoin::key::PublicKey::from_str("020202020202020202020202020202020202020202020202020202020202020202").unwrap(); - let script = crate::Script::from_hex("0014d2bcde17e7744f6377466ca1bd35d212954674c8").unwrap(); + let script = crate::Script::from_hex_no_prefix("0014d2bcde17e7744f6377466ca1bd35d212954674c8").unwrap(); let sats_in = 10000; let sats_fee = 1000; let btc_txout_secrets = TxOutSecrets { diff --git a/src/script.rs b/src/script.rs index b44e66c4..3f0dfea7 100644 --- a/src/script.rs +++ b/src/script.rs @@ -27,13 +27,12 @@ use std::default::Default; use std::{fmt, io, ops, str}; -use hex_conservative::DecodeVariableLengthBytesError; use secp256k1_zkp::{Verification, Secp256k1}; #[cfg(feature = "serde")] use serde; use crate::encode::{self, Decodable, Encodable}; use crate::hashes::Hash; -use crate::{hex, opcodes, ScriptHash, WScriptHash, PubkeyHash, WPubkeyHash}; +use crate::{opcodes, ScriptHash, WScriptHash, PubkeyHash, WPubkeyHash}; use bitcoin::PublicKey; @@ -78,22 +77,6 @@ impl fmt::UpperHex for Script { } } -impl hex::FromHex for Script { - type Err = DecodeVariableLengthBytesError; - - fn from_hex(s: &str) -> Result { - hex_conservative::decode_to_vec(s).map(|v| Script(Box::<[u8]>::from(v))) - } -} - -impl str::FromStr for Script { - type Err = ::Err; - - fn from_str(s: &str) -> Result { - hex::FromHex::from_hex(s) - } -} - #[derive(PartialEq, Eq, Debug, Clone)] /// An object which can be used to construct a script piece by piece pub struct Builder(Vec, Option); @@ -234,6 +217,17 @@ impl Script { /// Creates a new empty script pub fn new() -> Script { Script(vec![].into_boxed_slice()) } + /// Parse a hex-string with no length prefix as a [`Script`]. + #[deprecated(since = "0.27.0", note = "use from_hex_no_prefix instead")] + pub fn from_hex(s: &str) -> Result { + Self::from_hex_no_prefix(s) + } + + /// Parse a hex-string with no length prefix as a [`Script`]. + pub fn from_hex_no_prefix(s: &str) -> Result { + hex_conservative::decode_to_vec(s).map(|v| Script(Box::<[u8]>::from(v))) + } + /// Generates P2PK-type of scriptPubkey pub fn new_p2pk(pubkey: &PublicKey) -> Script { Builder::new() diff --git a/src/taproot.rs b/src/taproot.rs index 7f5940e3..e401bd6a 100644 --- a/src/taproot.rs +++ b/src/taproot.rs @@ -854,7 +854,6 @@ mod tests{ use super::*; use crate::hashes::HashEngine; use crate::hashes::sha256t::Tag; - use crate::hex::FromHex; use std::str::FromStr; fn tag_engine(tag_name: &str) -> sha256::HashEngine { @@ -892,11 +891,11 @@ mod tests{ let internal_key = UntweakedPublicKey::from_str("93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51").unwrap(); let script_weights = vec![ - (10, Script::from_hex("51").unwrap()), // semantics of script don't matter for this test - (20, Script::from_hex("52").unwrap()), - (20, Script::from_hex("53").unwrap()), - (30, Script::from_hex("54").unwrap()), - (19, Script::from_hex("55").unwrap()), + (10, Script::from_hex_no_prefix("51").unwrap()), // semantics of script don't matter for this test + (20, Script::from_hex_no_prefix("52").unwrap()), + (20, Script::from_hex_no_prefix("53").unwrap()), + (30, Script::from_hex_no_prefix("54").unwrap()), + (19, Script::from_hex_no_prefix("55").unwrap()), ]; let tree_info = TaprootSpendInfo::with_huffman_tree(&secp, internal_key, script_weights.clone()).unwrap(); @@ -915,7 +914,7 @@ mod tests{ length, tree_info .script_map - .get(&(Script::from_hex(script).unwrap(), LeafVersion::default())) + .get(&(Script::from_hex_no_prefix(script).unwrap(), LeafVersion::default())) .expect("Present Key") .iter() .next() @@ -952,11 +951,11 @@ mod tests{ // A B C / \ // D E let scripts = [ - Script::from_hex("51").unwrap(), - Script::from_hex("52").unwrap(), - Script::from_hex("53").unwrap(), - Script::from_hex("54").unwrap(), - Script::from_hex("55").unwrap(), + Script::from_hex_no_prefix("51").unwrap(), + Script::from_hex_no_prefix("52").unwrap(), + Script::from_hex_no_prefix("53").unwrap(), + Script::from_hex_no_prefix("54").unwrap(), + Script::from_hex_no_prefix("55").unwrap(), ]; let builder = builder .add_leaf(2, scripts[0].clone()).unwrap() From c307d3599b5316505434d93d9e2b4950b3cb378f Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 16:51:35 +0000 Subject: [PATCH 05/10] replace ToHex with hex-conservative 1.1 functions This eliminates crate::hex except in a couple of places: * examples/fuzz/doctests/elementsd-test, which need a re-export of hex-conservative * serde_utils, which will be updated in the next commit --- src/confidential.rs | 32 +++++++++++++++----------------- src/dynafed.rs | 36 ++++++++++++++---------------------- src/encode.rs | 2 +- src/issuance.rs | 3 +-- src/pset/elip100.rs | 21 ++++++++++++--------- src/pset/elip102.rs | 8 ++++---- src/pset/mod.rs | 8 ++++---- src/pset/raw.rs | 5 ++--- src/pset/serialize.rs | 4 ++-- 9 files changed, 55 insertions(+), 64 deletions(-) diff --git a/src/confidential.rs b/src/confidential.rs index 3949f208..0b5d2e02 100644 --- a/src/confidential.rs +++ b/src/confidential.rs @@ -18,7 +18,7 @@ //! use crate::hashes::{sha256d, Hash}; -use crate::hex; +use hex_conservative as hex; use secp256k1_zkp::{self, CommitmentSecrets, Generator, PedersenCommitment, PublicKey, Secp256k1, SecretKey, Signing, Tweak, ZERO_TWEAK, compute_adaptive_blinding_factor, @@ -775,7 +775,7 @@ impl std::error::Error for TweakHexDecodeError { } /// Blinding factor used for asset commitments. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct AssetBlindingFactor(pub(crate) Tweak); impl AssetBlindingFactor { @@ -806,15 +806,14 @@ impl AssetBlindingFactor { } } -impl fmt::Display for AssetBlindingFactor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex::format_hex_reverse(self.0.as_ref(), f) - } +impl core::borrow::Borrow<[u8]> for AssetBlindingFactor { + fn borrow(&self) -> &[u8] { &self.0[..] } } -impl fmt::LowerHex for AssetBlindingFactor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex::format_hex_reverse(self.0.as_ref(), f) +hex::impl_fmt_traits! { + #[display_backward(true)] + impl fmt_traits for AssetBlindingFactor { + const LENGTH: usize = 32; } } @@ -906,7 +905,7 @@ impl<'de> Deserialize<'de> for AssetBlindingFactor { } /// Blinding factor used for value commitments. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct ValueBlindingFactor(pub(crate) Tweak); impl ValueBlindingFactor { @@ -1003,15 +1002,14 @@ impl Neg for ValueBlindingFactor { } } -impl fmt::Display for ValueBlindingFactor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex::format_hex_reverse(self.0.as_ref(), f) - } +impl core::borrow::Borrow<[u8]> for ValueBlindingFactor { + fn borrow(&self) -> &[u8] { &self.0[..] } } -impl fmt::LowerHex for ValueBlindingFactor { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex::format_hex_reverse(self.0.as_ref(), f) +hex::impl_fmt_traits! { + #[display_backward(true)] + impl fmt_traits for ValueBlindingFactor { + const LENGTH: usize = 32; } } diff --git a/src/dynafed.rs b/src/dynafed.rs index 48a9f076..d2edba96 100644 --- a/src/dynafed.rs +++ b/src/dynafed.rs @@ -16,6 +16,7 @@ use std::{fmt, io}; +use hex_conservative::DisplayHex as _; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] @@ -26,22 +27,13 @@ use crate::hashes::{Hash, sha256, sha256d}; use crate::Script; /// ad-hoc struct to fmt in hex +#[cfg(feature = "serde")] struct HexBytes<'a>(&'a [u8]); -impl fmt::Display for HexBytes<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - crate::hex::format_hex(self.0, f) - } -} -impl fmt::Debug for HexBytes<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} #[cfg(feature = "serde")] impl Serialize for HexBytes<'_> { fn serialize(&self, s: S) -> Result { if s.is_human_readable() { - s.collect_str(self) + s.collect_str(&self.0.as_hex()) } else { s.serialize_bytes(self.0) } @@ -54,10 +46,11 @@ impl fmt::Display for HexBytesArray<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[")?; for (i, e) in self.0.iter().enumerate() { - if i != 0 { - write!(f, ", ")?; + if i == 0 { + write!(f, "{}", e.as_hex())?; + } else { + write!(f, ", {}", e.as_hex())?; } - crate::hex::format_hex(&e[..], f)?; } write!(f, "]") } @@ -165,10 +158,10 @@ impl FullParams { /// Format for [`fmt::Debug`]. fn fmt_debug(&self, f: &mut fmt::Formatter, name: &'static str) -> fmt::Result { let mut s = f.debug_struct(name); - s.field("signblockscript", &HexBytes(&self.signblockscript[..])); + s.field("signblockscript", &self.signblockscript[..].as_hex()); s.field("signblock_witness_limit", &self.signblock_witness_limit); - s.field("fedpeg_program", &HexBytes(self.fedpeg_program.as_ref())); - s.field("fedpegscript", &HexBytes(&self.fedpegscript[..])); + s.field("fedpeg_program", &self.fedpeg_program.as_bytes().as_hex()); + s.field("fedpegscript", &self.fedpegscript[..].as_hex()); s.field("extension_space", &HexBytesArray(&self.extension_space)); s.finish() } @@ -242,7 +235,7 @@ impl fmt::Debug for Params { Params::Null => write!(f, "Null"), Params::Compact { signblockscript, signblock_witness_limit, elided_root } => { let mut s = f.debug_struct("Compact"); - s.field("signblockscript", &HexBytes(&signblockscript[..])); + s.field("signblockscript", &signblockscript[..].as_hex()); s.field("signblock_witness_limit", signblock_witness_limit); s.field("elided_root", elided_root); s.finish() @@ -649,7 +642,6 @@ mod tests { use std::fmt::{self, Write}; use crate::hashes::sha256; - use crate::hex::ToHex; use crate::{BlockHash, TxMerkleNode}; use super::*; @@ -695,7 +687,7 @@ mod tests { elided_root: sha256::Midstate::from_byte_array([0; 32]), }; assert_eq!( - compact_entry.calculate_root().to_hex(), + format!("{:x}", compact_entry.calculate_root()), "f98f149fd11da6fbe26d0ee53cadd28372fa9eed2cb7080f41da7ca311531777" ); @@ -707,7 +699,7 @@ mod tests { ext, )); assert_eq!( - full_entry.calculate_root().to_hex(), + format!("{:x}", full_entry.calculate_root()), "8eb1b83cce69a3d8b0bfb7fbe77ae8f1d24b57a9cae047b8c0aba084ad878249" ); @@ -724,7 +716,7 @@ mod tests { height: Default::default(), }; assert_eq!( - header.calculate_dynafed_params_root().unwrap().to_hex(), + format!("{:x}", header.calculate_dynafed_params_root().unwrap()), "113160f76dc17fe367a2def79aefe06feeea9c795310c9e88aeedc23e145982e" ); } diff --git a/src/encode.rs b/src/encode.rs index b1556335..7f874e22 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -174,7 +174,7 @@ pub fn serialize(data: &T) -> Vec { /// Encode an object into a hex-encoded string pub fn serialize_hex(data: &T) -> String { - crate::hex::ToHex::to_hex(&serialize(data)[..]) + hex_conservative::DisplayHex::to_lower_hex_string(&serialize(data)[..]) } /// Deserialize an object from a vector, will error if said deserialization diff --git a/src/issuance.rs b/src/issuance.rs index d6387617..fd59a542 100644 --- a/src/issuance.rs +++ b/src/issuance.rs @@ -188,9 +188,8 @@ impl Decodable for AssetId { #[cfg(feature = "serde")] impl ::serde::Serialize for AssetId { fn serialize(&self, s: S) -> Result { - use crate::hex::ToHex; if s.is_human_readable() { - s.serialize_str(&self.to_hex()) + s.collect_str(self) } else { s.serialize_bytes(&self.0[..]) } diff --git a/src/pset/elip100.rs b/src/pset/elip100.rs index f617c9a6..8af1b466 100644 --- a/src/pset/elip100.rs +++ b/src/pset/elip100.rs @@ -223,10 +223,10 @@ mod test { use crate::{OutPoint, Txid}; use bitcoin::hashes::Hash; use hex_conservative as hex; + use hex_conservative::DisplayHex as _; use crate::{ encode::{serialize_hex, Encodable}, - hex::ToHex, pset::{elip100::PSET_HWW_PREFIX, map::Map, PartiallySignedTransaction}, AssetId, }; @@ -280,7 +280,10 @@ mod test { crate::ContractHash::from_json_contract(VALID_CONTRACT).unwrap(), contract_hash ); - assert_eq!(asset_metadata.serialize().to_hex(),"b47b22656e74697479223a7b22646f6d61696e223a227465746865722e746f227d2c226973737565725f7075626b6579223a22303333376363656563306265656130323332656265313463626130313937613966626434356663663265633934363734396465393230653731343334633262393034222c226e616d65223a2254657468657220555344222c22707265636973696f6e223a382c227469636b6572223a2255534474222c2276657273696f6e223a307d688628ce04bab832e264ba83944033a6ae59d8e6350402c0baf50e2759d2969500000000"); + assert_eq!( + asset_metadata.serialize().to_lower_hex_string(), + "b47b22656e74697479223a7b22646f6d61696e223a227465746865722e746f227d2c226973737565725f7075626b6579223a22303333376363656563306265656130323332656265313463626130313937613966626434356663663265633934363734396465393230653731343334633262393034222c226e616d65223a2254657468657220555344222c22707265636973696f6e223a382c227469636b6572223a2255534474222c2276657273696f6e223a307d688628ce04bab832e264ba83944033a6ae59d8e6350402c0baf50e2759d2969500000000", + ); assert_eq!( AssetMetadata::deserialize(&asset_metadata.serialize()).unwrap(), @@ -297,11 +300,11 @@ mod test { key.consensus_encode(&mut vec).unwrap(); assert_eq!( - vec.to_hex(), - format!("08{}00{}", PSET_HWW_PREFIX.to_hex(), asset_id.into_tag()) + vec.to_lower_hex_string(), + format!("08{}00{}", PSET_HWW_PREFIX.to_lower_hex_string(), asset_id.into_tag()) ); - assert!(vec.to_hex().starts_with(&ELIP0100_IDENTIFIER[2..])); // cut prefix "fc: which is PSET_GLOBAL_PROPRIETARY serialized one level up + assert!(vec.to_lower_hex_string().starts_with(&ELIP0100_IDENTIFIER[2..])); // cut prefix "fc: which is PSET_GLOBAL_PROPRIETARY serialized one level up } #[test] @@ -351,9 +354,9 @@ mod test { .map(|p| p.value) .collect(); assert_eq!(values.len(), 1); - assert_eq!(values[0].to_hex(), ELIP0100_ASSET_METADATA_RECORD_VALUE); + assert_eq!(values[0].to_lower_hex_string(), ELIP0100_ASSET_METADATA_RECORD_VALUE); - let txid_hex_non_convention = txid.as_byte_array().to_vec().to_hex(); + let txid_hex_non_convention = txid.as_byte_array().to_lower_hex_string(); assert_eq!( ELIP0100_ASSET_METADATA_RECORD_VALUE, ELIP0100_ASSET_METADATA_RECORD_VALUE_WRONG @@ -380,7 +383,7 @@ mod test { .map(|p| p.value) .collect(); assert_eq!(values.len(), 1); - assert_eq!(values[0].to_hex(), ELIP0100_TOKEN_METADATA_RECORD_VALUE); + assert_eq!(values[0].to_lower_hex_string(), ELIP0100_TOKEN_METADATA_RECORD_VALUE); } #[cfg(feature = "json-contract")] @@ -398,6 +401,6 @@ mod test { let expected = AssetId::from_str(ELIP0100_ASSET_TAG).unwrap(); - assert_eq!(asset_id.to_hex(), expected.to_hex()); + assert_eq!(asset_id.to_string(), expected.to_string()); } } diff --git a/src/pset/elip102.rs b/src/pset/elip102.rs index d4f5a0d4..5886d1ce 100644 --- a/src/pset/elip102.rs +++ b/src/pset/elip102.rs @@ -69,8 +69,8 @@ mod test { use super::*; use crate::AssetId; use crate::encode::{serialize_hex, Encodable}; - use crate::hex::ToHex; use hex_conservative as hex; + use hex_conservative::DisplayHex as _; // b'\xfc\rpset_liquidex' const ELIP0102_IDENTIFIER: &str = "fc0d707365745f6c69717569646578"; @@ -82,11 +82,11 @@ mod test { key.consensus_encode(&mut vec).unwrap(); assert_eq!( - vec.to_hex(), - format!("0d{}00", PSET_LIQUIDEX_PREFIX.to_hex()) + vec.to_lower_hex_string(), + format!("0d{}00", PSET_LIQUIDEX_PREFIX.to_lower_hex_string()), ); - assert!(vec.to_hex().starts_with(&ELIP0102_IDENTIFIER[2..])); // cut proprietary prefix "fc" + assert!(vec.to_lower_hex_string().starts_with(&ELIP0102_IDENTIFIER[2..])); // cut proprietary prefix "fc" } #[test] diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 6c5e9d88..61684c3b 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -785,8 +785,8 @@ impl Decodable for PartiallySignedTransaction { #[cfg(test)] mod tests { use super::*; - use crate::hex::ToHex; use hex_conservative as hex; + use hex_conservative::DisplayHex as _; #[track_caller] fn tx_pset_rtt(tx_hex: &str) { @@ -961,13 +961,13 @@ mod tests { let bytes = hex::decode_to_vec(pset_str).unwrap(); let pset = encode::deserialize::(&bytes).unwrap(); - assert_eq!(pset_str.len(), encode::serialize(&pset).to_hex().len()); - let back_hex = encode::serialize(&pset).to_hex(); + assert_eq!(pset_str.len(), encode::serialize(&pset).to_lower_hex_string().len()); + let back_hex = encode::serialize(&pset).to_lower_hex_string(); //assert_eq!(pset_str, &back_hex); //TODO this fails, field ordering? let bytes = hex::decode_to_vec(&back_hex).unwrap(); let pset = encode::deserialize::(&bytes).unwrap(); - assert_eq!(&back_hex, &encode::serialize(&pset).to_hex()); + assert_eq!(&back_hex, &encode::serialize(&pset).to_lower_hex_string()); } #[test] diff --git a/src/pset/raw.rs b/src/pset/raw.rs index 66a4b9a2..7c97efd8 100644 --- a/src/pset/raw.rs +++ b/src/pset/raw.rs @@ -21,7 +21,7 @@ use std::{fmt, io}; use super::Error; use crate::encode::{self, deserialize, serialize, Decodable, Encodable, VarInt, MAX_VEC_SIZE}; -use crate::hex; +use hex_conservative::DisplayHex as _; /// A PSET key in its raw byte form. #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] #[cfg_attr( @@ -111,8 +111,7 @@ impl ProprietaryKey { impl fmt::Display for Key { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "type: {:#x}, key: ", self.type_value)?; - hex::format_hex(&self.key[..], f) + write!(f, "type: {:#x}, key: {}", self.type_value, self.key.as_hex()) } } diff --git a/src/pset/serialize.rs b/src/pset/serialize.rs index 31f86d32..5ed03c1e 100644 --- a/src/pset/serialize.rs +++ b/src/pset/serialize.rs @@ -25,7 +25,6 @@ use crate::encode::{ self, deserialize, deserialize_partial, serialize, Decodable, Encodable, VarInt, }; use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash}; -use crate::hex::ToHex; use crate::{AssetId, BlockHash, Script, Transaction, TxOut, Txid}; use bitcoin; use bitcoin::bip32::{ChildNumber, Fingerprint, KeySource}; @@ -54,7 +53,8 @@ pub trait Deserialize: Sized { /// Encode an object into a hex-encoded string pub fn serialize_hex(data: &T) -> String { - Serialize::serialize(data)[..].to_hex() + use hex_conservative::DisplayHex as _; + Serialize::serialize(data)[..].to_lower_hex_string() } impl_pset_de_serialize!(Transaction); From 0e28e229b60cfbc6503f0de657054bbf1671ebe8 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 17:12:23 +0000 Subject: [PATCH 06/10] serde_utils: change deserialization bound on hex_bytes from FromHex to From> The 'hex_bytes' module is somewhat confused: it demands AsRef<[u8]> to serialize, and does so by converting to bytes then hex-serializing the bytes. But to deserialize, it calls FromHex directly. This implicitly requires that the underlying type have a FromHex impl which is compatible with "interpret the type as raw bytes". In this crate, this module is used exclusively by the Vec and [u8] types, so this is true and things work. To make the requirements clearer, change the deserialization bound from FromHex to From>. This is more correct, and also will work with hex-conservative, which has no equivalent to the FromHex trait. --- src/serde_utils.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/serde_utils.rs b/src/serde_utils.rs index 2924edf8..91e38419 100644 --- a/src/serde_utils.rs +++ b/src/serde_utils.rs @@ -239,14 +239,11 @@ pub mod hex_bytes { pub fn deserialize<'de, D, B>(d: D) -> Result where D: serde::Deserializer<'de>, - B: serde::Deserialize<'de> + FromHex, - ::Err: std::fmt::Display, + B: serde::Deserialize<'de> + From>, { struct Visitor(::std::marker::PhantomData); - impl serde::de::Visitor<'_> for Visitor - where - ::Err: std::fmt::Display, + impl>> serde::de::Visitor<'_> for Visitor { type Value = B; @@ -258,7 +255,7 @@ pub mod hex_bytes { where E: serde::de::Error, { if let Ok(hex) = ::std::str::from_utf8(v) { - FromHex::from_hex(hex).map_err(E::custom) + FromHex::from_hex(hex).map_err(E::custom).map(B::from) } else { Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)) } @@ -267,7 +264,7 @@ pub mod hex_bytes { fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { - FromHex::from_hex(v).map_err(E::custom) + FromHex::from_hex(v).map_err(E::custom).map(B::from) } } From de8927ccbc1acf8df0cb5d7f2332104137cada14 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 17:00:37 +0000 Subject: [PATCH 07/10] serde: remove old hex module from 'hex_bytes' module --- src/serde_utils.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/serde_utils.rs b/src/serde_utils.rs index 91e38419..f7e26c19 100644 --- a/src/serde_utils.rs +++ b/src/serde_utils.rs @@ -223,7 +223,8 @@ pub mod hex_bytes { //! Module for serialization of byte arrays as hex strings. #![allow(missing_docs)] - use crate::hex::{FromHex, ToHex}; + use hex_conservative as hex; + use hex_conservative::DisplayHex as _; use serde; pub fn serialize(bytes: &T, s: S) -> Result @@ -231,7 +232,7 @@ pub mod hex_bytes { { // Don't do anything special when not human readable. if s.is_human_readable() { - s.serialize_str(&bytes.as_ref().to_hex()) + s.collect_str(&bytes.as_ref().as_hex()) } else { serde::Serialize::serialize(bytes, s) } @@ -254,8 +255,8 @@ pub mod hex_bytes { fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error, { - if let Ok(hex) = ::std::str::from_utf8(v) { - FromHex::from_hex(hex).map_err(E::custom).map(B::from) + if let Ok(hex) = ::core::str::from_utf8(v) { + hex::decode_to_vec(hex).map_err(E::custom).map(B::from) } else { Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)) } @@ -264,7 +265,7 @@ pub mod hex_bytes { fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { - FromHex::from_hex(v).map_err(E::custom).map(B::from) + hex::decode_to_vec(v).map_err(E::custom).map(B::from) } } From 1c37bb1a80d85cccb99370083290412c04400de1 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 17:19:42 +0000 Subject: [PATCH 08/10] serde_utils: remove old hex module Despite the generic FromHex/ToHex traits being thrown around here, these are exclusively used for byte vectors and so we can just replace the generic calls with hex::decode_to_vec. --- src/serde_utils.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/serde_utils.rs b/src/serde_utils.rs index f7e26c19..4a566928 100644 --- a/src/serde_utils.rs +++ b/src/serde_utils.rs @@ -7,7 +7,8 @@ pub mod btreemap_byte_values { // NOTE: This module can be exactly copied to use with HashMap. use ::std::collections::BTreeMap; - use crate::hex::{FromHex, ToHex}; + use hex_conservative as hex; + use hex_conservative::DisplayHex as _; use serde; pub fn serialize(v: &BTreeMap>, s: S) @@ -21,7 +22,7 @@ pub mod btreemap_byte_values { if s.is_human_readable() { let mut map = s.serialize_map(Some(v.len()))?; for (key, value) in v { - map.serialize_entry(key, &value.to_hex())?; + map.serialize_entry(key, &value.to_lower_hex_string())?; } map.end() } else { @@ -51,7 +52,7 @@ pub mod btreemap_byte_values { { let mut ret = BTreeMap::new(); while let Some((key, value)) = a.next_entry()? { - ret.insert(key, FromHex::from_hex(value).map_err(serde::de::Error::custom)?); + ret.insert(key, hex::decode_to_vec(value).map_err(serde::de::Error::custom)?); } Ok(ret) } From f30b28afa19511fd755c0743fe56220d1f3d29f0 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 17:33:20 +0000 Subject: [PATCH 09/10] re-export 'hex_conservative' as hex The next commit will clean this up a bit. This one just replaces the hex module with the hex-conservative crate and does mechanical fixes to the examples and doctests. --- elementsd-tests/src/pset.rs | 6 +++--- elementsd-tests/src/taproot.rs | 4 ++-- examples/pset_blind_coinjoin.rs | 10 +++++----- examples/raw_blind.rs | 14 +++++++------- examples/tx.rs | 4 ++-- src/blind.rs | 12 ++++++------ src/lib.rs | 3 ++- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/elementsd-tests/src/pset.rs b/elementsd-tests/src/pset.rs index fcafcd17..7ce1d95b 100644 --- a/elementsd-tests/src/pset.rs +++ b/elementsd-tests/src/pset.rs @@ -7,9 +7,9 @@ extern crate rand; use crate::{setup, Call}; use bitcoin::{self, Address, Amount}; -use elements::hex::ToHex; use elements::encode::serialize; use elements::hashes::Hash; +use elements::hex::DisplayHex as _; use elements::pset::PartiallySignedTransaction; use elements::{AssetId, ContractHash}; use elementsd::bitcoincore_rpc::jsonrpc::serde_json::json; @@ -116,7 +116,7 @@ fn tx_pegin() { bitcoind.client.generate_to_address(101, &btc_addr).unwrap(); let proof = bitcoind.client.get_tx_out_proof(&[txid], None).unwrap(); elementsd.generate(2); - let inputs = json!([ {"txid":txid, "vout": vout,"pegin_bitcoin_tx": tx_bytes.to_hex(), "pegin_txout_proof": proof.to_hex(), "pegin_claim_script": claim_script } ]); + let inputs = json!([ {"txid":txid, "vout": vout,"pegin_bitcoin_tx": tx_bytes.to_lower_hex_string(), "pegin_txout_proof": proof.to_lower_hex_string(), "pegin_claim_script": claim_script } ]); let outputs = json!([ {address_lbtc: "0.9", "blinder_index": 0}, {"fee": "0.1" } @@ -158,7 +158,7 @@ fn psbt_rtt(elementsd: &ElementsD, base64: &str) { b_bytes[i] = b_bytes[i].wrapping_add(1); let base64 = BASE64_STANDARD.encode(&b_bytes); if let Some(decoded) = elementsd.decode_psbt(&base64) { - assert_ne!(a, decoded, "{} with changed byte {}", b_bytes.to_hex(), i); + assert_ne!(a, decoded, "{} with changed byte {}", b_bytes.as_hex(), i); } b_bytes[i] = b_bytes[i].wrapping_sub(1); } diff --git a/elementsd-tests/src/taproot.rs b/elementsd-tests/src/taproot.rs index 2c37a9d3..8dcc6b13 100644 --- a/elementsd-tests/src/taproot.rs +++ b/elementsd-tests/src/taproot.rs @@ -7,7 +7,7 @@ use crate::{Call, setup}; use bitcoin::key::{XOnlyPublicKey, Keypair}; use bitcoin::Amount; -use elements::hex::FromHex; +use elements::hex; use elements::confidential::{AssetBlindingFactor, ValueBlindingFactor}; use elements::encode::{deserialize, serialize_hex}; use elements::hashes::Hash; @@ -101,7 +101,7 @@ fn funded_tap_txout( elementsd.generate(1); let tx_hex = elementsd.get_transaction(&txid_hex); - let tx = deserialize::(&Vec::::from_hex(&tx_hex).unwrap()).unwrap(); + let tx = deserialize::(&hex::decode_to_vec(&tx_hex).unwrap()).unwrap(); let mut outpoint: Option = None; for (i, out) in tx.output.iter().enumerate() { diff --git a/examples/pset_blind_coinjoin.rs b/examples/pset_blind_coinjoin.rs index e70d610a..0f9931e6 100644 --- a/examples/pset_blind_coinjoin.rs +++ b/examples/pset_blind_coinjoin.rs @@ -28,7 +28,7 @@ use elements::{pset, secp256k1_zkp}; use elements::encode::{deserialize, serialize_hex}; use elements::{confidential, AssetId, TxOut}; -use elements::hex::FromHex; +use elements::hex; use rand::SeedableRng; // Assume txouts are simple pay to wpkh @@ -41,7 +41,7 @@ struct Secrets { } fn deser_pset(psbt_hex: &str) -> Pset { - deserialize::(&Vec::::from_hex(psbt_hex).unwrap()).unwrap() + deserialize::(&hex::decode_to_vec(psbt_hex).unwrap()).unwrap() } fn parse_txout(txout_info: &str) -> (TxOut, Secrets, pset::Input) { @@ -50,15 +50,15 @@ fn parse_txout(txout_info: &str) -> (TxOut, Secrets, pset::Input) { let txout = TxOut { asset: deserialize::( - &Vec::::from_hex(v["assetcommitment"].as_str().unwrap()).unwrap(), + &hex::decode_to_vec(v["assetcommitment"].as_str().unwrap()).unwrap(), ) .unwrap(), value: deserialize::( - &Vec::::from_hex(v["amountcommitment"].as_str().unwrap()).unwrap(), + &hex::decode_to_vec(v["amountcommitment"].as_str().unwrap()).unwrap(), ) .unwrap(), nonce: deserialize::( - &Vec::::from_hex(v["commitmentnonce"].as_str().unwrap()).unwrap(), + &hex::decode_to_vec(v["commitmentnonce"].as_str().unwrap()).unwrap(), ) .unwrap(), script_pubkey: Script::from_hex_no_prefix(v["scriptPubKey"].as_str().unwrap()).unwrap(), diff --git a/examples/raw_blind.rs b/examples/raw_blind.rs index d166bc80..c45be283 100644 --- a/examples/raw_blind.rs +++ b/examples/raw_blind.rs @@ -15,7 +15,7 @@ use elements::{pset, secp256k1_zkp, SurjectionInput}; use elements::encode::{deserialize, serialize_hex}; use elements::{confidential, AssetId, TxOut}; -use elements::hex::FromHex; +use elements::hex; use rand::SeedableRng; /// Pset example workflow: @@ -36,7 +36,7 @@ struct Secrets { } fn deser_pset(psbt_hex: &str) -> Pset { - deserialize::(&Vec::::from_hex(psbt_hex).unwrap()).unwrap() + deserialize::(&hex::decode_to_vec(psbt_hex).unwrap()).unwrap() } fn parse_txout(txout_info: &str) -> (TxOut, Secrets, pset::Input) { @@ -45,15 +45,15 @@ fn parse_txout(txout_info: &str) -> (TxOut, Secrets, pset::Input) { let txout = TxOut { asset: deserialize::( - &Vec::::from_hex(v["assetcommitment"].as_str().unwrap()).unwrap(), + &hex::decode_to_vec(v["assetcommitment"].as_str().unwrap()).unwrap(), ) .unwrap(), value: deserialize::( - &Vec::::from_hex(v["amountcommitment"].as_str().unwrap()).unwrap(), + &hex::decode_to_vec(v["amountcommitment"].as_str().unwrap()).unwrap(), ) .unwrap(), nonce: deserialize::( - &Vec::::from_hex(v["commitmentnonce"].as_str().unwrap()).unwrap(), + &hex::decode_to_vec(v["commitmentnonce"].as_str().unwrap()).unwrap(), ) .unwrap(), script_pubkey: Script::from_hex_no_prefix(v["scriptPubKey"].as_str().unwrap()).unwrap(), @@ -280,13 +280,13 @@ fn main() { tx.verify_tx_amt_proofs(&secp, &[btc_txout, asset_txout]) .unwrap(); - let inp0_sig = Vec::::from_hex("3044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801").unwrap(); + let inp0_sig = hex::hex!("3044022040d1802d6e10da4c27f05eff807550e614b3d2fa20c663dbf1ebf162d3952689022001f477c953b7c543bce877e3297fccb00ef5dba21d427e79c8bfb8522713309801").to_vec(); let inp0_pk = PublicKey::from_str( "0334c307ad8142e7c8a6bf1ad3552b12fbb860885ea7f2d76c1f49f93a7c4bbbe7", ) .unwrap(); - let inp1_sig = Vec::::from_hex("3044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa01").unwrap(); + let inp1_sig = hex::hex!("3044022017c696503f5e1539fe5cb8dd05f793bd3b6e39f193028a7299a80c94c817a02d022007889009088f46cd9d9f4d137815704170410f53d503b68c1e020292a85b93fa01").to_vec(); let inp1_pk = PublicKey::from_str( "03df8f51c053ba0dfb443cce9793b6dc3339ffb0ce97af4792dade3aae1eb890f6", ) diff --git a/examples/tx.rs b/examples/tx.rs index 3144c3e7..6e889809 100644 --- a/examples/tx.rs +++ b/examples/tx.rs @@ -9,12 +9,12 @@ use elements::{Transaction, TxOutWitness}; use elements::{AssetId, confidential, TxOut}; use elements::encode::deserialize; -use elements::hex::FromHex; +use elements::hex; fn main() { let secp = secp256k1_zkp::Secp256k1::new(); - let tx: Transaction = deserialize(&Vec::::from_hex("0200000001015f2d99582ea16cc9451e8f9e19bdfedf43379ad0ad1fafb8ff66d22359017f020000000000fdffffff030a49492a5168e8cd96aa97f60f5b294cec1ca476ba2f8c1b4c87171f274422e99d08b3b32e88a1df9b226722afe3ad85304ac33f011199fd5cc84fa3c952fd4327a90325221684f36be833d1641c5ede4e72ee065ff8e5151604e123116de12e4e44d4160014d567c426a83a1e920a93d3b5cdc0362f80c5a96c0b4c3cf42cf177683e412511dbe585bff4021abab3e3d0a3b7de0e6c9109b0366609bec8fa07871b09ee66577ade9d47bf71189f94dcd31b313c014fb9baae678554035708296db5b49bc05e8e011b0be421f75438b839c6be86f3f9904c64d4515dbd160014a9cef783b24f4df35aaf6331427713acaa4a5d9d01230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f60000650000000000000043010001c57cafd385e2d848774a87f19409fd61500c10841b5bde34c89b928d81b9a76ffc5c999184465faf5c91377b1edb2d6aaa0168805bed16bff7a065bdbdd60935fd4e1060330000000000000001efe38f01b2cd1dba9db6a3478dae64e5a4210307895791c9bd31d4d4dddda68a10e9a660a93151c6a41bfc9711e07c7a338a135f0dbfe4b3254c43e6a4ae7c0caf0a61ed7263d68c6df68f62c980ba8bcdb7d20d3ebaa924423c6df9658ed73c11e672a9b20adb560fb8de9acdcee91324d0f86242163f17e11352cc336ece4854444fccdad0aab7f8bdc7d50bd248e606ffe612cd040c4837a5b659e34d221cdda13598f12903b3930f4acbba8a7596f4d91635e94aa8857f6c6ccb8b19595fe25a81c0ab9b324333f03309ef797418bc971bc40bf7a1eec55e08785b7dcfdb108a3210eb9002fc77c3a69e368a3ad4b490cdb77b1f82af9e93a665f52b8b20be24c59e7b49535d2708f5f17fb985370d6f636c9178ae382b82f8b77ba287a22dcd057bc465a7d49944e847a480c20cd4ce9c9149a568b221a32c9ec7068da8fa149562a347dcacca61f2dc75eb477c5bed669cdf28b907f827d7f6ba7f22100937a5595556fafd43664a54aecf3d502bbf57458bc74b77ddc7880fad23f4f384fdd965bbb2d3c339864a494b3e8a6cf00e5bb80134e9c815dfbd1bed4dd4c886f76ff50992bd493e58269536548d53876a952c002f58fff90582b8eb1629e885e39b529fdd73b188b2d492674aa56bc8bb4f2d983f86d7e484955e09c2cd42bf2f5c1091a2f675700fc689552e580cf074826e12970c8e1023b9e50c9c4236a904e77b7c9733cb47be4467bfbfec59c2b82be8d5d00383bb4e8ba11691f0fc4853c953979c2fd213abf3fdf523b5258002ea89a0de0db9799d78860580b2fd81e7ceecc0555476fd300f632d12c877f104cc8aac7a1f4c71cba1da9e4d22aafa5bbc4666d5942960399916037b106ff5d527c322eed885429a81fd2ee81edf8b7caf8c2ddc40536f6f800b2d6275dd5df471d7d3aab5285bff6250129661a43ac32ba10d442847365ba7e955d646bf0ae2df07d264a49731493bf14a90199a7f72d37b241b78db1bf8af6d1bbb04064b6bf86ce7c7b543fddaf18d890c57b3fef59d2cc098b174d229d1361b7dfe5b669166b4b3f91e170983fb60c05094bbcc4ea682da6979ab72de6a281f82ab3bdd1f0e9431b70267c101979c7972c329be5694e030f784211a236c49bb38ca77f4389b591a1e2a5e49aaa556ea68b17f45591e4bd38d467356db029ba496b334f22945926ea959f3a07f657f8bcf086c36caaac97cc651a41dc2b53ce9b82a6cf0c126c1fba7f2ad35cdae353994de1456e9539ecf10b5c4eec9ad1ed5e05152dbcfa448c016d3af78794b68322a2b1ff2d1d81b4d0208eb7065c7791cd0f4046505db5a99c0448a3b8fb27bf9ba085d5a4b1b5206e876f6242bd1da01803321a4bcf71676a949996d2b46ccce6f1f1308fbc775051c5e841f243da64b4a91a27a7192d7579a21dabded2798c3b1e99bbd2aca6b7d1f4a3028e0c018aca143bdcd842bbaa8e4ef9d70f12bd7af3f15a6fc0ce958c134fa749b2dcb25a518535239f9dbebc1034f1fd7e74c3808cf53094da2370e518660b73503a787cd0fc87f02ede9a90d0364e07fccaa9238be9ef472b7abf2378676d75cee2d85e640885e28eb5ff0c730944835122065898df69fc37444da4825a4f2524053ba834c277dce029b9a145c7382d94d64df190a4fb1cecc057413643a56f6958f87511a5bb0dccb66cf7a52b6815a6251d9b2def2a532289ab9d5dc50be8d9d399ab858e0495c2c6d487551805ea8a70b70044816ea7f8e51390ab7a23c4a58ceab9a508fff0a66b4d1ada652689a77670572e5c0e0af3b3d9ebd14f507dc1e2e61c22e1ddbcf16ecb760e41343e851240df95e99eb33c8fe84d7509f6abd8a3a42e98dbbc59299d618706ae42c8edba2e1dd08714c446fe12720dc394e80b868c5f1bd8caecea8547410977247ac554d3b6054f6c866f08f692f873a0cc41c801486cc81ef3eaed06cceeaf9706d6b8da55beaeb7ae69151de494864e30e74cc92c8aabdf80e7c589a1e0e1862333810bb3195817ebe8006b7ccc60670ba8ff76f6b2ae767ff0bee689e5c417d1f8cd09a690e8e841a3cfb1f071f6282e3adce2770d1bca0fc02d2cf7c0cabe11b154c1186985a1bbc7a96c6ed5149a0ea6986498fd588bbbffccc453dca3d391d29946cab5832cfd70304a774e509099ba244dc7c044acfad786dbff6f5060ec87b8e5d722d1773a37d6cd363226084848756bf36c81edb4ac676e2abe9f013d12d697cdababfbd1cbbcc3ca7a5efd49d571579c69c0f16498e129acc6aae9c7b95b583683ca10e3490e031a34b0f01db351a151a8d57b78617c6d2501a1e36d6c35cf9f361c5d0becaa991855b4bcb58d2bdd3270042a686072ce551f3cc2dd62fc799b4f71146cc6ccad33cdf4e6ca11992a5e2f824581c7af09da4d4a83b486173025c0e43b4baa38391f76736c99aca3b370d5a80689f1a21790b012096b97a81df2ae2dd2f944630a6654051a4d02927ef414400e8f0de0088387fa2791046a2bf4447256eff6b5da0ceaba87c20f498dfdfb773aa22901bf2d7a5b622ebe2f7a7a8a6ec5a0eb80361c3cfe91e4939d57d32b0c2f678cfd828c0507e75ed4e1afb09a61be08366832d7c2bdd4b1f882e72bfc62fb33a5daec270fc6e30ae8922f81a3afbc5c5e1899ea1485b2f7379452b803cd47c2eb355261e323f07aa5917df219100ebd0e83b4e48530f459961f5b2dfb0f4bcd6fdbfdec88cb7327ffcf4ba88646c332ddb553e55b61ae2ab9ea7dde27a8ac1ce4bb179933c5b1abd1859a9b687d8fbdf34851abf04ea102952b9024b70b1d9ffd83801dc3b733a3f8b33bd7aa3fdb1a8ddc743f3022086ceae8f0f43398f8bf069ff46b24d32deaaaef3d4cb93f150053da8b4aa50d4c4b9415004eb34b98459e9664e8370dfd9c6aa447284a3d350b09f610fa4ac4662f792cbb5478f11637da553a3a52638d7f362281acf3a8901f7ce2dd6cbce21a40a94577608d1cb068ec62717f6927a79a8c768043f16af90e97ad3a466b6115a76137456736da941d51e13e53be95522e01cfb06ee8a102518ff1bf4af8856322463fd5e920c2a1ea2a7fd403a792c0c94121b0c2a1535440ddfc96a5b2ca44ea073a192e9a427ceb4665faf26b1764c6321d592b3157d8153a2cedb5175eaea0cfead8b137f9cda7335c4d642e71bfe5cae223684b1cc83dfcc2ece5505f701be1a3cceda62e78c853b01aa6232c9bc4f7926bbc75b30fa921a3c663bfcf7236b007bcd1edb7d6f8e804e6fbab804fbcd864daaff334698af6a8cc806fc83534e0e95bd5e30e56cee45cde30e0cef551625ba7ce2f4c679d939969e43856d092cf4bad04ec84569d3a46238f8238e88ec3eec0bace677e85d0f0c3ead4bbf8f52ff217362f18fa5e6898d5f3b62e833fb45b9f8b079dd4ac5f17d6f8856ee4787c6639643c4e5772c04bcf66fe3dbbd286afd51d6cdbcac9d786b3806ec618ca1ad4763e2e18955e43c778d22b7fb9acd76ac39864ac2c2728057e46a30485371f5be8e67b400432e71d833ff8304d77de0869d80fbe4d40abf02f3dc3ca4d2135c8b0fecae2da40a8c2149611231c059859b3e5304338a70f5e3303723b5b76c0386f5fe566cf95c78cb2b14d4ba675f3ab7d2db9431c753808b3b123509245d585fab9e0e7f9f1a302739745698953be4868107b8432c96cc082a2e93044a4ed65b4775b06f90208f8589506a702615878a6188b890adb69da7b2495cb55f65b256c8b2babf85f16d94e824cd3760eac63688e341e9a3f5f7ebfbe56d9dce37b90e2fea0bec87e5dde7b8d3a048368eab5ae2cdd7df69341f5213c780ea79598e96f407bd35ad8ae653bca954cc565dc5f9a5e28a821b5cc3ce981457b11eecf8c6ca7e65515a1c8bce3ac2e7303af1ad0e9b1a00983a03fbb0cfe52d85f5beb8bebd969f7ce2c5e57160873beba3a06cda0d99a1b3a887b443d82a6a14a33a69ee64059c65e41b01f6825cdbf73089f3977f02b6008879265720693afd1aeecfb6c050f9f38b75681982b0ae91164ff83cde04410274b2450cb6fcceef45365b2473aeabc075cf4108d94a584aed4fb48afe9c90add923883e27c6c202ca4bf323e8756127d628e09d13df0449006e7d14a73125673ed8a8661a19749e5a8a01d768f500f6fbf1af08a73b7ca99117aca1d521d46e16ba12d953cfc839b17702c6f4a333e6dba3cfe450ed330e48974e751d88fa76d73036b8aeb434375c2f1b65f1a1505ba194eb4f2238d2f4ffa39e9035143de33bbc710f473d6a37e92c7d341e010f2bb545d31b50debbffda7c327be59b9469e240e2b37ca93db3545644d619c2f3173f8f5d646b545c0bf86008933308e8bfc4e1c410d901f2b1e79c74594258113212a737b286a9ac3108ed059661680f11a9d0c8994fa1188ae27339d14595733009eff14607bbb77f407f7b08bcc9973104807a34f52c4ce675c8894b3e43be483713da3440393f6079670dccc7bf4f54d81638bc411c49ec794611bff52742aafc059ee5702e91cc748da13969a1476c904d3fc261ccb022a7409f8f1ae8fbd7c2a8506f3bb2ad84ff55c93998ba367531f1c3b411ac58549a31bf205c102c67351956eab23285cba63601fbfae5498bcdc10cc173937b395e437fcb79b16482b13d824ef597144a73b8f64cf853d9b49cc93c93ff45bf63cca325ad928ceaffd59e5e8762202cdd9f95def9e4ba2d92dbc4d13d25cbc1c7aa482b4ff08e2c92e66acc9ba1475f8ec56c1dfb80af495eedcc03ea0336f18cc76ea057f815e5d2a3ca88fbc293d014862c4b505fc5e7d72876d434029b9c003d97401f604eda90dbcd76350d80529496f55ad8003fbb85f7752df6ceaf9d9ffc3f60fc0bde381fca70306b17837a81e2429c85027a1b377682c0b554a8a78252636384f5559a77573b0070c3baa520d716263b385a0defd90c2384b7ebc564a030c33cd6997b472b43942e063e44817f28f5ca7d5a1ff48d80ab6703600a7dd11395a3f64d8683d47b7c9bb83723134f850b45e3038f9395faab53d6d6302cf9c1a693c86d978addd808807ae9f0dd87ea4e98129a0bd0f0813509764c213eac369692900b35063f0dcbf7bf5961d017bdde3a1ada42c24b71a8ec1f4e49257a35d575327a24ff6049444d4e125257aa7f4c20588d978eadafec231b242b158daa825e6aa5d67066c1f16c004c9e315162aa8c9bbcb254ca8e180c8a177d505b9962b2991f85cf235680df8ea3d531fa393497041736a032c68eee70bf92145b429a0ba825aab62a7e9f023b7c34c7aa4da2251415cafa0badbb046f661ad11718013378697e12eed08f02c21de96c5d0a2fee464b69e02c382f5967a3ce115f18f09e99c9216da22518f510555f44852c4d43cfd4bd4746bb955dec5629cf89c08816ea2d43585b95e5f7beba50200f7cff83d9415476daa7e99853b5fe9440db3aa610ec1f8420a212c5bd55a1f2a5cc674ea0dde9240a9010821b4e6edb312b1f480743bcccffbb8d4716317ac74a2217d6ea49de513838bbddd890a35aea5c5b47ec286389055202da360387bfb2327eb38a2ec5521680fbf7c54b20b0c4d21e2f23046939fe683d63bc60c9451d5985cb3d74ca56ec7d848037298f5acf7f3059ea5f73c5213408b458184d334bca66ddc792c674c626e6e3e2e366b2284b21cd8c134e0783e7494b5278dcc29af3b17d5609c04e1d6bf3f21670befce3fab0f7b2d9b7e6c46656bf423b500df83f2bfd0cc7502db1a3d8320235064708115f45b9ae7810ecaf73304e153662620a247d3d6d2d4251441c4dcdd14fb9b33f2f52f1b4a05fa1cd8e77c3c79178ae0ad961a9737c01a0ec073e4743010001662279b3e4efb9e9b04d9859d348dbdecaf42dcbe0664d7d035851e52630e9f537632b1b090f530aa6a9d3e001feb931eeea6006d339890fbbf481f842a96d05fd4e106033000000000000000198b771005818add879ce29234db70c78e5a9d046b424d5e2cab6e9499bd13df7432a9ee058a2454d33bc1ddef43b73de3a83eff603d0ba0686b127c6eb7f2c02c5d46b6d58a4fe22cbd3fa865bf378465d0133b2fafc47c9aaf56cde01dd065b2457911e889d4bf1f63e1575799ebeed4efa00edb19898b1b3d7e1eac163cfa25550e5ea917f0912d54aa9dd9980aa8757219e94e93325d126fd6f31fc3bb8784ff910cbaf274e46e62d42f1e25b8d78bea8498ebfd3cd52bbc41f971a50bb235d83d014e420a92969a24292aa2692021ebb7717691b1bd0bc81eb80c9ede4174e64352238ccce5efe4ff231db947cdd03b03786042cc7ca7cab2253850abf322cb98f039890a5ab690c0803e0692d2482e03a2cc56ef08f4e1cadf082764775ad8aa85bd380ee8ebedd4115b3a4513f3baa630ce21476ab129668994c7ae936f0b439be17e5a13326081d19ae36211992752e08549632cfeedd4b7effd2e07405baa70ac0cdd6accbc1c8f4b9f5b3d27e2ee3cced0254927d649a61ebec2d67ce51746911512e9c9547365ffe406d3604d67f6d8cad7dea01eebfbb32a986ea7b8b4d78d8df0a368c5da4039f53787369b1be5ed937e8608cd115a7d54c6e3819c34014e0a3b69e192e7f195cb570add2b1c583017834d20f5f2b83038859a2888344eb6ac38a2f9f1e7aa7468454351c9df871c802060525844e72cadcce258469dff954aca0403efa569212e348440b35a94f75fbf237d9508f406f6b88dcb76c46108371c969518f46c32590ce4a527500564e2504401a8b74c5edda5c2037b5e43ba1682916c5e4bedfd559b475e6b9afacd2bf4bc2861497c3154b684dd5669b80c1548114feff221b4ba6fa9630f15a348942a5ff0fc1b6b7bbaf10de7e9268b3f3059895bad350eab5e6678eb379c78b7cca0a19206fe2fb51b9543eafe174af2007badb1a86ac43ee32386150ebc1ab27123dedafa2a3b7e6e6ce4b6c4686529a157fed25c4ae5f7e44e0f63bad17c8d7c88b507280c03e952b7af36962381699150a15dae23aec75d78708bf9aab8f9197d6d3ad97d179d0d7890e16fae101fd57d49d17e090c01ac5b72d53111df514917c735926fe66665b7ac08ad1249f99e1d0fd1bd2c11f32a5edf273dac9a9d904abab6551745f71cdd2bcf5b114c31bec42b4f7078e5da4076e140f6370133b593366786bf10be1dbe9dc411bca1b7ec80587bf7735ecd3e3dbaca3855a9df3b01782ef6c009a916b597ac1b968040c0fb2054c7685ff34851a2f0153ea1f9f0aea6781234b7848148e03fb0f067d77e272ac86a59cbd54a501fa763be2c3bc8f083ad2accbb3d8b2cfb933823510b5b86b7ba22724511eebd7c497dd6b79243c5985054fd01b1328f7dcee2d6e7090bda4763e7d0aca6fa7a283a84be84ab15aa95beb1b4b5d6760f39e42ed72d69f7ab0c6740e92a14ef3490cc5d610bcdf0300a8192a2bba672c3971782ff9847e7a6d479896d87e9d5e95fc1158cf6e30d44697be519ea5d312855e3ee7205cbfc1e496cd8909a46e8e167b3d8bbb61a824340ed8cb434ebca7789ed0430d85fdb7548840e42a63e5d201bb77bb66f9c515fc7ed6d812916962adfd42f621ee50cdfed8b9593d747e094e618c94f8198707c598f1c1ad019aeb7fee68c72e66656f43b56f443014986c0d3c7446500999316ae004082843accea6fb833c893046094dd2b995d84e4cd74789956a5289d6ad4ff2a766d0e7a64d91cc7f7dc6f225fbc27ca0f2d30e6d2ba6105e5e04aa6c261ccc0a0dad14311863c6bb863858707779f6a708c5feb9c55b612452ba50c10472b18b5e0abf69f019f4b90246b2d36795b598a809a4599412623d810c94baca6c369a82dffae8c711fc2d105e92a8d7b4c244f3eecdeca19698e79f83462d6870d0b91fa926331dea367a418be40b1d7d530b1f239b77b893bc5a4525013252cf199a3c66166eeab9e7876cb47a0d6f4cc9df5c83bdc5230a345b44a4c7362e02a091fda5d7ff731d73bd7bbcf3092494eb7e873f976a2015f3631dd0faf76c0f54159dfcb6796fd5144c3e31c998ad5b6028b9182445e9e25faa8a8b5c332a19947d5cb14c2a1dfb76313d711a2eea0ca56c4b4c9edb8cfd089f03672a499e6419fca6914052f7d0176bb2e607c2fc6a3de7e58c3f63ac54f2122af3a9135d5e58b28918b9c481f9f8b94a76c5b2cb790df5e726a6b4c24dd56809d3ba683941fbe3f4334e62d37990aa4b64efa848404cb090cf98d254f0cc8ef48090a46997c64fe4b129ac84663bfc2b0a25a02bc5898a199643af41cbad18631c5db596048cb1bb89f0ea9243ec8f72ee67a6a95eb751ba7f59ded999f2875ca40082a72b62f9bdec52142562d0a48c50730a940db9613596ebbd359237fea5ad701fb2b68bd64f0fbdc2485a8102444fd321777a6e22f093e15dc23eb158035054681053c2035326135e407681a633370138fc265a7cda97825423b08f7955cff40bf4590b38e482bd388741c17a3d79a40662fb41fd760e15f4b58d540fb66b3ad698365c339d8fc6babfb7d3b039af01a840859f9ac7ede34cca3d9fa2efe8eeb7c804b02225d039aa1db5a18dfbb96445742e08e643d897e3db984bce40167997547657432c88c81005d1eba0a5c2b27bbf2fe3f92dfdd0d59a49a1432d2352e912480b8a76b7618576b6db40a57af5d5bf3f2df7bf01e30f8b823a4b714c39082afc4f2f1ec198586ae3db5d5557fb054ab069680736da45187f264ef8d9a45d4b8d0eb9a54f5f074a9c5b6fd8d82550f290e599e3a73c0eac52dd94dc918ae4b985f6863a5783d764662ce64a0d3eafe619e1ffdaa3faf4a6985dfe6a58f7a132ddf896d9a757349b0a51d10432730111c391d926b96fa605714c7dbb1719d868fb7ef6995d63d4d5619653e865dcff21bc8713e6093daab77f2acf5491a66244d9d46335da8a16f63e2d296e83f540f5e4f574f1a5a1500a20a8190b0bbf60f0b401a4a5c333edd38728866bf26ac44ebaf7f41356c8fd60f1bd60112a0d9715c11c9b271d2b7a3cede68f4a88790c47ae1b027700cc9edc1a9a63f8f63b796e9ff2773d5138bc8d1fc98a84a7624b3cd5d04d6a11d4e55e08ad2f69f1f90cbca0a1db3f53008bb85f155385de4bd312af8920b1c63489525b9e0a97bc5eb54b1ef6173af2950559e9f56b24374a61c96458184ceabc34ac24021c26ba82c3e3687a3d8a8e28ec3aa563c94ac9125ae8b0b9881e071b8c862827970028e55cf0c7821411c824a5c4da44fbdee147c86f943b718387c8232291fc844a89aab8466736296b930fe971d0346527dcc71090ae165c7a8e8edc2c72a9af00d5c3fcd52ba9253ac15132045fd311203339e782c6e54ff26e3a950f2430f74961f554593c7c435ee5a79a0a0bef3bdc347ea7faa6b3e4579adafeff126d6ded61b116d20c2fa9e5b020f71395c4d1efc8f18adae9f5326d52962b0862793fc889d984069631cae5d4295aceea308881579e1c313cd09833d67097c247def9cca36eb72a0e069dfb30ec4e14148196b08fd416de071cbac34895c13b754f354af6aeffcb6d64531e48becab49697177ebe29d550c17f22626d9d073d0c40c5151d99ecf52a51cc47d6c2c2bc2087fd94b8ab3452eb3acdd0a2e091fa3fe7baccb70e69348854504562752cb5489fd65765719108e5f6387f231e72a61f33ad1f50580519f9e6693695c767cc7f0a60a9b6927630e874f7ad8a072ad1ea326c8b65d51b0cf247d83acbc6efde4628581bda8449c5278ba69115c6d0e40531cd19783c34ff963204830cadd81e263062521ce8cd1559bcff6fcd4b331238e8620348b494fd9248ef2f364fa9f836abec7b499685ec7d03287042a8ef3d68292d27fafad43c78d3564ec4415e1549471bb4c93957be34315b81ad020ee257fe8e6f8c6b8f429257bbc91015ff376ef698d4236c7d925aabd87fb8c50c737cfd4dd37791b1c43d7d925dda0af5cef8e5828993dff41d4019e61152b20017f18723d6f8589a72ee6aa61df954b11a094dfee7f8de82b4c6e0b8378cdc20965297622ee78b665df2fc9e0a59e2416d8101aab95a72d5ec8c6bacc46b8b052454bed1b1155e323c778b76cc12c4337a0456479e99cd954ee9b7a610ef2fdd85115c8761e48a15ee0dc75a1c44a0595783ee7a3b3f0be27bd901f1118ffd7967aa98fef47180b3c7314a238223aa468b3acd5c568ea74934fdc10b06f42b18b23d7a425cb4180a5f5e76de3f54064df11ff9cee21403be789639ea2946e88ecc81bcb492adf6d7652a600ca07d614a0916c89eee9348ab1e356e153bc37434e37bc7e581bb797251198ffc955e555ee20ce6118f175166ab25e25cbc847b825f969a66085f745eb64ad7ab1e193a7dadf466c29eff0ded9a9a82323f1d0ab88134ada28d3691e98e90ceeaec3369d466e24526e4eee3255e0266318c2851476b98af959eeacafd88994d597c52afd23d22578876cadbe26026e10753aef97ed889dd436d0e9369bafc8cd50dd0b6090cc3944b81063bbada167cebcab6866fb3b87791b6dff1de3b2aab67397df70c60ebefa9389e741fd5337113a1da0d7ccf733348eb91cf40d0c323baa3f692f9b45881efb66edaf4ea7ac6d88b6a93fb7237f6a9bb43902ccdb2ea3e6a342abfaa5e36d9b685bb1a97f0a2b94a69c674935fad7b38d7702bdff95d3aca3895f3b05c70cf1754cacc5980610f09b6e2cb3e89311638fd4b271805efc7486d2c4f0cf0910598427c66627c74ae12f29b63a7ad778e0aaa38f7b1cc23189603d01891ba26c14e4e96c0f7c86e63c73d8d1098661540b4daf2424c89be4991f07ed284a8765d92c6b52c080bdf62bca1428a018352baa32571d8d36da5653a91415dfe8d0c4aa46ed6766f4c162a05ddbccdf14ca9f84e2d487199467f338e81f3f5058bcd22e96a04119d036de1ceb872ca05954e53c86b85626a44856e5685fe35d8217af87349d24650059e00ec7b80d7c0496950a1c827f443db6933a756723cd529c25d7a93e3be32666bf2d20f533d6b3e1378296cafa3b468a3926e7754781923b12d9701bad179da601a623e25f76731a98e93712415496ea84f88dffd243f7ec9a480cc22358bb6705d46be5807e3aa49019e16f86d0c35af6c6e6f7019cc38f5dee215298ae1319bcf248aed114fdb0a5b342b8d250fdbc3bd5ba21e3232a7655bf424eaed8c810b6b1912fa31e37399a56aa33a9a6a76974175ac96b67c43c1ecfeb5de2b0c7b8d4f29993def838ace907acee23a1a7fb52d53078a4d544c858ba18412f152f9596b31a15107e428c96175b5fd49dafda407a0c86bfc9ff6a44217a635bbe6c672c85156f21ec664465ca9e6b9e2e4636aaf6c7d02a9cc28907f5b84d08b1a0a216c8a8494f165a637f5d4edcd0e272390d8704840cd62846db58c4f4c118f19ae3087d9198a05f8b2b256cbe176bc9604df06bda9b7e49d7ded17a059f32b28e1ed47421f32d425004261ce060a2e6af1b7f583f9d7b6e887103df1c359f9d043fdcf91220c57c438fe37b6e606492850ae87dd6f0fc4339777202464dd8ba10e119775ec36daffcca9aebe2208249ffb7068009612a15fd4ee01fb564b567c7c31a5179f88bd1e71d4bd0771b51651ed98ea4bead8deb759c86b2d705d16f4335457b0c9d3b0e9cff91f8df33f265600bd0cc8e8128918456726dfd3cbd8b8c45b21506dab2c49975e10440a0673bee73c2d757f48ea9e4c8de2c4a6eeb55d3127c78b95c2f13b4b0f66c9ddfaf6d28ca7070a6b713d28e8ecb64d175b2a4e8151323f0f9e1769b4ca1228f7d555ed851aacfd6bb782629e6f38aae70000").unwrap()).unwrap(); + let tx: Transaction = deserialize(&hex::hex!("0200000001015f2d99582ea16cc9451e8f9e19bdfedf43379ad0ad1fafb8ff66d22359017f020000000000fdffffff030a49492a5168e8cd96aa97f60f5b294cec1ca476ba2f8c1b4c87171f274422e99d08b3b32e88a1df9b226722afe3ad85304ac33f011199fd5cc84fa3c952fd4327a90325221684f36be833d1641c5ede4e72ee065ff8e5151604e123116de12e4e44d4160014d567c426a83a1e920a93d3b5cdc0362f80c5a96c0b4c3cf42cf177683e412511dbe585bff4021abab3e3d0a3b7de0e6c9109b0366609bec8fa07871b09ee66577ade9d47bf71189f94dcd31b313c014fb9baae678554035708296db5b49bc05e8e011b0be421f75438b839c6be86f3f9904c64d4515dbd160014a9cef783b24f4df35aaf6331427713acaa4a5d9d01230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f60000650000000000000043010001c57cafd385e2d848774a87f19409fd61500c10841b5bde34c89b928d81b9a76ffc5c999184465faf5c91377b1edb2d6aaa0168805bed16bff7a065bdbdd60935fd4e1060330000000000000001efe38f01b2cd1dba9db6a3478dae64e5a4210307895791c9bd31d4d4dddda68a10e9a660a93151c6a41bfc9711e07c7a338a135f0dbfe4b3254c43e6a4ae7c0caf0a61ed7263d68c6df68f62c980ba8bcdb7d20d3ebaa924423c6df9658ed73c11e672a9b20adb560fb8de9acdcee91324d0f86242163f17e11352cc336ece4854444fccdad0aab7f8bdc7d50bd248e606ffe612cd040c4837a5b659e34d221cdda13598f12903b3930f4acbba8a7596f4d91635e94aa8857f6c6ccb8b19595fe25a81c0ab9b324333f03309ef797418bc971bc40bf7a1eec55e08785b7dcfdb108a3210eb9002fc77c3a69e368a3ad4b490cdb77b1f82af9e93a665f52b8b20be24c59e7b49535d2708f5f17fb985370d6f636c9178ae382b82f8b77ba287a22dcd057bc465a7d49944e847a480c20cd4ce9c9149a568b221a32c9ec7068da8fa149562a347dcacca61f2dc75eb477c5bed669cdf28b907f827d7f6ba7f22100937a5595556fafd43664a54aecf3d502bbf57458bc74b77ddc7880fad23f4f384fdd965bbb2d3c339864a494b3e8a6cf00e5bb80134e9c815dfbd1bed4dd4c886f76ff50992bd493e58269536548d53876a952c002f58fff90582b8eb1629e885e39b529fdd73b188b2d492674aa56bc8bb4f2d983f86d7e484955e09c2cd42bf2f5c1091a2f675700fc689552e580cf074826e12970c8e1023b9e50c9c4236a904e77b7c9733cb47be4467bfbfec59c2b82be8d5d00383bb4e8ba11691f0fc4853c953979c2fd213abf3fdf523b5258002ea89a0de0db9799d78860580b2fd81e7ceecc0555476fd300f632d12c877f104cc8aac7a1f4c71cba1da9e4d22aafa5bbc4666d5942960399916037b106ff5d527c322eed885429a81fd2ee81edf8b7caf8c2ddc40536f6f800b2d6275dd5df471d7d3aab5285bff6250129661a43ac32ba10d442847365ba7e955d646bf0ae2df07d264a49731493bf14a90199a7f72d37b241b78db1bf8af6d1bbb04064b6bf86ce7c7b543fddaf18d890c57b3fef59d2cc098b174d229d1361b7dfe5b669166b4b3f91e170983fb60c05094bbcc4ea682da6979ab72de6a281f82ab3bdd1f0e9431b70267c101979c7972c329be5694e030f784211a236c49bb38ca77f4389b591a1e2a5e49aaa556ea68b17f45591e4bd38d467356db029ba496b334f22945926ea959f3a07f657f8bcf086c36caaac97cc651a41dc2b53ce9b82a6cf0c126c1fba7f2ad35cdae353994de1456e9539ecf10b5c4eec9ad1ed5e05152dbcfa448c016d3af78794b68322a2b1ff2d1d81b4d0208eb7065c7791cd0f4046505db5a99c0448a3b8fb27bf9ba085d5a4b1b5206e876f6242bd1da01803321a4bcf71676a949996d2b46ccce6f1f1308fbc775051c5e841f243da64b4a91a27a7192d7579a21dabded2798c3b1e99bbd2aca6b7d1f4a3028e0c018aca143bdcd842bbaa8e4ef9d70f12bd7af3f15a6fc0ce958c134fa749b2dcb25a518535239f9dbebc1034f1fd7e74c3808cf53094da2370e518660b73503a787cd0fc87f02ede9a90d0364e07fccaa9238be9ef472b7abf2378676d75cee2d85e640885e28eb5ff0c730944835122065898df69fc37444da4825a4f2524053ba834c277dce029b9a145c7382d94d64df190a4fb1cecc057413643a56f6958f87511a5bb0dccb66cf7a52b6815a6251d9b2def2a532289ab9d5dc50be8d9d399ab858e0495c2c6d487551805ea8a70b70044816ea7f8e51390ab7a23c4a58ceab9a508fff0a66b4d1ada652689a77670572e5c0e0af3b3d9ebd14f507dc1e2e61c22e1ddbcf16ecb760e41343e851240df95e99eb33c8fe84d7509f6abd8a3a42e98dbbc59299d618706ae42c8edba2e1dd08714c446fe12720dc394e80b868c5f1bd8caecea8547410977247ac554d3b6054f6c866f08f692f873a0cc41c801486cc81ef3eaed06cceeaf9706d6b8da55beaeb7ae69151de494864e30e74cc92c8aabdf80e7c589a1e0e1862333810bb3195817ebe8006b7ccc60670ba8ff76f6b2ae767ff0bee689e5c417d1f8cd09a690e8e841a3cfb1f071f6282e3adce2770d1bca0fc02d2cf7c0cabe11b154c1186985a1bbc7a96c6ed5149a0ea6986498fd588bbbffccc453dca3d391d29946cab5832cfd70304a774e509099ba244dc7c044acfad786dbff6f5060ec87b8e5d722d1773a37d6cd363226084848756bf36c81edb4ac676e2abe9f013d12d697cdababfbd1cbbcc3ca7a5efd49d571579c69c0f16498e129acc6aae9c7b95b583683ca10e3490e031a34b0f01db351a151a8d57b78617c6d2501a1e36d6c35cf9f361c5d0becaa991855b4bcb58d2bdd3270042a686072ce551f3cc2dd62fc799b4f71146cc6ccad33cdf4e6ca11992a5e2f824581c7af09da4d4a83b486173025c0e43b4baa38391f76736c99aca3b370d5a80689f1a21790b012096b97a81df2ae2dd2f944630a6654051a4d02927ef414400e8f0de0088387fa2791046a2bf4447256eff6b5da0ceaba87c20f498dfdfb773aa22901bf2d7a5b622ebe2f7a7a8a6ec5a0eb80361c3cfe91e4939d57d32b0c2f678cfd828c0507e75ed4e1afb09a61be08366832d7c2bdd4b1f882e72bfc62fb33a5daec270fc6e30ae8922f81a3afbc5c5e1899ea1485b2f7379452b803cd47c2eb355261e323f07aa5917df219100ebd0e83b4e48530f459961f5b2dfb0f4bcd6fdbfdec88cb7327ffcf4ba88646c332ddb553e55b61ae2ab9ea7dde27a8ac1ce4bb179933c5b1abd1859a9b687d8fbdf34851abf04ea102952b9024b70b1d9ffd83801dc3b733a3f8b33bd7aa3fdb1a8ddc743f3022086ceae8f0f43398f8bf069ff46b24d32deaaaef3d4cb93f150053da8b4aa50d4c4b9415004eb34b98459e9664e8370dfd9c6aa447284a3d350b09f610fa4ac4662f792cbb5478f11637da553a3a52638d7f362281acf3a8901f7ce2dd6cbce21a40a94577608d1cb068ec62717f6927a79a8c768043f16af90e97ad3a466b6115a76137456736da941d51e13e53be95522e01cfb06ee8a102518ff1bf4af8856322463fd5e920c2a1ea2a7fd403a792c0c94121b0c2a1535440ddfc96a5b2ca44ea073a192e9a427ceb4665faf26b1764c6321d592b3157d8153a2cedb5175eaea0cfead8b137f9cda7335c4d642e71bfe5cae223684b1cc83dfcc2ece5505f701be1a3cceda62e78c853b01aa6232c9bc4f7926bbc75b30fa921a3c663bfcf7236b007bcd1edb7d6f8e804e6fbab804fbcd864daaff334698af6a8cc806fc83534e0e95bd5e30e56cee45cde30e0cef551625ba7ce2f4c679d939969e43856d092cf4bad04ec84569d3a46238f8238e88ec3eec0bace677e85d0f0c3ead4bbf8f52ff217362f18fa5e6898d5f3b62e833fb45b9f8b079dd4ac5f17d6f8856ee4787c6639643c4e5772c04bcf66fe3dbbd286afd51d6cdbcac9d786b3806ec618ca1ad4763e2e18955e43c778d22b7fb9acd76ac39864ac2c2728057e46a30485371f5be8e67b400432e71d833ff8304d77de0869d80fbe4d40abf02f3dc3ca4d2135c8b0fecae2da40a8c2149611231c059859b3e5304338a70f5e3303723b5b76c0386f5fe566cf95c78cb2b14d4ba675f3ab7d2db9431c753808b3b123509245d585fab9e0e7f9f1a302739745698953be4868107b8432c96cc082a2e93044a4ed65b4775b06f90208f8589506a702615878a6188b890adb69da7b2495cb55f65b256c8b2babf85f16d94e824cd3760eac63688e341e9a3f5f7ebfbe56d9dce37b90e2fea0bec87e5dde7b8d3a048368eab5ae2cdd7df69341f5213c780ea79598e96f407bd35ad8ae653bca954cc565dc5f9a5e28a821b5cc3ce981457b11eecf8c6ca7e65515a1c8bce3ac2e7303af1ad0e9b1a00983a03fbb0cfe52d85f5beb8bebd969f7ce2c5e57160873beba3a06cda0d99a1b3a887b443d82a6a14a33a69ee64059c65e41b01f6825cdbf73089f3977f02b6008879265720693afd1aeecfb6c050f9f38b75681982b0ae91164ff83cde04410274b2450cb6fcceef45365b2473aeabc075cf4108d94a584aed4fb48afe9c90add923883e27c6c202ca4bf323e8756127d628e09d13df0449006e7d14a73125673ed8a8661a19749e5a8a01d768f500f6fbf1af08a73b7ca99117aca1d521d46e16ba12d953cfc839b17702c6f4a333e6dba3cfe450ed330e48974e751d88fa76d73036b8aeb434375c2f1b65f1a1505ba194eb4f2238d2f4ffa39e9035143de33bbc710f473d6a37e92c7d341e010f2bb545d31b50debbffda7c327be59b9469e240e2b37ca93db3545644d619c2f3173f8f5d646b545c0bf86008933308e8bfc4e1c410d901f2b1e79c74594258113212a737b286a9ac3108ed059661680f11a9d0c8994fa1188ae27339d14595733009eff14607bbb77f407f7b08bcc9973104807a34f52c4ce675c8894b3e43be483713da3440393f6079670dccc7bf4f54d81638bc411c49ec794611bff52742aafc059ee5702e91cc748da13969a1476c904d3fc261ccb022a7409f8f1ae8fbd7c2a8506f3bb2ad84ff55c93998ba367531f1c3b411ac58549a31bf205c102c67351956eab23285cba63601fbfae5498bcdc10cc173937b395e437fcb79b16482b13d824ef597144a73b8f64cf853d9b49cc93c93ff45bf63cca325ad928ceaffd59e5e8762202cdd9f95def9e4ba2d92dbc4d13d25cbc1c7aa482b4ff08e2c92e66acc9ba1475f8ec56c1dfb80af495eedcc03ea0336f18cc76ea057f815e5d2a3ca88fbc293d014862c4b505fc5e7d72876d434029b9c003d97401f604eda90dbcd76350d80529496f55ad8003fbb85f7752df6ceaf9d9ffc3f60fc0bde381fca70306b17837a81e2429c85027a1b377682c0b554a8a78252636384f5559a77573b0070c3baa520d716263b385a0defd90c2384b7ebc564a030c33cd6997b472b43942e063e44817f28f5ca7d5a1ff48d80ab6703600a7dd11395a3f64d8683d47b7c9bb83723134f850b45e3038f9395faab53d6d6302cf9c1a693c86d978addd808807ae9f0dd87ea4e98129a0bd0f0813509764c213eac369692900b35063f0dcbf7bf5961d017bdde3a1ada42c24b71a8ec1f4e49257a35d575327a24ff6049444d4e125257aa7f4c20588d978eadafec231b242b158daa825e6aa5d67066c1f16c004c9e315162aa8c9bbcb254ca8e180c8a177d505b9962b2991f85cf235680df8ea3d531fa393497041736a032c68eee70bf92145b429a0ba825aab62a7e9f023b7c34c7aa4da2251415cafa0badbb046f661ad11718013378697e12eed08f02c21de96c5d0a2fee464b69e02c382f5967a3ce115f18f09e99c9216da22518f510555f44852c4d43cfd4bd4746bb955dec5629cf89c08816ea2d43585b95e5f7beba50200f7cff83d9415476daa7e99853b5fe9440db3aa610ec1f8420a212c5bd55a1f2a5cc674ea0dde9240a9010821b4e6edb312b1f480743bcccffbb8d4716317ac74a2217d6ea49de513838bbddd890a35aea5c5b47ec286389055202da360387bfb2327eb38a2ec5521680fbf7c54b20b0c4d21e2f23046939fe683d63bc60c9451d5985cb3d74ca56ec7d848037298f5acf7f3059ea5f73c5213408b458184d334bca66ddc792c674c626e6e3e2e366b2284b21cd8c134e0783e7494b5278dcc29af3b17d5609c04e1d6bf3f21670befce3fab0f7b2d9b7e6c46656bf423b500df83f2bfd0cc7502db1a3d8320235064708115f45b9ae7810ecaf73304e153662620a247d3d6d2d4251441c4dcdd14fb9b33f2f52f1b4a05fa1cd8e77c3c79178ae0ad961a9737c01a0ec073e4743010001662279b3e4efb9e9b04d9859d348dbdecaf42dcbe0664d7d035851e52630e9f537632b1b090f530aa6a9d3e001feb931eeea6006d339890fbbf481f842a96d05fd4e106033000000000000000198b771005818add879ce29234db70c78e5a9d046b424d5e2cab6e9499bd13df7432a9ee058a2454d33bc1ddef43b73de3a83eff603d0ba0686b127c6eb7f2c02c5d46b6d58a4fe22cbd3fa865bf378465d0133b2fafc47c9aaf56cde01dd065b2457911e889d4bf1f63e1575799ebeed4efa00edb19898b1b3d7e1eac163cfa25550e5ea917f0912d54aa9dd9980aa8757219e94e93325d126fd6f31fc3bb8784ff910cbaf274e46e62d42f1e25b8d78bea8498ebfd3cd52bbc41f971a50bb235d83d014e420a92969a24292aa2692021ebb7717691b1bd0bc81eb80c9ede4174e64352238ccce5efe4ff231db947cdd03b03786042cc7ca7cab2253850abf322cb98f039890a5ab690c0803e0692d2482e03a2cc56ef08f4e1cadf082764775ad8aa85bd380ee8ebedd4115b3a4513f3baa630ce21476ab129668994c7ae936f0b439be17e5a13326081d19ae36211992752e08549632cfeedd4b7effd2e07405baa70ac0cdd6accbc1c8f4b9f5b3d27e2ee3cced0254927d649a61ebec2d67ce51746911512e9c9547365ffe406d3604d67f6d8cad7dea01eebfbb32a986ea7b8b4d78d8df0a368c5da4039f53787369b1be5ed937e8608cd115a7d54c6e3819c34014e0a3b69e192e7f195cb570add2b1c583017834d20f5f2b83038859a2888344eb6ac38a2f9f1e7aa7468454351c9df871c802060525844e72cadcce258469dff954aca0403efa569212e348440b35a94f75fbf237d9508f406f6b88dcb76c46108371c969518f46c32590ce4a527500564e2504401a8b74c5edda5c2037b5e43ba1682916c5e4bedfd559b475e6b9afacd2bf4bc2861497c3154b684dd5669b80c1548114feff221b4ba6fa9630f15a348942a5ff0fc1b6b7bbaf10de7e9268b3f3059895bad350eab5e6678eb379c78b7cca0a19206fe2fb51b9543eafe174af2007badb1a86ac43ee32386150ebc1ab27123dedafa2a3b7e6e6ce4b6c4686529a157fed25c4ae5f7e44e0f63bad17c8d7c88b507280c03e952b7af36962381699150a15dae23aec75d78708bf9aab8f9197d6d3ad97d179d0d7890e16fae101fd57d49d17e090c01ac5b72d53111df514917c735926fe66665b7ac08ad1249f99e1d0fd1bd2c11f32a5edf273dac9a9d904abab6551745f71cdd2bcf5b114c31bec42b4f7078e5da4076e140f6370133b593366786bf10be1dbe9dc411bca1b7ec80587bf7735ecd3e3dbaca3855a9df3b01782ef6c009a916b597ac1b968040c0fb2054c7685ff34851a2f0153ea1f9f0aea6781234b7848148e03fb0f067d77e272ac86a59cbd54a501fa763be2c3bc8f083ad2accbb3d8b2cfb933823510b5b86b7ba22724511eebd7c497dd6b79243c5985054fd01b1328f7dcee2d6e7090bda4763e7d0aca6fa7a283a84be84ab15aa95beb1b4b5d6760f39e42ed72d69f7ab0c6740e92a14ef3490cc5d610bcdf0300a8192a2bba672c3971782ff9847e7a6d479896d87e9d5e95fc1158cf6e30d44697be519ea5d312855e3ee7205cbfc1e496cd8909a46e8e167b3d8bbb61a824340ed8cb434ebca7789ed0430d85fdb7548840e42a63e5d201bb77bb66f9c515fc7ed6d812916962adfd42f621ee50cdfed8b9593d747e094e618c94f8198707c598f1c1ad019aeb7fee68c72e66656f43b56f443014986c0d3c7446500999316ae004082843accea6fb833c893046094dd2b995d84e4cd74789956a5289d6ad4ff2a766d0e7a64d91cc7f7dc6f225fbc27ca0f2d30e6d2ba6105e5e04aa6c261ccc0a0dad14311863c6bb863858707779f6a708c5feb9c55b612452ba50c10472b18b5e0abf69f019f4b90246b2d36795b598a809a4599412623d810c94baca6c369a82dffae8c711fc2d105e92a8d7b4c244f3eecdeca19698e79f83462d6870d0b91fa926331dea367a418be40b1d7d530b1f239b77b893bc5a4525013252cf199a3c66166eeab9e7876cb47a0d6f4cc9df5c83bdc5230a345b44a4c7362e02a091fda5d7ff731d73bd7bbcf3092494eb7e873f976a2015f3631dd0faf76c0f54159dfcb6796fd5144c3e31c998ad5b6028b9182445e9e25faa8a8b5c332a19947d5cb14c2a1dfb76313d711a2eea0ca56c4b4c9edb8cfd089f03672a499e6419fca6914052f7d0176bb2e607c2fc6a3de7e58c3f63ac54f2122af3a9135d5e58b28918b9c481f9f8b94a76c5b2cb790df5e726a6b4c24dd56809d3ba683941fbe3f4334e62d37990aa4b64efa848404cb090cf98d254f0cc8ef48090a46997c64fe4b129ac84663bfc2b0a25a02bc5898a199643af41cbad18631c5db596048cb1bb89f0ea9243ec8f72ee67a6a95eb751ba7f59ded999f2875ca40082a72b62f9bdec52142562d0a48c50730a940db9613596ebbd359237fea5ad701fb2b68bd64f0fbdc2485a8102444fd321777a6e22f093e15dc23eb158035054681053c2035326135e407681a633370138fc265a7cda97825423b08f7955cff40bf4590b38e482bd388741c17a3d79a40662fb41fd760e15f4b58d540fb66b3ad698365c339d8fc6babfb7d3b039af01a840859f9ac7ede34cca3d9fa2efe8eeb7c804b02225d039aa1db5a18dfbb96445742e08e643d897e3db984bce40167997547657432c88c81005d1eba0a5c2b27bbf2fe3f92dfdd0d59a49a1432d2352e912480b8a76b7618576b6db40a57af5d5bf3f2df7bf01e30f8b823a4b714c39082afc4f2f1ec198586ae3db5d5557fb054ab069680736da45187f264ef8d9a45d4b8d0eb9a54f5f074a9c5b6fd8d82550f290e599e3a73c0eac52dd94dc918ae4b985f6863a5783d764662ce64a0d3eafe619e1ffdaa3faf4a6985dfe6a58f7a132ddf896d9a757349b0a51d10432730111c391d926b96fa605714c7dbb1719d868fb7ef6995d63d4d5619653e865dcff21bc8713e6093daab77f2acf5491a66244d9d46335da8a16f63e2d296e83f540f5e4f574f1a5a1500a20a8190b0bbf60f0b401a4a5c333edd38728866bf26ac44ebaf7f41356c8fd60f1bd60112a0d9715c11c9b271d2b7a3cede68f4a88790c47ae1b027700cc9edc1a9a63f8f63b796e9ff2773d5138bc8d1fc98a84a7624b3cd5d04d6a11d4e55e08ad2f69f1f90cbca0a1db3f53008bb85f155385de4bd312af8920b1c63489525b9e0a97bc5eb54b1ef6173af2950559e9f56b24374a61c96458184ceabc34ac24021c26ba82c3e3687a3d8a8e28ec3aa563c94ac9125ae8b0b9881e071b8c862827970028e55cf0c7821411c824a5c4da44fbdee147c86f943b718387c8232291fc844a89aab8466736296b930fe971d0346527dcc71090ae165c7a8e8edc2c72a9af00d5c3fcd52ba9253ac15132045fd311203339e782c6e54ff26e3a950f2430f74961f554593c7c435ee5a79a0a0bef3bdc347ea7faa6b3e4579adafeff126d6ded61b116d20c2fa9e5b020f71395c4d1efc8f18adae9f5326d52962b0862793fc889d984069631cae5d4295aceea308881579e1c313cd09833d67097c247def9cca36eb72a0e069dfb30ec4e14148196b08fd416de071cbac34895c13b754f354af6aeffcb6d64531e48becab49697177ebe29d550c17f22626d9d073d0c40c5151d99ecf52a51cc47d6c2c2bc2087fd94b8ab3452eb3acdd0a2e091fa3fe7baccb70e69348854504562752cb5489fd65765719108e5f6387f231e72a61f33ad1f50580519f9e6693695c767cc7f0a60a9b6927630e874f7ad8a072ad1ea326c8b65d51b0cf247d83acbc6efde4628581bda8449c5278ba69115c6d0e40531cd19783c34ff963204830cadd81e263062521ce8cd1559bcff6fcd4b331238e8620348b494fd9248ef2f364fa9f836abec7b499685ec7d03287042a8ef3d68292d27fafad43c78d3564ec4415e1549471bb4c93957be34315b81ad020ee257fe8e6f8c6b8f429257bbc91015ff376ef698d4236c7d925aabd87fb8c50c737cfd4dd37791b1c43d7d925dda0af5cef8e5828993dff41d4019e61152b20017f18723d6f8589a72ee6aa61df954b11a094dfee7f8de82b4c6e0b8378cdc20965297622ee78b665df2fc9e0a59e2416d8101aab95a72d5ec8c6bacc46b8b052454bed1b1155e323c778b76cc12c4337a0456479e99cd954ee9b7a610ef2fdd85115c8761e48a15ee0dc75a1c44a0595783ee7a3b3f0be27bd901f1118ffd7967aa98fef47180b3c7314a238223aa468b3acd5c568ea74934fdc10b06f42b18b23d7a425cb4180a5f5e76de3f54064df11ff9cee21403be789639ea2946e88ecc81bcb492adf6d7652a600ca07d614a0916c89eee9348ab1e356e153bc37434e37bc7e581bb797251198ffc955e555ee20ce6118f175166ab25e25cbc847b825f969a66085f745eb64ad7ab1e193a7dadf466c29eff0ded9a9a82323f1d0ab88134ada28d3691e98e90ceeaec3369d466e24526e4eee3255e0266318c2851476b98af959eeacafd88994d597c52afd23d22578876cadbe26026e10753aef97ed889dd436d0e9369bafc8cd50dd0b6090cc3944b81063bbada167cebcab6866fb3b87791b6dff1de3b2aab67397df70c60ebefa9389e741fd5337113a1da0d7ccf733348eb91cf40d0c323baa3f692f9b45881efb66edaf4ea7ac6d88b6a93fb7237f6a9bb43902ccdb2ea3e6a342abfaa5e36d9b685bb1a97f0a2b94a69c674935fad7b38d7702bdff95d3aca3895f3b05c70cf1754cacc5980610f09b6e2cb3e89311638fd4b271805efc7486d2c4f0cf0910598427c66627c74ae12f29b63a7ad778e0aaa38f7b1cc23189603d01891ba26c14e4e96c0f7c86e63c73d8d1098661540b4daf2424c89be4991f07ed284a8765d92c6b52c080bdf62bca1428a018352baa32571d8d36da5653a91415dfe8d0c4aa46ed6766f4c162a05ddbccdf14ca9f84e2d487199467f338e81f3f5058bcd22e96a04119d036de1ceb872ca05954e53c86b85626a44856e5685fe35d8217af87349d24650059e00ec7b80d7c0496950a1c827f443db6933a756723cd529c25d7a93e3be32666bf2d20f533d6b3e1378296cafa3b468a3926e7754781923b12d9701bad179da601a623e25f76731a98e93712415496ea84f88dffd243f7ec9a480cc22358bb6705d46be5807e3aa49019e16f86d0c35af6c6e6f7019cc38f5dee215298ae1319bcf248aed114fdb0a5b342b8d250fdbc3bd5ba21e3232a7655bf424eaed8c810b6b1912fa31e37399a56aa33a9a6a76974175ac96b67c43c1ecfeb5de2b0c7b8d4f29993def838ace907acee23a1a7fb52d53078a4d544c858ba18412f152f9596b31a15107e428c96175b5fd49dafda407a0c86bfc9ff6a44217a635bbe6c672c85156f21ec664465ca9e6b9e2e4636aaf6c7d02a9cc28907f5b84d08b1a0a216c8a8494f165a637f5d4edcd0e272390d8704840cd62846db58c4f4c118f19ae3087d9198a05f8b2b256cbe176bc9604df06bda9b7e49d7ded17a059f32b28e1ed47421f32d425004261ce060a2e6af1b7f583f9d7b6e887103df1c359f9d043fdcf91220c57c438fe37b6e606492850ae87dd6f0fc4339777202464dd8ba10e119775ec36daffcca9aebe2208249ffb7068009612a15fd4ee01fb564b567c7c31a5179f88bd1e71d4bd0771b51651ed98ea4bead8deb759c86b2d705d16f4335457b0c9d3b0e9cff91f8df33f265600bd0cc8e8128918456726dfd3cbd8b8c45b21506dab2c49975e10440a0673bee73c2d757f48ea9e4c8de2c4a6eeb55d3127c78b95c2f13b4b0f66c9ddfaf6d28ca7070a6b713d28e8ecb64d175b2a4e8151323f0f9e1769b4ca1228f7d555ed851aacfd6bb782629e6f38aae70000")).unwrap(); let asset_id = AssetId::from_str("b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23").expect("Valid asset id"); let btc_asset = confidential::Asset::Explicit(asset_id); let btc_value = confidential::Value::Explicit(21_000_000 * 100_000_000); diff --git a/src/blind.rs b/src/blind.rs index b7304784..1ea73bae 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -945,18 +945,18 @@ impl Transaction { /// /// ``` /// # use std::str::FromStr; - /// # use elements::hex::FromHex; + /// # use elements::hex; /// # use elements::encode::deserialize; /// # use elements::secp256k1_zkp; /// # use elements::{confidential, script, Transaction, TxOut, TxOutWitness}; /// # fn body() -> Result<(), Box> { /// let secp = secp256k1_zkp::Secp256k1::new(); - /// let tx: Transaction = deserialize(&Vec::::from_hex( + /// let tx: Transaction = deserialize(&hex::hex!( /// "0200000001014166d8bc73e9f6bf833f6372b021d6e412ae773cdd722467db163ff06d1e1fcb0100000000fdffffff030bbc8258e21ddcfa93f8b13e26675ce0696bab13e48b6e570087d27b8c2e58229108a6dd1a702dc30f897e040004def8dd2e67b7c6567a77b7c4d88e71d837531d76021d91021fab6f42fbae69c1ef0fe51ed088f08f69f9e658c5f702ab8a512334cb160014bea76c13404321e84760d712218e455b559f2ea20b637f6c0c63b8403cb889ee0502f2b4d8f391b8230798e938ea0aff882758f5fc09674f64e8313722b6fda15d4e3be5845a2c8fd7a243312413f026f6dc9541bb6e031465dee3abbf0059ebabf7933cd5bc8725a8e284f9f2868df84dcd78af6e15741600149928d95e500cf680ab923370529b5110b4c6b35501230f4f5d4b7c6fa845806ee4f67713459e1b69e8e60fcee2e4940c7a0d5de1b20100000000000000f900006f000000000002473044022018a96048b7b3d732fe44421655a26c076a84adc9b0d210856734ef52093b0ba8022045f3645b9d9f40a47963f56c5fe599a23079bd14fceaa2432750a235c623485e01210232edc2082acf05281c9ddb1d8e024de805ae65f6547848ea34441c09173bee3000430100012bfbd82937b25fc506c0b016d904d63eb15301c8fabc6e796549f0383cc08c7effd3d398b04e4feb1279f90f7c32d9a87907155514d69f9612b059f6fdf2a62ffd4e10603300000000000000013f2817003c824b0c690dbde0739e2e1263411a92287701d3bcb9917b2562397755e3945a5f0e917e4eb71b9245d225abcb97a43c7c8bae23fe9b389991db5e693937b2dc225072e5177673ba18545a9dcafd1f550501543ca45d11eaabd2769e49bc5a26fbe64eedaf38d56ef5f6d5cbac587c97c9846a6472a0525104dbabf24d34fb3db29244ef5dce6c9b71a12d9bd48bb796f6b4f89c1130e767ea70842402a1d1c1e4fa2ab18db1f407587e2b5ecbfc34c05b5fe5d10ab43fc9fda482ae7b08eb0115e9758b9d14de8f8d567133779a6153411e32456241f149e0731dbc263a5831317bb394a0efbed52cbf121abafce5dcde0949b619dffea3a942e0ce237a4725a865f4d3a7dd18f6c3baceefd2504fe03d898687ed44237e6105a237621a71f68a22d43ade7c59e14ebc5ea93e236f29b7d8cdaf933c8dc2df72dfd4b74c4469ce34a263373c7154ee89a66387bda99794ecfda0ac03298f1be66f60a67202053fcc98eea44839f8f6e5e0aa3657b72bd54a236362222ab91b5bc0abc7bf1b19138dbead02f904e0417b45699fa3699f7c8af319db491b7c0990a119ae0fbb0591e5c1185c50aa6b8a6ee85cbb841bc4fb99164e0b4d0e18fd8f61d41e05af83c4e94091256f27fe2838d8b44c657f0035c11c3c7636f62e0e3b2188faed87daa23b01f690a0712a06f06f464be8b5ae955f3f880f750d01d23c3f6ee7472b1a8508b0b7a200675dd347c14d520e77f7d61dc28e87f63129aeeb15c32fce6fc109ea7582bedef9594685b8290ead0fec8f7a0477babf661c61d7e651b19b46a59b06d92472ff1e30033534acfdc6a23bdd287e0582d3ca45be95436120ebae081c0c81da96d60db6870d02e386e5cf0ceeb0d5d746ab7178f9297c47be7d9fae7b73eda435319ed7865fd3357120645cc46bbb8ab4ff58fbffc3252888ac7e1bf6f61ef113c1823e38494c2344897f31f65374b13b677656b37386d95a66089b2d1c557b6f70d0354fb71a903c530ead4a0199d71052f589be243ccbc890537b9412f2d70a4d9585c8af6af9844f403acc40ff8633bd2232c032fff6538aa45218ecac24eb62a48f852b91dab12efea26f2b96f368fd850da25ba319d09289df0ee8052ebc0e39bb006966cc51757a3bc3da2a7483ccc7b82f4b13fdc5222a72f60bb750ffb469fa1821cff233ce8078676a9c8dc4cbdd89337275af2e51fe5351d7ed81ef62dcd944022da3ae3cc501e777d567217b21e13d8f1cc2cfac2d8494343e3b6ae80cff461ea20a3604bd41b42d2ead953bdbd75170c7129139724a6669ae77ac234370625a9533168bc1cad48839ef2abe517d2955d75b5d573e6b6e52e5342d9b6d9e2ed5413bd2cb8190fbbfa22a090da3eb462a886e2c2fbc076fc47c8778d3d10b15b7afdc2fd8886b4f85a565c2f517005b125df57a444a4d2528b7d3ac67a56454fdb2fc764f29d6e9fa8ec0bfb78f562ed9331d24f541c03a51628a932457e0287189ea36a35be4d01577e7a2a766f2081366840780abfd2aff20a9d4cc826fd751fbb0e7b353d518a3cd90bd61e694a7645a7859e21532d8f9759d32804c3341e41164f8815a38411484f4b394db6a8150591faa9d37cc76e812fc2b6cfb1e605d91552a31fe88b9d18cbbc7d2e558db74987564209ce126241c38a80da1df34db585a9d7a1330080cb16fdaf9ec1c37f309a8a0e2e7748ede59e7910b8b6b5caee51532ee6c5bd851db455c150b8d90445a36fbac9858798d73abf605dd0f515c23a0f975d50d09e6d7f541f0250c23c414219c87b15929ada1974a71709809db49ad8cab72958c31b1ddd0064d264641327a433d748713c57bc0063ec45b852a9beb2cc2be7465bd48b3d113ecf3d4981f2e3ddc7494714d21b860eb336ab91e894af0a5ff727f2b8d85c12f7ed321c90038e8f26f544c4918562b7c65e7cc1cecd5c6961ea2d1f806268d1dca92337f127a03c2626fcac5b8caf0a7abc3a6cc4d362f040572b56c5ad09e0dfd92235dbb2c1a8fbccdee13b2cf55681ec8f053575214c9200bee18428b25440b220079ca8708d23c84927103a8afac4bee58b95cce012ea23b175bd2a12636afc07e649675568ef945d352402f222fa62dcbad7f9f0dae132c089aea82d4c8b905655943e8b61f55475b3c3755d5967b01236e2c4b833ff6945031b50f0a68f0ec7130055761f8e9c2ebb2c9462d0b8aa9e99c7ebed1d3213abc471bbd49f44e78e057c750590f3ac02d3baa776d9f9ef39bc1a166dd7cb1cc3e63d94d7bb51544b9b02ad1278f7691973030612534ff513d2cf7988b3235b4449976b90fa5932639bafb7d0d33b58a167617ab4a46189e251bd488cc36a4b40968aa34c20a80f3ee5380152b7dd62de83c1e2a07307861b3713506115c1021880c19f89f45e40a16cebfc1980ebbab7bb9288eb33d4696c39bedada35a41f9e6832a0f5e12f2968303533c8186cc09da7c3ce4e96410f7a9bc5941706fd513a908ace16cd3605c5d0f4b872e931d79361134371285b6d223e1601ad129daa776ab58cb4dc7eaddd45cbf722d4cc4229d75a52e18c7470ed1a7a84671bd8bca4b9bdb0d7b0a34779d1a538fad3b6e2d7cc2972ab1bb98613b8ecc27f9fc25fd797aca4e5d0de4aa6df7f6607ad268baea41f3c1f9afc9dc5da929b29e4ac203a7476fe2c185ac25b835b6f2037c3f540852bfd2d643c179e0951cebc35743f6315a56d2965de934695ef5dbae70924f8548a858518340d7add64f45d2c7b69bfdbb8fb640a2284619fa857d2f5f8bbf615822e45b924622d32e78caedead8ab69fdfe142c97d7fb61af8cd32767d1006c6331d316e0e66b112a765388ff027eecd1181913ef9c701f2a46d0bf35abcaa3fe0cd26863e3d65ded79b262d1e914c538ae7d05ab30390465ba25a73a6ab53ce4296a3f5cbfd3901cca44bdd6818fa8d427ab2ceddc315f0adcd3fcae63074ea9e42f15fa02f1e3ec6276adc953beaadbce84ca6ef04966c882e3e7802436e4042fa5be4c3773d685bed66eec0c5a6cc463770c00740fef403badedadd28984e22027b38a0c66b7a409080adea574cb95ca236d701751056f7ea1e1b3082f0a26acbc630526053be88bd88267e23c2787daef884d709a5ac2c118c8c8b4b1eb6cd9d829ec42d9f249f754cf93b6c4cfdcf99cec0f9d742af36300274df095a35efa8ba95d412d2e61db8776660882519d4500f615e6a3e88640e93e921dc1fc4b74b5776cfdd47eb8b00d422fb0ee5c889c419bd352cef4573dab05fe44abd39bb7014e4ad0af6e5c9ed8236edb16d05057a6794ee76e923b6d1bef5e17e7078f6696af0f23064b1a592e89ff7073f040e9ea236450fa8d8fad6d04606b1a1a407ea14868b0c81c76c0f5fe9047e9c60dd150f9164533a7e4cbcc87f5c58e9e9ce317ce694cdd816b45fc497ec5c66736050ba925fa7ec598274f23a4ff022e7970dc520e4baefb30a26a5464fd5c75906e88a2c245cfcf00807c3b5e0deeb463886d606bfe7f30b73a512c5488f7c586dbcecd03ecc6cfc3caef921930aa01d2ca21ae3acfe5af26003acd436c344f80a4a9d9371a51b5b19b984d12b2a134f2ed89a6c5cf9905b2626d926bee7fd39988282411a0ea0ec1b61c22eceee21cd264c1fede96d9460cddc0624c9e22ccf42ff18bb13f8686bd6ef528aeda6181647a1c6c6ebd90fe05a69cbf169a971ae616d9d74840f1a7a3cc48c7a27b07a14e58bace67aa61dc594f0dc909283fc39c77a5dfadd50a358fc2c05118cb6197f3aba31d75fe2681219bff02e70f6d968f99d59a6c80a2af8bc09c21a2874ecfa47850844221fe066a1e6b40c0c5c4b59f8a8c22b78419c77be2306a9e085a76dbf9552ac9a575b872df0f9834f7aa8d89d585ec34ddb7c1d76c6d132356679263c8458a288c95f36631ca460ef925fdd9801154f886beae75dfb5e794ee58813cd1748e932e279ad65a3e2e894d190e221f07207d6ab5d2c7e328661746bc12e72d6075eb2a4e1f91a3b27d3309f9825d2467aef6f5236c38b071e5a6d17e3a7a88033a3ddb756e7aceb2c7d4fcca92a077a110684337fd8222f9c38e806554d30d9c3fcb647faa000f72adcc8e1d6c811634757a74b4d52f9e47826319f3954756d0623149a9f62f838feb135b1d26fe00e299a96dd94106fd39c9aa14360792870f33b8cde870e98353b27c1bbff569b79ef1d5f0161a4b585f4002b42c970b3e84912bf707c8d49fe56adfca407f8a039314a5c0720060061ace5a8144224bf52d5458e1fff84306c2c88b86061e18116a8b46cfb2adb6b33f704ae6d83aa2aac13bcd61b64c93cb6d2d5c3acc990626f891f9b7befa0f25c1a2665290309add936ff62d4fd182d68adeafb49f75fea798d8572444253886bc936589bda972b5e5625db267de1b30a8501ef215ab8a320574ce27a33fe603a67656ed8744f048b022cd61c132ece087fa0d94c2d4dfbb92a46ea5403341df3896ac49932955c6b3d700bc475c9d173c6173c8d883bd9499aede17e7840294334f1b0585b66f00e121ca298933703951801584c5db57854ef87802d254fc75d31319b8560f5ebee2ea80ffefa63e2a4c4e3d53b007ca18f83539f3078b2736f4fb4f8fff41823912227b04bab8aeeb7d95eb0db3dda58a98077f25e1db6dd454cfcd41068dcfb54f1d1e0b478013e58ca7efe874e98205d7c59ceeeb28cdd55cab4fa3a01ebaa957effe330364f75c0d6728b769dad34e58e9f217d1e8e96d79d896c193b425236ef2303eed072d114c06c198fd6a12a28f4d436dd126d1ab98c7e1621e0f59cc7276dbe7cf267ce2c6c0ed164deb57039fc5be8ae4e72efe26115e0fd59ae6fed9743eebbea873fca30c9d7eda201e73fe22e509b11c19580d368bca3f4cc59b949c8d03fa63e7b2b79f39983235d7ea3fc6fc92fab4c66a7680ec57f998fd818db6fa88ac2913f4a48a4cfbf68f1f565f799a6a95a22c8f6a4d6ba2a5307e51c99d22bcdb399520306446a6804f7cccff394986341187c4a72813392984e57ce3cab06c540722e25be50ba138ca0a54686c8960e2f6118380b3b9255d14071b1e2131d6cda16eb463bc4642cc11391a7c8a75a6da8c5f1424f7752ca3dbd37f2d9a2a3855f3b3aa7104c7a5be0c334df618dd478c43b9bb0fe7d774e93cbc8323816e1f0e1290e52079009150761207d99b1ec995ec7897a0385513abb96ec5f9d2c757662cd946d8e340646944b5fc6cf92f606ed2bd6872fe89c1cdabfa7f755b27dadce1337a18ecad4b78c0291f34e1cf0577eab17c70b05eea58bfb7bb3cdb46d46507db8fe8cbe3dca07d92d1ea2c5a6e354cabba8d532a47f6d9ba6ca48add4df8bf8ebbf3ccf8b0417f4b90756faf134ee210511d40314f218f9902897390fb0f405eabfc4a7ed4467e4fd14edd3ce4ee0337a5f0c21590816126768d5a85d67c8a7ef6b07c8d40dd13978cecbbfff0507d6030167e01bfbcb3557610ebad49f2f98cd9e003d3fe0a4dbc64d4202d4260ece552b7f7dad2be1dc61e3e7fbd5ae5be1f9bc0599807727c1e30eaa6d80ce79bc6d5a28c5c3efb8c1e99ffadde8ba7f42c2f27e3fbadec5b13e8673256b2aea4ea1a7b92d909ac4fd06fc3f03098cff0667224949eb1fc242ee42da5a9a06d93c5c4896e3c54e8815602d2a42c4bcad7a597e9261d24a404ba0f4645eb68f0521b7eb73d7b26ce2f802ba54674d011c07c485c1f7b6e31197c40a39c53e94cbd0b3de605c76ec9d7272a53ea5547b2131da2b51b2b0c099bc93214f02c2469c396dbc6fda284126d7d069fc3d51750037e545cf2ffe35b308d1c515870bf0fb062c2c666367061430100011850912d035bb6962d10e126e5a9666eb4128d7fefc4a0633ba0f388c5f28302a7a2e02653aebda6a6bad0cbdd972b57201a14a7f879c480fe5e1c36db90f749fd4e1060330000000000000001bdbe9301cb099b5fb8baac78310a3529d6677700658a6a87eb00a5f66dceb0862dc11cdcf845e07ba63ea84308200d309ffc3211996c507208560b7f65fa70f0a176dd0cb179ca911797c66d6fb56d27728a4fcc9998919a89c52d8bded3f732a5360861a6639c839f39503ea1457ae5d4ff7e1811ac2d33047823c5c118768343620abe7fd8cf459e5fca0f490ed91d9c09b37303662c201fff61247e8fefed8ffb29f999cddf601670469de151617021352c0dfe54512bc44c3b8e1a4ece73d2eaa727b28093d4741bd01dba0d9c7a4cb69e8a63bf6e887fcf6a57812ae40fd829dcfb6bab3a2a4ac678418e15179613f2436f53ae806ecb8f44115847b16cf935efadee467aa6de4a0cccaf8e4b1835b8dd1f9d04f0bbd4b3164dbc58a3a10db4537c94bafeb0289c6a192b28d5ba48df580a44a0d044ba82140295bfae70214127b73c7efac419bccaa75716867bc0bc75171e54dc3c439635d832cd052c4e9fa7370b1794b3da8a1a740b50cbcc605dc840f4d996f1283018a6356c437e79218a191ec68a48b193d3560b690d44741b354b13320ea16286405dc6476e8e8231d667978ef9c36e84f09e74387b4d557e39a40f51a62f70b5be58415c256f262486fd144489de4b8605a0d53945ed08daf543f3fac38888dcd4650903b95ebfcb4e0f57ca89b3f0132400e4012e00854c41b2788bd7c0d5d40845f48571d954e12013f6cf7ece536f32ff9a3c94ed10f1a2fd50b3f38a0f1272489d583deec9da33d9ac46914efea240aa004a8f17e1e168136b4ada57309b91e10c716eae0a5789c64747c0e09a696b67e8c7bba12c2b8d80248da93acfc7c1455a33b40f8761fd37812e74e572a9a21b0e2d7bc37ccad146d847a53d7a650122d96d00b179e353db2864e5ec929173550e0edf2c02b2ccb595b326582758d700009f4c433cf86837d1070686a6eeee6f4ab1e6ffc44bda783d7e2ff81f289991cdf982b61a73660020e544e5897c3021a446c8a4966ca625bbd6bfdc505e85d1f5acc663607cc2ba18945b74662be550b215878b35d9932f11cbe509456461ffa2b3bad33405f51c5b17b5081bbb4874c2656e0efecb2647d22028e53f263401e779e92ea3f70c860b0405e8109e10e27c2f4986e66965f4ddb895b943ba4dd0315372ac0460f78ec408cd562c21537d7f0f5e12c95e3d86066db77390b02e9073e241aa97af7588bbd6fa967a6776a3e226c0e56936fccae5ecd8aa20af1cc9b74a4579d8bd4fba988438fe455da8261f9aa96bf222e5af2fe297ce1901f0845334e856fa928119e23cc64f5ac541c699befad140a3e2cf53f591112d1ae57391eecf6fb729654fa98ba946ba8a532c3cb8b0dad5f08e3158f128cb065379b2ffc78d8394e5d2f1c7f4fa7b8a5031a7053f0144835e7ef53f4d60c8953bfde31e75fa3ab6bab86bc37617585db21f16318902138c1a7c25db16c212bef0de8aed1575e1c8e1064755b4b493adaec2dd320f8f8b9a240352f7a8a409ff3ac3beaf08114ba7294502f8f0f529e039ac7cda8a9d8e45b9aeb4e7a83d2de5a4edcb363a15020a5d285cf6acc3f43dfa724fd6c8ce76c33d485db88cdf379faaa7a0eb65f52c99daf2fb0edd8eed2e38e2990b044bb4ab7cda75d23b04fb72e842b54d88ed8a7ed236f61ce58e7a7fc34aa94e9100157cda06dcf81722058369df2b912442ea0768383b7c673f239a7f56dd4ec8739cd14698000747b979f22852e72352b0287fe7c0bddb68bd494341a0cbbd0df4fec1d613f7160f8fae32b9009c4d7146a8004a158763efea270c6724d022bd3d5954789e2ebcb50663b98a619182d800263485faee5e621d99f6819068f6d032aba95f7294aa6bb297f93fbd0e1def781351fe5ed7330ffb203d48aef9c6e6af244cca568dd164226131343f37977f11a770bea7f40e8b0593f5efd23ca0ff18594512004a9a34582de5ecfe06519f6223b5576ba1492d817e6da30791abfd2f4e85d235fc16f43ffa1879afd6f3c3aa252a232d567502dbdd70005997da48f8a0c64911af8ba5e8c123a3e81247de4a536ef41330d345c2681e1a508e4accee45140a194a1eedbe6559e67a9daa34580f00166db39d3f6e92d0b996754bb1d8cd3d68d692b872a0e9b086c14c1d143e03ffe5279a6687e5fe139534e59d43e2204ad9794a38a3d9cc9e63245c89123977e66dde7e33800f62a9ab3aa725b09670cbd58890056d62b459473ecdcca375d4784f278042fecd626c635414ed1ed1a1e2cec075d1a495004debb13df0c61e0bfc2f10ac84d94c404400559c6b4209fcc4fd0f4e041fc5101fa8265478fb794e7c008af8172d267e495d314d65b9dc1dc3ede3be27e4c80840ee7b75c31355bb4c940049bb0e02234370a2cd009753983409d87604ff5bd2d179061f9629be6663ffad62e3aed59de373892140475cf491a6482da6d9a1cc1031b4fce7737accce613a01fccaf36f0ac6fe1323828f3cf2a3e8c64cd0f95916c3db7176200e8f6384e6527f8020a761c0e46d388c4c1424118a69afc6bc5884d9ca3a19b5a65f95d3cc476b1f8e1c7bd41969b0f42d6b121816c1f3ebcff888c0c93d582d6f9b1bb5acc1cbdef4db323585ee059b4a68b37dd6ec85fa3a7bdc0ff7cd5e903cc76bc6a30b7965132e551bd5ac1c11ef069da69064086baa14435a9492444619dc3df5466bfb2cda341ff630d767ab55ec2bec5f92fa0e23cd8b4a5386c85cf540fdc4a15e9a27f7ea48c29d92a58c738eb2133005ab4b787d849acca740d58d258e5fe32dac3f2499773ffe3b362cb384632a8f24b9380c1ec1566108052ac157691ccdfe8ee497c57fcb8db7799ff2688288f07dcd7af020e3b21ce8ce9a730fa23f88fe2ade8291a439fd3b5769ff98284e042a1d795b1920b10cf755d3073a7a8e7f9b78b62baea353b77fc4be39caf38c709ad8c548432a7ed102e114f44b0ff22c7c04d4299f9d47bd81172385ddb1e5c9019809968a7638bde0b766d63514f85b22b1a795fb97b9c367b9693299c7447630e333265faf35ea516247d1d1ef7f9ded1219f9cba746100cbf6470becbe5e73fb817e7979bd1d502e9b7ab62bd70a70115cf3f9eee4e7ba131040a4baf9139e7bc6968b0053075f75afc787e2a083caff88d5b627d81d5e8584bb30334211866dceb96a2f03db6734e5a8cd28d4000119a55e32ac45dc38080c5fa05200e0054bea35713648f17634b6954b7be38e38fb29c3f5251f33c3f6531855f393fad9568b3f3ee02fdcf02f2172de1f8007a479d235091c4c39b76941bcf563b46e32248f9adbbb247bc62d552c5444ffdbd0cebf3e5a08212400cd7155236c21a410bb1dc9aca0f82b438c5e1d2c1632c577801ca18d30371e39efd3135092d008e290dba376f799a85dbfa317e9490bf2ee52444567ef8f74c5350e69331c03d51ddc8151822656cf7bbc054dcf9a5166a2bc72b01c5778c4c8f3076343ec1a6f7f3380d3e19bde7c248b23789bc724af6fe17c2173b0c204ff8b6342e5c9bd8f652ff0c80077fce0ce258b0879c74986f5d51e59eae4b946de1e2b785f039ef9bde314753011e35dd9ab9278fd95e4b10f04b4a157a16a6de9ba5a1793a4be0f2e2fd3cf2fd9366b2b7cd358f7a9a9397899833839c8bc968c5c37660488cf391637702de780b5ac526ab11fc895a5c783931dd0d486cc7672f417ceb30914b8f6fc51d270c932c81c7fda22b2b88ff14f7c9285f6341053fc529aefc97755fc5962a5e094b10291b98c991b0bee8c28b639f642bbcbd7c27d9217c19e11a94ecd58bc79c220feb9f1799f952e8a31b9607bb9fc4ababb8515aed1112050e0a75cb5c7811a63b90eafe411e92f2864fdbc4f23ac3c335d300440f9b6c0e7402a825fd5f4eb32ccb76ae4ef43441282356cac29b0147f780252427c9d21abdf7306c9f2836f599cef0a2c2eb4596df9498d661bcf8bcc88d5a7f0779489f9423ad045b735e421ba0f861744beecb7c1efcb5989386e9c2e4e07ef033ce75d5e3ae6b78775cbb3d5ad8fa5b29ee2137f6b59f865c71af63ac98c2f0cecaec428c773a747ba188f8f3dc30ede05077b422a920a313b885c31d247328c691f66a7440bb27581baea7d9365f8da23bf71a7cbbca02c74391928daf1f6b2b0f74acd3b89ad53e3dc87aa2716a25c89c4a6f1a363cbd97745910e399cfa766ddc5b25fe4f40412690316acab688493a1c882ccabf7ba2b1496f77ba6a34133b3a6d9f5c6526309f1d2e14c261959dae012420bf9fa0aa2b3e3862308f6c6f65e7f0660eed3b5fbf3278eb5b2893b1c8dbef827e7bee0fa92fad9393f037c4b90babf62a159e2637f22a46a18bee1baf9c4c3344186083b167de5936437a5fb379ae305e8a502fc22f849398daa9547c8f6c2554d231daba90a5f729069c24bdb2b749cd1a16489f7c0940a59ba7f324dcb2c42e47652179208bfff6d64a1ac5e557a34321a4c3bda6eae6f461e1a6ecc9cee9fbf36e2b6c504ae2e0a3bd03235fb6032725280d64fa1a33f58a7196b56c0a65dc7bbf0a429889d0ee2467796515f857800c78fe21bd17f65807342a7f4a0a7926d064f073d1a7dc76295b9e35195b7880fd83db7e2335709179cca4f285b0b14693fd0b6cef9958cc6906adacdf1ad1b572eaf9e6ef42b574d75a1f58927d49113726572b40bd792b6ca621daa7c5f56645b1f8ed5b0a7ac26f71c4c665b89b975b3c38ed6949271df097c8018e772b2a3f8bba41424bd9c1b06e111cfdedbac883dbdc5345e5a6aec531c722c94b0c6b072288b706afe77a6e179fd38c7f6a0051246f0b161d0a5c696374755b01822181bd843ee8d4f476ef5bf3efbf9cae0f3162ee5de88c0aeafcb3b5fb34a7edaad5292428a612eeea80a54c0dc3ac1ac7b00f103aa39015a038d4537271bdc277e4a8f8648797b6a67cebb7485625406f9963d17b51d1f4706674e58da1b5e4c415eb403791c72a62a2e6a5a4cf50d26fe78d7e9620c50f718dbd0d075efccbeb8b731f8b1ecc988f2b38dce9cda9a644441391728a47ccd8975dac442c39f59726802474ec44a45afb5e545512e8f069e139da079c6e0bafce31f30bef474bb2deeeb6a035ab37757b02d6f4de3ff85a0cd5109290259c1be2a8288a33dcad5518d9d0413a393f659095beef0572193af15d909acbff828b56adba008a3fdb653ee5fcb5653884ef69d8f8f6588b2b46a3dd361dd4983d205d22f9351f4ebc049f867832b35181a70f390158a2960fc9bc2551e23925f2c9a262b7b9e9da6c97f35e5ba21986f5cface9e8d829751921a9e6fdfbe084197a97a778c795c0a9e293c7a07033ac2a34e0f27ca53b4cc7833fc7682c0da1f5784e812e4223933dc2b4b20f77c4d01c40c4f7db5a556ad3de59605e45c02928f5b8a7720eb83f750c9789b062826bfc895ee526f0c813d3a3bdc3a6a03c27c9f3eeaec747bfa72c19da03af860ea21986df7c0509575c2b7f47f036758d9777e6843f620084bafac9c6a2f7910f703c8dff42c9f160a15d852cc4bf2f33b1b53c392959e804d34a3b56c1bf47a4813c7d67d36e66859b1eeb8f105c79aadab1cd2ea927cb9cc48a70da61241b5e3d3a5802c3ba003e7d318628f6a6a37725b6fc721899b30c9dd2b3d6f18d70df0f363ddac2fd3cc79fdde2ac26ccf16462534ba1a8d1baea51b789bc00226febe51678af19898e4f4456f072e5d79345323f8231b085b94419dd812bfae12c4defd363fa4baf09c4ceac1d543365ab52f230925f56840efff264b3b8e961c8aa8e62a8f3df6f204331a1dc08375c6521ebede7a0eaa92d378830d11a989681bd6e07b7a870195f4c2fb579a800000" - /// ).unwrap()).unwrap(); - /// let conf_asset : confidential::Asset = deserialize(&Vec::::from_hex("0b37d4818b8ce1df5d3d0b88d140c6848029d6d85fb0f6ee270865caf53d0b82d4").unwrap()).unwrap(); - /// let conf_value : confidential::Value = deserialize(&Vec::::from_hex("094e2cceeb8005ac14b611821c37fca757b47426afb0bb4eabe41c275d3997c046").unwrap()).unwrap(); - /// let spk : script::Script = deserialize(&Vec::::from_hex("16001475f578ed4f7a0103182a6e92942c66350dd949dc").unwrap()).unwrap(); + /// )).unwrap(); + /// let conf_asset : confidential::Asset = deserialize(&hex::hex!("0b37d4818b8ce1df5d3d0b88d140c6848029d6d85fb0f6ee270865caf53d0b82d4")).unwrap(); + /// let conf_value : confidential::Value = deserialize(&hex::hex!("094e2cceeb8005ac14b611821c37fca757b47426afb0bb4eabe41c275d3997c046")).unwrap(); + /// let spk : script::Script = deserialize(&hex::hex!("16001475f578ed4f7a0103182a6e92942c66350dd949dc")).unwrap(); /// /// let txout = TxOut { /// asset: conf_asset, diff --git a/src/lib.rs b/src/lib.rs index f90057ef..f64341b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,8 @@ mod error; mod ext; mod fast_merkle_root; pub mod hash_types; -pub mod hex; +pub use hex_conservative as hex; +//pub mod hex; pub mod issuance; pub mod locktime; pub mod opcodes; From 44a6974082031652ead21cfb1d88d09a9b8fb8da Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 9 May 2026 17:36:29 +0000 Subject: [PATCH 10/10] rename hex_conservative to hex, re-export it, delete old hex module Tada! --- Cargo.toml | 2 +- src/blind.rs | 1 - src/block.rs | 1 - src/confidential.rs | 11 +- src/dynafed.rs | 3 +- src/encode.rs | 4 +- src/hex.rs | 323 ------------------------------------------ src/lib.rs | 4 +- src/pset/elip100.rs | 3 +- src/pset/elip102.rs | 3 +- src/pset/mod.rs | 3 +- src/pset/raw.rs | 2 +- src/pset/serialize.rs | 2 +- src/script.rs | 9 +- src/serde_utils.rs | 6 +- src/sighash.rs | 1 - src/transaction.rs | 1 - 17 files changed, 22 insertions(+), 357 deletions(-) delete mode 100644 src/hex.rs diff --git a/Cargo.toml b/Cargo.toml index 35ea72e4..9108dd36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ serde_json = { version = "1.0", optional = true } actual-serde = { package = "serde", version = "1.0.103", features = [ "derive", ], optional = true } -hex-conservative = "1.1.0" +hex = { package = "hex-conservative", version = "1.1.0" } [target.wasm32-unknown-unknown.dev-dependencies] diff --git a/src/blind.rs b/src/blind.rs index 1ea73bae..bd611259 100644 --- a/src/blind.rs +++ b/src/blind.rs @@ -1380,7 +1380,6 @@ mod tests { use crate::encode::deserialize; use crate::Script; use bitcoin::{PrivateKey, PublicKey}; - use hex_conservative as hex; use rand::thread_rng; use secp256k1_zkp::SECP256K1; use std::str::FromStr; diff --git a/src/block.rs b/src/block.rs index a51052fc..0b72b69e 100644 --- a/src/block.rs +++ b/src/block.rs @@ -395,7 +395,6 @@ impl Block { #[cfg(test)] mod tests { use crate::Block; - use hex_conservative as hex; use super::*; diff --git a/src/confidential.rs b/src/confidential.rs index 0b5d2e02..91d692ad 100644 --- a/src/confidential.rs +++ b/src/confidential.rs @@ -18,7 +18,6 @@ //! use crate::hashes::{sha256d, Hash}; -use hex_conservative as hex; use secp256k1_zkp::{self, CommitmentSecrets, Generator, PedersenCommitment, PublicKey, Secp256k1, SecretKey, Signing, Tweak, ZERO_TWEAK, compute_adaptive_blinding_factor, @@ -724,7 +723,7 @@ impl<'de> Deserialize<'de> for Nonce { #[derive(Debug, Clone, PartialEq, Eq)] pub enum TweakHexDecodeError { /// Invalid hexadecimal string. - InvalidHex(hex_conservative::DecodeFixedLengthBytesError), + InvalidHex(hex::DecodeFixedLengthBytesError), /// Invalid tweak after decoding hexadecimal string. InvalidTweak(secp256k1_zkp::Error), } @@ -743,8 +742,8 @@ impl fmt::Display for TweakHexDecodeError { } #[doc(hidden)] -impl From for TweakHexDecodeError { - fn from(err: hex_conservative::DecodeFixedLengthBytesError) -> Self { +impl From for TweakHexDecodeError { + fn from(err: hex::DecodeFixedLengthBytesError) -> Self { TweakHexDecodeError::InvalidHex(err) } } @@ -821,7 +820,7 @@ impl str::FromStr for AssetBlindingFactor { type Err = encode::Error; fn from_str(s: &str) -> Result { - let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?; + let mut slice: [u8; 32] = hex::decode_to_array(s)?; slice.reverse(); let inner = Tweak::from_inner(slice)?; @@ -1017,7 +1016,7 @@ impl str::FromStr for ValueBlindingFactor { type Err = encode::Error; fn from_str(s: &str) -> Result { - let mut slice: [u8; 32] = hex_conservative::decode_to_array(s)?; + let mut slice: [u8; 32] = hex::decode_to_array(s)?; slice.reverse(); let inner = Tweak::from_inner(slice)?; diff --git a/src/dynafed.rs b/src/dynafed.rs index d2edba96..9316eca6 100644 --- a/src/dynafed.rs +++ b/src/dynafed.rs @@ -16,7 +16,7 @@ use std::{fmt, io}; -use hex_conservative::DisplayHex as _; +use hex::DisplayHex as _; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] @@ -459,7 +459,6 @@ impl<'de> Deserialize<'de> for Params { } fn visit_str(self, v: &str) -> Result { - use hex_conservative as hex; Ok(HexBytes(hex::decode_to_vec(v).map_err(E::custom)?)) } diff --git a/src/encode.rs b/src/encode.rs index 7f874e22..d140eef2 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -19,7 +19,7 @@ use std::io::Cursor; use std::{any, error, fmt, io, mem}; use bitcoin::ScriptBuf; -use hex_conservative::{DecodeFixedLengthBytesError, DecodeVariableLengthBytesError}; +use hex::{DecodeFixedLengthBytesError, DecodeVariableLengthBytesError}; use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak}; use crate::hashes::{sha256, Hash}; @@ -174,7 +174,7 @@ pub fn serialize(data: &T) -> Vec { /// Encode an object into a hex-encoded string pub fn serialize_hex(data: &T) -> String { - hex_conservative::DisplayHex::to_lower_hex_string(&serialize(data)[..]) + hex::DisplayHex::to_lower_hex_string(&serialize(data)[..]) } /// Deserialize an object from a vector, will error if said deserialization diff --git a/src/hex.rs b/src/hex.rs deleted file mode 100644 index 6384c7e3..00000000 --- a/src/hex.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Rust Elements Library -// Written in 2023 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Hex Encoding and Decoding - -// The rust-bitcoin hex stury is such a mess right now that the most -// straightforward thing is to just reimplement everything here. -// -// This is a copy/paste of the bitcoin_hashes hex module, with the -// std/alloc feature gates, and the benchmarks, removed. -// - -use std::{fmt, io, str}; - -use hex_conservative::{decode_to_vec, DecodeVariableLengthBytesError}; - -/// Trait for objects that can be serialized as hex strings. -pub trait ToHex { - /// Converts to a hexadecimal representation of the object. - fn to_hex(&self) -> String; -} - -/// Trait for objects that can be deserialized from hex strings. -pub trait FromHex: Sized { - /// Error returned by [`FromHex::from_hex`], may differ depending - /// on whether `Self` is fixed size of variable length. - type Err; - - /// Produces an object from a hex string. - fn from_hex(s: &str) -> Result; -} - -impl ToHex for T { - /// Outputs the hash in hexadecimal form. - fn to_hex(&self) -> String { - format!("{:x}", self) - } -} - -/// Outputs hex into an object implementing `fmt::Write`. -/// -/// This is usually more efficient than going through a `String` using [`ToHex`]. -pub fn format_hex(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { - let prec = f.precision().unwrap_or(2 * data.len()); - let width = f.width().unwrap_or(2 * data.len()); - for _ in (2 * data.len())..width { - f.write_str("0")?; - } - for ch in data.iter().take(prec / 2) { - write!(f, "{:02x}", *ch)?; - } - if prec < 2 * data.len() && prec % 2 == 1 { - write!(f, "{:x}", data[prec / 2] / 16)?; - } - Ok(()) -} - -/// Outputs hex in reverse order. -/// -/// Used for `sha256d::Hash` whose standard hex encoding has the bytes reversed. -pub fn format_hex_reverse(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { - let prec = f.precision().unwrap_or(2 * data.len()); - let width = f.width().unwrap_or(2 * data.len()); - for _ in (2 * data.len())..width { - f.write_str("0")?; - } - for ch in data.iter().rev().take(prec / 2) { - write!(f, "{:02x}", *ch)?; - } - if prec < 2 * data.len() && prec % 2 == 1 { - write!(f, "{:x}", data[data.len() - 1 - prec / 2] / 16)?; - } - Ok(()) -} - -impl ToHex for [u8] { - fn to_hex(&self) -> String { - use core::fmt::Write; - let mut ret = String::with_capacity(2 * self.len()); - for ch in self { - write!(ret, "{:02x}", ch).expect("writing to string"); - } - ret - } -} - -/// A struct implementing [`io::Write`] that converts what's written to it into -/// a hex String. -/// -/// If you already have the data to be converted in a `Vec` use [`ToHex`] -/// but if you have an encodable object, by using this you avoid the -/// serialization to `Vec` by going directly to `String`. -/// -/// Note that to achieve better performance than [`ToHex`] the struct must be -/// created with the right `capacity` of the final hex string so that the inner -/// `String` doesn't re-allocate. -pub struct HexWriter(String); - -impl HexWriter { - /// Creates a new [`HexWriter`] with the `capacity` of the inner `String` - /// that will contain final hex value. - pub fn new(capacity: usize) -> Self { - HexWriter(String::with_capacity(capacity)) - } - - /// Returns the resulting hex string. - pub fn result(self) -> String { - self.0 - } -} - -impl io::Write for HexWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - use core::fmt::Write; - for ch in buf { - write!(self.0, "{:02x}", ch).expect("writing to string"); - } - Ok(buf.len()) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl FromHex for Vec { - type Err = DecodeVariableLengthBytesError; - - fn from_hex(s: &str) -> Result { - decode_to_vec(s) - } -} - -macro_rules! impl_fromhex_array { - ($len:expr) => { - impl FromHex for [u8; $len] { - type Err = hex_conservative::DecodeFixedLengthBytesError; - - fn from_hex(s: &str) -> Result { - hex_conservative::decode_to_array(s) - } - } - } -} - -impl_fromhex_array!(2); -impl_fromhex_array!(4); -impl_fromhex_array!(6); -impl_fromhex_array!(8); -impl_fromhex_array!(10); -impl_fromhex_array!(12); -impl_fromhex_array!(14); -impl_fromhex_array!(16); -impl_fromhex_array!(20); -impl_fromhex_array!(24); -impl_fromhex_array!(28); -impl_fromhex_array!(32); -impl_fromhex_array!(33); -impl_fromhex_array!(64); -impl_fromhex_array!(65); -impl_fromhex_array!(128); -impl_fromhex_array!(256); -impl_fromhex_array!(384); -impl_fromhex_array!(512); - -#[cfg(test)] -mod tests { - use hex_conservative::DecodeFixedLengthBytesError; - - use super::*; - - use core::fmt; - use std::io::Write; - - #[test] - fn hex_roundtrip() { - let expected = "0123456789abcdef"; - let expected_up = "0123456789ABCDEF"; - - let parse: Vec = FromHex::from_hex(expected).expect("parse lowercase string"); - assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); - let ser = parse.to_hex(); - assert_eq!(ser, expected); - - let parse: Vec = FromHex::from_hex(expected_up).expect("parse uppercase string"); - assert_eq!(parse, vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); - let ser = parse.to_hex(); - assert_eq!(ser, expected); - - let parse: [u8; 8] = FromHex::from_hex(expected_up).expect("parse uppercase string"); - assert_eq!(parse, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); - let ser = parse.to_hex(); - assert_eq!(ser, expected); - } - - #[test] - fn hex_truncate() { - struct HexBytes(Vec); - impl fmt::LowerHex for HexBytes { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_hex(&self.0, f) - } - } - - let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - - assert_eq!( - format!("{:x}", bytes), - "0102030405060708090a" - ); - - for i in 0..20 { - assert_eq!( - format!("{:.prec$x}", bytes, prec = i), - &"0102030405060708090a"[0..i] - ); - } - - assert_eq!( - format!("{:25x}", bytes), - "000000102030405060708090a" - ); - assert_eq!( - format!("{:26x}", bytes), - "0000000102030405060708090a" - ); - } - - #[test] - fn hex_truncate_rev() { - struct HexBytes(Vec); - impl fmt::LowerHex for HexBytes { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - format_hex_reverse(&self.0, f) - } - } - - let bytes = HexBytes(vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - - assert_eq!( - format!("{:x}", bytes), - "0a090807060504030201" - ); - - for i in 0..20 { - assert_eq!( - format!("{:.prec$x}", bytes, prec = i), - &"0a090807060504030201"[0..i] - ); - } - - assert_eq!( - format!("{:25x}", bytes), - "000000a090807060504030201" - ); - assert_eq!( - format!("{:26x}", bytes), - "0000000a090807060504030201" - ); - } - - #[test] - fn hex_error() { - let oddlen = "0123456789abcdef0"; - let badchar1 = "Z123456789abcdef"; - let badchar2 = "012Y456789abcdeb"; - let badchar3 = "«23456789abcdef"; - - let result = Vec::::from_hex(oddlen); - assert!( - matches!(&result, Err(DecodeVariableLengthBytesError::OddLengthString(err)) - if err.length() == 17), - "Got: {:?}", result - ); - let result = <[u8; 4]>::from_hex(oddlen); - assert!( - matches!(&result, Err(DecodeFixedLengthBytesError::InvalidLength(err)) - if err.invalid_length() == 17), - "Got: {:?}", result - ); - let result = <[u8; 8]>::from_hex(oddlen); - assert!( - matches!(&result, Err(DecodeFixedLengthBytesError::InvalidLength(err)) - if err.invalid_length() == 17), - "Got: {:?}", result - ); - let result = Vec::::from_hex(badchar1); - assert!( - matches!(&result, Err(DecodeVariableLengthBytesError::InvalidChar(_))), - "Got: {:?}", result - ); - let result = Vec::::from_hex(badchar2); - assert!( - matches!(&result, Err(DecodeVariableLengthBytesError::InvalidChar(_))), - "Got: {:?}", result - ); - let result = Vec::::from_hex(badchar3); - assert!( - matches!(&result, Err(DecodeVariableLengthBytesError::InvalidChar(_))), - "Got: {:?}", result - ); - } - - - #[test] - fn hex_writer() { - let vec: Vec<_> = (0u8..32).collect(); - let mut writer = HexWriter::new(64); - writer.write_all(&vec[..]).unwrap(); - assert_eq!(vec.to_hex(), writer.result()); - } -} diff --git a/src/lib.rs b/src/lib.rs index f64341b1..5002c4ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,8 @@ /// Re-export of bitcoin crate pub extern crate bitcoin; +/// Re-export of hex crate +pub extern crate hex; /// Re-export of secp256k1-zkp crate pub extern crate secp256k1_zkp; /// Re-export of serde crate @@ -57,8 +59,6 @@ mod error; mod ext; mod fast_merkle_root; pub mod hash_types; -pub use hex_conservative as hex; -//pub mod hex; pub mod issuance; pub mod locktime; pub mod opcodes; diff --git a/src/pset/elip100.rs b/src/pset/elip100.rs index 8af1b466..56c1db00 100644 --- a/src/pset/elip100.rs +++ b/src/pset/elip100.rs @@ -222,8 +222,7 @@ mod test { use crate::encode::serialize; use crate::{OutPoint, Txid}; use bitcoin::hashes::Hash; - use hex_conservative as hex; - use hex_conservative::DisplayHex as _; + use hex::DisplayHex as _; use crate::{ encode::{serialize_hex, Encodable}, diff --git a/src/pset/elip102.rs b/src/pset/elip102.rs index 5886d1ce..89331603 100644 --- a/src/pset/elip102.rs +++ b/src/pset/elip102.rs @@ -69,8 +69,7 @@ mod test { use super::*; use crate::AssetId; use crate::encode::{serialize_hex, Encodable}; - use hex_conservative as hex; - use hex_conservative::DisplayHex as _; + use hex::DisplayHex as _; // b'\xfc\rpset_liquidex' const ELIP0102_IDENTIFIER: &str = "fc0d707365745f6c69717569646578"; diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 61684c3b..be62d61c 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -785,8 +785,7 @@ impl Decodable for PartiallySignedTransaction { #[cfg(test)] mod tests { use super::*; - use hex_conservative as hex; - use hex_conservative::DisplayHex as _; + use hex::DisplayHex as _; #[track_caller] fn tx_pset_rtt(tx_hex: &str) { diff --git a/src/pset/raw.rs b/src/pset/raw.rs index 7c97efd8..39db0606 100644 --- a/src/pset/raw.rs +++ b/src/pset/raw.rs @@ -21,7 +21,7 @@ use std::{fmt, io}; use super::Error; use crate::encode::{self, deserialize, serialize, Decodable, Encodable, VarInt, MAX_VEC_SIZE}; -use hex_conservative::DisplayHex as _; +use hex::DisplayHex as _; /// A PSET key in its raw byte form. #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] #[cfg_attr( diff --git a/src/pset/serialize.rs b/src/pset/serialize.rs index 5ed03c1e..227e21f5 100644 --- a/src/pset/serialize.rs +++ b/src/pset/serialize.rs @@ -53,7 +53,7 @@ pub trait Deserialize: Sized { /// Encode an object into a hex-encoded string pub fn serialize_hex(data: &T) -> String { - use hex_conservative::DisplayHex as _; + use hex::DisplayHex as _; Serialize::serialize(data)[..].to_lower_hex_string() } diff --git a/src/script.rs b/src/script.rs index 3f0dfea7..0b0a4507 100644 --- a/src/script.rs +++ b/src/script.rs @@ -219,13 +219,13 @@ impl Script { /// Parse a hex-string with no length prefix as a [`Script`]. #[deprecated(since = "0.27.0", note = "use from_hex_no_prefix instead")] - pub fn from_hex(s: &str) -> Result { + pub fn from_hex(s: &str) -> Result { Self::from_hex_no_prefix(s) } /// Parse a hex-string with no length prefix as a [`Script`]. - pub fn from_hex_no_prefix(s: &str) -> Result { - hex_conservative::decode_to_vec(s).map(|v| Script(Box::<[u8]>::from(v))) + pub fn from_hex_no_prefix(s: &str) -> Result { + hex::decode_to_vec(s).map(|v| Script(Box::<[u8]>::from(v))) } /// Generates P2PK-type of scriptPubkey @@ -892,7 +892,7 @@ impl<'de> serde::Deserialize<'de> for Script { where E: serde::de::Error, { - let v = hex_conservative::decode_to_vec(v).map_err(E::custom)?; + let v = hex::decode_to_vec(v).map_err(E::custom)?; Ok(Script::from(v)) } @@ -946,7 +946,6 @@ impl Decodable for Script { #[cfg(test)] mod test { - use hex_conservative as hex; use bitcoin::PublicKey; use std::str::FromStr; diff --git a/src/serde_utils.rs b/src/serde_utils.rs index 4a566928..f9ba7fcd 100644 --- a/src/serde_utils.rs +++ b/src/serde_utils.rs @@ -7,8 +7,7 @@ pub mod btreemap_byte_values { // NOTE: This module can be exactly copied to use with HashMap. use ::std::collections::BTreeMap; - use hex_conservative as hex; - use hex_conservative::DisplayHex as _; + use hex::DisplayHex as _; use serde; pub fn serialize(v: &BTreeMap>, s: S) @@ -224,8 +223,7 @@ pub mod hex_bytes { //! Module for serialization of byte arrays as hex strings. #![allow(missing_docs)] - use hex_conservative as hex; - use hex_conservative::DisplayHex as _; + use hex::DisplayHex as _; use serde; pub fn serialize(bytes: &T, s: S) -> Result diff --git a/src/sighash.rs b/src/sighash.rs index 5d6c26ae..4b42b663 100644 --- a/src/sighash.rs +++ b/src/sighash.rs @@ -969,7 +969,6 @@ impl std::str::FromStr for SchnorrSighashType { mod tests{ use super::*; use crate::encode::deserialize; - use hex_conservative as hex; use std::str::FromStr; fn test_segwit_sighash(tx: &str, script: &str, input_index: usize, value: &str, hash_type: EcdsaSighashType, expected_result: &str) { diff --git a/src/transaction.rs b/src/transaction.rs index b6c6f105..69b08bf3 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1304,7 +1304,6 @@ mod tests { use crate::{encode::serialize, pset::PartiallySignedTransaction}; use crate::confidential; - use hex_conservative as hex; use secp256k1_zkp::{self, ZERO_TWEAK}; use crate::script;