From 62026c1e2dd0a1d0b8f12fc6d55c06de0ddc002e Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Tue, 13 May 2025 22:05:56 -0500 Subject: [PATCH 1/3] Don't use PSBT_GLOBAL_XPUB as an unknown key in Psbt serde test The previous test used global key id 1 which is not unknown, it's PSBT_GLOBAL_XPUB. That's an inconsistent state for a Psbt to be in, and will cause a deserialization error when the Psbt serde implementation is modified to use the BIP-174 format. --- bitcoin/src/psbt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9418ae8bf..9b146a9d6 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1586,7 +1586,7 @@ mod tests { }], }; let unknown: BTreeMap> = - vec![(raw::Key { type_value: 1, key_data: vec![0, 1] }, vec![3, 4, 5])] + vec![(raw::Key { type_value: 42, key_data: vec![0, 1] }, vec![3, 4, 5])] .into_iter() .collect(); let key_source = ("deadbeef".parse().unwrap(), "0'/1".parse().unwrap()); From d7e9a8433939e23838123932ef0186fe315e5c42 Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Tue, 13 May 2025 22:06:16 -0500 Subject: [PATCH 2/3] Fix Psbt preimage keys in serde test The preimage values in the serde Psbt don't actually correspond to the hash keys they should in the serde test. This doesn't cause an error currently because the derived serde implementation doesn't enforce their validity during deserialization, but it will when the serde implementation is modified to use the BIP-174 format. --- bitcoin/src/psbt/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9b146a9d6..47be38fa8 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1641,10 +1641,10 @@ mod tests { )].into_iter().collect(), bip32_derivation: keypaths.clone(), final_script_witness: Some(Witness::from_slice(&[vec![1, 3], vec![5]])), - ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), - sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), - hash160_preimages: vec![(hash160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), - hash256_preimages: vec![(sha256d::Hash::hash(&[]), vec![1, 2])].into_iter().collect(), + ripemd160_preimages: vec![(ripemd160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), + sha256_preimages: vec![(sha256::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), + hash160_preimages: vec![(hash160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), + hash256_preimages: vec![(sha256d::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(), proprietary: proprietary.clone(), unknown: unknown.clone(), ..Default::default() From 9aa235c24d65d23de2afc21fcbd019892bf4ad2a Mon Sep 17 00:00:00 2001 From: Daniel Roberts Date: Sun, 11 May 2025 10:28:19 -0500 Subject: [PATCH 3/3] BREAKING: Change Psbt serde implementations Replace derived Psbt serde implementation with one that conforms to BIP-174. In human readable serde contexts, serialize to the base64 encoded format, and in binary serde contexts, serialize to the raw binary format. The previous derived serde implementation cannot be used in a backward or forward compatible way in binary formats like bincode, which means that every field added to the Psbt struct would break serde de/serialization into binary formats. Instead, this one-time breaking change will fix the issue going forward. Downstream users with persisted data in the old serde format should continue using 0.32.x to create migrations to the new format. --- bitcoin/CHANGELOG.md | 4 + bitcoin/Cargo.toml | 2 +- bitcoin/src/lib.rs | 2 - bitcoin/src/psbt/map/input.rs | 12 - bitcoin/src/psbt/map/output.rs | 5 - bitcoin/src/psbt/mod.rs | 50 ++- bitcoin/src/psbt/raw.rs | 7 - bitcoin/src/serde_utils.rs | 298 ------------------ .../tests/data/serde/proprietary_key_bincode | Bin 32 -> 0 bytes bitcoin/tests/data/serde/psbt_base64.json | 1 + bitcoin/tests/data/serde/psbt_bincode | Bin 1377 -> 810 bytes bitcoin/tests/data/serde/raw_pair_bincode | Bin 32 -> 0 bytes bitcoin/tests/serde.rs | 29 +- 13 files changed, 58 insertions(+), 352 deletions(-) delete mode 100644 bitcoin/src/serde_utils.rs delete mode 100644 bitcoin/tests/data/serde/proprietary_key_bincode create mode 100644 bitcoin/tests/data/serde/psbt_base64.json delete mode 100644 bitcoin/tests/data/serde/raw_pair_bincode diff --git a/bitcoin/CHANGELOG.md b/bitcoin/CHANGELOG.md index bbe596b71..6b593c7bf 100644 --- a/bitcoin/CHANGELOG.md +++ b/bitcoin/CHANGELOG.md @@ -4,6 +4,10 @@ - Use MAX_MONEY in serde regression test [#3950](https://github.com/rust-bitcoin/rust-bitcoin/pull/3950) +## Breaking changes + +- Change Psbt serde implementation to contextually use the PSBT binary or base64 encoded formats described in BIP-174. + # 0.33.0-alpha.0 - 2024-11-18 This series of alpha releases is meant for two things: diff --git a/bitcoin/Cargo.toml b/bitcoin/Cargo.toml index 075ddbd89..39547f023 100644 --- a/bitcoin/Cargo.toml +++ b/bitcoin/Cargo.toml @@ -19,7 +19,7 @@ default = [ "std", "secp-recovery" ] std = ["base58/std", "bech32/std", "hashes/std", "hex/std", "internals/std", "io/std", "primitives/std", "secp256k1/std", "units/std", "base64?/std", "bitcoinconsensus?/std"] rand-std = ["secp256k1/rand", "std"] rand = ["secp256k1/rand"] -serde = ["dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"] +serde = ["base64", "dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"] secp-lowmemory = ["secp256k1/lowmemory"] secp-recovery = ["secp256k1/recovery"] arbitrary = ["dep:arbitrary", "units/arbitrary", "primitives/arbitrary"] diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index a57ababde..cb68c3543 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -92,8 +92,6 @@ pub extern crate secp256k1; extern crate serde; mod internal_macros; -#[cfg(feature = "serde")] -mod serde_utils; #[macro_use] pub mod p2p; diff --git a/bitcoin/src/psbt/map/input.rs b/bitcoin/src/psbt/map/input.rs index d33be651b..287c7f362 100644 --- a/bitcoin/src/psbt/map/input.rs +++ b/bitcoin/src/psbt/map/input.rs @@ -65,7 +65,6 @@ const PSBT_IN_PROPRIETARY: u64 = 0xFC; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Input { /// The non-witness transaction this input spends from. Should only be /// `Option::Some` for inputs which spend non-SegWit outputs or @@ -87,7 +86,6 @@ pub struct Input { pub witness_script: Option, /// A map from public keys needed to sign this input to their corresponding /// master key fingerprints and derivation paths. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub bip32_derivation: BTreeMap, /// The finalized, fully-constructed scriptSig with signatures and any other /// scripts necessary for this input to pass validation. @@ -96,37 +94,28 @@ pub struct Input { /// other scripts necessary for this input to pass validation. pub final_script_witness: Option, /// RIPEMD160 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub ripemd160_preimages: BTreeMap>, /// SHA256 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub sha256_preimages: BTreeMap>, /// HASH160 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub hash160_preimages: BTreeMap>, /// HASH256 hash to preimage map. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))] pub hash256_preimages: BTreeMap>, /// Serialized Taproot signature with sighash type for key spend. pub tap_key_sig: Option, /// Map of `|` with signature. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), taproot::Signature>, /// Map of Control blocks to Script version pair. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_scripts: BTreeMap, /// Map of tap root x only keys to origin info and leaf hashes contained in it. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_key_origins: BTreeMap, KeySource)>, /// Taproot Internal key. pub tap_internal_key: Option, /// Taproot Merkle root. pub tap_merkle_root: Option, /// Proprietary key-value pairs for this input. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this input. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub unknown: BTreeMap>, } @@ -147,7 +136,6 @@ pub struct Input { /// let _tap_sighash_all: PsbtSighashType = TapSighashType::All.into(); /// ``` #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PsbtSighashType { pub(in crate::psbt) inner: u32, } diff --git a/bitcoin/src/psbt/map/output.rs b/bitcoin/src/psbt/map/output.rs index 22e28abc6..7f86bdb65 100644 --- a/bitcoin/src/psbt/map/output.rs +++ b/bitcoin/src/psbt/map/output.rs @@ -26,7 +26,6 @@ const PSBT_OUT_PROPRIETARY: u64 = 0xFC; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. #[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Output { /// The redeem script for this output. pub redeem_script: Option, @@ -34,20 +33,16 @@ pub struct Output { pub witness_script: Option, /// A map from public keys needed to spend this output to their /// corresponding master key fingerprints and derivation paths. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub bip32_derivation: BTreeMap, /// The internal pubkey. pub tap_internal_key: Option, /// Taproot Output tree. pub tap_tree: Option, /// Map of tap root x only keys to origin info and leaf hashes contained in it. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] pub tap_key_origins: BTreeMap, KeySource)>, /// Proprietary key-value pairs for this output. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, /// Unknown key-value pairs for this output. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub unknown: BTreeMap>, } diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 47be38fa8..a9c8c3951 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -40,7 +40,6 @@ pub use self::{ /// A Partially Signed Transaction. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Psbt { /// The unsigned transaction, scriptSigs and witnesses for each input must be empty. pub unsigned_tx: Transaction, @@ -50,10 +49,8 @@ pub struct Psbt { /// derivation path as defined by BIP 32. pub xpub: BTreeMap, /// Global proprietary key-value pairs. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub proprietary: BTreeMap>, /// Unknown global key-value pairs. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))] pub unknown: BTreeMap>, /// The corresponding key-value map for each input in the unsigned transaction. @@ -731,6 +728,53 @@ impl Psbt { } } +#[cfg(feature = "serde")] +impl serde::Serialize for Psbt { + fn serialize(&self, serializer: S) -> Result { + use crate::prelude::ToString; + + if serializer.is_human_readable() { + serializer.serialize_str(&self.to_string()) + } else { + serializer.serialize_bytes(&self.serialize()) + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Psbt { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> + { + struct Visitor; + + impl<'de> serde::de::Visitor<'de> for Visitor + { + type Value = Psbt; + + fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "a psbt") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result { + Psbt::deserialize(bytes) + .map_err(|e| serde::de::Error::custom(e)) + } + + fn visit_str(self, s: &str) -> Result { + s.parse().map_err(|e| serde::de::Error::custom(e)) + } + } + + if deserializer.is_human_readable() { + deserializer.deserialize_str(Visitor) + } else { + deserializer.deserialize_bytes(Visitor) + } + } +} + /// Data required to call [`GetKey`] to get the private key to sign an input. #[derive(Clone, Debug, PartialEq, Eq)] #[non_exhaustive] diff --git a/bitcoin/src/psbt/raw.rs b/bitcoin/src/psbt/raw.rs index 4502bde61..205d076b5 100644 --- a/bitcoin/src/psbt/raw.rs +++ b/bitcoin/src/psbt/raw.rs @@ -21,25 +21,21 @@ use crate::psbt::Error; /// /// ` := ` #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Key { /// The type of this PSBT key. pub type_value: u64, // Encoded as a compact size. /// The key data itself in raw byte form. - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub key_data: Vec, } /// A PSBT key-value pair in its raw byte form. /// ` := ` #[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Pair { /// The key of this key-value pair. pub key: Key, /// The value data of this key-value pair in raw byte form. /// ` := ` - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub value: Vec, } @@ -49,19 +45,16 @@ pub type ProprietaryType = u64; /// Proprietary keys (i.e. keys starting with 0xFC byte) with their internal /// structure according to BIP 174. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ProprietaryKey where Subtype: Copy + From + Into, { /// Proprietary type prefix used for grouping together keys under some /// application and avoid namespace collision - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub prefix: Vec, /// Custom proprietary subtype pub subtype: Subtype, /// Additional key bytes (like serialized public key data etc) - #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] pub key: Vec, } diff --git a/bitcoin/src/serde_utils.rs b/bitcoin/src/serde_utils.rs deleted file mode 100644 index df306d9df..000000000 --- a/bitcoin/src/serde_utils.rs +++ /dev/null @@ -1,298 +0,0 @@ -// SPDX-License-Identifier: CC0-1.0 - -//! Bitcoin serde utilities. -//! -//! This module is for special serde serializations. - -pub(crate) struct SerializeBytesAsHex<'a>(pub(crate) &'a [u8]); - -impl serde::Serialize for SerializeBytesAsHex<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use hex::DisplayHex; - - serializer.collect_str(&format_args!("{:x}", self.0.as_hex())) - } -} - -pub mod btreemap_byte_values { - //! Module for serialization of BTreeMaps with hex byte values. - #![allow(missing_docs)] - - // NOTE: This module can be exactly copied to use with HashMap. - - use hex::FromHex; - - use crate::prelude::{BTreeMap, Vec}; - - pub fn serialize(v: &BTreeMap>, s: S) -> Result - where - S: serde::Serializer, - T: serde::Serialize + core::hash::Hash + Eq + Ord, - { - use serde::ser::SerializeMap; - - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(v, s) - } else { - let mut map = s.serialize_map(Some(v.len()))?; - for (key, value) in v.iter() { - map.serialize_entry(key, &super::SerializeBytesAsHex(value))?; - } - map.end() - } - } - - pub fn deserialize<'de, D, T>(d: D) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - use core::marker::PhantomData; - - struct Visitor(PhantomData); - impl<'de, T> serde::de::Visitor<'de> for Visitor - where - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - type Value = BTreeMap>; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a map with hexadecimal values") - } - - fn visit_map>( - self, - mut a: A, - ) -> Result { - 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)?); - } - Ok(ret) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_map(Visitor(PhantomData)) - } - } -} - -pub mod btreemap_as_seq { - //! Module for serialization of BTreeMaps as lists of sequences because - //! serde_json will not serialize hashmaps with non-string keys be default. - #![allow(missing_docs)] - - // NOTE: This module can be exactly copied to use with HashMap. - - use crate::prelude::BTreeMap; - - pub fn serialize(v: &BTreeMap, s: S) -> Result - where - S: serde::Serializer, - T: serde::Serialize + core::hash::Hash + Eq + Ord, - U: serde::Serialize, - { - use serde::ser::SerializeSeq; - - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(v, s) - } else { - let mut seq = s.serialize_seq(Some(v.len()))?; - for pair in v.iter() { - seq.serialize_element(&pair)?; - } - seq.end() - } - } - - pub fn deserialize<'de, D, T, U>(d: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - U: serde::Deserialize<'de>, - { - use core::marker::PhantomData; - - struct Visitor(PhantomData<(T, U)>); - impl<'de, T, U> serde::de::Visitor<'de> for Visitor - where - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - U: serde::Deserialize<'de>, - { - type Value = BTreeMap; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a sequence of pairs") - } - - fn visit_seq>( - self, - mut a: A, - ) -> Result { - let mut ret = BTreeMap::new(); - while let Some((key, value)) = a.next_element()? { - ret.insert(key, value); - } - Ok(ret) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_seq(Visitor(PhantomData)) - } - } -} - -pub mod btreemap_as_seq_byte_values { - //! Module for serialization of BTreeMaps as lists of sequences because - //! serde_json will not serialize hashmaps with non-string keys be default. - #![allow(missing_docs)] - - // NOTE: This module can be exactly copied to use with HashMap. - - use crate::prelude::{BTreeMap, Vec}; - - /// A custom key-value pair type that serialized the bytes as hex. - #[derive(Debug, Deserialize)] - struct OwnedPair( - T, - #[serde(deserialize_with = "crate::serde_utils::hex_bytes::deserialize")] Vec, - ); - - /// A custom key-value pair type that serialized the bytes as hex. - #[derive(Debug, Serialize)] - struct BorrowedPair<'a, T: 'static>( - &'a T, - #[serde(serialize_with = "crate::serde_utils::hex_bytes::serialize")] &'a [u8], - ); - - pub fn serialize(v: &BTreeMap>, s: S) -> Result - where - S: serde::Serializer, - T: serde::Serialize + core::hash::Hash + Eq + Ord + 'static, - { - use serde::ser::SerializeSeq; - - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(v, s) - } else { - let mut seq = s.serialize_seq(Some(v.len()))?; - for (key, value) in v.iter() { - seq.serialize_element(&BorrowedPair(key, value))?; - } - seq.end() - } - } - - pub fn deserialize<'de, D, T>(d: D) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - use core::marker::PhantomData; - - struct Visitor(PhantomData); - impl<'de, T> serde::de::Visitor<'de> for Visitor - where - T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord, - { - type Value = BTreeMap>; - - fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!(f, "a sequence of pairs") - } - - fn visit_seq>( - self, - mut a: A, - ) -> Result { - let mut ret = BTreeMap::new(); - while let Option::Some(OwnedPair(key, value)) = a.next_element()? { - ret.insert(key, value); - } - Ok(ret) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_seq(Visitor(PhantomData)) - } - } -} - -pub mod hex_bytes { - //! Module for serialization of byte arrays as hex strings. - #![allow(missing_docs)] - - use hex::FromHex; - - pub fn serialize(bytes: &T, s: S) -> Result - where - T: serde::Serialize + AsRef<[u8]>, - S: serde::Serializer, - { - // Don't do anything special when not human readable. - if !s.is_human_readable() { - serde::Serialize::serialize(bytes, s) - } else { - serde::Serialize::serialize(&super::SerializeBytesAsHex(bytes.as_ref()), s) - } - } - - pub fn deserialize<'de, D, B>(d: D) -> Result - where - D: serde::Deserializer<'de>, - B: serde::Deserialize<'de> + FromHex, - { - struct Visitor(core::marker::PhantomData); - - impl serde::de::Visitor<'_> for Visitor { - type Value = B; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_str("an ASCII hex string") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - if let Ok(hex) = core::str::from_utf8(v) { - FromHex::from_hex(hex).map_err(E::custom) - } else { - Err(E::invalid_value(serde::de::Unexpected::Bytes(v), &self)) - } - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - FromHex::from_hex(v).map_err(E::custom) - } - } - - // Don't do anything special when not human readable. - if !d.is_human_readable() { - serde::Deserialize::deserialize(d) - } else { - d.deserialize_str(Visitor(core::marker::PhantomData)) - } - } -} diff --git a/bitcoin/tests/data/serde/proprietary_key_bincode b/bitcoin/tests/data/serde/proprietary_key_bincode deleted file mode 100644 index 8c0100713be8a87a97c9e4926701c50a89dcac89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 TcmZQ!fC5G)W=1HJ1xXA50dN2o diff --git a/bitcoin/tests/data/serde/psbt_base64.json b/bitcoin/tests/data/serde/psbt_base64.json new file mode 100644 index 000000000..6bb318f10 --- /dev/null +++ b/bitcoin/tests/data/serde/psbt_base64.json @@ -0,0 +1 @@ +"cHNidP8BAFMBAAAAAYmjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAAAD/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAAAAAE8BBIiyHgAAAAAAAAAAAIc9/4HAL1JWI/0f5RZ+rDpVoEnePTFLtC7iJ//tN9UIAzmjYBMwFZfa70H75ZOgLMUT0LVVJ+wt8QUOLo/0nIXCDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAAEAjwEAAAAAAQGJo8ceq00g4Dcbu6TMaY+ilclGOvouOX+FM8y2L5Vn5QEAAAAXFgAUvhjRUqmwEgOdrz2n3k9TNJ7suYX/////AXL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUAAAAAAQEgcv74TiwAAAAXqRQzlyW6Ie/WKsdTqbzQZ9bHpqOdBYciAgM5iA3JI5S3NV49BDn6KDwx3nWQgS6gEcQkXAZ0poXog0cwRAIgT2fir7dhQtRPrliiSV0zo0GdqibNDbjQTzRStjKJrA8CIBB2Kp+2fpTMXK2QJvbcmf9/Bw9CeNMPvH0Mhp3TjH/nAQEDBIMAAAABBAFRIgYDOYgNySOUtzVePQQ5+ig8Md51kIEuoBHEJFwGdKaF6IMM3q2+7wAAAIABAAAAAQgGAgIBAwEFFQoYn3yLGjhv/o7tkbODDHp7zR53jAIBAiELoShx/uIQ+4YZKR6uoZRYHL0lMeSyN1nSJfaAaSP2MiICAQIVDBXMSeGRy8Ug2RlEYApct3r2qjKRAgECIQ12pWrO2RXSUT3NhMLDeLLoqlzWMrW3HKLyrFsOOmSb2wIBAhD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFACICAzmIDckjlLc1Xj0EOfooPDHedZCBLqARxCRcBnSmheiDDN6tvu8AAACAAQAAABD8BXByZWZ4KnRlc3Rfa2V5AwUGBwMJAAEDAwQFAA==" \ No newline at end of file diff --git a/bitcoin/tests/data/serde/psbt_bincode b/bitcoin/tests/data/serde/psbt_bincode index 2c352b99c33227c4258ba8380928e5fa0a2e694f..35d580f4b0ddd26395b7974739e0cd48ad82fbe4 100644 GIT binary patch delta 447 zcmaFJwTewtiJ1Wm3W}3T{xdQJGXi;x6D3sn{sRGH(Z3&lIzSQe$pK8_^&o}*j4U0S z8KE zSw*=d=GSyfS>*rgdpmJ+Gf!3ZS-J8aCPpSj?#WA;6TzdDCGnxI1rk-@O`lV-C-)ekjoBq`Fr!e&(<^O>I zs*M3AUi9yWpAJw^94fI=#CW>uF2(oPw2lX_+;buQ+VN$J=d!kgWMNwJp-L+XN|VgY z41Fto%N+}Yl9Js@BGQ9RizB@poeB%xEhBw$olOD_gHjR;EYpKsE&K{g$}5xHGg1R0 zjnboxEM0@$vI@QOol6aaN(-`5Eh0%tr&yIK8cG#D>n!+&s}f3{GNZX$-Fl^TS3tRGhPvD zEc2y@VI@ zQ?{GN*|J#v(y%eSS303lZ-L+ul^C{?Wvwro-Jlu_T$mL6(;uzhp6GPNe_g~P&sgKd zj&oP3o#owe!QUikn^ET)ekKKhGOhXB>ZY8DSvx`P+nt&J>)H98DlYTyspV;#d%36n zIXBd_U{7}s$6$|mM;{-?W}p~6_yggokeQInU}*$By)ZDsVj4y>GQ)x&9;_lzhe*t? z>6Ws{|JV0+;^t?vECb?&CHdN|}8dp%dybY!uA#G|e}NQiJ^Xf;*n3E(QSM&@@m0 diff --git a/bitcoin/tests/data/serde/raw_pair_bincode b/bitcoin/tests/data/serde/raw_pair_bincode deleted file mode 100644 index bf1d3218ac25dc751f2281d92e2067b95d236da0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32 TcmZQ%fB+UK&A`aSjLZfA0W1I( diff --git a/bitcoin/tests/serde.rs b/bitcoin/tests/serde.rs index f9e7e4a6a..136d72418 100644 --- a/bitcoin/tests/serde.rs +++ b/bitcoin/tests/serde.rs @@ -30,7 +30,7 @@ use bitcoin::consensus::encode::deserialize; use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d}; use bitcoin::hex::FromHex; use bitcoin::locktime::{absolute, relative}; -use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey}; +use bitcoin::psbt::raw; use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType}; use bitcoin::script::ScriptBufExt as _; use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; @@ -320,30 +320,11 @@ fn serde_regression_psbt() { let got = serialize(&psbt).unwrap(); let want = include_bytes!("data/serde/psbt_bincode") as &[_]; - assert_eq!(got, want) -} + assert_eq!(got, want); -#[test] -fn serde_regression_raw_pair() { - let pair = Pair { - key: Key { type_value: 1u64, key_data: vec![0u8, 1u8, 2u8, 3u8] }, - value: vec![0u8, 1u8, 2u8, 3u8], - }; - let got = serialize(&pair).unwrap(); - let want = include_bytes!("data/serde/raw_pair_bincode") as &[_]; - assert_eq!(got, want) -} - -#[test] -fn serde_regression_proprietary_key() { - let key = ProprietaryKey { - prefix: vec![0u8, 1u8, 2u8, 3u8], - subtype: 1u64, - key: vec![0u8, 1u8, 2u8, 3u8], - }; - let got = serialize(&key).unwrap(); - let want = include_bytes!("data/serde/proprietary_key_bincode") as &[_]; - assert_eq!(got, want) + let got = serde_json::to_string(&psbt).unwrap(); + let want = include_str!("data/serde/psbt_base64.json"); + assert_eq!(got, want); } #[test]