From e302e30e7c1eb786debbaa476d90bb739b437fee Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 28 Feb 2024 09:14:32 +1100 Subject: [PATCH 1/6] Import with super::* in unit test As is customary import using a wildcard. Includes `use Hash as _` to remove naming conflict between the trait and type. --- hashes/src/sha256.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 77eca04b..19d166f8 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -817,7 +817,8 @@ impl HashEngine { #[cfg(test)] mod tests { - use crate::{sha256, Hash, HashEngine}; + use crate::{sha256, Hash as _, HashEngine}; + use super::*; #[test] #[cfg(feature = "alloc")] @@ -964,14 +965,14 @@ mod tests { #[test] fn const_hash() { - assert_eq!(super::Hash::hash(&[]), super::Hash::const_hash(&[])); + assert_eq!(Hash::hash(&[]), Hash::const_hash(&[])); let mut bytes = Vec::new(); for i in 0..256 { bytes.push(i as u8); assert_eq!( - super::Hash::hash(&bytes), - super::Hash::const_hash(&bytes), + Hash::hash(&bytes), + Hash::const_hash(&bytes), "hashes don't match for length {}", i + 1 ); @@ -980,8 +981,6 @@ mod tests { #[test] fn const_midstate() { - use super::Midstate; - assert_eq!( Midstate::hash_tag(b"TapLeaf"), Midstate([ From 6820f5140873813e7d74c19d4725578dba1d5cec Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 28 Feb 2024 09:32:08 +1100 Subject: [PATCH 2/6] hashes: Add fmt roundtrip tests Different hashes output to hex strings differently depending on whether they display backward or not but we are not currently testing that our parsing and formatting impls both correctly handle backwards/forwards. Add unit tests to roundtrip through a hex string, do so for one forwards printing hash (sha256), on backwards printing hash (sha256d), and also test that the `hash_newtype!` macro correctly passes on display backward. --- hashes/src/lib.rs | 8 ++++++++ hashes/src/sha256.rs | 17 +++++++++++++++++ hashes/src/sha256d.rs | 14 +++++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index d2e7b850..d612493f 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -273,4 +273,12 @@ mod tests { let h2: TestNewtype = h.to_string().parse().unwrap(); assert_eq!(h2.to_raw_hash(), h); } + + #[test] + fn newtype_fmt_roundtrip() { + let orig = TestNewtype::hash(&[]); + let hex = format!("{}", orig); + let rinsed = hex.parse::().expect("failed to parse hex"); + assert_eq!(rinsed, orig) + } } diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 19d166f8..8405232e 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -883,6 +883,15 @@ mod tests { } } + #[test] + #[cfg(feature = "alloc")] + fn fmt_roundtrips() { + let hash = sha256::Hash::hash(b"some arbitrary bytes"); + let hex = format!("{}", hash); + let rinsed = hex.parse::().expect("failed to parse hex"); + assert_eq!(rinsed, hash) + } + #[test] #[rustfmt::skip] fn midstate() { @@ -990,6 +999,14 @@ mod tests { ) } + #[test] + fn midstate_fmt_roundtrip() { + let midstate = Midstate::hash_tag(b"ArbitraryTag"); + let hex = format!("{}", midstate); + let rinsed = hex.parse::().expect("failed to parse hex"); + assert_eq!(rinsed, midstate) + } + #[cfg(feature = "serde")] #[test] fn sha256_serde() { diff --git a/hashes/src/sha256d.rs b/hashes/src/sha256d.rs index 4fb813bd..fb3b0c5e 100644 --- a/hashes/src/sha256d.rs +++ b/hashes/src/sha256d.rs @@ -30,10 +30,12 @@ fn from_engine(e: sha256::HashEngine) -> Hash { #[cfg(test)] mod tests { + use crate::{sha256d, Hash as _}; + #[test] #[cfg(feature = "alloc")] fn test() { - use crate::{sha256, sha256d, Hash, HashEngine}; + use crate::{sha256, HashEngine}; #[derive(Clone)] struct Test { @@ -81,13 +83,19 @@ mod tests { } } + #[test] + fn fmt_roundtrips() { + let hash = sha256d::Hash::hash(b"some arbitrary bytes"); + let hex = format!("{}", hash); + let rinsed = hex.parse::().expect("failed to parse hex"); + assert_eq!(rinsed, hash) + } + #[cfg(feature = "serde")] #[test] fn sha256_serde() { use serde_test::{assert_tokens, Configure, Token}; - use crate::{sha256d, Hash}; - #[rustfmt::skip] static HASH_BYTES: [u8; 32] = [ 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, From f0558e8eb9743381a2ef3b83de1fb894dfdc8ff8 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 28 Feb 2024 09:47:21 +1100 Subject: [PATCH 3/6] Use fmt_hex_exact Currently we have two functions for displaying forwards and backwards and we also have `fmt_hex_exact`. I do not know why we added the functions. In the latest version of hex we do not have the ability to construct a `DisplayArray` type so we have to use `fmt_hex_exact`. Make the change now, separate from the `hex` upgrade, to assist review. --- hashes/src/internal_macros.rs | 16 ---------------- hashes/src/util.rs | 16 ++++++++-------- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 9352cde5..5534f697 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -71,22 +71,6 @@ pub(crate) use arr_newtype_fmt_impl; macro_rules! hash_trait_impls { ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => { impl<$($gen: $gent),*> Hash<$($gen),*> { - /// Displays hex forwards, regardless of how this type would display it naturally. - /// - /// This is mainly intended as an internal method and you shouldn't need it unless - /// you're doing something special. - pub fn forward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex { - $crate::hex::DisplayHex::as_hex(&self.0) - } - - /// Displays hex backwards, regardless of how this type would display it naturally. - /// - /// This is mainly intended as an internal method and you shouldn't need it unless - /// you're doing something special. - pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex { - $crate::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev()) - } - /// Zero cost conversion between a fixed length byte array shared reference and /// a shared reference to this Hash type. pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self { diff --git a/hashes/src/util.rs b/hashes/src/util.rs index 92fd4855..fcb1b173 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -3,17 +3,17 @@ #[macro_export] /// Adds hexadecimal formatting implementation of a trait `$imp` to a given type `$ty`. macro_rules! hex_fmt_impl( - ($reverse:expr, $ty:ident) => ( - $crate::hex_fmt_impl!($reverse, $ty, ); + ($reverse:expr, $len:expr, $ty:ident) => ( + $crate::hex_fmt_impl!($reverse, $len, $ty, ); ); - ($reverse:expr, $ty:ident, $($gen:ident: $gent:ident),*) => ( + ($reverse:expr, $len:expr, $ty:ident, $($gen:ident: $gent:ident),*) => ( impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> { #[inline] fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { if $reverse { - $crate::_export::_core::fmt::LowerHex::fmt(&self.0.backward_hex(), f) + $crate::hex::fmt_hex_exact!(f, $len, ::as_byte_array(&self).iter().rev(), $crate::hex::Case::Lower) } else { - $crate::_export::_core::fmt::LowerHex::fmt(&self.0.forward_hex(), f) + $crate::hex::fmt_hex_exact!(f, $len, ::as_byte_array(&self), $crate::hex::Case::Lower) } } } @@ -22,9 +22,9 @@ macro_rules! hex_fmt_impl( #[inline] fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { if $reverse { - $crate::_export::_core::fmt::UpperHex::fmt(&self.0.backward_hex(), f) + $crate::hex::fmt_hex_exact!(f, $len, ::as_byte_array(&self).iter().rev(), $crate::hex::Case::Upper) } else { - $crate::_export::_core::fmt::UpperHex::fmt(&self.0.forward_hex(), f) + $crate::hex::fmt_hex_exact!(f, $len, ::as_byte_array(&self), $crate::hex::Case::Upper) } } } @@ -188,7 +188,7 @@ macro_rules! hash_newtype { $({ $($type_attrs)* })* } - $crate::hex_fmt_impl!(<$newtype as $crate::Hash>::DISPLAY_BACKWARD, $newtype); + $crate::hex_fmt_impl!(<$newtype as $crate::Hash>::DISPLAY_BACKWARD, <$newtype as $crate::Hash>::LEN, $newtype); $crate::serde_impl!($newtype, <$newtype as $crate::Hash>::LEN); $crate::borrow_slice_impl!($newtype); From 4bfb466bb959bddc3aed96aeed74b4ebcc13176b Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 28 Feb 2024 09:56:27 +1100 Subject: [PATCH 4/6] Upgrade hex dependency Upgrade to the new `hex v0.2.0` release. --- Cargo-minimal.lock | 13 +++++++-- Cargo-recent.lock | 13 +++++++-- base58/Cargo.toml | 2 +- bitcoin/Cargo.toml | 2 +- bitcoin/src/blockdata/witness.rs | 9 +++--- bitcoin/src/consensus/serde.rs | 32 +++++++-------------- bitcoin/src/crypto/key.rs | 26 ++++++++--------- bitcoin/src/psbt/mod.rs | 2 +- bitcoin/src/taproot/serialized_signature.rs | 5 +--- hashes/Cargo.toml | 2 +- hashes/src/internal_macros.rs | 14 ++++----- hashes/src/sha256.rs | 14 ++++----- hashes/src/util.rs | 12 ++++---- 13 files changed, 73 insertions(+), 73 deletions(-) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 7e6c3026..c81b5361 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -8,6 +8,12 @@ version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "base58check" version = "0.1.0" @@ -159,9 +165,12 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index 196e597d..2b0e4072 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -8,6 +8,12 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "base58check" version = "0.1.0" @@ -158,9 +164,12 @@ checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "e1aa273bf451e37ed35ced41c71a5e2a4e29064afb104158f2514bcd71c2c986" +dependencies = [ + "arrayvec", +] [[package]] name = "hex_lit" diff --git a/base58/Cargo.toml b/base58/Cargo.toml index 7c294a5f..fb312dd3 100644 --- a/base58/Cargo.toml +++ b/base58/Cargo.toml @@ -25,4 +25,4 @@ hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = fa internals = { package = "bitcoin-internals", version = "0.2.0" } [dev-dependencies] -hex = { package = "hex-conservative", version = "0.1.1", default-features = false, features = ["alloc"] } +hex = { package = "hex-conservative", version = "0.2.0", default-features = false, features = ["alloc"] } diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index ffc02bb1..8a46cb1b 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -31,7 +31,7 @@ rustdoc-args = ["--cfg", "docsrs"] base58 = { package = "base58check", version = "0.1.0", default-features = false } bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } hashes = { package = "bitcoin_hashes", version = "0.13.0", default-features = false, features = ["alloc", "io"] } -hex = { package = "hex-conservative", version = "0.1.1", default-features = false, features = ["alloc"] } +hex = { package = "hex-conservative", version = "0.2.0", default-features = false, features = ["alloc"] } hex_lit = "0.1.1" internals = { package = "bitcoin-internals", version = "0.2.0" } io = { package = "bitcoin-io", version = "0.1.1", default-features = false, features = ["alloc"] } diff --git a/bitcoin/src/blockdata/witness.rs b/bitcoin/src/blockdata/witness.rs index 2974de43..d48d3b38 100644 --- a/bitcoin/src/blockdata/witness.rs +++ b/bitcoin/src/blockdata/witness.rs @@ -506,18 +506,19 @@ impl<'de> serde::Deserialize<'de> for Witness { while let Some(elem) = a.next_element::()? { let vec = Vec::::from_hex(&elem).map_err(|e| match e { - InvalidChar(b) => match core::char::from_u32(b.into()) { + InvalidChar(ref e) => match core::char::from_u32(e.invalid_char( + ).into()) { Some(c) => de::Error::invalid_value( Unexpected::Char(c), &"a valid hex character", ), None => de::Error::invalid_value( - Unexpected::Unsigned(b.into()), + Unexpected::Unsigned(e.invalid_char().into()), &"a valid hex character", ), }, - OddLengthString(len) => - de::Error::invalid_length(len, &"an even length string"), + OddLengthString(ref e) => + de::Error::invalid_length(e.length(), &"an even length string"), })?; ret.push(vec); } diff --git a/bitcoin/src/consensus/serde.rs b/bitcoin/src/consensus/serde.rs index eb5acfd4..5a096e6c 100644 --- a/bitcoin/src/consensus/serde.rs +++ b/bitcoin/src/consensus/serde.rs @@ -71,11 +71,11 @@ pub mod hex { /// Hex byte encoder. // We wrap `BufEncoder` to not leak internal representation. - pub struct Encoder(BufEncoder<[u8; HEX_BUF_SIZE]>, PhantomData); + pub struct Encoder(BufEncoder<{ HEX_BUF_SIZE }>, PhantomData); impl From> for Encoder { fn from(_: super::Hex) -> Self { - Encoder(BufEncoder::new([0; HEX_BUF_SIZE]), Default::default()) + Encoder(BufEncoder::new(), Default::default()) } } @@ -100,15 +100,15 @@ pub mod hex { // Newtypes to hide internal details. /// Error returned when a hex string decoder can't be created. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub struct DecodeInitError(hex::HexToBytesError); + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct DecodeInitError(hex::OddLengthStringError); /// Error returned when a hex string contains invalid characters. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub struct DecodeError(hex::HexToBytesError); + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct DecodeError(hex::InvalidCharError); /// Hex decoder state. - pub struct Decoder<'a>(hex::HexToBytesIter<'a>); + pub struct Decoder<'a>(hex::HexSliceToBytesIter<'a>); impl<'a> Decoder<'a> { fn new(s: &'a str) -> Result { @@ -137,29 +137,19 @@ pub mod hex { impl super::IntoDeError for DecodeInitError { fn into_de_error(self) -> E { - use hex::HexToBytesError; - - match self.0 { - HexToBytesError::OddLengthString(len) => - E::invalid_length(len, &"an even number of ASCII-encoded hex digits"), - error => panic!("unexpected error: {:?}", error), - } + E::invalid_length(self.0.length(), &"an even number of ASCII-encoded hex digits") } } impl super::IntoDeError for DecodeError { fn into_de_error(self) -> E { - use hex::HexToBytesError; use serde::de::Unexpected; const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit"; - match self.0 { - HexToBytesError::InvalidChar(c) if c.is_ascii() => - E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR), - HexToBytesError::InvalidChar(c) => - E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR), - error => panic!("unexpected error: {:?}", error), + match self.0.invalid_char() { + c if c.is_ascii() => E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR), + c => E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR), } } } diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index 48ac319c..e3babd05 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -10,7 +10,7 @@ use core::ops; use core::str::FromStr; use hashes::{hash160, Hash}; -use hex::{FromHex, HexToArrayError, HexToBytesError}; +use hex::{FromHex, HexToArrayError}; use internals::array_vec::ArrayVec; use internals::write_err; use io::{Read, Write}; @@ -233,22 +233,22 @@ impl fmt::Display for PublicKey { impl FromStr for PublicKey { type Err = ParsePublicKeyError; fn from_str(s: &str) -> Result { + use HexToArrayError::*; + match s.len() { 66 => { - PublicKey::from_slice(&<[u8; 33]>::from_hex(s).map_err(|op| { - match op { - HexToArrayError::Conversion(HexToBytesError::InvalidChar(char)) => ParsePublicKeyError::InvalidChar(char), - HexToArrayError::Conversion(HexToBytesError::OddLengthString(_)) | HexToArrayError::InvalidLength(_,_) => unreachable!("invalid length"), - } - })?).map_err(From::from) + let bytes = <[u8; 33]>::from_hex(s).map_err(|e| match e { + InvalidChar(e) => ParsePublicKeyError::InvalidChar(e.invalid_char()), + InvalidLength(_) => unreachable!("length checked already") + })?; + Ok(PublicKey::from_slice(&bytes).expect("length checked already")) }, 130 => { - PublicKey::from_slice(&<[u8; 65]>::from_hex(s).map_err(|op| { - match op { - HexToArrayError::Conversion(HexToBytesError::InvalidChar(char)) => ParsePublicKeyError::InvalidChar(char), - HexToArrayError::Conversion(HexToBytesError::OddLengthString(_)) | HexToArrayError::InvalidLength(_,_) => unreachable!("invalid length"), - } - })?).map_err(From::from) + let bytes = <[u8; 65]>::from_hex(s).map_err(|e| match e { + InvalidChar(e) => ParsePublicKeyError::InvalidChar(e.invalid_char()), + InvalidLength(_) => unreachable!("length checked already") + })?; + Ok(PublicKey::from_slice(&bytes).expect("length checked already")) } len => Err(ParsePublicKeyError::InvalidHexLength(len)), } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index d14e186a..4eac052d 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1035,7 +1035,7 @@ mod tests { #[track_caller] pub fn hex_psbt(s: &str) -> Result { - let r: Result, hex::HexToBytesError> = Vec::from_hex(s); + let r = Vec::from_hex(s); match r { Err(_e) => panic!("unable to parse hex string {}", s), Ok(v) => Psbt::deserialize(&v), diff --git a/bitcoin/src/taproot/serialized_signature.rs b/bitcoin/src/taproot/serialized_signature.rs index 337ced5f..4def2e57 100644 --- a/bitcoin/src/taproot/serialized_signature.rs +++ b/bitcoin/src/taproot/serialized_signature.rs @@ -28,10 +28,7 @@ impl fmt::Debug for SerializedSignature { impl fmt::Display for SerializedSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut buf = [0u8; MAX_LEN * 2]; - let mut encoder = hex::buf_encoder::BufEncoder::new(&mut buf); - encoder.put_bytes(self, hex::Case::Lower); - f.pad_integral(true, "0x", encoder.as_str()) + hex::fmt_hex_exact!(f, MAX_LEN, self, hex::Case::Lower) } } diff --git a/hashes/Cargo.toml b/hashes/Cargo.toml index 70a6758e..14368252 100644 --- a/hashes/Cargo.toml +++ b/hashes/Cargo.toml @@ -27,7 +27,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -hex = { package = "hex-conservative", version = "0.1.1", default-features = false } +hex = { package = "hex-conservative", version = "0.2.0", default-features = false } bitcoin-io = { version = "0.1.1", default-features = false, optional = true } schemars = { version = "0.8.3", default-features = false, optional = true } diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 5534f697..9b3f9dde 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -89,15 +89,13 @@ macro_rules! hash_trait_impls { impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> { type Err = $crate::hex::HexToArrayError; fn from_str(s: &str) -> $crate::_export::_core::result::Result { - use $crate::hex::{FromHex, HexToBytesIter}; - use $crate::Hash; + use $crate::{Hash, hex::{FromHex}}; - let inner: [u8; $bits / 8] = if $reverse { - FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())? - } else { - FromHex::from_byte_iter(HexToBytesIter::new(s)?)? - }; - Ok(Self::from_byte_array(inner)) + let mut bytes = <[u8; $bits / 8]>::from_hex(s)?; + if $reverse { + bytes.reverse(); + } + Ok(Self::from_byte_array(bytes)) } } diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 8405232e..628809ea 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -176,15 +176,13 @@ impl Midstate { } impl hex::FromHex for Midstate { - type Err = hex::HexToArrayError; - fn from_byte_iter(iter: I) -> Result - where - I: Iterator> - + ExactSizeIterator - + DoubleEndedIterator, - { + type Error = hex::HexToArrayError; + + fn from_hex(s: &str) -> Result { // DISPLAY_BACKWARD is true - Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?)) + let mut bytes = <[u8; 32]>::from_hex(s)?; + bytes.reverse(); + Ok(Midstate(bytes)) } } diff --git a/hashes/src/util.rs b/hashes/src/util.rs index fcb1b173..c84b928a 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -270,15 +270,13 @@ macro_rules! hash_newtype { impl $crate::_export::_core::str::FromStr for $newtype { type Err = $crate::hex::HexToArrayError; fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> { - use $crate::hex::{FromHex, HexToBytesIter}; - use $crate::Hash; + use $crate::{Hash, hex::FromHex}; - let inner: <$hash as Hash>::Bytes = if ::DISPLAY_BACKWARD { - FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())? - } else { - FromHex::from_byte_iter(HexToBytesIter::new(s)?)? + let mut bytes = <[u8; ::LEN]>::from_hex(s)?; + if ::DISPLAY_BACKWARD { + bytes.reverse(); }; - Ok($newtype(<$hash>::from_byte_array(inner))) + Ok($newtype(<$hash>::from_byte_array(bytes))) } } From 0cea90d505c0741220bf902ecf22ca5d87333375 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 28 Feb 2024 10:10:46 +1100 Subject: [PATCH 5/6] Test hashes honour Formatter::precision Test that the new version of `hex` honours `Formatter::precision` for new wrapped hash types (ie, types created with `hashes::hash_newtype`). Fix: #2494 --- bitcoin/src/blockdata/transaction.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index f957e702..c18d43cb 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -1960,6 +1960,10 @@ mod tests { format!("{:x}", tx.compute_txid()), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec" ); + assert_eq!( + format!("{:.10x}", tx.compute_txid()), + "9652aa62b0" + ); assert_eq!(tx.weight(), Weight::from_wu(2718)); // non-segwit tx from my mempool From f337dec2b15c9f8a89cd3cf4f6f93d244aac3b55 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sun, 10 Mar 2024 10:34:57 +1100 Subject: [PATCH 6/6] hashes: Remove unnecessary feature guard from test --- hashes/src/sha256.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs index 628809ea..63e214a9 100644 --- a/hashes/src/sha256.rs +++ b/hashes/src/sha256.rs @@ -882,7 +882,6 @@ mod tests { } #[test] - #[cfg(feature = "alloc")] fn fmt_roundtrips() { let hash = sha256::Hash::hash(b"some arbitrary bytes"); let hex = format!("{}", hash);