From 766f498b33873dc6d66dd5d013cd400050161501 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 13 Nov 2024 12:21:28 +1100 Subject: [PATCH] Pull serde stuff out of impl_bytelike_traits macro The `impl_bytelike_traits` macro is public and it is used in the `hash_newtype` macro, also public. Currently if a user calls the `hash_newtype` macro in a crate that depends on `hashes` without the `serde` feature enabled and with no `serde` dependency everything works. However if the user then adds a dependency that happens to enable the `serde` feature in `hashes` their build will blow up because `serde` code will start getting called from the original crate's call to `hash_newtype`. Pull the serde stuff out of `hash_newtype` and provide a macro to implement it `impl_serde_for_newtype`. --- bitcoin/src/bip158.rs | 3 +++ bitcoin/src/bip32.rs | 3 +++ bitcoin/src/blockdata/script/mod.rs | 4 ++++ bitcoin/src/crypto/key.rs | 4 ++++ bitcoin/src/crypto/sighash.rs | 6 ++++++ hashes/src/internal_macros.rs | 3 +++ hashes/src/macros.rs | 18 +++++++++++++----- primitives/src/block.rs | 3 +++ primitives/src/merkle_tree.rs | 3 +++ primitives/src/taproot.rs | 9 +++++++++ primitives/src/transaction.rs | 3 +++ 11 files changed, 54 insertions(+), 5 deletions(-) diff --git a/bitcoin/src/bip158.rs b/bitcoin/src/bip158.rs index 8c5499ad5..d0a81aa83 100644 --- a/bitcoin/src/bip158.rs +++ b/bitcoin/src/bip158.rs @@ -62,6 +62,9 @@ hashes::hash_newtype! { pub struct FilterHeader(sha256d::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(FilterHash, FilterHeader); + impl_hashencode!(FilterHash); impl_hashencode!(FilterHeader); diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 6f609b59a..a3477c765 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -58,6 +58,9 @@ hash_newtype! { pub struct XKeyIdentifier(hash160::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(XKeyIdentifier); + /// Extended private key #[derive(Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "std", derive(Debug))] diff --git a/bitcoin/src/blockdata/script/mod.rs b/bitcoin/src/blockdata/script/mod.rs index 774e95c3b..be3bf676a 100644 --- a/bitcoin/src/blockdata/script/mod.rs +++ b/bitcoin/src/blockdata/script/mod.rs @@ -92,6 +92,10 @@ hashes::hash_newtype! { /// SegWit version of a Bitcoin Script bytecode hash. pub struct WScriptHash(sha256::Hash); } + +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(ScriptHash, WScriptHash); + impl_asref_push_bytes!(ScriptHash, WScriptHash); impl ScriptHash { diff --git a/bitcoin/src/crypto/key.rs b/bitcoin/src/crypto/key.rs index a0627ba0d..753d81ac5 100644 --- a/bitcoin/src/crypto/key.rs +++ b/bitcoin/src/crypto/key.rs @@ -264,6 +264,10 @@ hashes::hash_newtype! { /// SegWit version of a public key hash. pub struct WPubkeyHash(hash160::Hash); } + +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(PubkeyHash, WPubkeyHash); + impl_asref_push_bytes!(PubkeyHash, WPubkeyHash); impl From for PubkeyHash { diff --git a/bitcoin/src/crypto/sighash.rs b/bitcoin/src/crypto/sighash.rs index e6530921a..f5a59e897 100644 --- a/bitcoin/src/crypto/sighash.rs +++ b/bitcoin/src/crypto/sighash.rs @@ -56,6 +56,9 @@ hash_newtype! { pub struct SegwitV0Sighash(sha256d::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(LegacySighash, SegwitV0Sighash); + impl_message_from_hash!(LegacySighash); impl_message_from_hash!(SegwitV0Sighash); @@ -82,6 +85,9 @@ hash_newtype! { pub struct TapSighash(sha256t::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapSighash); + impl_message_from_hash!(TapSighash); /// Efficiently calculates signature hash message for legacy, segwit and Taproot inputs. diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index a707d2222..9702444a3 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -28,6 +28,9 @@ macro_rules! hash_trait_impls { fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) } } + #[cfg(feature = "serde")] + $crate::serde_impl!(Hash, { $bits / 8} $(, $gen: $gent)*); + impl<$($gen: $gent),*> $crate::Hash for Hash<$($gen),*> { type Bytes = [u8; $bits / 8]; diff --git a/hashes/src/macros.rs b/hashes/src/macros.rs index 5520ffe90..3501a564c 100644 --- a/hashes/src/macros.rs +++ b/hashes/src/macros.rs @@ -4,6 +4,7 @@ //! //! - [`sha256t_tag`](crate::sha256t_tag) //! - [`hash_newtype`](crate::hash_newtype) +//! - [`impl_serde_for_newtype`](crate::impl_serde_for_newtype) /// Macro used to define a tag. /// @@ -71,8 +72,7 @@ macro_rules! sha256t_tag { /// /// You can add arbitrary doc comments or other attributes to the struct or it's field. Note that /// the macro already derives [`Copy`], [`Clone`], [`Eq`], [`PartialEq`], -/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`]. With the `serde` feature on, this also adds -/// `Serialize` and `Deserialize` implementations. +/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`]. /// /// You can also define multiple newtypes within one macro call: /// @@ -201,7 +201,6 @@ macro_rules! hash_newtype { /// * `str::FromStr` /// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`. /// * `fmt::{Display, Debug}` by calling `LowerHex` -/// * `serde::{Deserialize, Serialize}` /// * `AsRef[u8; $len]` /// * `AsRef[u8]` /// * `Borrow<[u8; $len]>` @@ -247,8 +246,6 @@ macro_rules! impl_bytelike_traits { } } - $crate::serde_impl!($ty, $len $(, $gen: $gent)*); - impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> { #[inline] fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() } @@ -433,6 +430,17 @@ pub mod serde_details { } } +/// Implements `Serialize` and `Deserialize` for a new type created with [`crate::hash_newtype`] macro. +#[macro_export] +#[cfg(feature = "serde")] +macro_rules! impl_serde_for_newtype { + ($($newtype:ident),*) => { + $( + $crate::serde_impl!($newtype, { <$newtype as $crate::Hash>::LEN }); + )* + } +} + /// Implements `Serialize` and `Deserialize` for a type `$t` which /// represents a newtype over a byte-slice over length `$len`. #[doc(hidden)] diff --git a/primitives/src/block.rs b/primitives/src/block.rs index 20475c942..4fdd9d605 100644 --- a/primitives/src/block.rs +++ b/primitives/src/block.rs @@ -162,6 +162,9 @@ hashes::hash_newtype! { pub struct WitnessCommitment(sha256d::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(BlockHash, WitnessCommitment); + impl BlockHash { /// Dummy hash used as the previous blockhash of the genesis block. pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]); diff --git a/primitives/src/merkle_tree.rs b/primitives/src/merkle_tree.rs index 763ace1fa..5f3c5de71 100644 --- a/primitives/src/merkle_tree.rs +++ b/primitives/src/merkle_tree.rs @@ -10,3 +10,6 @@ hashes::hash_newtype! { /// A hash corresponding to the Merkle tree root for witness data. pub struct WitnessMerkleNode(sha256d::Hash); } + +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TxMerkleNode, WitnessMerkleNode); diff --git a/primitives/src/taproot.rs b/primitives/src/taproot.rs index 452b10af5..b85ac5617 100644 --- a/primitives/src/taproot.rs +++ b/primitives/src/taproot.rs @@ -18,6 +18,9 @@ hash_newtype! { pub struct TapLeafHash(sha256t::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapLeafHash); + sha256t_tag! { pub struct TapBranchTag = hash_str("TapBranch"); } @@ -29,6 +32,9 @@ hash_newtype! { pub struct TapNodeHash(sha256t::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapNodeHash); + sha256t_tag! { pub struct TapTweakTag = hash_str("TapTweak"); } @@ -40,6 +46,9 @@ hash_newtype! { pub struct TapTweakHash(sha256t::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(TapTweakHash); + impl From for TapNodeHash { fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) } } diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs index 5b6fe1086..dbfc3c896 100644 --- a/primitives/src/transaction.rs +++ b/primitives/src/transaction.rs @@ -476,6 +476,9 @@ hashes::hash_newtype! { pub struct Wtxid(sha256d::Hash); } +#[cfg(feature = "serde")] +hashes::impl_serde_for_newtype!(Txid, Wtxid); + impl Txid { /// The `Txid` used in a coinbase prevout. ///