Skip to content

Commit ecf4b2b

Browse files
committed
Merge rust-bitcoin#4496: BREAKING: Change Psbt serde implementations
9aa235c BREAKING: Change Psbt serde implementations (Daniel Roberts) d7e9a84 Fix Psbt preimage keys in serde test (Daniel Roberts) 62026c1 Don't use PSBT_GLOBAL_XPUB as an unknown key in Psbt serde test (Daniel Roberts) Pull request description: Implements the conclusion of rust-bitcoin#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 rust-bitcoin#4440 ) and this will always break formats like bincode. ACKs for top commit: apoelstra: ACK 9aa235c; successfully ran local tests tcharding: ACK 9aa235c Tree-SHA512: 4dc9dbf1a71f06769d74fada7e3d5557a3df3ee78769c66c2d8480c434baa0abd2efba555137563af58da2cc1d545813eb43b6c696b363a5777a9836bc1b7382
2 parents c913e0a + 9aa235c commit ecf4b2b

File tree

13 files changed

+63
-357
lines changed

13 files changed

+63
-357
lines changed

bitcoin/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
- Use MAX_MONEY in serde regression test [#3950](https://github.com/rust-bitcoin/rust-bitcoin/pull/3950)
66

7+
## Breaking changes
8+
9+
- Change Psbt serde implementation to contextually use the PSBT binary or base64 encoded formats described in BIP-174.
10+
711
# 0.33.0-alpha.0 - 2024-11-18
812

913
This series of alpha releases is meant for two things:

bitcoin/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ default = [ "std", "secp-recovery" ]
1919
std = ["base58/std", "bech32/std", "hashes/std", "hex/std", "internals/std", "io/std", "primitives/std", "secp256k1/std", "units/std", "base64?/std", "bitcoinconsensus?/std"]
2020
rand-std = ["secp256k1/rand", "std"]
2121
rand = ["secp256k1/rand"]
22-
serde = ["dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"]
22+
serde = ["base64", "dep:serde", "hashes/serde", "internals/serde", "primitives/serde", "secp256k1/serde", "units/serde"]
2323
secp-lowmemory = ["secp256k1/lowmemory"]
2424
secp-recovery = ["secp256k1/recovery"]
2525
arbitrary = ["dep:arbitrary", "units/arbitrary", "primitives/arbitrary"]

bitcoin/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ pub extern crate secp256k1;
9292
extern crate serde;
9393

9494
mod internal_macros;
95-
#[cfg(feature = "serde")]
96-
mod serde_utils;
9795

9896
#[macro_use]
9997
pub mod p2p;

bitcoin/src/psbt/map/input.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ const PSBT_IN_PROPRIETARY: u64 = 0xFC;
6565
/// A key-value map for an input of the corresponding index in the unsigned
6666
/// transaction.
6767
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
68-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
6968
pub struct Input {
7069
/// The non-witness transaction this input spends from. Should only be
7170
/// `Option::Some` for inputs which spend non-SegWit outputs or
@@ -87,7 +86,6 @@ pub struct Input {
8786
pub witness_script: Option<ScriptBuf>,
8887
/// A map from public keys needed to sign this input to their corresponding
8988
/// master key fingerprints and derivation paths.
90-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
9189
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
9290
/// The finalized, fully-constructed scriptSig with signatures and any other
9391
/// scripts necessary for this input to pass validation.
@@ -96,37 +94,28 @@ pub struct Input {
9694
/// other scripts necessary for this input to pass validation.
9795
pub final_script_witness: Option<Witness>,
9896
/// RIPEMD160 hash to preimage map.
99-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
10097
pub ripemd160_preimages: BTreeMap<ripemd160::Hash, Vec<u8>>,
10198
/// SHA256 hash to preimage map.
102-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
10399
pub sha256_preimages: BTreeMap<sha256::Hash, Vec<u8>>,
104100
/// HASH160 hash to preimage map.
105-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
106101
pub hash160_preimages: BTreeMap<hash160::Hash, Vec<u8>>,
107102
/// HASH256 hash to preimage map.
108-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_byte_values"))]
109103
pub hash256_preimages: BTreeMap<sha256d::Hash, Vec<u8>>,
110104
/// Serialized Taproot signature with sighash type for key spend.
111105
pub tap_key_sig: Option<taproot::Signature>,
112106
/// Map of `<xonlypubkey>|<leafhash>` with signature.
113-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
114107
pub tap_script_sigs: BTreeMap<(XOnlyPublicKey, TapLeafHash), taproot::Signature>,
115108
/// Map of Control blocks to Script version pair.
116-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
117109
pub tap_scripts: BTreeMap<ControlBlock, (ScriptBuf, LeafVersion)>,
118110
/// Map of tap root x only keys to origin info and leaf hashes contained in it.
119-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
120111
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
121112
/// Taproot Internal key.
122113
pub tap_internal_key: Option<XOnlyPublicKey>,
123114
/// Taproot Merkle root.
124115
pub tap_merkle_root: Option<TapNodeHash>,
125116
/// Proprietary key-value pairs for this input.
126-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
127117
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
128118
/// Unknown key-value pairs for this input.
129-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
130119
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
131120
}
132121

@@ -147,7 +136,6 @@ pub struct Input {
147136
/// let _tap_sighash_all: PsbtSighashType = TapSighashType::All.into();
148137
/// ```
149138
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
150-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
151139
pub struct PsbtSighashType {
152140
pub(in crate::psbt) inner: u32,
153141
}

bitcoin/src/psbt/map/output.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,23 @@ const PSBT_OUT_PROPRIETARY: u64 = 0xFC;
2626
/// A key-value map for an output of the corresponding index in the unsigned
2727
/// transaction.
2828
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
29-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3029
pub struct Output {
3130
/// The redeem script for this output.
3231
pub redeem_script: Option<ScriptBuf>,
3332
/// The witness script for this output.
3433
pub witness_script: Option<ScriptBuf>,
3534
/// A map from public keys needed to spend this output to their
3635
/// corresponding master key fingerprints and derivation paths.
37-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
3836
pub bip32_derivation: BTreeMap<secp256k1::PublicKey, KeySource>,
3937
/// The internal pubkey.
4038
pub tap_internal_key: Option<XOnlyPublicKey>,
4139
/// Taproot Output tree.
4240
pub tap_tree: Option<TapTree>,
4341
/// Map of tap root x only keys to origin info and leaf hashes contained in it.
44-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
4542
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
4643
/// Proprietary key-value pairs for this output.
47-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
4844
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
4945
/// Unknown key-value pairs for this output.
50-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
5146
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
5247
}
5348

bitcoin/src/psbt/mod.rs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ pub use self::{
4141

4242
/// A Partially Signed Transaction.
4343
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
4544
pub struct Psbt {
4645
/// The unsigned transaction, scriptSigs and witnesses for each input must be empty.
4746
pub unsigned_tx: Transaction,
@@ -51,10 +50,8 @@ pub struct Psbt {
5150
/// derivation path as defined by BIP 32.
5251
pub xpub: BTreeMap<Xpub, KeySource>,
5352
/// Global proprietary key-value pairs.
54-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
5553
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
5654
/// Unknown global key-value pairs.
57-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
5855
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
5956

6057
/// The corresponding key-value map for each input in the unsigned transaction.
@@ -735,6 +732,53 @@ impl Psbt {
735732
}
736733
}
737734

735+
#[cfg(feature = "serde")]
736+
impl serde::Serialize for Psbt {
737+
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
738+
use crate::prelude::ToString;
739+
740+
if serializer.is_human_readable() {
741+
serializer.serialize_str(&self.to_string())
742+
} else {
743+
serializer.serialize_bytes(&self.serialize())
744+
}
745+
}
746+
}
747+
748+
#[cfg(feature = "serde")]
749+
impl<'de> serde::Deserialize<'de> for Psbt {
750+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
751+
where
752+
D: serde::Deserializer<'de>
753+
{
754+
struct Visitor;
755+
756+
impl<'de> serde::de::Visitor<'de> for Visitor
757+
{
758+
type Value = Psbt;
759+
760+
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
761+
write!(f, "a psbt")
762+
}
763+
764+
fn visit_bytes<E: serde::de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
765+
Psbt::deserialize(bytes)
766+
.map_err(|e| serde::de::Error::custom(e))
767+
}
768+
769+
fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
770+
s.parse().map_err(|e| serde::de::Error::custom(e))
771+
}
772+
}
773+
774+
if deserializer.is_human_readable() {
775+
deserializer.deserialize_str(Visitor)
776+
} else {
777+
deserializer.deserialize_bytes(Visitor)
778+
}
779+
}
780+
}
781+
738782
/// Data required to call [`GetKey`] to get the private key to sign an input.
739783
#[derive(Clone, Debug, PartialEq, Eq)]
740784
#[non_exhaustive]
@@ -1590,7 +1634,7 @@ mod tests {
15901634
}],
15911635
};
15921636
let unknown: BTreeMap<raw::Key, Vec<u8>> =
1593-
vec![(raw::Key { type_value: 1, key_data: vec![0, 1] }, vec![3, 4, 5])]
1637+
vec![(raw::Key { type_value: 42, key_data: vec![0, 1] }, vec![3, 4, 5])]
15941638
.into_iter()
15951639
.collect();
15961640
let key_source = ("deadbeef".parse().unwrap(), "0'/1".parse().unwrap());
@@ -1645,10 +1689,10 @@ mod tests {
16451689
)].into_iter().collect(),
16461690
bip32_derivation: keypaths.clone(),
16471691
final_script_witness: Some(Witness::from_slice(&[vec![1, 3], vec![5]])),
1648-
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1649-
sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1650-
hash160_preimages: vec![(hash160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1651-
hash256_preimages: vec![(sha256d::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1692+
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
1693+
sha256_preimages: vec![(sha256::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
1694+
hash160_preimages: vec![(hash160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
1695+
hash256_preimages: vec![(sha256d::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
16521696
proprietary: proprietary.clone(),
16531697
unknown: unknown.clone(),
16541698
..Default::default()

bitcoin/src/psbt/raw.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,21 @@ use crate::psbt::Error;
2121
///
2222
/// `<key> := <keylen> <keytype> <keydata>`
2323
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
24-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2524
pub struct Key {
2625
/// The type of this PSBT key.
2726
pub type_value: u64, // Encoded as a compact size.
2827
/// The key data itself in raw byte form.
29-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
3028
pub key_data: Vec<u8>,
3129
}
3230

3331
/// A PSBT key-value pair in its raw byte form.
3432
/// `<keypair> := <key> <value>`
3533
#[derive(Debug, PartialEq, Eq)]
36-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3734
pub struct Pair {
3835
/// The key of this key-value pair.
3936
pub key: Key,
4037
/// The value data of this key-value pair in raw byte form.
4138
/// `<value> := <valuelen> <valuedata>`
42-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
4339
pub value: Vec<u8>,
4440
}
4541

@@ -49,19 +45,16 @@ pub type ProprietaryType = u64;
4945
/// Proprietary keys (i.e. keys starting with 0xFC byte) with their internal
5046
/// structure according to BIP 174.
5147
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
52-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
5348
pub struct ProprietaryKey<Subtype = ProprietaryType>
5449
where
5550
Subtype: Copy + From<u64> + Into<u64>,
5651
{
5752
/// Proprietary type prefix used for grouping together keys under some
5853
/// application and avoid namespace collision
59-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
6054
pub prefix: Vec<u8>,
6155
/// Custom proprietary subtype
6256
pub subtype: Subtype,
6357
/// Additional key bytes (like serialized public key data etc)
64-
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
6558
pub key: Vec<u8>,
6659
}
6760

0 commit comments

Comments
 (0)