From 905d18d6132ca4fb63a4cd71c6a5a9c83c220d41 Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 6 Oct 2024 13:55:05 -0400 Subject: [PATCH 1/3] Impl conversion from v2::Psbt to v0::Psbt --- src/v0/bitcoin/raw.rs | 14 ++++++++++ src/v2/map/input.rs | 62 ++++++++++++++++++++++++------------------- src/v2/map/output.rs | 36 +++++++++++++++---------- src/v2/mod.rs | 44 +++++++++++++++++++++--------- 4 files changed, 103 insertions(+), 53 deletions(-) diff --git a/src/v0/bitcoin/raw.rs b/src/v0/bitcoin/raw.rs index 8dcb27d..40e896c 100644 --- a/src/v0/bitcoin/raw.rs +++ b/src/v0/bitcoin/raw.rs @@ -16,6 +16,7 @@ use bitcoin::consensus::encode::{ use super::serialize::{Deserialize, Serialize}; use crate::io::{self, BufRead, Write}; use crate::prelude::*; +use crate::raw; use crate::v0::bitcoin::Error; /// A PSBT key in its raw byte form. @@ -103,6 +104,10 @@ impl Key { } } +impl From for Key { + fn from(key: raw::Key) -> Self { Key { type_value: key.type_value, key: key.key } } +} + impl Serialize for Key { fn serialize(&self) -> Vec { let mut buf = Vec::new(); @@ -199,3 +204,12 @@ where Ok(deserialize(&key.key)?) } } + +impl From> for ProprietaryKey +where + SubType: Copy + From + Into, +{ + fn from(key: raw::ProprietaryKey) -> Self { + ProprietaryKey:: { prefix: key.prefix, subtype: key.subtype, key: key.key } + } +} diff --git a/src/v2/map/input.rs b/src/v2/map/input.rs index 91dedbb..f03a868 100644 --- a/src/v2/map/input.rs +++ b/src/v2/map/input.rs @@ -30,7 +30,7 @@ use crate::prelude::*; use crate::serialize::{Deserialize, Serialize}; use crate::sighash_type::{InvalidSighashTypeError, PsbtSighashType}; use crate::v2::map::Map; -use crate::{raw, serialize}; +use crate::{raw, serialize, v0}; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. @@ -156,32 +156,40 @@ impl Input { } } - // /// Converts this `Input` to a `v0::Input`. - // pub(crate) fn into_v0(self) -> v0::Input { - // v0::Input { - // non_witness_utxo: self.non_witness_utxo, - // witness_utxo: self.witness_utxo, - // partial_sigs: self.partial_sigs, - // sighash_type: self.sighash_type, - // redeem_script: self.redeem_script, - // witness_script: self.witness_script, - // bip32_derivation: self.bip32_derivations, - // final_script_sig: self.final_script_sig, - // final_script_witness: self.final_script_witness, - // ripemd160_preimages: self.ripemd160_preimages, - // sha256_preimages: self.sha256_preimages, - // hash160_preimages: self.hash160_preimages, - // hash256_preimages: self.hash256_preimages, - // tap_key_sig: self.tap_key_sig, - // tap_script_sigs: self.tap_script_sigs, - // tap_scripts: self.tap_scripts, - // tap_key_origins: self.tap_key_origins, - // tap_internal_key: self.tap_internal_key, - // tap_merkle_root: self.tap_merkle_root, - // proprietary: self.proprietaries, - // unknown: self.unknowns, - // } - // } + /// Converts this `Input` to a `v0::Input`. + pub(crate) fn into_v0(self) -> v0::Input { + let proprietary = self + .proprietaries + .into_iter() + .map(|(k, v)| (v0::bitcoin::raw::ProprietaryKey::from(k), v)) + .collect(); + let unknown = + self.unknowns.into_iter().map(|(k, v)| (v0::bitcoin::raw::Key::from(k), v)).collect(); + + v0::Input { + non_witness_utxo: self.non_witness_utxo, + witness_utxo: self.witness_utxo, + partial_sigs: self.partial_sigs, + sighash_type: self.sighash_type, + redeem_script: self.redeem_script, + witness_script: self.witness_script, + bip32_derivation: self.bip32_derivations, + final_script_sig: self.final_script_sig, + final_script_witness: self.final_script_witness, + ripemd160_preimages: self.ripemd160_preimages, + sha256_preimages: self.sha256_preimages, + hash160_preimages: self.hash160_preimages, + hash256_preimages: self.hash256_preimages, + tap_key_sig: self.tap_key_sig, + tap_script_sigs: self.tap_script_sigs, + tap_scripts: self.tap_scripts, + tap_key_origins: self.tap_key_origins, + tap_internal_key: self.tap_internal_key, + tap_merkle_root: self.tap_merkle_root, + proprietary, + unknown, + } + } /// Creates a new finalized input. /// diff --git a/src/v2/map/output.rs b/src/v2/map/output.rs index 60745cf..816116e 100644 --- a/src/v2/map/output.rs +++ b/src/v2/map/output.rs @@ -18,7 +18,7 @@ use crate::error::write_err; use crate::prelude::*; use crate::serialize::{Deserialize, Serialize}; use crate::v2::map::Map; -use crate::{raw, serialize}; +use crate::{raw, serialize, v0}; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. @@ -72,19 +72,27 @@ impl Output { } } - // /// Converts this `Output` to a `v0::Output`. - // pub(crate) fn into_v0(self) -> v0::Output { - // v0::Output { - // redeem_script: self.redeem_script, - // witness_script: self.witness_script, - // bip32_derivation: self.bip32_derivations, - // tap_internal_key: self.tap_internal_key, - // tap_tree: self.tap_tree, - // tap_key_origins: self.tap_key_origins, - // proprietary: self.proprietaries, - // unknown: self.unknowns, - // } - // } + /// Converts this `Output` to a `v0::Output`. + pub(crate) fn into_v0(self) -> v0::Output { + let proprietary = self + .proprietaries + .into_iter() + .map(|(k, v)| (v0::bitcoin::raw::ProprietaryKey::from(k), v)) + .collect(); + let unknown = + self.unknowns.into_iter().map(|(k, v)| (v0::bitcoin::raw::Key::from(k), v)).collect(); + + v0::Output { + redeem_script: self.redeem_script, + witness_script: self.witness_script, + bip32_derivation: self.bip32_derivations, + tap_internal_key: self.tap_internal_key, + tap_tree: self.tap_tree, + tap_key_origins: self.tap_key_origins, + proprietary, + unknown, + } + } /// Creates the [`TxOut`] associated with this `Output`. pub(crate) fn tx_out(&self) -> TxOut { diff --git a/src/v2/mod.rs b/src/v2/mod.rs index 73a7208..fcce411 100644 --- a/src/v2/mod.rs +++ b/src/v2/mod.rs @@ -44,6 +44,7 @@ use bitcoin::{ecdsa, transaction, Amount, Sequence, Transaction, TxOut, Txid}; use crate::error::{write_err, FeeError, FundingUtxoError}; use crate::prelude::*; use crate::v2::map::Map; +use crate::{v0, Version}; #[rustfmt::skip] // Keep public exports separate. #[doc(inline)] @@ -404,18 +405,37 @@ impl Updater { Ok(self) } - // /// Converts the inner PSBT v2 to a PSBT v0. - // pub fn into_psbt_v0(self) -> v0::Psbt { - // let unsigned_tx = - // self.0.unsigned_tx().expect("Updater guarantees lock time can be determined"); - // let psbt = self.psbt(); - - // let global = psbt.global.into_v0(unsigned_tx); - // let inputs = psbt.inputs.into_iter().map(|input| input.into_v0()).collect(); - // let outputs = psbt.outputs.into_iter().map(|output| output.into_v0()).collect(); - - // v0::Psbt { global, inputs, outputs } - // } + /// Converts the inner PSBT v2 to a PSBT v0. + pub fn into_psbt_v0(self) -> v0::Psbt { + let unsigned_tx = + self.0.unsigned_tx().expect("Updater guarantees lock time can be determined"); + let inputs = self.0.inputs.into_iter().map(|input| input.into_v0()).collect(); + let outputs = self.0.outputs.into_iter().map(|output| output.into_v0()).collect(); + let proprietary = self + .0 + .global + .proprietaries + .into_iter() + .map(|(k, v)| (v0::bitcoin::raw::ProprietaryKey::from(k), v)) + .collect(); + let unknown = self + .0 + .global + .unknowns + .into_iter() + .map(|(k, v)| (v0::bitcoin::raw::Key::from(k), v)) + .collect(); + + v0::Psbt { + unsigned_tx, + inputs, + outputs, + version: Version::ZERO.to_u32(), + xpub: self.0.global.xpubs, + proprietary, + unknown, + } + } /// Returns the inner [`Psbt`]. pub fn psbt(self) -> Psbt { self.0 } From 431364628078389a045628cc5fb1bb7bd4305d4d Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 6 Oct 2024 14:02:54 -0400 Subject: [PATCH 2/3] Impl {ProprietaryKey,Key}::into_v0 --- src/raw.rs | 14 +++++++++++++- src/v0/bitcoin/raw.rs | 14 -------------- src/v2/map/input.rs | 9 ++------- src/v2/map/output.rs | 9 ++------- src/v2/mod.rs | 17 +++-------------- 5 files changed, 20 insertions(+), 43 deletions(-) diff --git a/src/raw.rs b/src/raw.rs index a2c0b0a..a5ecec5 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -20,8 +20,8 @@ use bitcoin::hex::DisplayHex; use crate::io::{self, BufRead, Write}; use crate::prelude::*; -use crate::serialize; use crate::serialize::{Deserialize, Serialize}; +use crate::{serialize, v0}; /// A PSBT key-value pair in its raw byte form. /// @@ -112,6 +112,10 @@ impl Key { Ok(Key { type_value, key }) } + + pub(crate) fn into_v0(self) -> v0::bitcoin::raw::Key { + v0::bitcoin::raw::Key { type_value: self.type_value, key: self.key } + } } impl Serialize for Key { @@ -160,6 +164,14 @@ where { /// Constructs full [Key] corresponding to this proprietary key type pub fn to_key(&self) -> Key { Key { type_value: 0xFC, key: serialize(self) } } + + pub(crate) fn into_v0(self) -> v0::bitcoin::raw::ProprietaryKey { + v0::bitcoin::raw::ProprietaryKey { + prefix: self.prefix, + subtype: self.subtype, + key: self.key, + } + } } impl TryFrom for ProprietaryKey diff --git a/src/v0/bitcoin/raw.rs b/src/v0/bitcoin/raw.rs index 40e896c..8dcb27d 100644 --- a/src/v0/bitcoin/raw.rs +++ b/src/v0/bitcoin/raw.rs @@ -16,7 +16,6 @@ use bitcoin::consensus::encode::{ use super::serialize::{Deserialize, Serialize}; use crate::io::{self, BufRead, Write}; use crate::prelude::*; -use crate::raw; use crate::v0::bitcoin::Error; /// A PSBT key in its raw byte form. @@ -104,10 +103,6 @@ impl Key { } } -impl From for Key { - fn from(key: raw::Key) -> Self { Key { type_value: key.type_value, key: key.key } } -} - impl Serialize for Key { fn serialize(&self) -> Vec { let mut buf = Vec::new(); @@ -204,12 +199,3 @@ where Ok(deserialize(&key.key)?) } } - -impl From> for ProprietaryKey -where - SubType: Copy + From + Into, -{ - fn from(key: raw::ProprietaryKey) -> Self { - ProprietaryKey:: { prefix: key.prefix, subtype: key.subtype, key: key.key } - } -} diff --git a/src/v2/map/input.rs b/src/v2/map/input.rs index f03a868..b0cc43d 100644 --- a/src/v2/map/input.rs +++ b/src/v2/map/input.rs @@ -158,13 +158,8 @@ impl Input { /// Converts this `Input` to a `v0::Input`. pub(crate) fn into_v0(self) -> v0::Input { - let proprietary = self - .proprietaries - .into_iter() - .map(|(k, v)| (v0::bitcoin::raw::ProprietaryKey::from(k), v)) - .collect(); - let unknown = - self.unknowns.into_iter().map(|(k, v)| (v0::bitcoin::raw::Key::from(k), v)).collect(); + let proprietary = self.proprietaries.into_iter().map(|(k, v)| (k.into_v0(), v)).collect(); + let unknown = self.unknowns.into_iter().map(|(k, v)| (k.into_v0(), v)).collect(); v0::Input { non_witness_utxo: self.non_witness_utxo, diff --git a/src/v2/map/output.rs b/src/v2/map/output.rs index 816116e..656d966 100644 --- a/src/v2/map/output.rs +++ b/src/v2/map/output.rs @@ -74,13 +74,8 @@ impl Output { /// Converts this `Output` to a `v0::Output`. pub(crate) fn into_v0(self) -> v0::Output { - let proprietary = self - .proprietaries - .into_iter() - .map(|(k, v)| (v0::bitcoin::raw::ProprietaryKey::from(k), v)) - .collect(); - let unknown = - self.unknowns.into_iter().map(|(k, v)| (v0::bitcoin::raw::Key::from(k), v)).collect(); + let proprietary = self.proprietaries.into_iter().map(|(k, v)| (k.into_v0(), v)).collect(); + let unknown = self.unknowns.into_iter().map(|(k, v)| (k.into_v0(), v)).collect(); v0::Output { redeem_script: self.redeem_script, diff --git a/src/v2/mod.rs b/src/v2/mod.rs index fcce411..04b56c1 100644 --- a/src/v2/mod.rs +++ b/src/v2/mod.rs @@ -411,20 +411,9 @@ impl Updater { self.0.unsigned_tx().expect("Updater guarantees lock time can be determined"); let inputs = self.0.inputs.into_iter().map(|input| input.into_v0()).collect(); let outputs = self.0.outputs.into_iter().map(|output| output.into_v0()).collect(); - let proprietary = self - .0 - .global - .proprietaries - .into_iter() - .map(|(k, v)| (v0::bitcoin::raw::ProprietaryKey::from(k), v)) - .collect(); - let unknown = self - .0 - .global - .unknowns - .into_iter() - .map(|(k, v)| (v0::bitcoin::raw::Key::from(k), v)) - .collect(); + let proprietary = + self.0.global.proprietaries.into_iter().map(|(k, v)| (k.into_v0(), v)).collect(); + let unknown = self.0.global.unknowns.into_iter().map(|(k, v)| (k.into_v0(), v)).collect(); v0::Psbt { unsigned_tx, From 7256a982d0e7f2e58cf3d3e5b0c585e535e99519 Mon Sep 17 00:00:00 2001 From: DanGould Date: Sun, 6 Oct 2024 14:14:44 -0400 Subject: [PATCH 3/3] Doc v2::Psbt::into_psbt_v0 --- src/v2/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/v2/mod.rs b/src/v2/mod.rs index 04b56c1..615657e 100644 --- a/src/v2/mod.rs +++ b/src/v2/mod.rs @@ -406,6 +406,11 @@ impl Updater { } /// Converts the inner PSBT v2 to a PSBT v0. + /// + /// Conversion is lossy because PSBT v2 introduced global types not present in v0. + /// See [BIP-370] for a list of differences. + /// + /// [BIP-370]: pub fn into_psbt_v0(self) -> v0::Psbt { let unsigned_tx = self.0.unsigned_tx().expect("Updater guarantees lock time can be determined");