Merge rust-bitcoin/rust-bitcoin#4496: BREAKING: Change Psbt serde implementations

9aa235c24d BREAKING: Change Psbt serde implementations (Daniel Roberts)
d7e9a84339 Fix Psbt preimage keys in serde test (Daniel Roberts)
62026c1e2d Don't use PSBT_GLOBAL_XPUB as an unknown key in Psbt serde test (Daniel Roberts)

Pull request description:

  Implements the conclusion of #3454 by serializing Psbts using the BIP-174 binary encoding, optionally using base64 where appropriate.

  The core of the problem is the old derived serde implementation by its nature can't be backwards compatible when serialized in binary formats like bincode. Fields will be added to the Psbt (my motivating case in #4440 ) and this will always break formats like bincode.

ACKs for top commit:
  apoelstra:
    ACK 9aa235c24d65d23de2afc21fcbd019892bf4ad2a; successfully ran local tests
  tcharding:
    ACK 9aa235c24d

Tree-SHA512: 4dc9dbf1a71f06769d74fada7e3d5557a3df3ee78769c66c2d8480c434baa0abd2efba555137563af58da2cc1d545813eb43b6c696b363a5777a9836bc1b7382
This commit is contained in:
merge-script 2025-05-24 16:03:33 +00:00
commit ecf4b2bcee
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
13 changed files with 63 additions and 357 deletions

View File

@ -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:

View File

@ -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"]

View File

@ -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;

View File

@ -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<ScriptBuf>,
/// 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<secp256k1::PublicKey, KeySource>,
/// 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<Witness>,
/// RIPEMD160 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
/// SHA256 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
/// HASH160 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
/// HASH256 hash to preimage map.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
/// Serialized Taproot signature with sighash type for key spend.
pub tap_key_sig: Option<taproot::Signature>,
/// Map of `<xonlypubkey>|<leafhash>` 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<ControlBlock, (ScriptBuf, LeafVersion)>,
/// 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<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Taproot Internal key.
pub tap_internal_key: Option<XOnlyPublicKey>,
/// Taproot Merkle root.
pub tap_merkle_root: Option<TapNodeHash>,
/// Proprietary key-value pairs for this input.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
/// Unknown key-value pairs for this input.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
}
@ -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,
}

View File

@ -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<ScriptBuf>,
@ -34,20 +33,16 @@ pub struct Output {
pub witness_script: Option<ScriptBuf>,
/// 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<secp256k1::PublicKey, KeySource>,
/// The internal pubkey.
pub tap_internal_key: Option<XOnlyPublicKey>,
/// Taproot Output tree.
pub tap_tree: Option<TapTree>,
/// 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<XOnlyPublicKey, (Vec<TapLeafHash>, 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<raw::ProprietaryKey, Vec<u8>>,
/// Unknown key-value pairs for this output.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
}

View File

@ -41,7 +41,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,
@ -51,10 +50,8 @@ pub struct Psbt {
/// derivation path as defined by BIP 32.
pub xpub: BTreeMap<Xpub, KeySource>,
/// Global proprietary key-value pairs.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
/// Unknown global key-value pairs.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
/// The corresponding key-value map for each input in the unsigned transaction.
@ -735,6 +732,53 @@ impl Psbt {
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Psbt {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
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<D>(deserializer: D) -> Result<Self, D::Error>
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<E: serde::de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
Psbt::deserialize(bytes)
.map_err(|e| serde::de::Error::custom(e))
}
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
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]
@ -1590,7 +1634,7 @@ mod tests {
}],
};
let unknown: BTreeMap<raw::Key, Vec<u8>> =
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());
@ -1645,10 +1689,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()

View File

@ -21,25 +21,21 @@ use crate::psbt::Error;
///
/// `<key> := <keylen> <keytype> <keydata>`
#[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<u8>,
}
/// A PSBT key-value pair in its raw byte form.
/// `<keypair> := <key> <value>`
#[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.
/// `<value> := <valuelen> <valuedata>`
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
pub value: Vec<u8>,
}
@ -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<Subtype = ProprietaryType>
where
Subtype: Copy + From<u64> + Into<u64>,
{
/// 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<u8>,
/// 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<u8>,
}

View File

@ -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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<S, T>(v: &BTreeMap<T, Vec<u8>>, s: S) -> Result<S::Ok, S::Error>
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<BTreeMap<T, Vec<u8>>, D::Error>
where
D: serde::Deserializer<'de>,
T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord,
{
use core::marker::PhantomData;
struct Visitor<T>(PhantomData<T>);
impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
where
T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord,
{
type Value = BTreeMap<T, Vec<u8>>;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "a map with hexadecimal values")
}
fn visit_map<A: serde::de::MapAccess<'de>>(
self,
mut a: A,
) -> Result<Self::Value, A::Error> {
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<S, T, U>(v: &BTreeMap<T, U>, s: S) -> Result<S::Ok, S::Error>
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<BTreeMap<T, U>, 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<T, U>(PhantomData<(T, U)>);
impl<'de, T, U> serde::de::Visitor<'de> for Visitor<T, U>
where
T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord,
U: serde::Deserialize<'de>,
{
type Value = BTreeMap<T, U>;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "a sequence of pairs")
}
fn visit_seq<A: serde::de::SeqAccess<'de>>(
self,
mut a: A,
) -> Result<Self::Value, A::Error> {
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>(
T,
#[serde(deserialize_with = "crate::serde_utils::hex_bytes::deserialize")] Vec<u8>,
);
/// 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<S, T>(v: &BTreeMap<T, Vec<u8>>, s: S) -> Result<S::Ok, S::Error>
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<BTreeMap<T, Vec<u8>>, D::Error>
where
D: serde::Deserializer<'de>,
T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord,
{
use core::marker::PhantomData;
struct Visitor<T>(PhantomData<T>);
impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
where
T: serde::Deserialize<'de> + core::hash::Hash + Eq + Ord,
{
type Value = BTreeMap<T, Vec<u8>>;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "a sequence of pairs")
}
fn visit_seq<A: serde::de::SeqAccess<'de>>(
self,
mut a: A,
) -> Result<Self::Value, A::Error> {
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<T, S>(bytes: &T, s: S) -> Result<S::Ok, S::Error>
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<B, D::Error>
where
D: serde::Deserializer<'de>,
B: serde::Deserialize<'de> + FromHex,
{
struct Visitor<B>(core::marker::PhantomData<B>);
impl<B: FromHex> serde::de::Visitor<'_> for Visitor<B> {
type Value = B;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("an ASCII hex string")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
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<E>(self, v: &str) -> Result<Self::Value, E>
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))
}
}
}

View File

@ -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=="

View File

@ -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]