Skip to main content

psbt_v2/v0/bitcoin/map/
output.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::convert::TryFrom;
4
5use bitcoin::bip32::KeySource;
6use bitcoin::blockdata::script::ScriptBuf;
7use bitcoin::key::PublicKey;
8use bitcoin::secp256k1::XOnlyPublicKey;
9use bitcoin::taproot::{TapLeafHash, TapTree};
10
11use crate::prelude::*;
12use crate::v0::bitcoin::map::Map;
13use crate::v0::bitcoin::{raw, Error};
14
15/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
16const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
17/// Type: Witness ScriptBuf PSBT_OUT_WITNESS_SCRIPT = 0x01
18const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01;
19/// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 0x02
20const PSBT_OUT_BIP32_DERIVATION: u8 = 0x02;
21/// Type: Taproot Internal Key PSBT_OUT_TAP_INTERNAL_KEY = 0x05
22const PSBT_OUT_TAP_INTERNAL_KEY: u8 = 0x05;
23/// Type: Taproot Tree PSBT_OUT_TAP_TREE = 0x06
24const PSBT_OUT_TAP_TREE: u8 = 0x06;
25/// Type: Taproot Key BIP 32 Derivation Path PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
26const PSBT_OUT_TAP_BIP32_DERIVATION: u8 = 0x07;
27/// Type: Output Amount PSBT_OUT_AMOUNT = 0x03
28const PSBT_OUT_AMOUNT: u8 = 0x03;
29/// Type: Output Script PSBT_OUT_SCRIPT = 0x04
30const PSBT_OUT_SCRIPT: u8 = 0x04;
31/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
32const PSBT_OUT_PROPRIETARY: u8 = 0xFC;
33
34/// A key-value map for an output of the corresponding index in the unsigned
35/// transaction.
36#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38pub struct Output {
39    /// The redeem script for this output.
40    pub redeem_script: Option<ScriptBuf>,
41    /// The witness script for this output.
42    pub witness_script: Option<ScriptBuf>,
43    /// A map from public keys needed to spend this output to their
44    /// corresponding master key fingerprints and derivation paths.
45    #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
46    pub bip32_derivation: BTreeMap<PublicKey, KeySource>,
47    /// The internal pubkey.
48    pub tap_internal_key: Option<XOnlyPublicKey>,
49    /// Taproot Output tree.
50    pub tap_tree: Option<TapTree>,
51    /// Map of tap root x only keys to origin info and leaf hashes contained in it.
52    #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
53    pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
54    /// Proprietary key-value pairs for this output.
55    #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
56    pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
57    /// Unknown key-value pairs for this output.
58    #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
59    pub unknown: BTreeMap<raw::Key, Vec<u8>>,
60}
61
62impl Output {
63    pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
64        let raw::Pair { key: raw_key, value: raw_value } = pair;
65
66        match raw_key.type_value {
67            PSBT_OUT_REDEEM_SCRIPT => {
68                impl_psbt_insert_pair! {
69                    self.redeem_script <= <raw_key: _>|<raw_value: ScriptBuf>
70                }
71            }
72            PSBT_OUT_WITNESS_SCRIPT => {
73                impl_psbt_insert_pair! {
74                    self.witness_script <= <raw_key: _>|<raw_value: ScriptBuf>
75                }
76            }
77            PSBT_OUT_BIP32_DERIVATION => {
78                impl_psbt_insert_pair! {
79                    self.bip32_derivation <= <raw_key: PublicKey>|<raw_value: KeySource>
80                }
81            }
82            PSBT_OUT_PROPRIETARY => {
83                let key = raw::ProprietaryKey::try_from(raw_key.clone())?;
84                match self.proprietary.entry(key) {
85                    btree_map::Entry::Vacant(empty_key) => {
86                        empty_key.insert(raw_value);
87                    }
88                    btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
89                }
90            }
91            PSBT_OUT_TAP_INTERNAL_KEY => {
92                impl_psbt_insert_pair! {
93                    self.tap_internal_key <= <raw_key: _>|<raw_value: XOnlyPublicKey>
94                }
95            }
96            PSBT_OUT_TAP_TREE => {
97                impl_psbt_insert_pair! {
98                    self.tap_tree <= <raw_key: _>|<raw_value: TapTree>
99                }
100            }
101            PSBT_OUT_TAP_BIP32_DERIVATION => {
102                impl_psbt_insert_pair! {
103                    self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
104                }
105            }
106            v if v == PSBT_OUT_AMOUNT || v == PSBT_OUT_SCRIPT => {
107                return Err(Error::ExcludedKey { key_type_value: v });
108            }
109            _ => match self.unknown.entry(raw_key) {
110                btree_map::Entry::Vacant(empty_key) => {
111                    empty_key.insert(raw_value);
112                }
113                btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())),
114            },
115        }
116
117        Ok(())
118    }
119
120    /// Combines this [`Output`] with `other` `Output` (as described by BIP 174).
121    pub fn combine(&mut self, other: Self) {
122        self.bip32_derivation.extend(other.bip32_derivation);
123        self.proprietary.extend(other.proprietary);
124        self.unknown.extend(other.unknown);
125        self.tap_key_origins.extend(other.tap_key_origins);
126
127        combine!(redeem_script, self, other);
128        combine!(witness_script, self, other);
129        combine!(tap_internal_key, self, other);
130        combine!(tap_tree, self, other);
131    }
132}
133
134impl Map for Output {
135    fn get_pairs(&self) -> Vec<raw::Pair> {
136        let mut rv: Vec<raw::Pair> = Default::default();
137
138        impl_psbt_get_pair! {
139            rv.push(self.redeem_script, PSBT_OUT_REDEEM_SCRIPT)
140        }
141
142        impl_psbt_get_pair! {
143            rv.push(self.witness_script, PSBT_OUT_WITNESS_SCRIPT)
144        }
145
146        impl_psbt_get_pair! {
147            rv.push_map(self.bip32_derivation, PSBT_OUT_BIP32_DERIVATION)
148        }
149
150        impl_psbt_get_pair! {
151            rv.push(self.tap_internal_key, PSBT_OUT_TAP_INTERNAL_KEY)
152        }
153
154        impl_psbt_get_pair! {
155            rv.push(self.tap_tree, PSBT_OUT_TAP_TREE)
156        }
157
158        impl_psbt_get_pair! {
159            rv.push_map(self.tap_key_origins, PSBT_OUT_TAP_BIP32_DERIVATION)
160        }
161
162        for (key, value) in self.proprietary.iter() {
163            rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
164        }
165
166        for (key, value) in self.unknown.iter() {
167            rv.push(raw::Pair { key: key.clone(), value: value.clone() });
168        }
169
170        rv
171    }
172}
173
174impl_psbtmap_ser_de_serialize!(Output);