diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index 608ee1d4..de014517 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -518,6 +518,7 @@ impl_array!(8); impl_array!(12); impl_array!(16); impl_array!(32); +impl_array!(33); impl> Encodable for [T] { #[inline] diff --git a/src/util/psbt/macros.rs b/src/util/psbt/macros.rs index 628d8ba2..a36fbd08 100644 --- a/src/util/psbt/macros.rs +++ b/src/util/psbt/macros.rs @@ -1,3 +1,11 @@ +macro_rules! merge { + ($thing:ident, $slf:ident, $other:ident) => { + if let (&None, Some($thing)) = (&$slf.$thing, $other.$thing) { + $slf.$thing = Some($thing); + } + }; +} + macro_rules! impl_psbt_de_serialize { ($thing:ty) => { impl_psbt_serialize!($thing); @@ -38,3 +46,86 @@ macro_rules! impl_psbtmap_consensus_encoding { } }; } + +macro_rules! impl_psbtmap_consensus_decoding { + ($thing:ty) => { + impl ::consensus::encode::Decodable for $thing { + fn consensus_decode(d: &mut D) -> Result { + let mut rv: Self = ::std::default::Default::default(); + + loop { + match ::consensus::encode::Decodable::consensus_decode(d) { + Ok(pair) => ::util::psbt::Map::insert_pair(&mut rv, pair)?, + Err(::consensus::encode::Error::Psbt(::util::psbt::Error::NoMorePairs)) => return Ok(rv), + Err(e) => return Err(e), + } + } + } + } + }; +} + +macro_rules! impl_psbtmap_consensus_enc_dec_oding { + ($thing:ty) => { + impl_psbtmap_consensus_decoding!($thing); + impl_psbtmap_consensus_encoding!($thing); + }; +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +macro_rules! impl_psbt_insert_pair { + ($slf:ident.$unkeyed_name:ident <= <$raw_key:ident: _>|<$raw_value:ident: $unkeyed_value_type:ty>) => { + if $raw_key.key.is_empty() { + if let None = $slf.$unkeyed_name { + let val: $unkeyed_value_type = ::util::psbt::serialize::Deserialize::deserialize(&$raw_value)?; + + $slf.$unkeyed_name = Some(val) + } else { + return Err(::util::psbt::Error::DuplicateKey($raw_key).into()); + } + } else { + return Err(::util::psbt::Error::InvalidKey($raw_key).into()); + } + }; + ($slf:ident.$keyed_name:ident <= <$raw_key:ident: $keyed_key_type:ty>|<$raw_value:ident: $keyed_value_type:ty>) => { + if !$raw_key.key.is_empty() { + let key_val: $keyed_key_type = ::util::psbt::serialize::Deserialize::deserialize(&$raw_key.key)?; + + if $slf.$keyed_name.contains_key(&key_val) { + return Err(::util::psbt::Error::DuplicateKey($raw_key).into()); + } else { + let val: $keyed_value_type = ::util::psbt::serialize::Deserialize::deserialize(&$raw_value)?; + + $slf.$keyed_name.insert(key_val, val); + } + } else { + return Err(::util::psbt::Error::InvalidKey($raw_key).into()); + } + }; +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +macro_rules! impl_psbt_get_pair { + ($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>|<$unkeyed_value_type:ty>)) => { + if let Some(ref $unkeyed_name) = $slf.$unkeyed_name { + $rv.push(::util::psbt::raw::Pair { + key: ::util::psbt::raw::Key { + type_value: $unkeyed_typeval, + key: vec![], + }, + value: ::util::psbt::serialize::Serialize::serialize($unkeyed_name), + }); + } + }; + ($rv:ident.push($slf:ident.$keyed_name:ident as <$keyed_typeval:expr, $keyed_key_type:ty>|<$keyed_value_type:ty>)) => { + for (key, val) in &$slf.$keyed_name { + $rv.push(::util::psbt::raw::Pair { + key: ::util::psbt::raw::Key { + type_value: $keyed_typeval, + key: ::util::psbt::serialize::Serialize::serialize(key), + }, + value: ::util::psbt::serialize::Serialize::serialize(val), + }); + } + }; +} diff --git a/src/util/psbt/map/mod.rs b/src/util/psbt/map/mod.rs index b353e427..6ad915ce 100644 --- a/src/util/psbt/map/mod.rs +++ b/src/util/psbt/map/mod.rs @@ -16,5 +16,7 @@ pub trait Map { // place at end to pick up macros mod global; +mod output; pub use self::global::Global; +pub use self::output::Output; diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs new file mode 100644 index 00000000..6dd23384 --- /dev/null +++ b/src/util/psbt/map/output.rs @@ -0,0 +1,98 @@ +use std::collections::HashMap; + +use blockdata::script::Script; +use consensus::encode; +use util::bip32::{DerivationPath, Fingerprint}; +use util::key::PublicKey; +use util::psbt; +use util::psbt::map::Map; +use util::psbt::raw; +use util::psbt::Error; + +/// A key-value map for an output of the corresponding index in the unsigned +/// transaction. +#[derive(Clone, Default, Debug, PartialEq)] +pub struct Output { + /// The redeem script for this output. + pub redeem_script: Option