diff --git a/src/util/psbt/map/global.rs b/src/util/psbt/map/global.rs index 15e9c945..e834d181 100644 --- a/src/util/psbt/map/global.rs +++ b/src/util/psbt/map/global.rs @@ -32,6 +32,8 @@ const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00; const PSBT_GLOBAL_XPUB: u8 = 0x01; /// Type: Version Number PSBT_GLOBAL_VERSION = 0xFB const PSBT_GLOBAL_VERSION: u8 = 0xFB; +/// Type: Proprietary Use Type PSBT_GLOBAL_PROPRIETARY = 0xFC +const PSBT_GLOBAL_PROPRIETARY: u8 = 0xFC; /// A key-value map for global data. #[derive(Clone, Debug, PartialEq)] @@ -44,10 +46,12 @@ pub struct Global { /// A global map from extended public keys to the used key fingerprint and /// derivation path as defined by BIP 32 pub xpub: BTreeMap, + /// Global proprietary key-value pairs. + pub proprietary: BTreeMap>, /// Unknown global key-value pairs. pub unknown: BTreeMap>, } -serde_struct_impl!(Global, unsigned_tx, version, xpub, unknown); +serde_struct_impl!(Global, unsigned_tx, version, xpub, proprietary, unknown); impl Global { /// Create a Global from an unsigned transaction, error if not unsigned @@ -66,6 +70,7 @@ impl Global { unsigned_tx: tx, xpub: Default::default(), version: 0, + proprietary: Default::default(), unknown: Default::default(), }) } @@ -80,6 +85,10 @@ impl Map for Global { match raw_key.type_value { PSBT_GLOBAL_UNSIGNED_TX => return Err(Error::DuplicateKey(raw_key).into()), + PSBT_GLOBAL_PROPRIETARY => match self.proprietary.entry(raw_key) { + Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + } _ => match self.unknown.entry(raw_key) { Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), @@ -135,6 +144,13 @@ impl Map for Global { }); } + for (key, value) in self.proprietary.iter() { + rv.push(raw::Pair { + key: key.clone(), + value: value.clone(), + }); + } + for (key, value) in self.unknown.iter() { rv.push(raw::Pair { key: key.clone(), @@ -201,6 +217,7 @@ impl Map for Global { } } + self.proprietary.extend(other.proprietary); self.unknown.extend(other.unknown); Ok(()) } @@ -215,6 +232,7 @@ impl Decodable for Global { let mut version: Option = None; let mut unknowns: BTreeMap> = Default::default(); let mut xpub_map: BTreeMap = Default::default(); + let mut proprietary: BTreeMap> = Default::default(); loop { match raw::Pair::consensus_decode(&mut d) { @@ -299,6 +317,10 @@ impl Decodable for Global { return Err(Error::InvalidKey(pair.key).into()) } } + PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(pair.key) { + Entry::Vacant(empty_key) => {empty_key.insert(pair.value);}, + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + } _ => match unknowns.entry(pair.key) { Entry::Vacant(empty_key) => {empty_key.insert(pair.value);}, Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs index ef8c3fc6..17f7503a 100644 --- a/src/util/psbt/map/input.rs +++ b/src/util/psbt/map/input.rs @@ -52,6 +52,8 @@ const PSBT_IN_SHA256: u8 = 0x0b; const PSBT_IN_HASH160: u8 = 0x0c; /// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d const PSBT_IN_HASH256: u8 = 0x0d; +/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC +const PSBT_IN_PROPRIETARY: u8 = 0xFC; /// A key-value map for an input of the corresponding index in the unsigned /// transaction. @@ -93,6 +95,8 @@ pub struct Input { pub hash160_preimages: BTreeMap>, /// HAS256 hash to preimage map pub hash256_preimages: BTreeMap>, + /// Proprietary key-value pairs for this input. + pub proprietary: BTreeMap>, /// Unknown key-value pairs for this input. pub unknown: BTreeMap>, } @@ -101,7 +105,7 @@ serde_struct_impl!( sighash_type, redeem_script, witness_script, bip32_derivation, final_script_sig, final_script_witness, ripemd160_preimages, sha256_preimages, hash160_preimages, hash256_preimages, - unknown + proprietary, unknown ); impl Map for Input { @@ -169,6 +173,10 @@ impl Map for Input { PSBT_IN_HASH256 => { psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?; } + PSBT_IN_PROPRIETARY => match self.proprietary.entry(raw_key) { + ::std::collections::btree_map::Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, + ::std::collections::btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + } _ => match self.unknown.entry(raw_key) { ::std::collections::btree_map::Entry::Vacant(empty_key) => { empty_key.insert(raw_value); @@ -237,6 +245,13 @@ impl Map for Input { rv.push(self.hash256_preimages as |>) } + for (key, value) in self.proprietary.iter() { + rv.push(raw::Pair { + key: key.clone(), + value: value.clone(), + }); + } + for (key, value) in self.unknown.iter() { rv.push(raw::Pair { key: key.clone(), @@ -261,6 +276,7 @@ impl Map for Input { self.sha256_preimages.extend(other.sha256_preimages); self.hash160_preimages.extend(other.hash160_preimages); self.hash256_preimages.extend(other.hash256_preimages); + self.proprietary.extend(other.proprietary); self.unknown.extend(other.unknown); merge!(redeem_script, self, other); diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index 7be5a37c..3e25d300 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -30,6 +30,8 @@ const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00; const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01; /// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 0x02 const PSBT_OUT_BIP32_DERIVATION: u8 = 0x02; +/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC +const PSBT_OUT_PROPRIETARY: u8 = 0xFC; /// A key-value map for an output of the corresponding index in the unsigned /// transaction. @@ -42,11 +44,13 @@ pub struct Output { /// A map from public keys needed to spend this output to their /// corresponding master key fingerprints and derivation paths. pub bip32_derivation: BTreeMap, + /// Proprietary key-value pairs for this output. + pub proprietary: BTreeMap>, /// Unknown key-value pairs for this output. pub unknown: BTreeMap>, } serde_struct_impl!( - Output, redeem_script, witness_script, bip32_derivation, unknown + Output, redeem_script, witness_script, bip32_derivation, proprietary, unknown ); impl Map for Output { @@ -72,6 +76,10 @@ impl Map for Output { self.bip32_derivation <= | } } + PSBT_OUT_PROPRIETARY => match self.proprietary.entry(raw_key) { + Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, + Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), + } _ => match self.unknown.entry(raw_key) { Entry::Vacant(empty_key) => {empty_key.insert(raw_value);}, Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone()).into()), @@ -96,6 +104,13 @@ impl Map for Output { rv.push(self.bip32_derivation as |) } + for (key, value) in self.proprietary.iter() { + rv.push(raw::Pair { + key: key.clone(), + value: value.clone(), + }); + } + for (key, value) in self.unknown.iter() { rv.push(raw::Pair { key: key.clone(), @@ -108,6 +123,7 @@ impl Map for Output { fn merge(&mut self, other: Self) -> Result<(), psbt::Error> { self.bip32_derivation.extend(other.bip32_derivation); + self.proprietary.extend(other.proprietary); self.unknown.extend(other.unknown); merge!(redeem_script, self, other); diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index f3384d4a..caaae382 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -194,6 +194,7 @@ mod tests { }, xpub: Default::default(), version: 0, + proprietary: BTreeMap::new(), unknown: BTreeMap::new(), }, inputs: vec![], @@ -283,6 +284,7 @@ mod tests { }, xpub: Default::default(), version: 0, + proprietary: Default::default(), unknown: Default::default(), }; @@ -387,6 +389,7 @@ mod tests { }, xpub: Default::default(), version: 0, + proprietary: BTreeMap::new(), unknown: BTreeMap::new(), }, inputs: vec![Input { @@ -612,6 +615,7 @@ mod tests { }, version: 0, xpub: Default::default(), + proprietary: Default::default(), unknown: BTreeMap::new(), }, inputs: vec![Input {