psbt: Run the formatter

Run `cargo +nightly fmt`, no other manual changes.
This commit is contained in:
Tobin C. Harding 2022-12-06 10:03:19 +11:00
parent ef306db5e2
commit a52746d01c
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
9 changed files with 470 additions and 468 deletions

View File

@ -1,18 +1,15 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use crate::prelude::*;
use core::fmt; use core::fmt;
use bitcoin_internals::write_err; use bitcoin_internals::write_err;
use crate::bip32::ExtendedPubKey;
use crate::blockdata::transaction::Transaction; use crate::blockdata::transaction::Transaction;
use crate::consensus::encode; use crate::consensus::encode;
use crate::prelude::*;
use crate::psbt::raw; use crate::psbt::raw;
use crate::{hashes, io};
use crate::hashes;
use crate::io;
use crate::bip32::ExtendedPubKey;
/// Enum for marking psbt hash error. /// Enum for marking psbt hash error.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
@ -113,29 +110,41 @@ impl fmt::Display for Error {
Error::InvalidMagic => f.write_str("invalid magic"), Error::InvalidMagic => f.write_str("invalid magic"),
Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"), Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"),
Error::InvalidSeparator => f.write_str("invalid separator"), Error::InvalidSeparator => f.write_str("invalid separator"),
Error::PsbtUtxoOutOfbounds => f.write_str("output index is out of bounds of non witness script output array"), Error::PsbtUtxoOutOfbounds =>
f.write_str("output index is out of bounds of non witness script output array"),
Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey), Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"), Error::InvalidProprietaryKey =>
write!(f, "non-proprietary key type found when proprietary key was expected"),
Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey),
Error::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"), Error::UnsignedTxHasScriptSigs =>
Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"), f.write_str("the unsigned transaction has script sigs"),
Error::MustHaveUnsignedTx => { Error::UnsignedTxHasScriptWitnesses =>
f.write_str("partially signed transactions must have an unsigned transaction") f.write_str("the unsigned transaction has script witnesses"),
} Error::MustHaveUnsignedTx =>
f.write_str("partially signed transactions must have an unsigned transaction"),
Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"), Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "different unsigned transaction: expected {}, actual {}", e.txid(), a.txid()), Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
Error::NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), f,
"different unsigned transaction: expected {}, actual {}",
e.txid(),
a.txid()
),
Error::NonStandardSighashType(ref sht) =>
write!(f, "non-standard sighash type: {}", sht),
Error::HashParse(ref e) => write_err!(f, "hash parse error"; e), Error::HashParse(ref e) => write_err!(f, "hash parse error"; e),
Error::InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => { Error::InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => {
// directly using debug forms of psbthash enums // directly using debug forms of psbthash enums
write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash) write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash)
}, }
Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) }, Error::CombineInconsistentKeySources(ref s) => {
write!(f, "combine conflict: {}", s)
}
Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e), Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e),
Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"), Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"), Error::FeeOverflow => f.write_str("integer overflow in fee calculation"),
Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e), Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
Error::InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e), Error::InvalidSecp256k1PublicKey(ref e) =>
write_err!(f, "invalid secp256k1 public key"; e),
Error::InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"), Error::InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
Error::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e), Error::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e),
Error::InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e), Error::InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e),
@ -145,7 +154,8 @@ impl fmt::Display for Error {
Error::TapTree(ref e) => write_err!(f, "taproot tree error"; e), Error::TapTree(ref e) => write_err!(f, "taproot tree error"; e),
Error::XPubKey(s) => write!(f, "xpub key error - {}", s), Error::XPubKey(s) => write!(f, "xpub key error - {}", s),
Error::Version(s) => write!(f, "version error {}", s), Error::Version(s) => write!(f, "version error {}", s),
Error::PartialDataConsumption => f.write_str("data not consumed entirely when explicitly deserializing"), Error::PartialDataConsumption =>
f.write_str("data not consumed entirely when explicitly deserializing"),
Error::Io(ref e) => write_err!(f, "I/O error"; e), Error::Io(ref e) => write_err!(f, "I/O error"; e),
} }
} }
@ -161,7 +171,7 @@ impl std::error::Error for Error {
HashParse(e) => Some(e), HashParse(e) => Some(e),
ConsensusEncoding(e) => Some(e), ConsensusEncoding(e) => Some(e),
Io(e) => Some(e), Io(e) => Some(e),
| InvalidMagic InvalidMagic
| MissingUtxo | MissingUtxo
| InvalidSeparator | InvalidSeparator
| PsbtUtxoOutOfbounds | PsbtUtxoOutOfbounds
@ -196,19 +206,13 @@ impl std::error::Error for Error {
#[doc(hidden)] #[doc(hidden)]
impl From<hashes::Error> for Error { impl From<hashes::Error> for Error {
fn from(e: hashes::Error) -> Error { fn from(e: hashes::Error) -> Error { Error::HashParse(e) }
Error::HashParse(e)
}
} }
impl From<encode::Error> for Error { impl From<encode::Error> for Error {
fn from(e: encode::Error) -> Self { fn from(e: encode::Error) -> Self { Error::ConsensusEncoding(e) }
Error::ConsensusEncoding(e)
}
} }
impl From<io::Error> for Error { impl From<io::Error> for Error {
fn from(e: io::Error) -> Self { fn from(e: io::Error) -> Self { Error::Io(e) }
Error::Io(e)
}
} }

View File

@ -2,7 +2,11 @@
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! hex_psbt { macro_rules! hex_psbt {
($s:expr) => { <$crate::psbt::PartiallySignedTransaction>::deserialize(&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()) }; ($s:expr) => {
<$crate::psbt::PartiallySignedTransaction>::deserialize(
&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap(),
)
};
} }
macro_rules! combine { macro_rules! combine {
@ -33,9 +37,7 @@ macro_rules! impl_psbt_deserialize {
macro_rules! impl_psbt_serialize { macro_rules! impl_psbt_serialize {
($thing:ty) => { ($thing:ty) => {
impl $crate::psbt::serialize::Serialize for $thing { impl $crate::psbt::serialize::Serialize for $thing {
fn serialize(&self) -> $crate::prelude::Vec<u8> { fn serialize(&self) -> $crate::prelude::Vec<u8> { $crate::consensus::serialize(self) }
$crate::consensus::serialize(self)
}
} }
}; };
} }
@ -43,9 +45,7 @@ macro_rules! impl_psbt_serialize {
macro_rules! impl_psbtmap_serialize { macro_rules! impl_psbtmap_serialize {
($thing:ty) => { ($thing:ty) => {
impl $crate::psbt::serialize::Serialize for $thing { impl $crate::psbt::serialize::Serialize for $thing {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { self.serialize_map() }
self.serialize_map()
}
} }
}; };
} }
@ -157,9 +157,7 @@ macro_rules! impl_psbt_hash_deserialize {
($hash_type:ty) => { ($hash_type:ty) => {
impl $crate::psbt::serialize::Deserialize for $hash_type { impl $crate::psbt::serialize::Deserialize for $hash_type {
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> { fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> {
<$hash_type>::from_slice(&bytes[..]).map_err(|e| { <$hash_type>::from_slice(&bytes[..]).map_err(|e| $crate::psbt::Error::from(e))
$crate::psbt::Error::from(e)
})
} }
} }
}; };
@ -168,9 +166,7 @@ macro_rules! impl_psbt_hash_deserialize {
macro_rules! impl_psbt_hash_serialize { macro_rules! impl_psbt_hash_serialize {
($hash_type:ty) => { ($hash_type:ty) => {
impl $crate::psbt::serialize::Serialize for $hash_type { impl $crate::psbt::serialize::Serialize for $hash_type {
fn serialize(&self) -> $crate::prelude::Vec<u8> { fn serialize(&self) -> $crate::prelude::Vec<u8> { self.as_byte_array().to_vec() }
self.as_byte_array().to_vec()
}
} }
}; };
} }

View File

@ -2,16 +2,14 @@
use core::convert::TryFrom; use core::convert::TryFrom;
use crate::prelude::*; use crate::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint};
use crate::io::{self, Cursor, Read};
use crate::blockdata::transaction::Transaction; use crate::blockdata::transaction::Transaction;
use crate::consensus::encode::MAX_VEC_SIZE; use crate::consensus::encode::MAX_VEC_SIZE;
use crate::consensus::{encode, Decodable}; use crate::consensus::{encode, Decodable};
use crate::io::{self, Cursor, Read};
use crate::prelude::*;
use crate::psbt::map::Map; use crate::psbt::map::Map;
use crate::psbt::{raw, Error, PartiallySignedTransaction}; use crate::psbt::{raw, Error, PartiallySignedTransaction};
use crate::bip32::{ExtendedPubKey, Fingerprint, DerivationPath, ChildNumber};
/// Type: Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX = 0x00 /// Type: Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX = 0x00
const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00; const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00;
@ -27,10 +25,7 @@ impl Map for PartiallySignedTransaction {
let mut rv: Vec<raw::Pair> = Default::default(); let mut rv: Vec<raw::Pair> = Default::default();
rv.push(raw::Pair { rv.push(raw::Pair {
key: raw::Key { key: raw::Key { type_value: PSBT_GLOBAL_UNSIGNED_TX, key: vec![] },
type_value: PSBT_GLOBAL_UNSIGNED_TX,
key: vec![],
},
value: { value: {
// Manually serialized to ensure 0-input txs are serialized // Manually serialized to ensure 0-input txs are serialized
// without witnesses. // without witnesses.
@ -45,42 +40,30 @@ impl Map for PartiallySignedTransaction {
for (xpub, (fingerprint, derivation)) in &self.xpub { for (xpub, (fingerprint, derivation)) in &self.xpub {
rv.push(raw::Pair { rv.push(raw::Pair {
key: raw::Key { key: raw::Key { type_value: PSBT_GLOBAL_XPUB, key: xpub.encode().to_vec() },
type_value: PSBT_GLOBAL_XPUB,
key: xpub.encode().to_vec(),
},
value: { value: {
let mut ret = Vec::with_capacity(4 + derivation.len() * 4); let mut ret = Vec::with_capacity(4 + derivation.len() * 4);
ret.extend(fingerprint.as_bytes()); ret.extend(fingerprint.as_bytes());
derivation.into_iter().for_each(|n| ret.extend(&u32::from(*n).to_le_bytes())); derivation.into_iter().for_each(|n| ret.extend(&u32::from(*n).to_le_bytes()));
ret ret
} },
}); });
} }
// Serializing version only for non-default value; otherwise test vectors fail // Serializing version only for non-default value; otherwise test vectors fail
if self.version > 0 { if self.version > 0 {
rv.push(raw::Pair { rv.push(raw::Pair {
key: raw::Key { key: raw::Key { type_value: PSBT_GLOBAL_VERSION, key: vec![] },
type_value: PSBT_GLOBAL_VERSION, value: self.version.to_le_bytes().to_vec(),
key: vec![],
},
value: self.version.to_le_bytes().to_vec()
}); });
} }
for (key, value) in self.proprietary.iter() { for (key, value) in self.proprietary.iter() {
rv.push(raw::Pair { rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
key: key.to_key(),
value: value.clone(),
});
} }
for (key, value) in self.unknown.iter() { for (key, value) in self.unknown.iter() {
rv.push(raw::Pair { rv.push(raw::Pair { key: key.clone(), value: value.clone() });
key: key.clone(),
value: value.clone(),
});
} }
rv rv
@ -93,7 +76,8 @@ impl PartiallySignedTransaction {
let mut tx: Option<Transaction> = None; let mut tx: Option<Transaction> = None;
let mut version: Option<u32> = None; let mut version: Option<u32> = None;
let mut unknowns: BTreeMap<raw::Key, Vec<u8>> = Default::default(); let mut unknowns: BTreeMap<raw::Key, Vec<u8>> = Default::default();
let mut xpub_map: BTreeMap<ExtendedPubKey, (Fingerprint, DerivationPath)> = Default::default(); let mut xpub_map: BTreeMap<ExtendedPubKey, (Fingerprint, DerivationPath)> =
Default::default();
let mut proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = Default::default(); let mut proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = Default::default();
loop { loop {
@ -119,13 +103,13 @@ impl PartiallySignedTransaction {
}); });
if decoder.position() != vlen as u64 { if decoder.position() != vlen as u64 {
return Err(Error::PartialDataConsumption) return Err(Error::PartialDataConsumption);
} }
} else { } else {
return Err(Error::DuplicateKey(pair.key)) return Err(Error::DuplicateKey(pair.key));
} }
} else { } else {
return Err(Error::InvalidKey(pair.key)) return Err(Error::InvalidKey(pair.key));
} }
} }
PSBT_GLOBAL_XPUB => { PSBT_GLOBAL_XPUB => {
@ -136,24 +120,33 @@ impl PartiallySignedTransaction {
))?; ))?;
if pair.value.is_empty() || pair.value.len() % 4 != 0 { if pair.value.is_empty() || pair.value.len() % 4 != 0 {
return Err(Error::XPubKey("Incorrect length of global xpub derivation data")) return Err(Error::XPubKey(
"Incorrect length of global xpub derivation data",
));
} }
let child_count = pair.value.len() / 4 - 1; let child_count = pair.value.len() / 4 - 1;
let mut decoder = Cursor::new(pair.value); let mut decoder = Cursor::new(pair.value);
let mut fingerprint = [0u8; 4]; let mut fingerprint = [0u8; 4];
decoder.read_exact(&mut fingerprint[..]).map_err(|_| Error::XPubKey("Can't read global xpub fingerprint"))?; decoder.read_exact(&mut fingerprint[..]).map_err(|_| {
Error::XPubKey("Can't read global xpub fingerprint")
})?;
let mut path = Vec::<ChildNumber>::with_capacity(child_count); let mut path = Vec::<ChildNumber>::with_capacity(child_count);
while let Ok(index) = u32::consensus_decode(&mut decoder) { while let Ok(index) = u32::consensus_decode(&mut decoder) {
path.push(ChildNumber::from(index)) path.push(ChildNumber::from(index))
} }
let derivation = DerivationPath::from(path); let derivation = DerivationPath::from(path);
// Keys, according to BIP-174, must be unique // Keys, according to BIP-174, must be unique
if xpub_map.insert(xpub, (Fingerprint::from(fingerprint), derivation)).is_some() { if xpub_map
return Err(Error::XPubKey("Repeated global xpub key")) .insert(xpub, (Fingerprint::from(fingerprint), derivation))
.is_some()
{
return Err(Error::XPubKey("Repeated global xpub key"));
} }
} else { } else {
return Err(Error::XPubKey("Xpub global key must contain serialized Xpub data")) return Err(Error::XPubKey(
"Xpub global key must contain serialized Xpub data",
));
} }
} }
PSBT_GLOBAL_VERSION => { PSBT_GLOBAL_VERSION => {
@ -164,33 +157,41 @@ impl PartiallySignedTransaction {
let vlen: usize = pair.value.len(); let vlen: usize = pair.value.len();
let mut decoder = Cursor::new(pair.value); let mut decoder = Cursor::new(pair.value);
if vlen != 4 { if vlen != 4 {
return Err(Error::Version("invalid global version value length (must be 4 bytes)")) return Err(Error::Version(
"invalid global version value length (must be 4 bytes)",
));
} }
version = Some(Decodable::consensus_decode(&mut decoder)?); version = Some(Decodable::consensus_decode(&mut decoder)?);
// We only understand version 0 PSBTs. According to BIP-174 we // We only understand version 0 PSBTs. According to BIP-174 we
// should throw an error if we see anything other than version 0. // should throw an error if we see anything other than version 0.
if version != Some(0) { if version != Some(0) {
return Err(Error::Version("PSBT versions greater than 0 are not supported")) return Err(Error::Version(
"PSBT versions greater than 0 are not supported",
));
} }
} else { } else {
return Err(Error::DuplicateKey(pair.key)) return Err(Error::DuplicateKey(pair.key));
} }
} else { } else {
return Err(Error::InvalidKey(pair.key)) return Err(Error::InvalidKey(pair.key));
} }
} }
PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(raw::ProprietaryKey::try_from(pair.key.clone())?) { PSBT_GLOBAL_PROPRIETARY => match proprietary
.entry(raw::ProprietaryKey::try_from(pair.key.clone())?)
{
btree_map::Entry::Vacant(empty_key) => { btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(pair.value); empty_key.insert(pair.value);
},
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(pair.key)),
} }
btree_map::Entry::Occupied(_) =>
return Err(Error::DuplicateKey(pair.key)),
},
_ => match unknowns.entry(pair.key) { _ => match unknowns.entry(pair.key) {
btree_map::Entry::Vacant(empty_key) => { btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(pair.value); empty_key.insert(pair.value);
},
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())),
} }
btree_map::Entry::Occupied(k) =>
return Err(Error::DuplicateKey(k.key().clone())),
},
} }
} }
Err(crate::psbt::Error::NoMorePairs) => break, Err(crate::psbt::Error::NoMorePairs) => break,
@ -206,7 +207,7 @@ impl PartiallySignedTransaction {
proprietary, proprietary,
unknown: unknowns, unknown: unknowns,
inputs: vec![], inputs: vec![],
outputs: vec![] outputs: vec![],
}) })
} else { } else {
Err(Error::MustHaveUnsignedTx) Err(Error::MustHaveUnsignedTx)

View File

@ -1,24 +1,25 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use crate::prelude::*; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::str::FromStr; use core::str::FromStr;
use core::convert::TryFrom;
use secp256k1::XOnlyPublicKey; use secp256k1::XOnlyPublicKey;
use crate::blockdata::script::ScriptBuf;
use crate::blockdata::witness::Witness;
use crate::blockdata::transaction::{Transaction, TxOut};
use crate::crypto::{ecdsa, taproot};
use crate::crypto::key::PublicKey;
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d};
use crate::bip32::KeySource; use crate::bip32::KeySource;
use crate::blockdata::script::ScriptBuf;
use crate::blockdata::transaction::{Transaction, TxOut};
use crate::blockdata::witness::Witness;
use crate::crypto::key::PublicKey;
use crate::crypto::{ecdsa, taproot};
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d};
use crate::prelude::*;
use crate::psbt::map::Map; use crate::psbt::map::Map;
use crate::psbt::serialize::Deserialize; use crate::psbt::serialize::Deserialize;
use crate::psbt::{self, error, raw, Error}; use crate::psbt::{self, error, raw, Error};
use crate::sighash::{self, NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, TapSighashType}; use crate::sighash::{
self, EcdsaSighashType, NonStandardSighashType, SighashTypeParseError, TapSighashType,
};
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash}; use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
@ -132,7 +133,6 @@ pub struct Input {
pub unknown: BTreeMap<raw::Key, Vec<u8>>, pub unknown: BTreeMap<raw::Key, Vec<u8>>,
} }
/// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash /// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash
/// type can be either [`EcdsaSighashType`] or [`TapSighashType`] but it is not possible to know /// type can be either [`EcdsaSighashType`] or [`TapSighashType`] but it is not possible to know
/// directly which signature hash type the user is dealing with. Therefore, the user is responsible /// directly which signature hash type the user is dealing with. Therefore, the user is responsible
@ -208,17 +208,12 @@ impl PsbtSighashType {
/// ///
/// Allows construction of a non-standard or non-valid sighash flag /// Allows construction of a non-standard or non-valid sighash flag
/// ([`EcdsaSighashType`], [`TapSighashType`] respectively). /// ([`EcdsaSighashType`], [`TapSighashType`] respectively).
pub fn from_u32(n: u32) -> PsbtSighashType { pub fn from_u32(n: u32) -> PsbtSighashType { PsbtSighashType { inner: n } }
PsbtSighashType { inner: n }
}
/// Converts [`PsbtSighashType`] to a raw `u32` sighash flag. /// Converts [`PsbtSighashType`] to a raw `u32` sighash flag.
/// ///
/// No guarantees are made as to the standardness or validity of the returned value. /// No guarantees are made as to the standardness or validity of the returned value.
pub fn to_u32(self) -> u32 { pub fn to_u32(self) -> u32 { self.inner }
self.inner
}
} }
impl Input { impl Input {
@ -247,10 +242,7 @@ impl Input {
} }
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> { pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
let raw::Pair { let raw::Pair { key: raw_key, value: raw_value } = pair;
key: raw_key,
value: raw_value,
} = pair;
match raw_key.type_value { match raw_key.type_value {
PSBT_IN_NON_WITNESS_UTXO => { PSBT_IN_NON_WITNESS_UTXO => {
@ -299,16 +291,36 @@ impl Input {
} }
} }
PSBT_IN_RIPEMD160 => { PSBT_IN_RIPEMD160 => {
psbt_insert_hash_pair(&mut self.ripemd160_preimages, raw_key, raw_value, error::PsbtHash::Ripemd)?; psbt_insert_hash_pair(
&mut self.ripemd160_preimages,
raw_key,
raw_value,
error::PsbtHash::Ripemd,
)?;
} }
PSBT_IN_SHA256 => { PSBT_IN_SHA256 => {
psbt_insert_hash_pair(&mut self.sha256_preimages, raw_key, raw_value, error::PsbtHash::Sha256)?; psbt_insert_hash_pair(
&mut self.sha256_preimages,
raw_key,
raw_value,
error::PsbtHash::Sha256,
)?;
} }
PSBT_IN_HASH160 => { PSBT_IN_HASH160 => {
psbt_insert_hash_pair(&mut self.hash160_preimages, raw_key, raw_value, error::PsbtHash::Hash160)?; psbt_insert_hash_pair(
&mut self.hash160_preimages,
raw_key,
raw_value,
error::PsbtHash::Hash160,
)?;
} }
PSBT_IN_HASH256 => { PSBT_IN_HASH256 => {
psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?; psbt_insert_hash_pair(
&mut self.hash256_preimages,
raw_key,
raw_value,
error::PsbtHash::Hash256,
)?;
} }
PSBT_IN_TAP_KEY_SIG => { PSBT_IN_TAP_KEY_SIG => {
impl_psbt_insert_pair! { impl_psbt_insert_pair! {
@ -345,7 +357,7 @@ impl Input {
match self.proprietary.entry(key) { match self.proprietary.entry(key) {
btree_map::Entry::Vacant(empty_key) => { btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value); empty_key.insert(raw_value);
}, }
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)), btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
} }
} }
@ -471,17 +483,11 @@ impl Map for Input {
rv.push(self.tap_merkle_root, PSBT_IN_TAP_MERKLE_ROOT) rv.push(self.tap_merkle_root, PSBT_IN_TAP_MERKLE_ROOT)
} }
for (key, value) in self.proprietary.iter() { for (key, value) in self.proprietary.iter() {
rv.push(raw::Pair { rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
key: key.to_key(),
value: value.clone(),
});
} }
for (key, value) in self.unknown.iter() { for (key, value) in self.unknown.iter() {
rv.push(raw::Pair { rv.push(raw::Pair { key: key.clone(), value: value.clone() });
key: key.clone(),
value: value.clone(),
});
} }
rv rv

View File

@ -1,7 +1,6 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use crate::prelude::*; use crate::prelude::*;
use crate::psbt::raw; use crate::psbt::raw;
mod global; mod global;
@ -10,7 +9,6 @@ mod output;
pub use self::input::{Input, PsbtSighashType}; pub use self::input::{Input, PsbtSighashType};
pub use self::output::Output; pub use self::output::Output;
use super::serialize::Serialize; use super::serialize::Serialize;
/// A trait that describes a PSBT key-value map. /// A trait that describes a PSBT key-value map.

View File

@ -1,18 +1,16 @@
// SPDX-License-Identifier: CC0-1.0 // SPDX-License-Identifier: CC0-1.0
use crate::prelude::*;
use core;
use core::convert::TryFrom; use core::convert::TryFrom;
use crate::blockdata::script::ScriptBuf;
use secp256k1::XOnlyPublicKey; use secp256k1::XOnlyPublicKey;
use crate::bip32::KeySource; use {core, secp256k1};
use secp256k1;
use crate::psbt::map::Map;
use crate::psbt::raw;
use crate::psbt::Error;
use crate::taproot::{TapTree, TapLeafHash}; use crate::bip32::KeySource;
use crate::blockdata::script::ScriptBuf;
use crate::prelude::*;
use crate::psbt::map::Map;
use crate::psbt::{raw, Error};
use crate::taproot::{TapLeafHash, TapTree};
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00 /// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00; const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
@ -51,25 +49,16 @@ pub struct Output {
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))] #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>, pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
/// Proprietary key-value pairs for this output. /// Proprietary key-value pairs for this output.
#[cfg_attr( #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
feature = "serde",
serde(with = "crate::serde_utils::btreemap_as_seq_byte_values")
)]
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>, pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
/// Unknown key-value pairs for this output. /// Unknown key-value pairs for this output.
#[cfg_attr( #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
feature = "serde",
serde(with = "crate::serde_utils::btreemap_as_seq_byte_values")
)]
pub unknown: BTreeMap<raw::Key, Vec<u8>>, pub unknown: BTreeMap<raw::Key, Vec<u8>>,
} }
impl Output { impl Output {
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> { pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
let raw::Pair { let raw::Pair { key: raw_key, value: raw_value } = pair;
key: raw_key,
value: raw_value,
} = pair;
match raw_key.type_value { match raw_key.type_value {
PSBT_OUT_REDEEM_SCRIPT => { PSBT_OUT_REDEEM_SCRIPT => {
@ -92,7 +81,7 @@ impl Output {
match self.proprietary.entry(key) { match self.proprietary.entry(key) {
btree_map::Entry::Vacant(empty_key) => { btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value); empty_key.insert(raw_value);
}, }
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)), btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
} }
} }
@ -116,7 +105,7 @@ impl Output {
empty_key.insert(raw_value); empty_key.insert(raw_value);
} }
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())), btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())),
} },
} }
Ok(()) Ok(())
@ -165,17 +154,11 @@ impl Map for Output {
} }
for (key, value) in self.proprietary.iter() { for (key, value) in self.proprietary.iter() {
rv.push(raw::Pair { rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
key: key.to_key(),
value: value.clone(),
});
} }
for (key, value) in self.unknown.iter() { for (key, value) in self.unknown.iter() {
rv.push(raw::Pair { rv.push(raw::Pair { key: key.clone(), value: value.clone() });
key: key.clone(),
value: value.clone(),
});
} }
rv rv

View File

@ -7,24 +7,22 @@
//! except we define PSBTs containing non-standard sighash types as invalid. //! except we define PSBTs containing non-standard sighash types as invalid.
//! //!
use core::{cmp, fmt};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use core::{fmt, cmp};
use secp256k1::{Message, Secp256k1, Signing};
use bitcoin_internals::write_err; use bitcoin_internals::write_err;
use secp256k1::{Message, Secp256k1, Signing};
use crate::{prelude::*, Amount}; use crate::bip32::{self, ExtendedPrivKey, ExtendedPubKey, KeySource};
use crate::blockdata::script::ScriptBuf; use crate::blockdata::script::ScriptBuf;
use crate::blockdata::transaction::{Transaction, TxOut}; use crate::blockdata::transaction::{Transaction, TxOut};
use crate::bip32::{self, ExtendedPrivKey, ExtendedPubKey, KeySource};
use crate::crypto::ecdsa; use crate::crypto::ecdsa;
use crate::crypto::key::{PublicKey, PrivateKey}; use crate::crypto::key::{PrivateKey, PublicKey};
use crate::sighash::{self, EcdsaSighashType, SighashCache}; use crate::prelude::*;
pub use crate::sighash::Prevouts; pub use crate::sighash::Prevouts;
use crate::sighash::{self, EcdsaSighashType, SighashCache};
use crate::Amount;
#[macro_use] #[macro_use]
mod macros; mod macros;
@ -86,7 +84,7 @@ impl PartiallySignedTransaction {
(None, Some(non_witness_utxo)) => { (None, Some(non_witness_utxo)) => {
let vout = tx_input.previous_output.vout as usize; let vout = tx_input.previous_output.vout as usize;
non_witness_utxo.output.get(vout).ok_or(Error::PsbtUtxoOutOfbounds) non_witness_utxo.output.get(vout).ok_or(Error::PsbtUtxoOutOfbounds)
}, }
(None, None) => Err(Error::MissingUtxo), (None, None) => Err(Error::MissingUtxo),
} }
}) })
@ -161,7 +159,7 @@ impl PartiallySignedTransaction {
match self.xpub.entry(xpub) { match self.xpub.entry(xpub) {
btree_map::Entry::Vacant(entry) => { btree_map::Entry::Vacant(entry) => {
entry.insert((fingerprint1, derivation1)); entry.insert((fingerprint1, derivation1));
}, }
btree_map::Entry::Occupied(mut entry) => { btree_map::Entry::Occupied(mut entry) => {
// Here in case of the conflict we select the version with algorithm: // Here in case of the conflict we select the version with algorithm:
// 1) if everything is equal we do nothing // 1) if everything is equal we do nothing
@ -174,15 +172,17 @@ impl PartiallySignedTransaction {
let (fingerprint2, derivation2) = entry.get().clone(); let (fingerprint2, derivation2) = entry.get().clone();
if (derivation1 == derivation2 && fingerprint1 == fingerprint2) || if (derivation1 == derivation2 && fingerprint1 == fingerprint2)
(derivation1.len() < derivation2.len() && derivation1[..] == derivation2[derivation2.len() - derivation1.len()..]) || (derivation1.len() < derivation2.len()
&& derivation1[..]
== derivation2[derivation2.len() - derivation1.len()..])
{ {
continue continue;
} } else if derivation2[..]
else if derivation2[..] == derivation1[derivation1.len() - derivation2.len()..] == derivation1[derivation1.len() - derivation2.len()..]
{ {
entry.insert((fingerprint1, derivation1)); entry.insert((fingerprint1, derivation1));
continue continue;
} }
return Err(Error::CombineInconsistentKeySources(Box::new(xpub))); return Err(Error::CombineInconsistentKeySources(Box::new(xpub)));
} }
@ -237,8 +237,12 @@ impl PartiallySignedTransaction {
for i in 0..self.inputs.len() { for i in 0..self.inputs.len() {
if let Ok(SigningAlgorithm::Ecdsa) = self.signing_algorithm(i) { if let Ok(SigningAlgorithm::Ecdsa) = self.signing_algorithm(i) {
match self.bip32_sign_ecdsa(k, i, &mut cache, secp) { match self.bip32_sign_ecdsa(k, i, &mut cache, secp) {
Ok(v) => { used.insert(i, v); }, Ok(v) => {
Err(e) => { errors.insert(i, e); }, used.insert(i, v);
}
Err(e) => {
errors.insert(i, e);
}
} }
}; };
} }
@ -289,10 +293,8 @@ impl PartiallySignedTransaction {
Ok((msg, sighash_ty)) => (msg, sighash_ty), Ok((msg, sighash_ty)) => (msg, sighash_ty),
}; };
let sig = ecdsa::Signature { let sig =
sig: secp.sign_ecdsa(&msg, &sk.inner), ecdsa::Signature { sig: secp.sign_ecdsa(&msg, &sk.inner), hash_ty: sighash_ty };
hash_ty: sighash_ty,
};
let pk = sk.public_key(secp); let pk = sk.public_key(secp);
@ -323,35 +325,42 @@ impl PartiallySignedTransaction {
let utxo = self.spend_utxo(input_index)?; let utxo = self.spend_utxo(input_index)?;
let spk = &utxo.script_pubkey; // scriptPubkey for input spend utxo. let spk = &utxo.script_pubkey; // scriptPubkey for input spend utxo.
let hash_ty = input.ecdsa_hash_ty() let hash_ty = input.ecdsa_hash_ty().map_err(|_| SignError::InvalidSighashType)?; // Only support standard sighash types.
.map_err(|_| SignError::InvalidSighashType)?; // Only support standard sighash types.
match self.output_type(input_index)? { match self.output_type(input_index)? {
Bare => { Bare => {
let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?; let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?;
Ok((Message::from(sighash), hash_ty)) Ok((Message::from(sighash), hash_ty))
}, }
Sh => { Sh => {
let script_code = input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?; let script_code =
let sighash = cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?; input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
let sighash =
cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?;
Ok((Message::from(sighash), hash_ty)) Ok((Message::from(sighash), hash_ty))
}, }
Wpkh => { Wpkh => {
let script_code = ScriptBuf::p2wpkh_script_code(spk).ok_or(SignError::NotWpkh)?; let script_code = ScriptBuf::p2wpkh_script_code(spk).ok_or(SignError::NotWpkh)?;
let sighash = cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?; let sighash =
cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?;
Ok((Message::from(sighash), hash_ty)) Ok((Message::from(sighash), hash_ty))
}, }
ShWpkh => { ShWpkh => {
let script_code = ScriptBuf::p2wpkh_script_code(input.redeem_script.as_ref().expect("checked above")) let script_code = ScriptBuf::p2wpkh_script_code(
input.redeem_script.as_ref().expect("checked above"),
)
.ok_or(SignError::NotWpkh)?; .ok_or(SignError::NotWpkh)?;
let sighash = cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?; let sighash =
cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?;
Ok((Message::from(sighash), hash_ty)) Ok((Message::from(sighash), hash_ty))
}, }
Wsh | ShWsh => { Wsh | ShWsh => {
let script_code = input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?; let script_code =
let sighash = cache.segwit_signature_hash(input_index, script_code, utxo.value, hash_ty)?; input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?;
let sighash =
cache.segwit_signature_hash(input_index, script_code, utxo.value, hash_ty)?;
Ok((Message::from(sighash), hash_ty)) Ok((Message::from(sighash), hash_ty))
}, }
Tr => { Tr => {
// This PSBT signing API is WIP, taproot to come shortly. // This PSBT signing API is WIP, taproot to come shortly.
Err(SignError::Unsupported) Err(SignError::Unsupported)
@ -481,13 +490,21 @@ pub trait GetKey {
/// - `Some(key)` if the key is found. /// - `Some(key)` if the key is found.
/// - `None` if the key was not found but no error was encountered. /// - `None` if the key was not found but no error was encountered.
/// - `Err` if an error was encountered while looking for the key. /// - `Err` if an error was encountered while looking for the key.
fn get_key<C: Signing>(&self, key_request: KeyRequest, secp: &Secp256k1<C>) -> Result<Option<PrivateKey>, Self::Error>; fn get_key<C: Signing>(
&self,
key_request: KeyRequest,
secp: &Secp256k1<C>,
) -> Result<Option<PrivateKey>, Self::Error>;
} }
impl GetKey for ExtendedPrivKey { impl GetKey for ExtendedPrivKey {
type Error = GetKeyError; type Error = GetKeyError;
fn get_key<C: Signing>(&self, key_request: KeyRequest, secp: &Secp256k1<C>) -> Result<Option<PrivateKey>, Self::Error> { fn get_key<C: Signing>(
&self,
key_request: KeyRequest,
secp: &Secp256k1<C>,
) -> Result<Option<PrivateKey>, Self::Error> {
match key_request { match key_request {
KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported), KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
KeyRequest::Bip32((fingerprint, path)) => { KeyRequest::Bip32((fingerprint, path)) => {
@ -577,7 +594,8 @@ impl fmt::Display for GetKeyError {
match *self { match *self {
Bip32(ref e) => write_err!(f, "a bip23 error"; e), Bip32(ref e) => write_err!(f, "a bip23 error"; e),
NotSupported => f.write_str("the GetKey operation is not supported for this key request"), NotSupported =>
f.write_str("the GetKey operation is not supported for this key request"),
} }
} }
} }
@ -596,9 +614,7 @@ impl std::error::Error for GetKeyError {
} }
impl From<bip32::Error> for GetKeyError { impl From<bip32::Error> for GetKeyError {
fn from(e: bip32::Error) -> Self { fn from(e: bip32::Error) -> Self { GetKeyError::Bip32(e) }
GetKeyError::Bip32(e)
}
} }
/// The various output types supported by the Bitcoin network. /// The various output types supported by the Bitcoin network.
@ -676,7 +692,7 @@ pub enum SignError {
/// Attempt to sign an input with the wrong signing algorithm. /// Attempt to sign an input with the wrong signing algorithm.
WrongSigningAlgorithm, WrongSigningAlgorithm,
/// Signing request currently unsupported. /// Signing request currently unsupported.
Unsupported Unsupported,
} }
impl fmt::Display for SignError { impl fmt::Display for SignError {
@ -698,7 +714,8 @@ impl fmt::Display for SignError {
SighashComputation(e) => write!(f, "sighash: {}", e), SighashComputation(e) => write!(f, "sighash: {}", e),
UnknownOutputType => write!(f, "unable to determine the output type"), UnknownOutputType => write!(f, "unable to determine the output type"),
KeyNotFound => write!(f, "unable to find key"), KeyNotFound => write!(f, "unable to find key"),
WrongSigningAlgorithm => write!(f, "attempt to sign an input with the wrong signing algorithm"), WrongSigningAlgorithm =>
write!(f, "attempt to sign an input with the wrong signing algorithm"),
Unsupported => write!(f, "signing request currently unsupported"), Unsupported => write!(f, "signing request currently unsupported"),
} }
} }
@ -730,19 +747,19 @@ impl std::error::Error for SignError {
} }
impl From<sighash::Error> for SignError { impl From<sighash::Error> for SignError {
fn from(e: sighash::Error) -> Self { fn from(e: sighash::Error) -> Self { SignError::SighashComputation(e) }
SignError::SighashComputation(e)
}
} }
#[cfg(feature = "base64")] #[cfg(feature = "base64")]
mod display_from_str { mod display_from_str {
use super::{PartiallySignedTransaction, Error}; use core::fmt::{self, Display, Formatter};
use core::fmt::{Display, Formatter, self};
use core::str::FromStr; use core::str::FromStr;
use base64::display::Base64Display; use base64::display::Base64Display;
use bitcoin_internals::write_err; use bitcoin_internals::write_err;
use super::{Error, PartiallySignedTransaction};
/// Error encountered during PSBT decoding from Base64 string. /// Error encountered during PSBT decoding from Base64 string.
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))] #[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
@ -751,7 +768,7 @@ mod display_from_str {
/// Error in internal PSBT data structure. /// Error in internal PSBT data structure.
PsbtEncoding(Error), PsbtEncoding(Error),
/// Error in PSBT Base64 encoding. /// Error in PSBT Base64 encoding.
Base64Encoding(::base64::DecodeError) Base64Encoding(::base64::DecodeError),
} }
impl Display for PsbtParseError { impl Display for PsbtParseError {
@ -801,26 +818,24 @@ pub use self::display_from_str::PsbtParseError;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use std::collections::BTreeMap;
use crate::blockdata::locktime::absolute; use secp256k1::{self, Secp256k1};
use crate::hashes::{sha256, hash160, Hash, ripemd160};
use crate::psbt::serialize::{Serialize, Deserialize};
use secp256k1::{Secp256k1, self};
#[cfg(feature = "rand-std")] #[cfg(feature = "rand-std")]
use secp256k1::{All, SecretKey}; use secp256k1::{All, SecretKey};
use crate::blockdata::script::ScriptBuf; use super::*;
use crate::blockdata::transaction::{Transaction, TxIn, TxOut, OutPoint, Sequence};
use crate::network::constants::Network::Bitcoin;
use crate::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource}; use crate::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource};
use crate::psbt::map::{Output, Input}; use crate::blockdata::locktime::absolute;
use crate::psbt::raw; use crate::blockdata::script::ScriptBuf;
use crate::internal_macros::hex; use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut};
use std::collections::BTreeMap;
use crate::blockdata::witness::Witness; use crate::blockdata::witness::Witness;
use crate::hashes::{hash160, ripemd160, sha256, Hash};
use crate::internal_macros::hex;
use crate::network::constants::Network::Bitcoin;
use crate::psbt::map::{Input, Output};
use crate::psbt::raw;
use crate::psbt::serialize::{Deserialize, Serialize};
#[test] #[test]
fn trivial_psbt() { fn trivial_psbt() {
@ -844,7 +859,6 @@ mod tests {
#[test] #[test]
fn psbt_uncompressed_key() { fn psbt_uncompressed_key() {
let psbt: PartiallySignedTransaction = hex_psbt!("70736274ff01003302000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff000000000000420204bb0d5d0cca36e7b9c80f63bc04c1240babb83bcd2803ef7ac8b6e2af594291daec281e856c98d210c5ab14dfd5828761f8ee7d5f45ca21ad3e4c4b41b747a3a047304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe70100").unwrap(); let psbt: PartiallySignedTransaction = hex_psbt!("70736274ff01003302000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff000000000000420204bb0d5d0cca36e7b9c80f63bc04c1240babb83bcd2803ef7ac8b6e2af594291daec281e856c98d210c5ab14dfd5828761f8ee7d5f45ca21ad3e4c4b41b747a3a047304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe70100").unwrap();
assert!(psbt.inputs[0].partial_sigs.len() == 1); assert!(psbt.inputs[0].partial_sigs.len() == 1);
@ -881,8 +895,12 @@ mod tests {
hd_keypaths.insert(pk.public_key, (fprint, dpath.into())); hd_keypaths.insert(pk.public_key, (fprint, dpath.into()));
let expected: Output = Output { let expected: Output = Output {
redeem_script: Some(ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap()), redeem_script: Some(
witness_script: Some(ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap()), ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
),
witness_script: Some(
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
),
bip32_derivation: hd_keypaths, bip32_derivation: hd_keypaths,
..Default::default() ..Default::default()
}; };
@ -898,25 +916,31 @@ mod tests {
unsigned_tx: Transaction { unsigned_tx: Transaction {
version: 2, version: 2,
lock_time: absolute::LockTime::from_consensus(1257139), lock_time: absolute::LockTime::from_consensus(1257139),
input: vec![ input: vec![TxIn {
TxIn {
previous_output: OutPoint { previous_output: OutPoint {
txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(), txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126"
.parse()
.unwrap(),
vout: 0, vout: 0,
}, },
script_sig: ScriptBuf::new(), script_sig: ScriptBuf::new(),
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF, sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
witness: Witness::default(), witness: Witness::default(),
} }],
],
output: vec![ output: vec![
TxOut { TxOut {
value: 99999699, value: 99999699,
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(), script_pubkey: ScriptBuf::from_hex(
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
)
.unwrap(),
}, },
TxOut { TxOut {
value: 100000000, value: 100000000,
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(), script_pubkey: ScriptBuf::from_hex(
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
)
.unwrap(),
}, },
], ],
}, },
@ -935,10 +959,7 @@ mod tests {
#[test] #[test]
fn serialize_then_deserialize_psbtkvpair() { fn serialize_then_deserialize_psbtkvpair() {
let expected = raw::Pair { let expected = raw::Pair {
key: raw::Key { key: raw::Key { type_value: 0u8, key: vec![42u8, 69u8] },
type_value: 0u8,
key: vec![42u8, 69u8],
},
value: vec![69u8, 42u8, 4u8], value: vec![69u8, 42u8, 4u8],
}; };
@ -965,33 +986,39 @@ mod tests {
let tx = Transaction { let tx = Transaction {
version: 1, version: 1,
lock_time: absolute::LockTime::ZERO, lock_time: absolute::LockTime::ZERO,
input: vec![ input: vec![TxIn {
TxIn {
previous_output: OutPoint { previous_output: OutPoint {
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(), txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389"
.parse()
.unwrap(),
vout: 1, vout: 1,
}, },
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(), script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
.unwrap(),
sequence: Sequence::MAX, sequence: Sequence::MAX,
witness: Witness::from_slice(&[hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105")]), witness: Witness::from_slice(&[hex!(
} "03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"
], )]),
output: vec![ }],
TxOut { output: vec![TxOut {
value: 190303501938, value: 190303501938,
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(), script_pubkey: ScriptBuf::from_hex(
}, "a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
], )
.unwrap(),
}],
}; };
let unknown: BTreeMap<raw::Key, Vec<u8>> = vec![( let unknown: BTreeMap<raw::Key, Vec<u8>> =
raw::Key { type_value: 1, key: vec![0, 1] }, vec![(raw::Key { type_value: 1, key: vec![0, 1] }, vec![3, 4, 5])]
vec![3, 4 ,5], .into_iter()
)].into_iter().collect(); .collect();
let key_source = ("deadbeef".parse().unwrap(), "m/0'/1".parse().unwrap()); let key_source = ("deadbeef".parse().unwrap(), "m/0'/1".parse().unwrap());
let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![( let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![(
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(), "0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
key_source.clone(), key_source.clone(),
)].into_iter().collect(); )]
.into_iter()
.collect();
let proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = vec![( let proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = vec![(
raw::ProprietaryKey { raw::ProprietaryKey {
@ -1000,7 +1027,9 @@ mod tests {
key: "test_key".as_bytes().to_vec(), key: "test_key".as_bytes().to_vec(),
}, },
vec![5, 6, 7], vec![5, 6, 7],
)].into_iter().collect(); )]
.into_iter()
.collect();
let psbt = PartiallySignedTransaction { let psbt = PartiallySignedTransaction {
version: 0, version: 0,
@ -1059,19 +1088,18 @@ mod tests {
} }
mod bip_vectors { mod bip_vectors {
use super::*; use std::collections::BTreeMap;
#[cfg(feature = "base64")] #[cfg(feature = "base64")]
use std::str::FromStr; use std::str::FromStr;
use crate::blockdata::script::ScriptBuf; use super::*;
use crate::blockdata::transaction::{Transaction, TxIn, TxOut, OutPoint, Sequence};
use crate::blockdata::locktime::absolute; use crate::blockdata::locktime::absolute;
use crate::psbt::map::{Map, Input, Output}; use crate::blockdata::script::ScriptBuf;
use crate::psbt::{raw, PartiallySignedTransaction, Error}; use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut};
use crate::sighash::EcdsaSighashType;
use std::collections::BTreeMap;
use crate::blockdata::witness::Witness; use crate::blockdata::witness::Witness;
use crate::psbt::map::{Input, Map, Output};
use crate::psbt::{raw, Error, PartiallySignedTransaction};
use crate::sighash::EcdsaSighashType;
#[test] #[test]
#[should_panic(expected = "InvalidMagic")] #[should_panic(expected = "InvalidMagic")]
@ -1242,11 +1270,15 @@ mod tests {
assert_eq!(unserialized.serialize_hex(), base16str); assert_eq!(unserialized.serialize_hex(), base16str);
assert_eq!(unserialized, hex_psbt!(base16str).unwrap()); assert_eq!(unserialized, hex_psbt!(base16str).unwrap());
#[cfg(feature = "base64")] { #[cfg(feature = "base64")]
{
let base64str = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"; let base64str = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA";
assert_eq!(PartiallySignedTransaction::from_str(base64str).unwrap(), unserialized); assert_eq!(PartiallySignedTransaction::from_str(base64str).unwrap(), unserialized);
assert_eq!(base64str, unserialized.to_string()); assert_eq!(base64str, unserialized.to_string());
assert_eq!(PartiallySignedTransaction::from_str(base64str).unwrap(), hex_psbt!(base16str).unwrap()); assert_eq!(
PartiallySignedTransaction::from_str(base64str).unwrap(),
hex_psbt!(base16str).unwrap()
);
} }
} }
@ -1260,7 +1292,8 @@ mod tests {
assert!(&psbt.inputs[0].final_script_sig.is_some()); assert!(&psbt.inputs[0].final_script_sig.is_some());
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap(); let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
let expected_out = ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(); let expected_out =
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
assert!(redeem_script.is_v0_p2wpkh()); assert!(redeem_script.is_v0_p2wpkh());
assert_eq!( assert_eq!(
@ -1287,8 +1320,7 @@ mod tests {
assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.txid()); assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.txid());
assert!(psbt_non_witness_utxo.output[tx_input.previous_output.vout as usize] assert!(psbt_non_witness_utxo.output[tx_input.previous_output.vout as usize]
.script_pubkey .script_pubkey
.is_p2pkh() .is_p2pkh());
);
assert_eq!( assert_eq!(
psbt.inputs[0].sighash_type.as_ref().unwrap().ecdsa_hash_ty().unwrap(), psbt.inputs[0].sighash_type.as_ref().unwrap().ecdsa_hash_ty().unwrap(),
EcdsaSighashType::All EcdsaSighashType::All
@ -1306,7 +1338,8 @@ mod tests {
assert!(&psbt.inputs[1].final_script_sig.is_none()); assert!(&psbt.inputs[1].final_script_sig.is_none());
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap(); let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
let expected_out = ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(); let expected_out =
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
assert!(redeem_script.is_v0_p2wpkh()); assert!(redeem_script.is_v0_p2wpkh());
assert_eq!( assert_eq!(
@ -1330,7 +1363,8 @@ mod tests {
assert!(&psbt.inputs[0].final_script_sig.is_none()); assert!(&psbt.inputs[0].final_script_sig.is_none());
let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap(); let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap();
let expected_out = ScriptBuf::from_hex("a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87").unwrap(); let expected_out =
ScriptBuf::from_hex("a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87").unwrap();
assert!(redeem_script.is_v0_p2wsh()); assert!(redeem_script.is_v0_p2wsh());
assert_eq!( assert_eq!(
@ -1355,10 +1389,7 @@ mod tests {
); );
let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new(); let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new();
let key: raw::Key = raw::Key { let key: raw::Key = raw::Key { type_value: 0x0fu8, key: hex!("010203040506070809") };
type_value: 0x0fu8,
key: hex!("010203040506070809"),
};
let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f"); let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f");
unknown.insert(key, value); unknown.insert(key, value);
@ -1378,7 +1409,10 @@ mod tests {
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert_eq!(err.to_string(), "invalid taproot signature"); assert_eq!(err.to_string(), "invalid taproot signature");
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 66"); assert_eq!(
err.to_string(),
"invalid taproot signature: invalid taproot signature size: 66"
);
let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err(); let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err();
assert_eq!(err.to_string(), "invalid xonly public key"); assert_eq!(err.to_string(), "invalid xonly public key");
let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err(); let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err();
@ -1394,12 +1428,18 @@ mod tests {
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert_eq!(err.to_string(), "invalid taproot signature"); assert_eq!(err.to_string(), "invalid taproot signature");
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 66"); assert_eq!(
err.to_string(),
"invalid taproot signature: invalid taproot signature size: 66"
);
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err(); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
#[cfg(feature = "std")] #[cfg(feature = "std")]
assert_eq!(err.to_string(), "invalid taproot signature"); assert_eq!(err.to_string(), "invalid taproot signature");
#[cfg(not(feature = "std"))] #[cfg(not(feature = "std"))]
assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 57"); assert_eq!(
err.to_string(),
"invalid taproot signature: invalid taproot signature size: 57"
);
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err(); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
assert_eq!(err.to_string(), "invalid control block"); assert_eq!(err.to_string(), "invalid control block");
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err(); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
@ -1575,11 +1615,10 @@ mod tests {
#[test] #[test]
fn serialize_and_deserialize_proprietary() { fn serialize_and_deserialize_proprietary() {
let mut psbt: PartiallySignedTransaction = hex_psbt!("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap(); let mut psbt: PartiallySignedTransaction = hex_psbt!("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
psbt.proprietary.insert(raw::ProprietaryKey { psbt.proprietary.insert(
prefix: b"test".to_vec(), raw::ProprietaryKey { prefix: b"test".to_vec(), subtype: 0u8, key: b"test".to_vec() },
subtype: 0u8, b"test".to_vec(),
key: b"test".to_vec(), );
}, b"test".to_vec());
assert!(!psbt.proprietary.is_empty()); assert!(!psbt.proprietary.is_empty());
let rtt: PartiallySignedTransaction = hex_psbt!(&psbt.serialize_hex()).unwrap(); let rtt: PartiallySignedTransaction = hex_psbt!(&psbt.serialize_hex()).unwrap();
assert!(!rtt.proprietary.is_empty()); assert!(!rtt.proprietary.is_empty());
@ -1725,31 +1764,31 @@ mod tests {
let mut t2 = t.clone(); let mut t2 = t.clone();
t2.inputs[0].non_witness_utxo = None; t2.inputs[0].non_witness_utxo = None;
match t2.fee().unwrap_err() { match t2.fee().unwrap_err() {
Error::MissingUtxo => {}, Error::MissingUtxo => {}
e => panic!("unexpected error: {:?}", e) e => panic!("unexpected error: {:?}", e),
} }
// negative fee // negative fee
let mut t3 = t.clone(); let mut t3 = t.clone();
t3.unsigned_tx.output[0].value = prev_output_val; t3.unsigned_tx.output[0].value = prev_output_val;
match t3.fee().unwrap_err() { match t3.fee().unwrap_err() {
Error::NegativeFee => {}, Error::NegativeFee => {}
e => panic!("unexpected error: {:?}", e) e => panic!("unexpected error: {:?}", e),
} }
// overflow // overflow
t.unsigned_tx.output[0].value = u64::max_value(); t.unsigned_tx.output[0].value = u64::max_value();
t.unsigned_tx.output[1].value = u64::max_value(); t.unsigned_tx.output[1].value = u64::max_value();
match t.fee().unwrap_err() { match t.fee().unwrap_err() {
Error::FeeOverflow => {}, Error::FeeOverflow => {}
e => panic!("unexpected error: {:?}", e) e => panic!("unexpected error: {:?}", e),
} }
} }
#[test] #[test]
#[cfg(feature = "rand-std")] #[cfg(feature = "rand-std")]
fn sign_psbt() { fn sign_psbt() {
use crate::WPubkeyHash;
use crate::address::WitnessProgram; use crate::address::WitnessProgram;
use crate::bip32::{Fingerprint, DerivationPath}; use crate::bip32::{DerivationPath, Fingerprint};
use crate::WPubkeyHash;
let unsigned_tx = Transaction { let unsigned_tx = Transaction {
version: 2, version: 2,
@ -1778,13 +1817,10 @@ mod tests {
psbt.inputs[0].bip32_derivation = map; psbt.inputs[0].bip32_derivation = map;
// Second input is unspendable by us e.g., from another wallet that supports future upgrades. // Second input is unspendable by us e.g., from another wallet that supports future upgrades.
let unknown_prog = WitnessProgram::new( let unknown_prog =
crate::address::WitnessVersion::V4, vec![0xaa; 34] WitnessProgram::new(crate::address::WitnessVersion::V4, vec![0xaa; 34]).unwrap();
).unwrap(); let txout_unknown_future =
let txout_unknown_future = TxOut{ TxOut { value: 10, script_pubkey: ScriptBuf::new_witness_program(&unknown_prog) };
value: 10,
script_pubkey: ScriptBuf::new_witness_program(&unknown_prog),
};
psbt.inputs[1].witness_utxo = Some(txout_unknown_future); psbt.inputs[1].witness_utxo = Some(txout_unknown_future);
let sigs = psbt.sign(&key_map, &secp).unwrap(); let sigs = psbt.sign(&key_map, &secp).unwrap();

View File

@ -6,16 +6,17 @@
//! <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>. //! <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>.
//! //!
use crate::prelude::*;
use core::fmt;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt;
use super::serialize::{Deserialize, Serialize};
use crate::consensus::encode::{
self, deserialize, serialize, Decodable, Encodable, ReadExt, VarInt, WriteExt, MAX_VEC_SIZE,
};
use crate::io; use crate::io;
use crate::consensus::encode::{self, ReadExt, WriteExt, Decodable, Encodable, VarInt, serialize, deserialize, MAX_VEC_SIZE}; use crate::prelude::*;
use crate::psbt::Error; use crate::psbt::Error;
use super::serialize::{Serialize, Deserialize};
/// A PSBT key in its raw byte form. /// A PSBT key in its raw byte form.
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)] #[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -51,7 +52,10 @@ pub type ProprietaryType = u8;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
pub struct ProprietaryKey<Subtype=ProprietaryType> where Subtype: Copy + From<u8> + Into<u8> { pub struct ProprietaryKey<Subtype = ProprietaryType>
where
Subtype: Copy + From<u8> + Into<u8>,
{
/// Proprietary type prefix used for grouping together keys under some /// Proprietary type prefix used for grouping together keys under some
/// application and avoid namespace collision /// application and avoid namespace collision
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
@ -83,7 +87,7 @@ impl Key {
return Err(encode::Error::OversizedVectorAllocation { return Err(encode::Error::OversizedVectorAllocation {
requested: key_byte_size as usize, requested: key_byte_size as usize,
max: MAX_VEC_SIZE, max: MAX_VEC_SIZE,
})? })?;
} }
let type_value: u8 = Decodable::consensus_decode(r)?; let type_value: u8 = Decodable::consensus_decode(r)?;
@ -100,7 +104,9 @@ impl Key {
impl Serialize for Key { impl Serialize for Key {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::new(); let mut buf = Vec::new();
VarInt((self.key.len() + 1) as u64).consensus_encode(&mut buf).expect("in-memory writers don't error"); VarInt((self.key.len() + 1) as u64)
.consensus_encode(&mut buf)
.expect("in-memory writers don't error");
self.type_value.consensus_encode(&mut buf).expect("in-memory writers don't error"); self.type_value.consensus_encode(&mut buf).expect("in-memory writers don't error");
@ -131,14 +137,14 @@ impl Deserialize for Pair {
impl Pair { impl Pair {
pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> { pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Pair { Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
key: Key::decode(r)?,
value: Decodable::consensus_decode(r)?,
})
} }
} }
impl<Subtype> Encodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> { impl<Subtype> Encodable for ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
let mut len = self.prefix.consensus_encode(w)? + 1; let mut len = self.prefix.consensus_encode(w)? + 1;
w.emit_u8(self.subtype.into())?; w.emit_u8(self.subtype.into())?;
@ -148,7 +154,10 @@ impl<Subtype> Encodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u
} }
} }
impl<Subtype> Decodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> { impl<Subtype> Decodable for ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let prefix = Vec::<u8>::consensus_decode(r)?; let prefix = Vec::<u8>::consensus_decode(r)?;
let subtype = Subtype::from(r.read_u8()?); let subtype = Subtype::from(r.read_u8()?);
@ -158,19 +167,18 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u
} }
} }
impl<Subtype> ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> { impl<Subtype> ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
/// Constructs full [Key] corresponding to this proprietary key type /// Constructs full [Key] corresponding to this proprietary key type
pub fn to_key(&self) -> Key { pub fn to_key(&self) -> Key { Key { type_value: 0xFC, key: serialize(self) } }
Key {
type_value: 0xFC,
key: serialize(self)
}
}
} }
impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype> impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype>
where where
Subtype:Copy + From<u8> + Into<u8> { Subtype: Copy + From<u8> + Into<u8>,
{
type Error = Error; type Error = Error;
/// Constructs a [`ProprietaryKey`] from a [`Key`]. /// Constructs a [`ProprietaryKey`] from a [`Key`].
@ -179,7 +187,7 @@ where
/// Returns [`Error::InvalidProprietaryKey`] if `key` does not start with `0xFC` byte. /// Returns [`Error::InvalidProprietaryKey`] if `key` does not start with `0xFC` byte.
fn try_from(key: Key) -> Result<Self, Self::Error> { fn try_from(key: Key) -> Result<Self, Self::Error> {
if key.type_value != 0xFC { if key.type_value != 0xFC {
return Err(Error::InvalidProprietaryKey) return Err(Error::InvalidProprietaryKey);
} }
Ok(deserialize(&key.key)?) Ok(deserialize(&key.key)?)
@ -194,7 +202,7 @@ pub(crate) fn read_to_end<D: io::Read>(mut d: D) -> Result<Vec<u8>, io::Error> {
match d.read(&mut buf) { match d.read(&mut buf) {
Ok(0) => break, Ok(0) => break,
Ok(n) => result.extend_from_slice(&buf[0..n]), Ok(n) => result.extend_from_slice(&buf[0..n]),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}, Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
} }

View File

@ -6,31 +6,26 @@
//! according to the BIP-174 specification. //! according to the BIP-174 specification.
//! //!
use core::convert::TryFrom; use core::convert::{TryFrom, TryInto};
use core::convert::TryInto;
use crate::VarInt;
use crate::prelude::*;
use crate::io;
use crate::blockdata::script::ScriptBuf;
use crate::blockdata::witness::Witness;
use crate::blockdata::transaction::{Transaction, TxOut};
use crate::consensus::encode::{self, serialize, Decodable, Encodable, deserialize_partial};
use crate::taproot::TapTree;
use secp256k1::{self, XOnlyPublicKey}; use secp256k1::{self, XOnlyPublicKey};
use crate::bip32::{ChildNumber, Fingerprint, KeySource};
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
use crate::crypto::{ecdsa, taproot};
use crate::psbt::{Error, PartiallySignedTransaction};
use crate::taproot::{TapNodeHash, TapLeafHash, ControlBlock, LeafVersion};
use crate::crypto::key::PublicKey;
use super::map::{Map, Input, Output, PsbtSighashType}; use super::map::{Input, Map, Output, PsbtSighashType};
use super::Psbt; use super::Psbt;
use crate::bip32::{ChildNumber, Fingerprint, KeySource};
use crate::taproot::TaprootBuilder; use crate::blockdata::script::ScriptBuf;
use crate::blockdata::transaction::{Transaction, TxOut};
use crate::blockdata::witness::Witness;
use crate::consensus::encode::{self, deserialize_partial, serialize, Decodable, Encodable};
use crate::crypto::key::PublicKey;
use crate::crypto::{ecdsa, taproot};
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
use crate::prelude::*;
use crate::psbt::{Error, PartiallySignedTransaction};
use crate::taproot::{
ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TapTree, TaprootBuilder,
};
use crate::{io, VarInt};
/// A trait for serializing a value as raw data for insertion into PSBT /// A trait for serializing a value as raw data for insertion into PSBT
/// key-value maps. /// key-value maps.
pub(crate) trait Serialize { pub(crate) trait Serialize {
@ -46,9 +41,7 @@ pub(crate) trait Deserialize: Sized {
impl PartiallySignedTransaction { impl PartiallySignedTransaction {
/// Serialize a value as bytes in hex. /// Serialize a value as bytes in hex.
pub fn serialize_hex(&self) -> String { pub fn serialize_hex(&self) -> String { self.serialize().to_lower_hex_string() }
self.serialize().to_lower_hex_string()
}
/// Serialize as raw binary data /// Serialize as raw binary data
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
@ -72,7 +65,6 @@ impl PartiallySignedTransaction {
buf buf
} }
/// Deserialize a value from raw binary data. /// Deserialize a value from raw binary data.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> { pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
const MAGIC_BYTES: &[u8] = b"psbt"; const MAGIC_BYTES: &[u8] = b"psbt";
@ -133,15 +125,11 @@ impl_psbt_hash_de_serialize!(sha256d::Hash);
impl_psbt_de_serialize!(Vec<TapLeafHash>); impl_psbt_de_serialize!(Vec<TapLeafHash>);
impl Serialize for ScriptBuf { impl Serialize for ScriptBuf {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { self.to_bytes() }
self.to_bytes()
}
} }
impl Deserialize for ScriptBuf { impl Deserialize for ScriptBuf {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> { Ok(Self::from(bytes.to_vec())) }
Ok(Self::from(bytes.to_vec()))
}
} }
impl Serialize for PublicKey { impl Serialize for PublicKey {
@ -154,28 +142,22 @@ impl Serialize for PublicKey {
impl Deserialize for PublicKey { impl Deserialize for PublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
PublicKey::from_slice(bytes) PublicKey::from_slice(bytes).map_err(Error::InvalidPublicKey)
.map_err(Error::InvalidPublicKey)
} }
} }
impl Serialize for secp256k1::PublicKey { impl Serialize for secp256k1::PublicKey {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { self.serialize().to_vec() }
self.serialize().to_vec()
}
} }
impl Deserialize for secp256k1::PublicKey { impl Deserialize for secp256k1::PublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
secp256k1::PublicKey::from_slice(bytes) secp256k1::PublicKey::from_slice(bytes).map_err(Error::InvalidSecp256k1PublicKey)
.map_err(Error::InvalidSecp256k1PublicKey)
} }
} }
impl Serialize for ecdsa::Signature { impl Serialize for ecdsa::Signature {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { self.to_vec() }
self.to_vec()
}
} }
impl Deserialize for ecdsa::Signature { impl Deserialize for ecdsa::Signature {
@ -193,17 +175,10 @@ impl Deserialize for ecdsa::Signature {
// also has a field sighash_u32 (See BIP141). For example, when signing with non-standard // also has a field sighash_u32 (See BIP141). For example, when signing with non-standard
// 0x05, the sighash message would have the last field as 0x05u32 while, the verification // 0x05, the sighash message would have the last field as 0x05u32 while, the verification
// would use check the signature assuming sighash_u32 as `0x01`. // would use check the signature assuming sighash_u32 as `0x01`.
ecdsa::Signature::from_slice(bytes) ecdsa::Signature::from_slice(bytes).map_err(|e| match e {
.map_err(|e| match e { ecdsa::Error::EmptySignature => Error::InvalidEcdsaSignature(e),
ecdsa::Error::EmptySignature => { ecdsa::Error::NonStandardSighashType(flag) => Error::NonStandardSighashType(flag),
Error::InvalidEcdsaSignature(e) ecdsa::Error::Secp256k1(..) => Error::InvalidEcdsaSignature(e),
}
ecdsa::Error::NonStandardSighashType(flag) => {
Error::NonStandardSighashType(flag)
}
ecdsa::Error::Secp256k1(..) => {
Error::InvalidEcdsaSignature(e)
}
ecdsa::Error::HexEncoding(..) => { ecdsa::Error::HexEncoding(..) => {
unreachable!("Decoding from slice, not hex") unreachable!("Decoding from slice, not hex")
} }
@ -228,7 +203,7 @@ impl Serialize for KeySource {
impl Deserialize for KeySource { impl Deserialize for KeySource {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() < 4 { if bytes.len() < 4 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into());
} }
let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length"); let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length");
@ -248,21 +223,15 @@ impl Deserialize for KeySource {
// partial sigs // partial sigs
impl Serialize for Vec<u8> { impl Serialize for Vec<u8> {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { self.clone() }
self.clone()
}
} }
impl Deserialize for Vec<u8> { impl Deserialize for Vec<u8> {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> { Ok(bytes.to_vec()) }
Ok(bytes.to_vec())
}
} }
impl Serialize for PsbtSighashType { impl Serialize for PsbtSighashType {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { serialize(&self.to_u32()) }
serialize(&self.to_u32())
}
} }
impl Deserialize for PsbtSighashType { impl Deserialize for PsbtSighashType {
@ -274,37 +243,25 @@ impl Deserialize for PsbtSighashType {
// Taproot related ser/deser // Taproot related ser/deser
impl Serialize for XOnlyPublicKey { impl Serialize for XOnlyPublicKey {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { XOnlyPublicKey::serialize(self).to_vec() }
XOnlyPublicKey::serialize(self).to_vec()
}
} }
impl Deserialize for XOnlyPublicKey { impl Deserialize for XOnlyPublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
XOnlyPublicKey::from_slice(bytes) XOnlyPublicKey::from_slice(bytes).map_err(|_| Error::InvalidXOnlyPublicKey)
.map_err(|_| Error::InvalidXOnlyPublicKey)
} }
} }
impl Serialize for taproot::Signature { impl Serialize for taproot::Signature {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { self.to_vec() }
self.to_vec()
}
} }
impl Deserialize for taproot::Signature { impl Deserialize for taproot::Signature {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
taproot::Signature::from_slice(bytes) taproot::Signature::from_slice(bytes).map_err(|e| match e {
.map_err(|e| match e { taproot::Error::InvalidSighashType(flag) => Error::NonStandardSighashType(flag as u32),
taproot::Error::InvalidSighashType(flag) => { taproot::Error::InvalidSignatureSize(_) => Error::InvalidTaprootSignature(e),
Error::NonStandardSighashType(flag as u32) taproot::Error::Secp256k1(..) => Error::InvalidTaprootSignature(e),
}
taproot::Error::InvalidSignatureSize(_) => {
Error::InvalidTaprootSignature(e)
}
taproot::Error::Secp256k1(..) => {
Error::InvalidTaprootSignature(e)
}
}) })
} }
} }
@ -322,7 +279,7 @@ impl Serialize for (XOnlyPublicKey, TapLeafHash) {
impl Deserialize for (XOnlyPublicKey, TapLeafHash) { impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() < 32 { if bytes.len() < 32 {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into());
} }
let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?; let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?;
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?; let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
@ -331,15 +288,12 @@ impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
} }
impl Serialize for ControlBlock { impl Serialize for ControlBlock {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> { ControlBlock::serialize(self) }
ControlBlock::serialize(self)
}
} }
impl Deserialize for ControlBlock { impl Deserialize for ControlBlock {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Self::decode(bytes) Self::decode(bytes).map_err(|_| Error::InvalidControlBlock)
.map_err(|_| Error::InvalidControlBlock)
} }
} }
@ -356,7 +310,7 @@ impl Serialize for (ScriptBuf, LeafVersion) {
impl Deserialize for (ScriptBuf, LeafVersion) { impl Deserialize for (ScriptBuf, LeafVersion) {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
if bytes.is_empty() { if bytes.is_empty() {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into());
} }
// The last byte is LeafVersion. // The last byte is LeafVersion.
let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?; let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?;
@ -366,7 +320,6 @@ impl Deserialize for (ScriptBuf, LeafVersion) {
} }
} }
impl Serialize for (Vec<TapLeafHash>, KeySource) { impl Serialize for (Vec<TapLeafHash>, KeySource) {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(32 * self.0.len() + key_source_len(&self.1)); let mut buf = Vec::with_capacity(32 * self.0.len() + key_source_len(&self.1));
@ -387,11 +340,14 @@ impl Deserialize for (Vec<TapLeafHash>, KeySource) {
impl Serialize for TapTree { impl Serialize for TapTree {
fn serialize(&self) -> Vec<u8> { fn serialize(&self) -> Vec<u8> {
let capacity = self.script_leaves().map(|l| { let capacity = self
.script_leaves()
.map(|l| {
l.script().len() + VarInt(l.script().len() as u64).len() // script version l.script().len() + VarInt(l.script().len() as u64).len() // script version
+ 1 // merkle branch + 1 // merkle branch
+ 1 // leaf version + 1 // leaf version
}).sum::<usize>(); })
.sum::<usize>();
let mut buf = Vec::with_capacity(capacity); let mut buf = Vec::with_capacity(capacity);
for leaf_info in self.script_leaves() { for leaf_info in self.script_leaves() {
// # Cast Safety: // # Cast Safety:
@ -416,9 +372,10 @@ impl Deserialize for TapTree {
if consumed > 0 { if consumed > 0 {
bytes_iter.nth(consumed - 1); bytes_iter.nth(consumed - 1);
} }
let leaf_version = LeafVersion::from_consensus(*version) let leaf_version =
.map_err(|_| Error::InvalidLeafVersion)?; LeafVersion::from_consensus(*version).map_err(|_| Error::InvalidLeafVersion)?;
builder = builder.add_leaf_with_ver(*depth, script, leaf_version) builder = builder
.add_leaf_with_ver(*depth, script, leaf_version)
.map_err(|_| Error::Taproot("Tree not in DFS order"))?; .map_err(|_| Error::Taproot("Tree not in DFS order"))?;
} }
TapTree::try_from(builder).map_err(Error::TapTree) TapTree::try_from(builder).map_err(Error::TapTree)
@ -426,9 +383,7 @@ impl Deserialize for TapTree {
} }
// Helper function to compute key source len // Helper function to compute key source len
fn key_source_len(key_source: &KeySource) -> usize { fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_ref().len() }
4 + 4 * (key_source.1).as_ref().len()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -439,7 +394,10 @@ mod tests {
// Composes tree matching a given depth map, filled with dumb script leafs, // Composes tree matching a given depth map, filled with dumb script leafs,
// each of which consists of a single push-int op code, with int value // each of which consists of a single push-int op code, with int value
// increased for each consecutive leaf. // increased for each consecutive leaf.
pub fn compose_taproot_builder<'map>(opcode: u8, depth_map: impl IntoIterator<Item = &'map u8>) -> TaprootBuilder { pub fn compose_taproot_builder<'map>(
opcode: u8,
depth_map: impl IntoIterator<Item = &'map u8>,
) -> TaprootBuilder {
let mut val = opcode; let mut val = opcode;
let mut builder = TaprootBuilder::new(); let mut builder = TaprootBuilder::new();
for depth in depth_map { for depth in depth_map {
@ -454,7 +412,13 @@ mod tests {
#[test] #[test]
fn taptree_hidden() { fn taptree_hidden() {
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]); let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]);
builder = builder.add_leaf_with_ver(3, ScriptBuf::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap(); builder = builder
.add_leaf_with_ver(
3,
ScriptBuf::from_hex("b9").unwrap(),
LeafVersion::from_consensus(0xC2).unwrap(),
)
.unwrap();
builder = builder.add_hidden_node(3, TapNodeHash::all_zeros()).unwrap(); builder = builder.add_hidden_node(3, TapNodeHash::all_zeros()).unwrap();
assert!(TapTree::try_from(builder).is_err()); assert!(TapTree::try_from(builder).is_err());
} }
@ -462,7 +426,13 @@ mod tests {
#[test] #[test]
fn taptree_roundtrip() { fn taptree_roundtrip() {
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2, 3]); let mut builder = compose_taproot_builder(0x51, &[2, 2, 2, 3]);
builder = builder.add_leaf_with_ver(3, ScriptBuf::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap(); builder = builder
.add_leaf_with_ver(
3,
ScriptBuf::from_hex("b9").unwrap(),
LeafVersion::from_consensus(0xC2).unwrap(),
)
.unwrap();
let tree = TapTree::try_from(builder).unwrap(); let tree = TapTree::try_from(builder).unwrap();
let tree_prime = TapTree::deserialize(&tree.serialize()).unwrap(); let tree_prime = TapTree::deserialize(&tree.serialize()).unwrap();
assert_eq!(tree, tree_prime); assert_eq!(tree, tree_prime);