1use core::convert::TryFrom;
4use core::fmt;
5
6use bitcoin::bip32::KeySource;
7use bitcoin::io::Read;
8use bitcoin::key::{PublicKey, XOnlyPublicKey};
9use bitcoin::taproot::{TapLeafHash, TapTree};
10use bitcoin::{Amount, ScriptBuf, TxOut};
11
12use crate::consts::{
13 PSBT_OUT_AMOUNT, PSBT_OUT_BIP32_DERIVATION, PSBT_OUT_PROPRIETARY, PSBT_OUT_REDEEM_SCRIPT,
14 PSBT_OUT_SCRIPT, PSBT_OUT_TAP_BIP32_DERIVATION, PSBT_OUT_TAP_INTERNAL_KEY, PSBT_OUT_TAP_TREE,
15 PSBT_OUT_WITNESS_SCRIPT,
16};
17#[cfg(feature = "silent-payments")]
18use crate::consts::{PSBT_OUT_SP_V0_INFO, PSBT_OUT_SP_V0_LABEL};
19use crate::error::write_err;
20use crate::prelude::*;
21use crate::serialize::{Deserialize, Serialize};
22use crate::v2::map::Map;
23use crate::{raw, serialize};
24
25#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub struct Output {
30 pub amount: Amount,
32
33 pub script_pubkey: ScriptBuf,
35
36 pub redeem_script: Option<ScriptBuf>,
38 pub witness_script: Option<ScriptBuf>,
40 #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
43 pub bip32_derivations: BTreeMap<PublicKey, KeySource>,
44 pub tap_internal_key: Option<XOnlyPublicKey>,
46 pub tap_tree: Option<TapTree>,
48 #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
50 pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
51
52 #[cfg(feature = "silent-payments")]
54 pub sp_v0_info: Option<Vec<u8>>,
55
56 #[cfg(feature = "silent-payments")]
58 pub sp_v0_label: Option<u32>,
59
60 #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
62 pub proprietaries: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
63 #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
65 pub unknowns: BTreeMap<raw::Key, Vec<u8>>,
66}
67
68impl Output {
69 pub fn new(utxo: TxOut) -> Self {
71 Output {
72 amount: utxo.value,
73 script_pubkey: utxo.script_pubkey,
74 redeem_script: None,
75 witness_script: None,
76 bip32_derivations: BTreeMap::new(),
77 tap_internal_key: None,
78 tap_tree: None,
79 tap_key_origins: BTreeMap::new(),
80 #[cfg(feature = "silent-payments")]
81 sp_v0_info: None,
82 #[cfg(feature = "silent-payments")]
83 sp_v0_label: None,
84 proprietaries: BTreeMap::new(),
85 unknowns: BTreeMap::new(),
86 }
87 }
88
89 pub(crate) fn tx_out(&self) -> TxOut {
105 TxOut { value: self.amount, script_pubkey: self.script_pubkey.clone() }
106 }
107
108 pub(in crate::v2) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, DecodeError> {
109 let invalid = TxOut { value: Amount::ZERO, script_pubkey: ScriptBuf::default() };
111 let mut rv = Self::new(invalid);
112
113 loop {
114 match raw::Pair::decode(r) {
115 Ok(pair) => rv.insert_pair(pair)?,
116 Err(serialize::Error::NoMorePairs) => break,
117 Err(e) => return Err(DecodeError::DeserPair(e)),
118 }
119 }
120
121 if rv.amount == Amount::ZERO {
122 return Err(DecodeError::MissingValue);
123 }
124 #[cfg(not(feature = "silent-payments"))]
126 if rv.script_pubkey == ScriptBuf::default() {
127 return Err(DecodeError::MissingScriptPubkey);
128 }
129
130 #[cfg(feature = "silent-payments")]
131 if rv.script_pubkey == ScriptBuf::default() && rv.sp_v0_info.is_none() {
132 return Err(DecodeError::MissingScriptPubkey);
133 }
134
135 #[cfg(feature = "silent-payments")]
136 if rv.sp_v0_label.is_some() && rv.sp_v0_info.is_none() {
137 return Err(DecodeError::LabelWithoutInfo);
138 }
139
140 Ok(rv)
141 }
142
143 fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), InsertPairError> {
144 let raw::Pair { key: raw_key, value: raw_value } = pair;
145
146 match raw_key.type_value {
147 PSBT_OUT_AMOUNT => {
148 if self.amount != Amount::ZERO {
149 return Err(InsertPairError::DuplicateKey(raw_key));
150 }
151 let amount: Amount = Deserialize::deserialize(&raw_value)?;
152 self.amount = amount;
153 }
154 PSBT_OUT_SCRIPT => {
155 if self.script_pubkey != ScriptBuf::default() {
156 return Err(InsertPairError::DuplicateKey(raw_key));
157 }
158 let script: ScriptBuf = Deserialize::deserialize(&raw_value)?;
159 self.script_pubkey = script;
160 }
161
162 PSBT_OUT_REDEEM_SCRIPT => {
163 v2_impl_psbt_insert_pair! {
164 self.redeem_script <= <raw_key: _>|<raw_value: ScriptBuf>
165 }
166 }
167 PSBT_OUT_WITNESS_SCRIPT => {
168 v2_impl_psbt_insert_pair! {
169 self.witness_script <= <raw_key: _>|<raw_value: ScriptBuf>
170 }
171 }
172 PSBT_OUT_BIP32_DERIVATION => {
173 v2_impl_psbt_insert_pair! {
174 self.bip32_derivations <= <raw_key: PublicKey>|<raw_value: KeySource>
175 }
176 }
177 PSBT_OUT_PROPRIETARY => {
178 let key = raw::ProprietaryKey::try_from(raw_key.clone())?;
179 match self.proprietaries.entry(key) {
180 btree_map::Entry::Vacant(empty_key) => {
181 empty_key.insert(raw_value);
182 }
183 btree_map::Entry::Occupied(_) =>
184 return Err(InsertPairError::DuplicateKey(raw_key)),
185 }
186 }
187 PSBT_OUT_TAP_INTERNAL_KEY => {
188 v2_impl_psbt_insert_pair! {
189 self.tap_internal_key <= <raw_key: _>|<raw_value: XOnlyPublicKey>
190 }
191 }
192 PSBT_OUT_TAP_TREE => {
193 v2_impl_psbt_insert_pair! {
194 self.tap_tree <= <raw_key: _>|<raw_value: TapTree>
195 }
196 }
197 PSBT_OUT_TAP_BIP32_DERIVATION => {
198 v2_impl_psbt_insert_pair! {
199 self.tap_key_origins <= <raw_key: XOnlyPublicKey>|< raw_value: (Vec<TapLeafHash>, KeySource)>
200 }
201 }
202 #[cfg(feature = "silent-payments")]
203 PSBT_OUT_SP_V0_INFO => {
204 if self.sp_v0_info.is_some() {
205 return Err(InsertPairError::DuplicateKey(raw_key));
206 }
207 if !raw_key.key.is_empty() {
208 return Err(InsertPairError::InvalidKeyDataNotEmpty(raw_key));
209 }
210 if raw_value.len() != 66 {
211 return Err(InsertPairError::ValueWrongLength(raw_value.len(), 66));
212 }
213 self.sp_v0_info = Some(raw_value);
214 }
215 #[cfg(feature = "silent-payments")]
216 PSBT_OUT_SP_V0_LABEL => {
217 if self.sp_v0_label.is_some() {
218 return Err(InsertPairError::DuplicateKey(raw_key));
219 }
220 if !raw_key.key.is_empty() {
221 return Err(InsertPairError::InvalidKeyDataNotEmpty(raw_key));
222 }
223 if raw_value.len() != 4 {
224 return Err(InsertPairError::ValueWrongLength(raw_value.len(), 4));
225 }
226 let label =
227 u32::from_le_bytes([raw_value[0], raw_value[1], raw_value[2], raw_value[3]]);
228 self.sp_v0_label = Some(label);
229 }
230 _ => match self.unknowns.entry(raw_key) {
232 btree_map::Entry::Vacant(empty_key) => {
233 empty_key.insert(raw_value);
234 }
235 btree_map::Entry::Occupied(k) =>
236 return Err(InsertPairError::DuplicateKey(k.key().clone())),
237 },
238 }
239
240 Ok(())
241 }
242
243 pub fn combine(&mut self, other: Self) -> Result<(), CombineError> {
245 if self.amount != other.amount {
246 return Err(CombineError::AmountMismatch { this: self.amount, that: other.amount });
247 }
248
249 if self.script_pubkey != other.script_pubkey {
250 return Err(CombineError::ScriptPubkeyMismatch {
251 this: self.script_pubkey.clone(),
252 that: other.script_pubkey,
253 });
254 }
255
256 v2_combine_option!(redeem_script, self, other);
257 v2_combine_option!(witness_script, self, other);
258 v2_combine_map!(bip32_derivations, self, other);
259 v2_combine_option!(tap_internal_key, self, other);
260 v2_combine_option!(tap_tree, self, other);
261 v2_combine_map!(tap_key_origins, self, other);
262 #[cfg(feature = "silent-payments")]
263 v2_combine_option!(sp_v0_info, self, other);
264 #[cfg(feature = "silent-payments")]
265 v2_combine_option!(sp_v0_label, self, other);
266 v2_combine_map!(proprietaries, self, other);
267 v2_combine_map!(unknowns, self, other);
268
269 Ok(())
270 }
271}
272
273impl Map for Output {
274 fn get_pairs(&self) -> Vec<raw::Pair> {
275 let mut rv: Vec<raw::Pair> = Default::default();
276
277 rv.push(raw::Pair {
278 key: raw::Key { type_value: PSBT_OUT_AMOUNT, key: vec![] },
279 value: self.amount.serialize(),
280 });
281
282 rv.push(raw::Pair {
283 key: raw::Key { type_value: PSBT_OUT_SCRIPT, key: vec![] },
284 value: self.script_pubkey.serialize(),
285 });
286
287 v2_impl_psbt_get_pair! {
288 rv.push(self.redeem_script, PSBT_OUT_REDEEM_SCRIPT)
289 }
290
291 v2_impl_psbt_get_pair! {
292 rv.push(self.witness_script, PSBT_OUT_WITNESS_SCRIPT)
293 }
294
295 v2_impl_psbt_get_pair! {
296 rv.push_map(self.bip32_derivations, PSBT_OUT_BIP32_DERIVATION)
297 }
298
299 v2_impl_psbt_get_pair! {
300 rv.push(self.tap_internal_key, PSBT_OUT_TAP_INTERNAL_KEY)
301 }
302
303 v2_impl_psbt_get_pair! {
304 rv.push(self.tap_tree, PSBT_OUT_TAP_TREE)
305 }
306
307 v2_impl_psbt_get_pair! {
308 rv.push_map(self.tap_key_origins, PSBT_OUT_TAP_BIP32_DERIVATION)
309 }
310
311 #[cfg(feature = "silent-payments")]
312 if let Some(sp_info) = &self.sp_v0_info {
313 rv.push(raw::Pair {
314 key: raw::Key { type_value: PSBT_OUT_SP_V0_INFO, key: vec![] },
315 value: sp_info.clone(),
316 });
317 }
318
319 #[cfg(feature = "silent-payments")]
320 if let Some(label) = self.sp_v0_label {
321 rv.push(raw::Pair {
322 key: raw::Key { type_value: PSBT_OUT_SP_V0_LABEL, key: vec![] },
323 value: label.to_le_bytes().to_vec(),
324 });
325 }
326
327 for (key, value) in self.proprietaries.iter() {
328 rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
329 }
330
331 for (key, value) in self.unknowns.iter() {
332 rv.push(raw::Pair { key: key.clone(), value: value.clone() });
333 }
334
335 rv
336 }
337}
338
339pub struct OutputBuilder(Output);
342
343impl OutputBuilder {
344 pub fn new(utxo: TxOut) -> Self { OutputBuilder(Output::new(utxo)) }
346
347 pub fn build(self) -> Output { self.0 }
349}
350
351#[derive(Debug)]
353#[non_exhaustive]
354pub enum DecodeError {
355 InsertPair(InsertPairError),
357 DeserPair(serialize::Error),
359 MissingValue,
361 MissingScriptPubkey,
363 LabelWithoutInfo,
365}
366
367impl fmt::Display for DecodeError {
368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369 use DecodeError::*;
370
371 match *self {
372 InsertPair(ref e) => write_err!(f, "error inserting a pair"; e),
373 DeserPair(ref e) => write_err!(f, "error deserializing a pair"; e),
374 MissingValue => write!(f, "encoded output is missing a value"),
375 MissingScriptPubkey => write!(f, "encoded output is missing a script pubkey"),
376 LabelWithoutInfo => write!(f, "output has a sp_v0_label without a sp_v0_info"),
377 }
378 }
379}
380
381#[cfg(feature = "std")]
382impl std::error::Error for DecodeError {
383 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
384 use DecodeError::*;
385
386 match *self {
387 InsertPair(ref e) => Some(e),
388 DeserPair(ref e) => Some(e),
389 MissingValue | MissingScriptPubkey | LabelWithoutInfo => None,
390 }
391 }
392}
393
394impl From<InsertPairError> for DecodeError {
395 fn from(e: InsertPairError) -> Self { Self::InsertPair(e) }
396}
397
398#[derive(Debug)]
400pub enum InsertPairError {
401 DuplicateKey(raw::Key),
403 Deser(serialize::Error),
405 InvalidKeyDataEmpty(raw::Key),
407 InvalidKeyDataNotEmpty(raw::Key),
409 ValueWrongLength(usize, usize),
411}
412
413impl fmt::Display for InsertPairError {
414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415 use InsertPairError::*;
416
417 match *self {
418 DuplicateKey(ref key) => write!(f, "duplicate key: {}", key),
419 Deser(ref e) => write_err!(f, "error deserializing raw value"; e),
420 InvalidKeyDataEmpty(ref key) => write!(f, "key should contain data: {}", key),
421 InvalidKeyDataNotEmpty(ref key) => write!(f, "key should not contain data: {}", key),
422 ValueWrongLength(got, expected) => {
423 write!(f, "value wrong length (got: {}, expected: {})", got, expected)
424 }
425 }
426 }
427}
428
429#[cfg(feature = "std")]
430impl std::error::Error for InsertPairError {
431 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
432 use InsertPairError::*;
433
434 match *self {
435 Deser(ref e) => Some(e),
436 DuplicateKey(_)
437 | InvalidKeyDataEmpty(_)
438 | InvalidKeyDataNotEmpty(_)
439 | ValueWrongLength(..) => None,
440 }
441 }
442}
443
444impl From<serialize::Error> for InsertPairError {
445 fn from(e: serialize::Error) -> Self { Self::Deser(e) }
446}
447
448#[derive(Debug, Clone, PartialEq, Eq)]
450#[non_exhaustive]
451pub enum CombineError {
452 AmountMismatch {
454 this: Amount,
456 that: Amount,
458 },
459 ScriptPubkeyMismatch {
461 this: ScriptBuf,
463 that: ScriptBuf,
465 },
466}
467
468impl fmt::Display for CombineError {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470 use CombineError::*;
471
472 match *self {
473 AmountMismatch { ref this, ref that } => {
474 write!(f, "combine two PSBTs with different amounts: {} {}", this, that)
475 }
476 ScriptPubkeyMismatch { ref this, ref that } => {
477 write!(f, "combine two PSBTs with different script_pubkeys: {:x} {:x}", this, that)
478 }
479 }
480 }
481}
482
483#[cfg(feature = "std")]
484impl std::error::Error for CombineError {
485 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
486 use CombineError::*;
487
488 match *self {
489 AmountMismatch { .. } | ScriptPubkeyMismatch { .. } => None,
490 }
491 }
492}
493
494#[cfg(test)]
495#[cfg(feature = "std")]
496mod tests {
497 use bitcoin::io::Cursor;
498
499 use super::*;
500
501 fn tx_out() -> TxOut {
502 let script = ScriptBuf::from_hex("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac")
504 .expect("failed to parse script form hex");
505 let value = Amount::from_sat(123_456_789);
506 TxOut { value, script_pubkey: script }
507 }
508
509 #[test]
510 fn serialize_roundtrip() {
511 let output = Output::new(tx_out());
512
513 let ser = output.serialize_map();
514 let mut d = Cursor::new(ser);
515
516 let decoded = Output::decode(&mut d).expect("failed to decode");
517
518 assert_eq!(decoded, output);
519 }
520}