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
use crate::prelude::*;
use core::fmt;
use bitcoin_internals::write_err;
use crate::bip32::ExtendedPubKey;
use crate::blockdata::transaction::Transaction;
use crate::consensus::encode;
use crate::prelude::*;
use crate::psbt::raw;
use crate::hashes;
use crate::io;
use crate::bip32::ExtendedPubKey;
use crate::{hashes, io};
/// Enum for marking psbt hash error.
#[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::MissingUtxo => f.write_str("UTXO information is not present in PSBT"),
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::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::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"),
Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"),
Error::MustHaveUnsignedTx => {
f.write_str("partially signed transactions must have an unsigned transaction")
}
Error::UnsignedTxHasScriptSigs =>
f.write_str("the unsigned transaction has script sigs"),
Error::UnsignedTxHasScriptWitnesses =>
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::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "different unsigned transaction: expected {}, actual {}", e.txid(), a.txid()),
Error::NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht),
Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
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::InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => {
// directly using debug forms of psbthash enums
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::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"),
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::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA 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::XPubKey(s) => write!(f, "xpub key 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),
}
}
@ -161,7 +171,7 @@ impl std::error::Error for Error {
HashParse(e) => Some(e),
ConsensusEncoding(e) => Some(e),
Io(e) => Some(e),
| InvalidMagic
InvalidMagic
| MissingUtxo
| InvalidSeparator
| PsbtUtxoOutOfbounds
@ -196,19 +206,13 @@ impl std::error::Error for Error {
#[doc(hidden)]
impl From<hashes::Error> for Error {
fn from(e: hashes::Error) -> Error {
Error::HashParse(e)
}
fn from(e: hashes::Error) -> Error { Error::HashParse(e) }
}
impl From<encode::Error> for Error {
fn from(e: encode::Error) -> Self {
Error::ConsensusEncoding(e)
}
fn from(e: encode::Error) -> Self { Error::ConsensusEncoding(e) }
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::Io(e)
}
fn from(e: io::Error) -> Self { Error::Io(e) }
}

View File

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

View File

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

View File

@ -1,24 +1,25 @@
// SPDX-License-Identifier: CC0-1.0
use crate::prelude::*;
use core::convert::TryFrom;
use core::fmt;
use core::str::FromStr;
use core::convert::TryFrom;
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::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::serialize::Deserialize;
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};
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
@ -132,7 +133,6 @@ pub struct Input {
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
}
/// 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
/// 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
/// ([`EcdsaSighashType`], [`TapSighashType`] respectively).
pub fn from_u32(n: u32) -> PsbtSighashType {
PsbtSighashType { inner: n }
}
pub fn from_u32(n: u32) -> PsbtSighashType { PsbtSighashType { inner: n } }
/// Converts [`PsbtSighashType`] to a raw `u32` sighash flag.
///
/// No guarantees are made as to the standardness or validity of the returned value.
pub fn to_u32(self) -> u32 {
self.inner
}
pub fn to_u32(self) -> u32 { self.inner }
}
impl Input {
@ -247,10 +242,7 @@ impl Input {
}
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
let raw::Pair {
key: raw_key,
value: raw_value,
} = pair;
let raw::Pair { key: raw_key, value: raw_value } = pair;
match raw_key.type_value {
PSBT_IN_NON_WITNESS_UTXO => {
@ -299,16 +291,36 @@ impl Input {
}
}
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_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_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_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 => {
impl_psbt_insert_pair! {
@ -345,7 +357,7 @@ impl Input {
match self.proprietary.entry(key) {
btree_map::Entry::Vacant(empty_key) => {
empty_key.insert(raw_value);
},
}
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)
}
for (key, value) in self.proprietary.iter() {
rv.push(raw::Pair {
key: key.to_key(),
value: value.clone(),
});
rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
}
for (key, value) in self.unknown.iter() {
rv.push(raw::Pair {
key: key.clone(),
value: value.clone(),
});
rv.push(raw::Pair { key: key.clone(), value: value.clone() });
}
rv

View File

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

View File

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

View File

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

View File

@ -6,16 +6,17 @@
//! <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>.
//!
use crate::prelude::*;
use core::fmt;
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::consensus::encode::{self, ReadExt, WriteExt, Decodable, Encodable, VarInt, serialize, deserialize, MAX_VEC_SIZE};
use crate::prelude::*;
use crate::psbt::Error;
use super::serialize::{Serialize, Deserialize};
/// A PSBT key in its raw byte form.
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -51,7 +52,10 @@ pub type ProprietaryType = u8;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[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
/// application and avoid namespace collision
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
@ -83,7 +87,7 @@ impl Key {
return Err(encode::Error::OversizedVectorAllocation {
requested: key_byte_size as usize,
max: MAX_VEC_SIZE,
})?
})?;
}
let type_value: u8 = Decodable::consensus_decode(r)?;
@ -100,7 +104,9 @@ impl Key {
impl Serialize for Key {
fn serialize(&self) -> Vec<u8> {
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");
@ -131,14 +137,14 @@ impl Deserialize for Pair {
impl Pair {
pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Pair {
key: Key::decode(r)?,
value: Decodable::consensus_decode(r)?,
})
Ok(Pair { 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> {
let mut len = self.prefix.consensus_encode(w)? + 1;
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> {
let prefix = Vec::<u8>::consensus_decode(r)?;
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
pub fn to_key(&self) -> Key {
Key {
type_value: 0xFC,
key: serialize(self)
}
}
pub fn to_key(&self) -> Key { Key { type_value: 0xFC, key: serialize(self) } }
}
impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype>
where
Subtype:Copy + From<u8> + Into<u8> {
Subtype: Copy + From<u8> + Into<u8>,
{
type Error = Error;
/// Constructs a [`ProprietaryKey`] from a [`Key`].
@ -179,7 +187,7 @@ where
/// Returns [`Error::InvalidProprietaryKey`] if `key` does not start with `0xFC` byte.
fn try_from(key: Key) -> Result<Self, Self::Error> {
if key.type_value != 0xFC {
return Err(Error::InvalidProprietaryKey)
return Err(Error::InvalidProprietaryKey);
}
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) {
Ok(0) => break,
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),
};
}

View File

@ -6,31 +6,26 @@
//! according to the BIP-174 specification.
//!
use core::convert::TryFrom;
use core::convert::TryInto;
use core::convert::{TryFrom, 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 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 crate::taproot::TaprootBuilder;
use crate::bip32::{ChildNumber, Fingerprint, KeySource};
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
/// key-value maps.
pub(crate) trait Serialize {
@ -46,9 +41,7 @@ pub(crate) trait Deserialize: Sized {
impl PartiallySignedTransaction {
/// Serialize a value as bytes in hex.
pub fn serialize_hex(&self) -> String {
self.serialize().to_lower_hex_string()
}
pub fn serialize_hex(&self) -> String { self.serialize().to_lower_hex_string() }
/// Serialize as raw binary data
pub fn serialize(&self) -> Vec<u8> {
@ -72,7 +65,6 @@ impl PartiallySignedTransaction {
buf
}
/// Deserialize a value from raw binary data.
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
const MAGIC_BYTES: &[u8] = b"psbt";
@ -133,15 +125,11 @@ impl_psbt_hash_de_serialize!(sha256d::Hash);
impl_psbt_de_serialize!(Vec<TapLeafHash>);
impl Serialize for ScriptBuf {
fn serialize(&self) -> Vec<u8> {
self.to_bytes()
}
fn serialize(&self) -> Vec<u8> { self.to_bytes() }
}
impl Deserialize for ScriptBuf {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Ok(Self::from(bytes.to_vec()))
}
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { Ok(Self::from(bytes.to_vec())) }
}
impl Serialize for PublicKey {
@ -154,28 +142,22 @@ impl Serialize for PublicKey {
impl Deserialize for PublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
PublicKey::from_slice(bytes)
.map_err(Error::InvalidPublicKey)
PublicKey::from_slice(bytes).map_err(Error::InvalidPublicKey)
}
}
impl Serialize for secp256k1::PublicKey {
fn serialize(&self) -> Vec<u8> {
self.serialize().to_vec()
}
fn serialize(&self) -> Vec<u8> { self.serialize().to_vec() }
}
impl Deserialize for secp256k1::PublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
secp256k1::PublicKey::from_slice(bytes)
.map_err(Error::InvalidSecp256k1PublicKey)
secp256k1::PublicKey::from_slice(bytes).map_err(Error::InvalidSecp256k1PublicKey)
}
}
impl Serialize for ecdsa::Signature {
fn serialize(&self) -> Vec<u8> {
self.to_vec()
}
fn serialize(&self) -> Vec<u8> { self.to_vec() }
}
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
// 0x05, the sighash message would have the last field as 0x05u32 while, the verification
// would use check the signature assuming sighash_u32 as `0x01`.
ecdsa::Signature::from_slice(bytes)
.map_err(|e| match e {
ecdsa::Error::EmptySignature => {
Error::InvalidEcdsaSignature(e)
}
ecdsa::Error::NonStandardSighashType(flag) => {
Error::NonStandardSighashType(flag)
}
ecdsa::Error::Secp256k1(..) => {
Error::InvalidEcdsaSignature(e)
}
ecdsa::Signature::from_slice(bytes).map_err(|e| match e {
ecdsa::Error::EmptySignature => Error::InvalidEcdsaSignature(e),
ecdsa::Error::NonStandardSighashType(flag) => Error::NonStandardSighashType(flag),
ecdsa::Error::Secp256k1(..) => Error::InvalidEcdsaSignature(e),
ecdsa::Error::HexEncoding(..) => {
unreachable!("Decoding from slice, not hex")
}
@ -228,7 +203,7 @@ impl Serialize for KeySource {
impl Deserialize for KeySource {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
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");
@ -248,21 +223,15 @@ impl Deserialize for KeySource {
// partial sigs
impl Serialize for Vec<u8> {
fn serialize(&self) -> Vec<u8> {
self.clone()
}
fn serialize(&self) -> Vec<u8> { self.clone() }
}
impl Deserialize for Vec<u8> {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Ok(bytes.to_vec())
}
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { Ok(bytes.to_vec()) }
}
impl Serialize for PsbtSighashType {
fn serialize(&self) -> Vec<u8> {
serialize(&self.to_u32())
}
fn serialize(&self) -> Vec<u8> { serialize(&self.to_u32()) }
}
impl Deserialize for PsbtSighashType {
@ -274,37 +243,25 @@ impl Deserialize for PsbtSighashType {
// Taproot related ser/deser
impl Serialize for XOnlyPublicKey {
fn serialize(&self) -> Vec<u8> {
XOnlyPublicKey::serialize(self).to_vec()
}
fn serialize(&self) -> Vec<u8> { XOnlyPublicKey::serialize(self).to_vec() }
}
impl Deserialize for XOnlyPublicKey {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
XOnlyPublicKey::from_slice(bytes)
.map_err(|_| Error::InvalidXOnlyPublicKey)
XOnlyPublicKey::from_slice(bytes).map_err(|_| Error::InvalidXOnlyPublicKey)
}
}
impl Serialize for taproot::Signature {
fn serialize(&self) -> Vec<u8> {
self.to_vec()
}
fn serialize(&self) -> Vec<u8> { self.to_vec() }
}
impl Deserialize for taproot::Signature {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
taproot::Signature::from_slice(bytes)
.map_err(|e| match e {
taproot::Error::InvalidSighashType(flag) => {
Error::NonStandardSighashType(flag as u32)
}
taproot::Error::InvalidSignatureSize(_) => {
Error::InvalidTaprootSignature(e)
}
taproot::Error::Secp256k1(..) => {
Error::InvalidTaprootSignature(e)
}
taproot::Signature::from_slice(bytes).map_err(|e| match e {
taproot::Error::InvalidSighashType(flag) => Error::NonStandardSighashType(flag as u32),
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) {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
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 b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
@ -331,15 +288,12 @@ impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
}
impl Serialize for ControlBlock {
fn serialize(&self) -> Vec<u8> {
ControlBlock::serialize(self)
}
fn serialize(&self) -> Vec<u8> { ControlBlock::serialize(self) }
}
impl Deserialize for ControlBlock {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
Self::decode(bytes)
.map_err(|_| Error::InvalidControlBlock)
Self::decode(bytes).map_err(|_| Error::InvalidControlBlock)
}
}
@ -356,7 +310,7 @@ impl Serialize for (ScriptBuf, LeafVersion) {
impl Deserialize for (ScriptBuf, LeafVersion) {
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
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.
let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?;
@ -366,7 +320,6 @@ impl Deserialize for (ScriptBuf, LeafVersion) {
}
}
impl Serialize for (Vec<TapLeafHash>, KeySource) {
fn serialize(&self) -> Vec<u8> {
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 {
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
+ 1 // merkle branch
+ 1 // leaf version
}).sum::<usize>();
})
.sum::<usize>();
let mut buf = Vec::with_capacity(capacity);
for leaf_info in self.script_leaves() {
// # Cast Safety:
@ -416,9 +372,10 @@ impl Deserialize for TapTree {
if consumed > 0 {
bytes_iter.nth(consumed - 1);
}
let leaf_version = LeafVersion::from_consensus(*version)
.map_err(|_| Error::InvalidLeafVersion)?;
builder = builder.add_leaf_with_ver(*depth, script, leaf_version)
let leaf_version =
LeafVersion::from_consensus(*version).map_err(|_| Error::InvalidLeafVersion)?;
builder = builder
.add_leaf_with_ver(*depth, script, leaf_version)
.map_err(|_| Error::Taproot("Tree not in DFS order"))?;
}
TapTree::try_from(builder).map_err(Error::TapTree)
@ -426,9 +383,7 @@ impl Deserialize for TapTree {
}
// Helper function to compute key source len
fn key_source_len(key_source: &KeySource) -> usize {
4 + 4 * (key_source.1).as_ref().len()
}
fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_ref().len() }
#[cfg(test)]
mod tests {
@ -439,7 +394,10 @@ mod tests {
// 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
// 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 builder = TaprootBuilder::new();
for depth in depth_map {
@ -454,7 +412,13 @@ mod tests {
#[test]
fn taptree_hidden() {
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();
assert!(TapTree::try_from(builder).is_err());
}
@ -462,7 +426,13 @@ mod tests {
#[test]
fn taptree_roundtrip() {
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_prime = TapTree::deserialize(&tree.serialize()).unwrap();
assert_eq!(tree, tree_prime);