1#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
10#![cfg_attr(docsrs, feature(doc_auto_cfg))]
12#![warn(missing_docs)]
14
15#[macro_use]
16extern crate alloc;
17
18#[cfg(feature = "serde")]
19#[macro_use]
20extern crate actual_serde as serde;
21
22pub extern crate bitcoin;
24
25#[macro_use]
26mod macros;
27mod error;
28mod map;
29#[cfg(feature = "serde")]
30mod serde_utils;
31
32pub mod raw;
33pub mod serialize;
34
35use core::{cmp, fmt};
36#[cfg(feature = "std")]
37use std::collections::{HashMap, HashSet};
38
39use bitcoin::bip32::{self, KeySource, Xpriv, Xpub};
40use bitcoin::blockdata::transaction::{self, Transaction, TxOut};
41use bitcoin::key::{PrivateKey, PublicKey, TapTweak, XOnlyPublicKey};
42use bitcoin::secp256k1::{Keypair, Message, Secp256k1, Signing, Verification};
43use bitcoin::sighash::{self, EcdsaSighashType, Prevouts, SighashCache};
44use bitcoin::{ecdsa, taproot, Amount, FeeRate, TapLeafHash, TapSighashType};
45use bitcoin_internals::write_err;
46
47use crate::prelude::*;
48
49#[rustfmt::skip] #[doc(inline)]
51pub use self::{
52 map::{Input, Output, PsbtSighashType},
53 error::Error,
54};
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
60pub struct Psbt {
61 pub unsigned_tx: Transaction,
63 pub version: u32,
65 pub xpub: BTreeMap<Xpub, KeySource>,
68 #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
70 pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
71 #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
73 pub unknown: BTreeMap<raw::Key, Vec<u8>>,
74
75 pub inputs: Vec<Input>,
77 pub outputs: Vec<Output>,
79}
80
81impl Psbt {
82 pub fn iter_funding_utxos(&self) -> impl Iterator<Item = Result<&TxOut, Error>> {
95 assert_eq!(self.inputs.len(), self.unsigned_tx.input.len());
96 self.unsigned_tx.input.iter().zip(&self.inputs).map(|(tx_input, psbt_input)| {
97 match (&psbt_input.witness_utxo, &psbt_input.non_witness_utxo) {
98 (Some(witness_utxo), _) => Ok(witness_utxo),
99 (None, Some(non_witness_utxo)) => {
100 let vout = tx_input.previous_output.vout as usize;
101 non_witness_utxo.output.get(vout).ok_or(Error::PsbtUtxoOutOfbounds)
102 }
103 (None, None) => Err(Error::MissingUtxo),
104 }
105 })
106 }
107
108 fn unsigned_tx_checks(&self) -> Result<(), Error> {
110 for txin in &self.unsigned_tx.input {
111 if !txin.script_sig.is_empty() {
112 return Err(Error::UnsignedTxHasScriptSigs);
113 }
114
115 if !txin.witness.is_empty() {
116 return Err(Error::UnsignedTxHasScriptWitnesses);
117 }
118 }
119
120 Ok(())
121 }
122
123 pub fn from_unsigned_tx(tx: Transaction) -> Result<Self, Error> {
129 let psbt = Psbt {
130 inputs: vec![Default::default(); tx.input.len()],
131 outputs: vec![Default::default(); tx.output.len()],
132
133 unsigned_tx: tx,
134 xpub: Default::default(),
135 version: 0,
136 proprietary: Default::default(),
137 unknown: Default::default(),
138 };
139 psbt.unsigned_tx_checks()?;
140 Ok(psbt)
141 }
142
143 pub const DEFAULT_MAX_FEE_RATE: FeeRate = FeeRate::from_sat_per_vb_unchecked(25_000);
150
151 pub fn extract_tx(self) -> Result<Transaction, ExtractTxError> {
155 self.internal_extract_tx_with_fee_rate_limit(Self::DEFAULT_MAX_FEE_RATE)
156 }
157
158 pub fn extract_tx_fee_rate_limit(self) -> Result<Transaction, ExtractTxError> {
166 self.internal_extract_tx_with_fee_rate_limit(Self::DEFAULT_MAX_FEE_RATE)
167 }
168
169 pub fn extract_tx_with_fee_rate_limit(
177 self,
178 max_fee_rate: FeeRate,
179 ) -> Result<Transaction, ExtractTxError> {
180 self.internal_extract_tx_with_fee_rate_limit(max_fee_rate)
181 }
182
183 pub fn extract_tx_unchecked_fee_rate(self) -> Transaction { self.internal_extract_tx() }
189
190 #[inline]
191 fn internal_extract_tx(self) -> Transaction {
192 let mut tx: Transaction = self.unsigned_tx;
193
194 for (vin, psbtin) in tx.input.iter_mut().zip(self.inputs.into_iter()) {
195 vin.script_sig = psbtin.final_script_sig.unwrap_or_default();
196 vin.witness = psbtin.final_script_witness.unwrap_or_default();
197 }
198
199 tx
200 }
201
202 #[inline]
203 fn internal_extract_tx_with_fee_rate_limit(
204 self,
205 max_fee_rate: FeeRate,
206 ) -> Result<Transaction, ExtractTxError> {
207 let fee = match self.fee() {
208 Ok(fee) => fee,
209 Err(Error::MissingUtxo) =>
210 return Err(ExtractTxError::MissingInputValue { tx: self.internal_extract_tx() }),
211 Err(Error::NegativeFee) => return Err(ExtractTxError::SendingTooMuch { psbt: self }),
212 Err(Error::FeeOverflow) =>
213 return Err(ExtractTxError::AbsurdFeeRate {
214 fee_rate: FeeRate::MAX,
215 tx: self.internal_extract_tx(),
216 }),
217 _ => unreachable!(),
218 };
219
220 let tx = self.internal_extract_tx();
222
223 let fee_rate =
225 FeeRate::from_sat_per_kwu(fee.to_sat().saturating_mul(1000) / tx.weight().to_wu());
226 if fee_rate > max_fee_rate {
228 return Err(ExtractTxError::AbsurdFeeRate { fee_rate, tx });
229 }
230
231 Ok(tx)
232 }
233
234 pub fn combine(&mut self, other: Self) -> Result<(), Error> {
238 if self.unsigned_tx != other.unsigned_tx {
239 return Err(Error::UnexpectedUnsignedTx {
240 expected: Box::new(self.unsigned_tx.clone()),
241 actual: Box::new(other.unsigned_tx),
242 });
243 }
244
245 self.version = cmp::max(self.version, other.version);
250
251 for (xpub, (fingerprint1, derivation1)) in other.xpub {
253 match self.xpub.entry(xpub) {
254 btree_map::Entry::Vacant(entry) => {
255 entry.insert((fingerprint1, derivation1));
256 }
257 btree_map::Entry::Occupied(mut entry) => {
258 let (fingerprint2, derivation2) = entry.get().clone();
268
269 if (derivation1 == derivation2 && fingerprint1 == fingerprint2)
270 || (derivation1.len() < derivation2.len()
271 && derivation1[..]
272 == derivation2[derivation2.len() - derivation1.len()..])
273 {
274 continue;
275 } else if derivation2[..]
276 == derivation1[derivation1.len() - derivation2.len()..]
277 {
278 entry.insert((fingerprint1, derivation1));
279 continue;
280 }
281 return Err(Error::CombineInconsistentKeySources(Box::new(xpub)));
282 }
283 }
284 }
285
286 self.proprietary.extend(other.proprietary);
287 self.unknown.extend(other.unknown);
288
289 for (self_input, other_input) in self.inputs.iter_mut().zip(other.inputs.into_iter()) {
290 self_input.combine(other_input);
291 }
292
293 for (self_output, other_output) in self.outputs.iter_mut().zip(other.outputs.into_iter()) {
294 self_output.combine(other_output);
295 }
296
297 Ok(())
298 }
299
300 pub fn sign<C, K>(
312 &mut self,
313 k: &K,
314 secp: &Secp256k1<C>,
315 ) -> Result<SigningKeysMap, (SigningKeysMap, SigningErrors)>
316 where
317 C: Signing + Verification,
318 K: GetKey,
319 {
320 let tx = self.unsigned_tx.clone(); let mut cache = SighashCache::new(&tx);
322
323 let mut used = BTreeMap::new();
324 let mut errors = BTreeMap::new();
325
326 for i in 0..self.inputs.len() {
327 match self.signing_algorithm(i) {
328 Ok(SigningAlgorithm::Ecdsa) =>
329 match self.bip32_sign_ecdsa(k, i, &mut cache, secp) {
330 Ok(v) => {
331 used.insert(i, SigningKeys::Ecdsa(v));
332 }
333 Err(e) => {
334 errors.insert(i, e);
335 }
336 },
337 Ok(SigningAlgorithm::Schnorr) => {
338 match self.bip32_sign_schnorr(k, i, &mut cache, secp) {
339 Ok(v) => {
340 used.insert(i, SigningKeys::Schnorr(v));
341 }
342 Err(e) => {
343 errors.insert(i, e);
344 }
345 }
346 }
347 Err(e) => {
348 errors.insert(i, e);
349 }
350 }
351 }
352 if errors.is_empty() {
353 Ok(used)
354 } else {
355 Err((used, errors))
356 }
357 }
358
359 fn bip32_sign_ecdsa<C, K, T>(
367 &mut self,
368 k: &K,
369 input_index: usize,
370 cache: &mut SighashCache<T>,
371 secp: &Secp256k1<C>,
372 ) -> Result<Vec<PublicKey>, SignError>
373 where
374 C: Signing,
375 T: Borrow<Transaction>,
376 K: GetKey,
377 {
378 let msg_sighash_ty_res = self.sighash_ecdsa(input_index, cache);
379
380 let input = &mut self.inputs[input_index]; let mut used = vec![]; for (pk, key_source) in input.bip32_derivation.iter() {
385 let sk = if let Ok(Some(sk)) = k.get_key(KeyRequest::Bip32(key_source.clone()), secp) {
386 sk
387 } else if let Ok(Some(sk)) = k.get_key(KeyRequest::Pubkey(PublicKey::new(*pk)), secp) {
388 sk
389 } else {
390 continue;
391 };
392
393 let (msg, sighash_ty) = match msg_sighash_ty_res {
395 Err(e) => return Err(e),
396 Ok((msg, sighash_ty)) => (msg, sighash_ty),
397 };
398
399 let sig = ecdsa::Signature {
400 signature: secp.sign_ecdsa(&msg, &sk.inner),
401 sighash_type: sighash_ty,
402 };
403
404 let pk = sk.public_key(secp);
405
406 input.partial_sigs.insert(pk, sig);
407 used.push(pk);
408 }
409
410 Ok(used)
411 }
412
413 fn bip32_sign_schnorr<C, K, T>(
422 &mut self,
423 k: &K,
424 input_index: usize,
425 cache: &mut SighashCache<T>,
426 secp: &Secp256k1<C>,
427 ) -> Result<Vec<XOnlyPublicKey>, SignError>
428 where
429 C: Signing + Verification,
430 T: Borrow<Transaction>,
431 K: GetKey,
432 {
433 let mut input = self.checked_input(input_index)?.clone();
434
435 let mut used = vec![]; for (&xonly, (leaf_hashes, key_source)) in input.tap_key_origins.iter() {
438 let sk = if let Ok(Some(secret_key)) =
439 k.get_key(KeyRequest::Bip32(key_source.clone()), secp)
440 {
441 secret_key
442 } else {
443 continue;
444 };
445
446 if let Some(internal_key) = input.tap_internal_key {
453 if internal_key == xonly && leaf_hashes.is_empty() && input.tap_key_sig.is_none() {
458 let (msg, sighash_type) = self.sighash_taproot(input_index, cache, None)?;
459 let key_pair = Keypair::from_secret_key(secp, &sk.inner)
460 .tap_tweak(secp, input.tap_merkle_root)
461 .to_inner();
462
463 #[cfg(feature = "rand-std")]
464 let signature = secp.sign_schnorr(&msg, &key_pair);
465 #[cfg(not(feature = "rand-std"))]
466 let signature = secp.sign_schnorr_no_aux_rand(&msg, &key_pair);
467
468 let signature = taproot::Signature { signature, sighash_type };
469 input.tap_key_sig = Some(signature);
470
471 used.push(internal_key);
472 }
473 }
474
475 if let Some((leaf_hashes, _)) = input.tap_key_origins.get(&xonly) {
477 let leaf_hashes = leaf_hashes
478 .iter()
479 .filter(|lh| !input.tap_script_sigs.contains_key(&(xonly, **lh)))
480 .cloned()
481 .collect::<Vec<_>>();
482
483 if !leaf_hashes.is_empty() {
484 let key_pair = Keypair::from_secret_key(secp, &sk.inner);
485
486 for lh in leaf_hashes {
487 let (msg, sighash_type) =
488 self.sighash_taproot(input_index, cache, Some(lh))?;
489
490 #[cfg(feature = "rand-std")]
491 let signature = secp.sign_schnorr(&msg, &key_pair);
492 #[cfg(not(feature = "rand-std"))]
493 let signature = secp.sign_schnorr_no_aux_rand(&msg, &key_pair);
494
495 let signature = taproot::Signature { signature, sighash_type };
496 input.tap_script_sigs.insert((xonly, lh), signature);
497 }
498
499 used.push(sk.public_key(secp).into());
500 }
501 }
502 }
503
504 self.inputs[input_index] = input; Ok(used)
507 }
508
509 pub fn sighash_ecdsa<T: Borrow<Transaction>>(
515 &self,
516 input_index: usize,
517 cache: &mut SighashCache<T>,
518 ) -> Result<(Message, EcdsaSighashType), SignError> {
519 use OutputType::*;
520
521 if self.signing_algorithm(input_index)? != SigningAlgorithm::Ecdsa {
522 return Err(SignError::WrongSigningAlgorithm);
523 }
524
525 let input = self.checked_input(input_index)?;
526 let utxo = self.spend_utxo(input_index)?;
527 let spk = &utxo.script_pubkey; let hash_ty = input.ecdsa_hash_ty().map_err(|_| SignError::InvalidSighashType)?; match self.output_type(input_index)? {
532 Bare => {
533 let sighash = cache
534 .legacy_signature_hash(input_index, spk, hash_ty.to_u32())
535 .expect("input checked above");
536 Ok((Message::from(sighash), hash_ty))
537 }
538 Sh => {
539 let script_code =
540 input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
541 let sighash = cache
542 .legacy_signature_hash(input_index, script_code, hash_ty.to_u32())
543 .expect("input checked above");
544 Ok((Message::from(sighash), hash_ty))
545 }
546 Wpkh => {
547 let sighash = cache.p2wpkh_signature_hash(input_index, spk, utxo.value, hash_ty)?;
548 Ok((Message::from(sighash), hash_ty))
549 }
550 ShWpkh => {
551 let redeem_script = input.redeem_script.as_ref().expect("checked above");
552 let sighash =
553 cache.p2wpkh_signature_hash(input_index, redeem_script, utxo.value, hash_ty)?;
554 Ok((Message::from(sighash), hash_ty))
555 }
556 Wsh | ShWsh => {
557 let witness_script =
558 input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?;
559 let sighash = cache
560 .p2wsh_signature_hash(input_index, witness_script, utxo.value, hash_ty)
561 .map_err(SignError::SegwitV0Sighash)?;
562 Ok((Message::from(sighash), hash_ty))
563 }
564 Tr => {
565 Err(SignError::Unsupported)
567 }
568 }
569 }
570
571 fn sighash_taproot<T: Borrow<Transaction>>(
576 &self,
577 input_index: usize,
578 cache: &mut SighashCache<T>,
579 leaf_hash: Option<TapLeafHash>,
580 ) -> Result<(Message, TapSighashType), SignError> {
581 use OutputType::*;
582
583 if self.signing_algorithm(input_index)? != SigningAlgorithm::Schnorr {
584 return Err(SignError::WrongSigningAlgorithm);
585 }
586
587 let input = self.checked_input(input_index)?;
588
589 match self.output_type(input_index)? {
590 Tr => {
591 let hash_ty = input
592 .sighash_type
593 .unwrap_or_else(|| TapSighashType::Default.into())
594 .taproot_hash_ty()
595 .map_err(|_| SignError::InvalidSighashType)?;
596
597 let spend_utxos =
598 (0..self.inputs.len()).map(|i| self.spend_utxo(i).ok()).collect::<Vec<_>>();
599 let all_spend_utxos;
600
601 let is_anyone_can_pay = PsbtSighashType::from(hash_ty).to_u32() & 0x80 != 0;
602
603 let prev_outs = if is_anyone_can_pay {
604 Prevouts::One(
605 input_index,
606 spend_utxos[input_index].ok_or(SignError::MissingSpendUtxo)?,
607 )
608 } else if spend_utxos.iter().all(Option::is_some) {
609 all_spend_utxos = spend_utxos.iter().filter_map(|x| *x).collect::<Vec<_>>();
610 Prevouts::All(&all_spend_utxos)
611 } else {
612 return Err(SignError::MissingSpendUtxo);
613 };
614
615 let sighash = if let Some(leaf_hash) = leaf_hash {
616 cache.taproot_script_spend_signature_hash(
617 input_index,
618 &prev_outs,
619 leaf_hash,
620 hash_ty,
621 )?
622 } else {
623 cache.taproot_key_spend_signature_hash(input_index, &prev_outs, hash_ty)?
624 };
625 Ok((Message::from(sighash), hash_ty))
626 }
627 _ => Err(SignError::Unsupported),
628 }
629 }
630
631 pub fn spend_utxo(&self, input_index: usize) -> Result<&TxOut, SignError> {
633 let input = self.checked_input(input_index)?;
634 let utxo = if let Some(witness_utxo) = &input.witness_utxo {
635 witness_utxo
636 } else if let Some(non_witness_utxo) = &input.non_witness_utxo {
637 let vout = self.unsigned_tx.input[input_index].previous_output.vout;
638 &non_witness_utxo.output[vout as usize]
639 } else {
640 return Err(SignError::MissingSpendUtxo);
641 };
642 Ok(utxo)
643 }
644
645 fn checked_input(&self, input_index: usize) -> Result<&Input, IndexOutOfBoundsError> {
647 self.check_index_is_within_bounds(input_index)?;
648 Ok(&self.inputs[input_index])
649 }
650
651 fn check_index_is_within_bounds(
654 &self,
655 input_index: usize,
656 ) -> Result<(), IndexOutOfBoundsError> {
657 if input_index >= self.inputs.len() {
658 return Err(IndexOutOfBoundsError::Inputs {
659 index: input_index,
660 length: self.inputs.len(),
661 });
662 }
663
664 if input_index >= self.unsigned_tx.input.len() {
665 return Err(IndexOutOfBoundsError::TxInput {
666 index: input_index,
667 length: self.unsigned_tx.input.len(),
668 });
669 }
670
671 Ok(())
672 }
673
674 fn signing_algorithm(&self, input_index: usize) -> Result<SigningAlgorithm, SignError> {
676 let output_type = self.output_type(input_index)?;
677 Ok(output_type.signing_algorithm())
678 }
679
680 fn output_type(&self, input_index: usize) -> Result<OutputType, SignError> {
682 let input = self.checked_input(input_index)?;
683 let utxo = self.spend_utxo(input_index)?;
684 let spk = utxo.script_pubkey.clone();
685
686 if !(spk.is_witness_program() || spk.is_p2sh()) {
688 return Ok(OutputType::Bare);
689 }
690
691 if spk.is_p2wpkh() {
692 return Ok(OutputType::Wpkh);
693 }
694
695 if spk.is_p2wsh() {
696 return Ok(OutputType::Wsh);
697 }
698
699 if spk.is_p2sh() {
700 if input.redeem_script.as_ref().map(|s| s.is_p2wpkh()).unwrap_or(false) {
701 return Ok(OutputType::ShWpkh);
702 }
703 if input.redeem_script.as_ref().map(|x| x.is_p2wsh()).unwrap_or(false) {
704 return Ok(OutputType::ShWsh);
705 }
706 return Ok(OutputType::Sh);
707 }
708
709 if spk.is_p2tr() {
710 return Ok(OutputType::Tr);
711 }
712
713 Err(SignError::UnknownOutputType)
716 }
717
718 pub fn fee(&self) -> Result<Amount, Error> {
729 let mut inputs: u64 = 0;
730 for utxo in self.iter_funding_utxos() {
731 inputs = inputs.checked_add(utxo?.value.to_sat()).ok_or(Error::FeeOverflow)?;
732 }
733 let mut outputs: u64 = 0;
734 for out in &self.unsigned_tx.output {
735 outputs = outputs.checked_add(out.value.to_sat()).ok_or(Error::FeeOverflow)?;
736 }
737 inputs.checked_sub(outputs).map(Amount::from_sat).ok_or(Error::NegativeFee)
738 }
739}
740
741#[derive(Clone, Debug, PartialEq, Eq)]
743#[non_exhaustive]
744pub enum KeyRequest {
745 Pubkey(PublicKey),
747 Bip32(KeySource),
749}
750
751pub trait GetKey {
753 type Error: core::fmt::Debug;
755
756 fn get_key<C: Signing>(
763 &self,
764 key_request: KeyRequest,
765 secp: &Secp256k1<C>,
766 ) -> Result<Option<PrivateKey>, Self::Error>;
767}
768
769impl GetKey for Xpriv {
770 type Error = GetKeyError;
771
772 fn get_key<C: Signing>(
773 &self,
774 key_request: KeyRequest,
775 secp: &Secp256k1<C>,
776 ) -> Result<Option<PrivateKey>, Self::Error> {
777 match key_request {
778 KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
779 KeyRequest::Bip32((fingerprint, path)) => {
780 let key = if self.fingerprint(secp) == fingerprint {
781 let k = self.derive_priv(secp, &path)?;
782 Some(k.to_priv())
783 } else {
784 None
785 };
786 Ok(key)
787 }
788 }
789 }
790}
791
792pub type SigningKeysMap = BTreeMap<usize, SigningKeys>;
794
795#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
797pub enum SigningKeys {
798 Ecdsa(Vec<PublicKey>),
800 Schnorr(Vec<XOnlyPublicKey>),
805}
806
807pub type SigningErrors = BTreeMap<usize, SignError>;
809
810#[rustfmt::skip]
811macro_rules! impl_get_key_for_set {
812 ($set:ident) => {
813
814impl GetKey for $set<Xpriv> {
815 type Error = GetKeyError;
816
817 fn get_key<C: Signing>(
818 &self,
819 key_request: KeyRequest,
820 secp: &Secp256k1<C>
821 ) -> Result<Option<PrivateKey>, Self::Error> {
822 match key_request {
823 KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
824 KeyRequest::Bip32((fingerprint, path)) => {
825 for xpriv in self.iter() {
826 if xpriv.parent_fingerprint == fingerprint {
827 let k = xpriv.derive_priv(secp, &path)?;
828 return Ok(Some(k.to_priv()));
829 }
830 }
831 Ok(None)
832 }
833 }
834 }
835}}}
836impl_get_key_for_set!(BTreeSet);
837#[cfg(feature = "std")]
838impl_get_key_for_set!(HashSet);
839
840#[rustfmt::skip]
841macro_rules! impl_get_key_for_map {
842 ($map:ident) => {
843
844impl GetKey for $map<PublicKey, PrivateKey> {
845 type Error = GetKeyError;
846
847 fn get_key<C: Signing>(
848 &self,
849 key_request: KeyRequest,
850 _: &Secp256k1<C>,
851 ) -> Result<Option<PrivateKey>, Self::Error> {
852 match key_request {
853 KeyRequest::Pubkey(pk) => Ok(self.get(&pk).cloned()),
854 KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported),
855 }
856 }
857}}}
858impl_get_key_for_map!(BTreeMap);
859#[cfg(feature = "std")]
860impl_get_key_for_map!(HashMap);
861
862#[derive(Debug, Clone, PartialEq, Eq)]
864#[non_exhaustive]
865pub enum GetKeyError {
866 Bip32(bip32::Error),
868 NotSupported,
870}
871
872bitcoin_internals::impl_from_infallible!(GetKeyError);
873
874impl fmt::Display for GetKeyError {
875 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
876 use GetKeyError::*;
877
878 match *self {
879 Bip32(ref e) => write_err!(f, "a bip23 error"; e),
880 NotSupported =>
881 f.write_str("the GetKey operation is not supported for this key request"),
882 }
883 }
884}
885
886#[cfg(feature = "std")]
887impl std::error::Error for GetKeyError {
888 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
889 use GetKeyError::*;
890
891 match *self {
892 NotSupported => None,
893 Bip32(ref e) => Some(e),
894 }
895 }
896}
897
898impl From<bip32::Error> for GetKeyError {
899 fn from(e: bip32::Error) -> Self { GetKeyError::Bip32(e) }
900}
901
902#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
904#[non_exhaustive]
905pub enum OutputType {
906 Bare,
908 Wpkh,
910 Wsh,
912 ShWpkh,
914 ShWsh,
916 Sh,
918 Tr,
920}
921
922impl OutputType {
923 pub fn signing_algorithm(&self) -> SigningAlgorithm {
925 use OutputType::*;
926
927 match self {
928 Bare | Wpkh | Wsh | ShWpkh | ShWsh | Sh => SigningAlgorithm::Ecdsa,
929 Tr => SigningAlgorithm::Schnorr,
930 }
931 }
932}
933
934#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
936pub enum SigningAlgorithm {
937 Ecdsa,
941 Schnorr,
945}
946
947#[derive(Debug, Clone, PartialEq, Eq)]
949#[non_exhaustive]
950pub enum SignError {
951 IndexOutOfBounds(IndexOutOfBoundsError),
953 InvalidSighashType,
955 MissingInputUtxo,
957 MissingRedeemScript,
959 MissingSpendUtxo,
961 MissingWitnessScript,
963 MismatchedAlgoKey,
965 NotEcdsa,
967 NotWpkh,
969 SegwitV0Sighash(transaction::InputsIndexError),
971 P2wpkhSighash(sighash::P2wpkhError),
973 TaprootError(sighash::TaprootError),
975 UnknownOutputType,
977 KeyNotFound,
979 WrongSigningAlgorithm,
981 Unsupported,
983}
984
985bitcoin_internals::impl_from_infallible!(SignError);
986
987impl fmt::Display for SignError {
988 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
989 use SignError::*;
990
991 match *self {
992 IndexOutOfBounds(ref e) => write_err!(f, "index out of bounds"; e),
993 InvalidSighashType => write!(f, "invalid sighash type"),
994 MissingInputUtxo => write!(f, "missing input utxo in PBST"),
995 MissingRedeemScript => write!(f, "missing redeem script"),
996 MissingSpendUtxo => write!(f, "missing spend utxo in PSBT"),
997 MissingWitnessScript => write!(f, "missing witness script"),
998 MismatchedAlgoKey => write!(f, "signing algorithm and key type does not match"),
999 NotEcdsa => write!(f, "attempted to ECDSA sign an non-ECDSA input"),
1000 NotWpkh => write!(f, "the scriptPubkey is not a P2WPKH script"),
1001 SegwitV0Sighash(ref e) => write_err!(f, "segwit v0 sighash"; e),
1002 P2wpkhSighash(ref e) => write_err!(f, "p2wpkh sighash"; e),
1003 TaprootError(ref e) => write_err!(f, "taproot sighash"; e),
1004 UnknownOutputType => write!(f, "unable to determine the output type"),
1005 KeyNotFound => write!(f, "unable to find key"),
1006 WrongSigningAlgorithm =>
1007 write!(f, "attempt to sign an input with the wrong signing algorithm"),
1008 Unsupported => write!(f, "signing request currently unsupported"),
1009 }
1010 }
1011}
1012
1013#[cfg(feature = "std")]
1014impl std::error::Error for SignError {
1015 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1016 use SignError::*;
1017
1018 match *self {
1019 SegwitV0Sighash(ref e) => Some(e),
1020 P2wpkhSighash(ref e) => Some(e),
1021 TaprootError(ref e) => Some(e),
1022 IndexOutOfBounds(ref e) => Some(e),
1023 InvalidSighashType
1024 | MissingInputUtxo
1025 | MissingRedeemScript
1026 | MissingSpendUtxo
1027 | MissingWitnessScript
1028 | MismatchedAlgoKey
1029 | NotEcdsa
1030 | NotWpkh
1031 | UnknownOutputType
1032 | KeyNotFound
1033 | WrongSigningAlgorithm
1034 | Unsupported => None,
1035 }
1036 }
1037}
1038
1039impl From<sighash::P2wpkhError> for SignError {
1040 fn from(e: sighash::P2wpkhError) -> Self { Self::P2wpkhSighash(e) }
1041}
1042
1043impl From<IndexOutOfBoundsError> for SignError {
1044 fn from(e: IndexOutOfBoundsError) -> Self { SignError::IndexOutOfBounds(e) }
1045}
1046
1047impl From<sighash::TaprootError> for SignError {
1048 fn from(e: sighash::TaprootError) -> Self { SignError::TaprootError(e) }
1049}
1050
1051#[derive(Debug, Clone, PartialEq, Eq)]
1053#[non_exhaustive]
1054pub enum ExtractTxError {
1055 AbsurdFeeRate {
1057 fee_rate: FeeRate,
1059 tx: Transaction,
1061 },
1062 MissingInputValue {
1064 tx: Transaction,
1066 },
1067 SendingTooMuch {
1069 psbt: Psbt,
1071 },
1072}
1073
1074bitcoin_internals::impl_from_infallible!(ExtractTxError);
1075
1076impl fmt::Display for ExtractTxError {
1077 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1078 use ExtractTxError::*;
1079
1080 match *self {
1081 AbsurdFeeRate { fee_rate, .. } =>
1082 write!(f, "An absurdly high fee rate of {}", fee_rate),
1083 MissingInputValue { .. } => write!(
1084 f,
1085 "One of the inputs lacked value information (witness_utxo or non_witness_utxo)"
1086 ),
1087 SendingTooMuch { .. } => write!(
1088 f,
1089 "Transaction would be invalid due to output value being greater than input value."
1090 ),
1091 }
1092 }
1093}
1094
1095#[cfg(feature = "std")]
1096impl std::error::Error for ExtractTxError {
1097 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1098 use ExtractTxError::*;
1099
1100 match *self {
1101 AbsurdFeeRate { .. } | MissingInputValue { .. } | SendingTooMuch { .. } => None,
1102 }
1103 }
1104}
1105
1106#[derive(Debug, Clone, PartialEq, Eq)]
1108#[non_exhaustive]
1109pub enum IndexOutOfBoundsError {
1110 Inputs {
1112 index: usize,
1114 length: usize,
1116 },
1117 TxInput {
1119 index: usize,
1121 length: usize,
1123 },
1124}
1125
1126bitcoin_internals::impl_from_infallible!(IndexOutOfBoundsError);
1127
1128impl fmt::Display for IndexOutOfBoundsError {
1129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1130 use IndexOutOfBoundsError::*;
1131
1132 match *self {
1133 Inputs { ref index, ref length } => write!(
1134 f,
1135 "index {} is out-of-bounds for PSBT inputs vector length {}",
1136 index, length
1137 ),
1138 TxInput { ref index, ref length } => write!(
1139 f,
1140 "index {} is out-of-bounds for PSBT unsigned tx input vector length {}",
1141 index, length
1142 ),
1143 }
1144 }
1145}
1146
1147#[cfg(feature = "std")]
1148impl std::error::Error for IndexOutOfBoundsError {
1149 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1150 use IndexOutOfBoundsError::*;
1151
1152 match *self {
1153 Inputs { .. } | TxInput { .. } => None,
1154 }
1155 }
1156}
1157
1158#[cfg(feature = "base64")]
1159mod display_from_str {
1160 use core::fmt::{self, Display, Formatter};
1161 use core::str::FromStr;
1162
1163 use base64::display::Base64Display;
1164 use base64::prelude::{Engine as _, BASE64_STANDARD};
1165 use bitcoin_internals::write_err;
1166
1167 use super::{Error, Psbt};
1168
1169 #[derive(Debug)]
1171 #[non_exhaustive]
1172 pub enum PsbtParseError {
1173 PsbtEncoding(Error),
1175 Base64Encoding(::base64::DecodeError),
1177 }
1178
1179 bitcoin_internals::impl_from_infallible!(PsbtParseError);
1180
1181 impl Display for PsbtParseError {
1182 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1183 use self::PsbtParseError::*;
1184
1185 match *self {
1186 PsbtEncoding(ref e) => write_err!(f, "error in internal PSBT data structure"; e),
1187 Base64Encoding(ref e) => write_err!(f, "error in PSBT base64 encoding"; e),
1188 }
1189 }
1190 }
1191
1192 #[cfg(feature = "std")]
1193 impl std::error::Error for PsbtParseError {
1194 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1195 use self::PsbtParseError::*;
1196
1197 match self {
1198 PsbtEncoding(e) => Some(e),
1199 Base64Encoding(e) => Some(e),
1200 }
1201 }
1202 }
1203
1204 impl Display for Psbt {
1205 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1206 write!(f, "{}", Base64Display::new(&self.serialize(), &BASE64_STANDARD))
1207 }
1208 }
1209
1210 impl FromStr for Psbt {
1211 type Err = PsbtParseError;
1212
1213 fn from_str(s: &str) -> Result<Self, Self::Err> {
1214 let data = BASE64_STANDARD.decode(s).map_err(PsbtParseError::Base64Encoding)?;
1215 Psbt::deserialize(&data).map_err(PsbtParseError::PsbtEncoding)
1216 }
1217 }
1218}
1219#[cfg(feature = "base64")]
1220pub use self::display_from_str::PsbtParseError;
1221
1222#[rustfmt::skip]
1223#[allow(unused_imports)]
1224mod prelude {
1225 #[cfg(all(not(feature = "std"), not(test)))]
1226 pub use alloc::{string::{String, ToString}, vec::Vec, boxed::Box, borrow::{Borrow, BorrowMut, Cow, ToOwned}, slice, rc};
1227
1228 #[cfg(all(not(feature = "std"), not(test), target_has_atomic = "ptr"))]
1229 pub use alloc::sync;
1230
1231 #[cfg(any(feature = "std", test))]
1232 pub use std::{string::{String, ToString}, vec::Vec, boxed::Box, borrow::{Borrow, BorrowMut, Cow, ToOwned}, rc, sync};
1233
1234 #[cfg(all(not(feature = "std"), not(test)))]
1235 pub use alloc::collections::{BTreeMap, BTreeSet, btree_map, BinaryHeap};
1236
1237 #[cfg(any(feature = "std", test))]
1238 pub use std::collections::{BTreeMap, BTreeSet, btree_map, BinaryHeap};
1239}
1240
1241#[cfg(test)]
1242mod tests {
1243 use bitcoin::bip32::ChildNumber;
1244 use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
1245 use bitcoin::hex::{test_hex_unwrap as hex, FromHex};
1246 use bitcoin::locktime::absolute;
1247 #[cfg(feature = "rand-std")]
1248 use bitcoin::secp256k1::{All, SecretKey};
1249 use bitcoin::{
1250 secp256k1, transaction, NetworkKind, OutPoint, ScriptBuf, Sequence, TxIn, Witness,
1251 };
1252
1253 use super::*;
1254 use crate::serialize::{Deserialize, Serialize};
1255
1256 #[track_caller]
1257 pub fn hex_psbt(s: &str) -> Result<Psbt, Error> {
1258 let r = Vec::from_hex(s);
1259 match r {
1260 Err(_e) => panic!("unable to parse hex string {}", s),
1261 Ok(v) => Psbt::deserialize(&v),
1262 }
1263 }
1264
1265 #[track_caller]
1266 fn psbt_with_values(input: u64, output: u64) -> Psbt {
1267 Psbt {
1268 unsigned_tx: Transaction {
1269 version: transaction::Version::TWO,
1270 lock_time: absolute::LockTime::ZERO,
1271 input: vec![TxIn {
1272 previous_output: OutPoint {
1273 txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126"
1274 .parse()
1275 .unwrap(),
1276 vout: 0,
1277 },
1278 script_sig: ScriptBuf::new(),
1279 sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
1280 witness: Witness::default(),
1281 }],
1282 output: vec![TxOut {
1283 value: Amount::from_sat(output),
1284 script_pubkey: ScriptBuf::from_hex(
1285 "a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
1286 )
1287 .unwrap(),
1288 }],
1289 },
1290 xpub: Default::default(),
1291 version: 0,
1292 proprietary: BTreeMap::new(),
1293 unknown: BTreeMap::new(),
1294
1295 inputs: vec![Input {
1296 witness_utxo: Some(TxOut {
1297 value: Amount::from_sat(input),
1298 script_pubkey: ScriptBuf::from_hex(
1299 "a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
1300 )
1301 .unwrap(),
1302 }),
1303 ..Default::default()
1304 }],
1305 outputs: vec![],
1306 }
1307 }
1308
1309 #[test]
1310 fn trivial_psbt() {
1311 let psbt = Psbt {
1312 unsigned_tx: Transaction {
1313 version: transaction::Version::TWO,
1314 lock_time: absolute::LockTime::ZERO,
1315 input: vec![],
1316 output: vec![],
1317 },
1318 xpub: Default::default(),
1319 version: 0,
1320 proprietary: BTreeMap::new(),
1321 unknown: BTreeMap::new(),
1322
1323 inputs: vec![],
1324 outputs: vec![],
1325 };
1326 assert_eq!(psbt.serialize_hex(), "70736274ff01000a0200000000000000000000");
1327 }
1328
1329 #[test]
1330 fn psbt_uncompressed_key() {
1331 let psbt: Psbt = hex_psbt("70736274ff01003302000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff000000000000420204bb0d5d0cca36e7b9c80f63bc04c1240babb83bcd2803ef7ac8b6e2af594291daec281e856c98d210c5ab14dfd5828761f8ee7d5f45ca21ad3e4c4b41b747a3a047304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe70100").unwrap();
1332 assert!(psbt.inputs[0].partial_sigs.len() == 1);
1333 let pk = psbt.inputs[0].partial_sigs.iter().next().unwrap().0;
1334 assert!(!pk.compressed);
1335 }
1336
1337 #[test]
1338 fn psbt_high_fee_checks() {
1339 let psbt = psbt_with_values(5_000_000_000_000, 1000);
1340 assert_eq!(
1341 psbt.clone().extract_tx().map_err(|e| match e {
1342 ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate,
1343 _ => panic!(""),
1344 }),
1345 Err(FeeRate::from_sat_per_kwu(15060240960843))
1346 );
1347 assert_eq!(
1348 psbt.clone().extract_tx_fee_rate_limit().map_err(|e| match e {
1349 ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate,
1350 _ => panic!(""),
1351 }),
1352 Err(FeeRate::from_sat_per_kwu(15060240960843))
1353 );
1354 assert_eq!(
1355 psbt.clone()
1356 .extract_tx_with_fee_rate_limit(FeeRate::from_sat_per_kwu(15060240960842))
1357 .map_err(|e| match e {
1358 ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate,
1359 _ => panic!(""),
1360 }),
1361 Err(FeeRate::from_sat_per_kwu(15060240960843))
1362 );
1363 assert!(psbt
1364 .extract_tx_with_fee_rate_limit(FeeRate::from_sat_per_kwu(15060240960843))
1365 .is_ok());
1366
1367 assert_eq!(
1369 psbt_with_values(2076001, 1000).extract_tx().map_err(|e| match e {
1370 ExtractTxError::AbsurdFeeRate { fee_rate, .. } => fee_rate,
1371 _ => panic!(""),
1372 }),
1373 Err(FeeRate::from_sat_per_kwu(6250003)) );
1375
1376 assert!(psbt_with_values(2076000, 1000).extract_tx().is_ok());
1379 }
1380
1381 #[test]
1382 fn serialize_then_deserialize_output() {
1383 let secp = &Secp256k1::new();
1384 let seed = hex!("000102030405060708090a0b0c0d0e0f");
1385
1386 let mut hd_keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = Default::default();
1387
1388 let mut sk: Xpriv = Xpriv::new_master(NetworkKind::Main, &seed).unwrap();
1389
1390 let fprint = sk.fingerprint(secp);
1391
1392 let dpath: Vec<ChildNumber> = vec![
1393 ChildNumber::from_normal_idx(0).unwrap(),
1394 ChildNumber::from_normal_idx(1).unwrap(),
1395 ChildNumber::from_normal_idx(2).unwrap(),
1396 ChildNumber::from_normal_idx(4).unwrap(),
1397 ChildNumber::from_normal_idx(42).unwrap(),
1398 ChildNumber::from_hardened_idx(69).unwrap(),
1399 ChildNumber::from_normal_idx(420).unwrap(),
1400 ChildNumber::from_normal_idx(31337).unwrap(),
1401 ];
1402
1403 sk = sk.derive_priv(secp, &dpath).unwrap();
1404
1405 let pk = Xpub::from_priv(secp, &sk);
1406
1407 hd_keypaths.insert(pk.public_key, (fprint, dpath.into()));
1408
1409 let expected: Output = Output {
1410 redeem_script: Some(
1411 ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
1412 ),
1413 witness_script: Some(
1414 ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
1415 ),
1416 bip32_derivation: hd_keypaths,
1417 ..Default::default()
1418 };
1419
1420 let actual = Output::deserialize(&expected.serialize()).unwrap();
1421
1422 assert_eq!(expected, actual);
1423 }
1424
1425 #[test]
1426 fn serialize_then_deserialize_global() {
1427 let expected = Psbt {
1428 unsigned_tx: Transaction {
1429 version: transaction::Version::TWO,
1430 lock_time: absolute::LockTime::from_consensus(1257139),
1431 input: vec![TxIn {
1432 previous_output: OutPoint {
1433 txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126"
1434 .parse()
1435 .unwrap(),
1436 vout: 0,
1437 },
1438 script_sig: ScriptBuf::new(),
1439 sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
1440 witness: Witness::default(),
1441 }],
1442 output: vec![
1443 TxOut {
1444 value: Amount::from_sat(99_999_699),
1445 script_pubkey: ScriptBuf::from_hex(
1446 "76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
1447 )
1448 .unwrap(),
1449 },
1450 TxOut {
1451 value: Amount::from_sat(100_000_000),
1452 script_pubkey: ScriptBuf::from_hex(
1453 "a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
1454 )
1455 .unwrap(),
1456 },
1457 ],
1458 },
1459 xpub: Default::default(),
1460 version: 0,
1461 proprietary: Default::default(),
1462 unknown: Default::default(),
1463 inputs: vec![Input::default()],
1464 outputs: vec![Output::default(), Output::default()],
1465 };
1466
1467 let actual: Psbt = Psbt::deserialize(&expected.serialize()).unwrap();
1468 assert_eq!(expected, actual);
1469 }
1470
1471 #[test]
1472 fn serialize_then_deserialize_psbtkvpair() {
1473 let expected = raw::Pair {
1474 key: raw::Key { type_value: 0u8, key: vec![42u8, 69u8] },
1475 value: vec![69u8, 42u8, 4u8],
1476 };
1477
1478 let actual = raw::Pair::deserialize(&expected.serialize()).unwrap();
1479
1480 assert_eq!(expected, actual);
1481 }
1482
1483 #[test]
1484 fn deserialize_and_serialize_psbt_with_two_partial_sigs() {
1485 let hex = "70736274ff0100890200000001207ae985d787dfe6143d5c58fad79cc7105e0e799fcf033b7f2ba17e62d7b3200000000000ffffffff02563d03000000000022002019899534b9a011043c0dd57c3ff9a381c3522c5f27c6a42319085b56ca543a1d6adc020000000000220020618b47a07ebecca4e156edb1b9ea7c24bdee0139fc049237965ffdaf56d5ee73000000000001012b801a0600000000002200201148e93e9315e37dbed2121be5239257af35adc03ffdfc5d914b083afa44dab82202025fe7371376d53cf8a2783917c28bf30bd690b0a4d4a207690093ca2b920ee076473044022007e06b362e89912abd4661f47945430739b006a85d1b2a16c01dc1a4bd07acab022061576d7aa834988b7ab94ef21d8eebd996ea59ea20529a19b15f0c9cebe3d8ac01220202b3fe93530020a8294f0e527e33fbdff184f047eb6b5a1558a352f62c29972f8a473044022002787f926d6817504431ee281183b8119b6845bfaa6befae45e13b6d430c9d2f02202859f149a6cd26ae2f03a107e7f33c7d91730dade305fe077bae677b5d44952a01010547522102b3fe93530020a8294f0e527e33fbdff184f047eb6b5a1558a352f62c29972f8a21025fe7371376d53cf8a2783917c28bf30bd690b0a4d4a207690093ca2b920ee07652ae0001014752210283ef76537f2d58ae3aa3a4bd8ae41c3f230ccadffb1a0bd3ca504d871cff05e7210353d79cc0cb1396f4ce278d005f16d948e02a6aec9ed1109f13747ecb1507b37b52ae00010147522102b3937241777b6665e0d694e52f9c1b188433641df852da6fc42187b5d8a368a321034cdd474f01cc5aa7ff834ad8bcc882a87e854affc775486bc2a9f62e8f49bd7852ae00";
1486 let psbt: Psbt = hex_psbt(hex).unwrap();
1487 assert_eq!(hex, psbt.serialize_hex());
1488 }
1489
1490 #[cfg(feature = "serde")]
1491 #[test]
1492 fn test_serde_psbt() {
1493 use bitcoin::hashes::sha256d;
1495
1496 use crate::map::Input;
1497
1498 let tx = Transaction {
1500 version: transaction::Version::ONE,
1501 lock_time: absolute::LockTime::ZERO,
1502 input: vec![TxIn {
1503 previous_output: OutPoint {
1504 txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389"
1505 .parse()
1506 .unwrap(),
1507 vout: 1,
1508 },
1509 script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
1510 .unwrap(),
1511 sequence: Sequence::MAX,
1512 witness: Witness::from_slice(&[hex!(
1513 "03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"
1514 )]),
1515 }],
1516 output: vec![TxOut {
1517 value: Amount::from_sat(190_303_501_938),
1518 script_pubkey: ScriptBuf::from_hex(
1519 "a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
1520 )
1521 .unwrap(),
1522 }],
1523 };
1524 let unknown: BTreeMap<raw::Key, Vec<u8>> =
1525 vec![(raw::Key { type_value: 1, key: vec![0, 1] }, vec![3, 4, 5])]
1526 .into_iter()
1527 .collect();
1528 let key_source = ("deadbeef".parse().unwrap(), "0'/1".parse().unwrap());
1529 let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![(
1530 "0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
1531 key_source.clone(),
1532 )]
1533 .into_iter()
1534 .collect();
1535
1536 let proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = vec![(
1537 raw::ProprietaryKey {
1538 prefix: "prefx".as_bytes().to_vec(),
1539 subtype: 42,
1540 key: "test_key".as_bytes().to_vec(),
1541 },
1542 vec![5, 6, 7],
1543 )]
1544 .into_iter()
1545 .collect();
1546
1547 let psbt = Psbt {
1548 version: 0,
1549 xpub: {
1550 let xpub: Xpub =
1551 "xpub661MyMwAqRbcGoRVtwfvzZsq2VBJR1LAHfQstHUoxqDorV89vRoMxUZ27kLrraAj6MPi\
1552 QfrDb27gigC1VS1dBXi5jGpxmMeBXEkKkcXUTg4".parse().unwrap();
1553 vec![(xpub, key_source)].into_iter().collect()
1554 },
1555 unsigned_tx: {
1556 let mut unsigned = tx.clone();
1557 unsigned.input[0].script_sig = ScriptBuf::new();
1558 unsigned.input[0].witness = Witness::default();
1559 unsigned
1560 },
1561 proprietary: proprietary.clone(),
1562 unknown: unknown.clone(),
1563
1564 inputs: vec![
1565 Input {
1566 non_witness_utxo: Some(tx),
1567 witness_utxo: Some(TxOut {
1568 value: Amount::from_sat(190_303_501_938),
1569 script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
1570 }),
1571 sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<PsbtSighashType>().unwrap()),
1572 redeem_script: Some(vec![0x51].into()),
1573 witness_script: None,
1574 partial_sigs: vec![(
1575 "0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
1576 "304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe701".parse().unwrap(),
1577 )].into_iter().collect(),
1578 bip32_derivation: keypaths.clone(),
1579 final_script_witness: Some(Witness::from_slice(&[vec![1, 3], vec![5]])),
1580 ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1581 sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1582 hash160_preimages: vec![(hash160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1583 hash256_preimages: vec![(sha256d::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
1584 proprietary: proprietary.clone(),
1585 unknown: unknown.clone(),
1586 ..Default::default()
1587 }
1588 ],
1589 outputs: vec![
1590 Output {
1591 bip32_derivation: keypaths,
1592 proprietary,
1593 unknown,
1594 ..Default::default()
1595 }
1596 ],
1597 };
1598 let encoded = serde_json::to_string(&psbt).unwrap();
1599 let decoded: Psbt = serde_json::from_str(&encoded).unwrap();
1600 assert_eq!(psbt, decoded);
1601 }
1602
1603 mod bip_vectors {
1604 #[cfg(feature = "base64")]
1605 use std::str::FromStr;
1606
1607 use super::*;
1608 use crate::map::Map;
1609
1610 #[test]
1611 #[should_panic(expected = "InvalidMagic")]
1612 fn invalid_vector_1() {
1613 hex_psbt("0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300").unwrap();
1614 }
1615
1616 #[cfg(feature = "base64")]
1617 #[test]
1618 #[should_panic(expected = "InvalidMagic")]
1619 fn invalid_vector_1_base64() {
1620 Psbt::from_str("AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAABqRzBEAiBwsiRRI+a/R01gxbUMBD1MaRpdJDXwmjSnZiqdwlF5CgIgATKcqdrPKAvfMHQOwDkEIkIsgctFg5RXrrdvwS7dlbMBIQJlfRGNM1e44PTCzUbbezn22cONmnCry5st5dyNv+TOMf7///8C09/1BQAAAAAZdqkU0MWZA8W6woaHYOkP1SGkZlqnZSCIrADh9QUAAAAAF6kUNUXm4zuDLEcFDyTT7rk8nAOUi8eHsy4TAA==").unwrap();
1621 }
1622
1623 #[test]
1624 #[should_panic(expected = "ConsensusEncoding")]
1625 fn invalid_vector_2() {
1626 hex_psbt("70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000")
1627 .unwrap();
1628 }
1629
1630 #[cfg(feature = "base64")]
1631 #[test]
1632 #[should_panic(expected = "ConsensusEncoding")]
1633 fn invalid_vector_2_base64() {
1634 Psbt::from_str("cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==")
1635 .unwrap();
1636 }
1637
1638 #[test]
1639 #[should_panic(expected = "UnsignedTxHasScriptSigs")]
1640 fn invalid_vector_3() {
1641 hex_psbt("70736274ff0100fd0a010200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be4000000006a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa88292feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
1642 }
1643
1644 #[cfg(feature = "base64")]
1645 #[test]
1646 #[should_panic(expected = "UnsignedTxHasScriptSigs")]
1647 fn invalid_vector_3_base64() {
1648 Psbt::from_str("cHNidP8BAP0KAQIAAAACqwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QAAAAAakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpL+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAABASAA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHhwEEFgAUhdE1N/LiZUBaNNuvqePdoB+4IwgAAAA=").unwrap();
1649 }
1650
1651 #[test]
1652 #[should_panic(expected = "MustHaveUnsignedTx")]
1653 fn invalid_vector_4() {
1654 hex_psbt("70736274ff000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000").unwrap();
1655 }
1656
1657 #[cfg(feature = "base64")]
1658 #[test]
1659 #[should_panic(expected = "MustHaveUnsignedTx")]
1660 fn invalid_vector_4_base64() {
1661 Psbt::from_str("cHNidP8AAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==").unwrap();
1662 }
1663
1664 #[test]
1665 #[should_panic(expected = "DuplicateKey(Key { type_value: 0, key: [] })")]
1666 fn invalid_vector_5() {
1667 hex_psbt("70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000000").unwrap();
1668 }
1669
1670 #[cfg(feature = "base64")]
1671 #[test]
1672 #[should_panic(expected = "DuplicateKey(Key { type_value: 0, key: [] })")]
1673 fn invalid_vector_5_base64() {
1674 Psbt::from_str("cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQA/AgAAAAH//////////////////////////////////////////wAAAAAA/////wEAAAAAAAAAAANqAQAAAAAAAAAA").unwrap();
1675 }
1676
1677 #[test]
1678 fn valid_vector_1() {
1679 let unserialized = Psbt {
1680 unsigned_tx: Transaction {
1681 version: transaction::Version::TWO,
1682 lock_time: absolute::LockTime::from_consensus(1257139),
1683 input: vec![
1684 TxIn {
1685 previous_output: OutPoint {
1686 txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(),
1687 vout: 0,
1688 },
1689 script_sig: ScriptBuf::new(),
1690 sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
1691 witness: Witness::default(),
1692 }
1693 ],
1694 output: vec![
1695 TxOut {
1696 value: Amount::from_sat(99_999_699),
1697 script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
1698 },
1699 TxOut {
1700 value: Amount::from_sat(100_000_000),
1701 script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
1702 },
1703 ],
1704 },
1705 xpub: Default::default(),
1706 version: 0,
1707 proprietary: BTreeMap::new(),
1708 unknown: BTreeMap::new(),
1709
1710 inputs: vec![
1711 Input {
1712 non_witness_utxo: Some(Transaction {
1713 version: transaction::Version::ONE,
1714 lock_time: absolute::LockTime::ZERO,
1715 input: vec![
1716 TxIn {
1717 previous_output: OutPoint {
1718 txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
1719 vout: 1,
1720 },
1721 script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
1722 sequence: Sequence::MAX,
1723 witness: Witness::from_slice(&[
1724 hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01"),
1725 hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"),
1726 ]),
1727 },
1728 TxIn {
1729 previous_output: OutPoint {
1730 txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
1731 vout: 1,
1732 },
1733 script_sig: ScriptBuf::from_hex("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
1734 sequence: Sequence::MAX,
1735 witness: Witness::from_slice(&[
1736 hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01"),
1737 hex!("0223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab3"),
1738 ]),
1739 }
1740 ],
1741 output: vec![
1742 TxOut {
1743 value: Amount::from_sat(200_000_000),
1744 script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
1745 },
1746 TxOut {
1747 value: Amount::from_sat(190_303_501_938),
1748 script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
1749 },
1750 ],
1751 }),
1752 ..Default::default()
1753 },
1754 ],
1755 outputs: vec![
1756 Output {
1757 ..Default::default()
1758 },
1759 Output {
1760 ..Default::default()
1761 },
1762 ],
1763 };
1764
1765 let base16str = "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000";
1766
1767 assert_eq!(unserialized.serialize_hex(), base16str);
1768 assert_eq!(unserialized, hex_psbt(base16str).unwrap());
1769
1770 #[cfg(feature = "base64")]
1771 {
1772 let base64str = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA";
1773 assert_eq!(Psbt::from_str(base64str).unwrap(), unserialized);
1774 assert_eq!(base64str, unserialized.to_string());
1775 assert_eq!(Psbt::from_str(base64str).unwrap(), hex_psbt(base16str).unwrap());
1776 }
1777 }
1778
1779 #[test]
1780 fn valid_vector_2() {
1781 let psbt: Psbt = hex_psbt("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
1782
1783 assert_eq!(psbt.inputs.len(), 2);
1784 assert_eq!(psbt.outputs.len(), 2);
1785
1786 assert!(&psbt.inputs[0].final_script_sig.is_some());
1787
1788 let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
1789 let expected_out =
1790 ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
1791
1792 assert!(redeem_script.is_p2wpkh());
1793 assert_eq!(
1794 redeem_script.to_p2sh(),
1795 psbt.inputs[1].witness_utxo.as_ref().unwrap().script_pubkey
1796 );
1797 assert_eq!(redeem_script.to_p2sh(), expected_out);
1798
1799 for output in psbt.outputs {
1800 assert_eq!(output.get_pairs().len(), 0)
1801 }
1802 }
1803
1804 #[test]
1805 fn valid_vector_3() {
1806 let psbt: Psbt = hex_psbt("70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001030401000000000000").unwrap();
1807
1808 assert_eq!(psbt.inputs.len(), 1);
1809 assert_eq!(psbt.outputs.len(), 2);
1810
1811 let tx_input = &psbt.unsigned_tx.input[0];
1812 let psbt_non_witness_utxo = psbt.inputs[0].non_witness_utxo.as_ref().unwrap();
1813
1814 assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.compute_txid());
1815 assert!(psbt_non_witness_utxo.output[tx_input.previous_output.vout as usize]
1816 .script_pubkey
1817 .is_p2pkh());
1818 assert_eq!(
1819 psbt.inputs[0].sighash_type.as_ref().unwrap().ecdsa_hash_ty().unwrap(),
1820 EcdsaSighashType::All
1821 );
1822 }
1823
1824 #[test]
1825 fn valid_vector_4() {
1826 let psbt: Psbt = hex_psbt("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000").unwrap();
1827
1828 assert_eq!(psbt.inputs.len(), 2);
1829 assert_eq!(psbt.outputs.len(), 2);
1830
1831 assert!(&psbt.inputs[0].final_script_sig.is_none());
1832 assert!(&psbt.inputs[1].final_script_sig.is_none());
1833
1834 let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
1835 let expected_out =
1836 ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
1837
1838 assert!(redeem_script.is_p2wpkh());
1839 assert_eq!(
1840 redeem_script.to_p2sh(),
1841 psbt.inputs[1].witness_utxo.as_ref().unwrap().script_pubkey
1842 );
1843 assert_eq!(redeem_script.to_p2sh(), expected_out);
1844
1845 for output in psbt.outputs {
1846 assert!(!output.get_pairs().is_empty())
1847 }
1848 }
1849
1850 #[test]
1851 fn valid_vector_5() {
1852 let psbt: Psbt = hex_psbt("70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000").unwrap();
1853
1854 assert_eq!(psbt.inputs.len(), 1);
1855 assert_eq!(psbt.outputs.len(), 1);
1856
1857 assert!(&psbt.inputs[0].final_script_sig.is_none());
1858
1859 let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap();
1860 let expected_out =
1861 ScriptBuf::from_hex("a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87").unwrap();
1862
1863 assert!(redeem_script.is_p2wsh());
1864 assert_eq!(
1865 redeem_script.to_p2sh(),
1866 psbt.inputs[0].witness_utxo.as_ref().unwrap().script_pubkey
1867 );
1868
1869 assert_eq!(redeem_script.to_p2sh(), expected_out);
1870 }
1871
1872 #[test]
1873 fn valid_vector_6() {
1874 let psbt: Psbt = hex_psbt("70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000").unwrap();
1875
1876 assert_eq!(psbt.inputs.len(), 1);
1877 assert_eq!(psbt.outputs.len(), 1);
1878
1879 let tx = &psbt.unsigned_tx;
1880 assert_eq!(
1881 tx.compute_txid(),
1882 "75c5c9665a570569ad77dd1279e6fd4628a093c4dcbf8d41532614044c14c115".parse().unwrap(),
1883 );
1884
1885 let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new();
1886 let key: raw::Key = raw::Key { type_value: 0x0fu8, key: hex!("010203040506070809") };
1887 let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f");
1888
1889 unknown.insert(key, value);
1890
1891 assert_eq!(psbt.inputs[0].unknown, unknown)
1892 }
1893 }
1894
1895 mod bip_371_vectors {
1896 use super::*;
1897
1898 #[test]
1899 fn invalid_vectors() {
1900 let err = hex_psbt("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a075701172102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232000000").unwrap_err();
1901 assert_eq!(err.to_string(), "invalid xonly public key");
1902 let err = hex_psbt("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757011342173bb3d36c074afb716fec6307a069a2e450b995f3c82785945ab8df0e24260dcd703b0cbf34de399184a9481ac2b3586db6601f026a77f7e4938481bc34751701aa000000").unwrap_err();
1903 #[cfg(feature = "std")]
1904 assert_eq!(err.to_string(), "invalid taproot signature");
1905 #[cfg(not(feature = "std"))]
1906 assert_eq!(
1907 err.to_string(),
1908 "invalid taproot signature: invalid taproot signature size: 66"
1909 );
1910 let err = hex_psbt("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err();
1911 assert_eq!(err.to_string(), "invalid xonly public key");
1912 let err = hex_psbt("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err();
1913 assert_eq!(err.to_string(), "invalid xonly public key");
1914 let err = hex_psbt("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07570000220702fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da7560000800100008000000080010000000000000000").unwrap_err();
1915 assert_eq!(err.to_string(), "invalid xonly public key");
1916 let err = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6924214022cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094089756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
1917 #[cfg(feature = "std")]
1918 assert_eq!(err.to_string(), "invalid hash when parsing slice");
1919 #[cfg(not(feature = "std"))]
1920 assert_eq!(
1921 err.to_string(),
1922 "invalid hash when parsing slice: invalid slice length 33 (expected 32)"
1923 );
1924 let err = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094289756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb01010000").unwrap_err();
1925 #[cfg(feature = "std")]
1926 assert_eq!(err.to_string(), "invalid taproot signature");
1927 #[cfg(not(feature = "std"))]
1928 assert_eq!(
1929 err.to_string(),
1930 "invalid taproot signature: invalid taproot signature size: 66"
1931 );
1932 let err = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
1933 #[cfg(feature = "std")]
1934 assert_eq!(err.to_string(), "invalid taproot signature");
1935 #[cfg(not(feature = "std"))]
1936 assert_eq!(
1937 err.to_string(),
1938 "invalid taproot signature: invalid taproot signature size: 57"
1939 );
1940 let err = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
1941 assert_eq!(err.to_string(), "invalid control block");
1942 let err = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
1943 assert_eq!(err.to_string(), "invalid control block");
1944 }
1945
1946 fn rtt_psbt(psbt: Psbt) {
1947 let enc = Psbt::serialize(&psbt);
1948 let psbt2 = Psbt::deserialize(&enc).unwrap();
1949 assert_eq!(psbt, psbt2);
1950 }
1951
1952 #[test]
1953 fn valid_psbt_vectors() {
1954 let psbt = hex_psbt("70736274ff010052020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a01000000160014768e1eeb4cf420866033f80aceff0f9720744969000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07572116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232002202036b772a6db74d8753c98a827958de6c78ab3312109f37d3e0304484242ece73d818772b2da7540000800100008000000080000000000000000000").unwrap();
1955 let internal_key = psbt.inputs[0].tap_internal_key.unwrap();
1956 assert!(psbt.inputs[0].tap_key_origins.contains_key(&internal_key));
1957 rtt_psbt(psbt);
1958
1959 let psbt = hex_psbt("70736274ff010052020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a01000000160014768e1eeb4cf420866033f80aceff0f9720744969000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757011340bb53ec917bad9d906af1ba87181c48b86ace5aae2b53605a725ca74625631476fc6f5baedaf4f2ee0f477f36f58f3970d5b8273b7e497b97af2e3f125c97af342116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232002202036b772a6db74d8753c98a827958de6c78ab3312109f37d3e0304484242ece73d818772b2da7540000800100008000000080000000000000000000").unwrap();
1961 let internal_key = psbt.inputs[0].tap_internal_key.unwrap();
1962 assert!(psbt.inputs[0].tap_key_origins.contains_key(&internal_key));
1963 assert!(psbt.inputs[0].tap_key_sig.is_some());
1964 rtt_psbt(psbt);
1965
1966 let psbt = hex_psbt("70736274ff01005e020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a0100000022512083698e458c6664e1595d75da2597de1e22ee97d798e706c4c0a4b5a9823cd743000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07572116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232000105201124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e67121071124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e6711900772b2da7560000800100008000000080000000000500000000").unwrap();
1968 let internal_key = psbt.outputs[0].tap_internal_key.unwrap();
1969 assert!(psbt.outputs[0].tap_key_origins.contains_key(&internal_key));
1970 rtt_psbt(psbt);
1971
1972 let psbt = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a0100000022512083698e458c6664e1595d75da2597de1e22ee97d798e706c4c0a4b5a9823cd743000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f823202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc04215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac097c6e6fea5ff714ff5724499990810e406e98aa10f5bf7e5f6784bc1d0a9a6ce23204320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b2acc06215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f82320fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca9acc021162cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d23901cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09772b2da7560000800100008002000080000000000000000021164320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b23901115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f8772b2da75600008001000080010000800000000000000000211650929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac005007c461e5d2116fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca939016f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970772b2da7560000800100008003000080000000000000000001172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0011820f0362e2f75a6f420a5bde3eb221d96ae6720cf25f81890c95b1d775acb515e65000105201124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e67121071124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e6711900772b2da7560000800100008000000080000000000500000000").unwrap();
1974 assert!(psbt.inputs[0].tap_internal_key.is_some());
1975 assert!(psbt.inputs[0].tap_merkle_root.is_some());
1976 assert!(!psbt.inputs[0].tap_key_origins.is_empty());
1977 assert!(!psbt.inputs[0].tap_scripts.is_empty());
1978 rtt_psbt(psbt);
1979
1980 let psbt = hex_psbt("70736274ff01005e020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff0148e6052a010000002251200a8cbdc86de1ce1c0f9caeb22d6df7ced3683fe423e05d1e402a879341d6f6f5000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07572116fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000011720fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2320001052050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac001066f02c02220736e572900fe1252589a2143c8f3c79f71a0412d2353af755e9701c782694a02ac02c02220631c5f3b5832b8fbdebfb19704ceeb323c21f40f7a24f43d68ef0cc26b125969ac01c0222044faa49a0338de488c8dfffecdfb6f329f380bd566ef20c8df6d813eab1c4273ac210744faa49a0338de488c8dfffecdfb6f329f380bd566ef20c8df6d813eab1c42733901f06b798b92a10ed9a9d0bbfd3af173a53b1617da3a4159ca008216cd856b2e0e772b2da75600008001000080010000800000000003000000210750929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac005007c461e5d2107631c5f3b5832b8fbdebfb19704ceeb323c21f40f7a24f43d68ef0cc26b125969390118ace409889785e0ea70ceebb8e1ca892a7a78eaede0f2e296cf435961a8f4ca772b2da756000080010000800200008000000000030000002107736e572900fe1252589a2143c8f3c79f71a0412d2353af755e9701c782694a02390129a5b4915090162d759afd3fe0f93fa3326056d0b4088cb933cae7826cb8d82c772b2da7560000800100008003000080000000000300000000").unwrap();
1982 assert!(psbt.outputs[0].tap_internal_key.is_some());
1983 assert!(!psbt.outputs[0].tap_key_origins.is_empty());
1984 assert!(psbt.outputs[0].tap_tree.is_some());
1985 rtt_psbt(psbt);
1986
1987 let psbt = hex_psbt("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a0100000022512083698e458c6664e1595d75da2597de1e22ee97d798e706c4c0a4b5a9823cd743000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b0940bf818d9757d6ffeb538ba057fb4c1fc4e0f5ef186e765beb564791e02af5fd3d5e2551d4e34e33d86f276b82c99c79aed3f0395a081efcd2cc2c65dd7e693d7941144320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b2115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f840e1f1ab6fabfa26b236f21833719dc1d428ab768d80f91f9988d8abef47bfb863bb1f2a529f768c15f00ce34ec283cdc07e88f8428be28f6ef64043c32911811a4114fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca96f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae97040ec1f0379206461c83342285423326708ab031f0da4a253ee45aafa5b8c92034d8b605490f8cd13e00f989989b97e215faa36f12dee3693d2daccf3781c1757f66215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f823202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc04215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac097c6e6fea5ff714ff5724499990810e406e98aa10f5bf7e5f6784bc1d0a9a6ce23204320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b2acc06215c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f82320fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca9acc021162cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d23901cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b09772b2da7560000800100008002000080000000000000000021164320b0bf16f011b53ea7be615924aa7f27e5d29ad20ea1155d848676c3bad1b23901115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f8772b2da75600008001000080010000800000000000000000211650929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac005007c461e5d2116fa0f7a3cef3b1d0c0a6ce7d26e17ada0b2e5c92d19efad48b41859cb8a451ca939016f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970772b2da7560000800100008003000080000000000000000001172050929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0011820f0362e2f75a6f420a5bde3eb221d96ae6720cf25f81890c95b1d775acb515e65000105201124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e67121071124da7aec92ccd06c954562647f437b138b95721a84be2bf2276bbddab3e6711900772b2da7560000800100008000000080000000000500000000").unwrap();
1989 assert!(psbt.inputs[0].tap_internal_key.is_some());
1990 assert!(psbt.inputs[0].tap_merkle_root.is_some());
1991 assert!(!psbt.inputs[0].tap_scripts.is_empty());
1992 assert!(!psbt.inputs[0].tap_script_sigs.is_empty());
1993 assert!(!psbt.inputs[0].tap_key_origins.is_empty());
1994 rtt_psbt(psbt);
1995 }
1996 }
1997
1998 #[test]
1999 fn serialize_and_deserialize_preimage_psbt() {
2000 let mut sha256_preimages = BTreeMap::new();
2002 sha256_preimages.insert(sha256::Hash::hash(&[1u8, 2u8]), vec![1u8, 2u8]);
2003 sha256_preimages.insert(sha256::Hash::hash(&[1u8]), vec![1u8]);
2004
2005 let mut hash160_preimages = BTreeMap::new();
2007 hash160_preimages.insert(hash160::Hash::hash(&[1u8, 2u8]), vec![1u8, 2u8]);
2008 hash160_preimages.insert(hash160::Hash::hash(&[1u8]), vec![1u8]);
2009
2010 let mut unserialized = Psbt {
2012 unsigned_tx: Transaction {
2013 version: transaction::Version::TWO,
2014 lock_time: absolute::LockTime::from_consensus(1257139),
2015 input: vec![
2016 TxIn {
2017 previous_output: OutPoint {
2018 txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(),
2019 vout: 0,
2020 },
2021 script_sig: ScriptBuf::new(),
2022 sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
2023 witness: Witness::default(),
2024 }
2025 ],
2026 output: vec![
2027 TxOut {
2028 value: Amount::from_sat(99_999_699),
2029 script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
2030 },
2031 TxOut {
2032 value: Amount::from_sat(100_000_000),
2033 script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
2034 },
2035 ],
2036 },
2037 version: 0,
2038 xpub: Default::default(),
2039 proprietary: Default::default(),
2040 unknown: BTreeMap::new(),
2041
2042 inputs: vec![
2043 Input {
2044 non_witness_utxo: Some(Transaction {
2045 version: transaction::Version::ONE,
2046 lock_time: absolute::LockTime::ZERO,
2047 input: vec![
2048 TxIn {
2049 previous_output: OutPoint {
2050 txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
2051 vout: 1,
2052 },
2053 script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
2054 sequence: Sequence::MAX,
2055 witness: Witness::from_slice(&[
2056 hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01"),
2057 hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"),
2058 ]),
2059 },
2060 TxIn {
2061 previous_output: OutPoint {
2062 txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
2063 vout: 1,
2064 },
2065 script_sig: ScriptBuf::from_hex("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
2066 sequence: Sequence::MAX,
2067 witness: Witness::from_slice(&[
2068 hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01"),
2069 hex!("0223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab3"),
2070 ]),
2071 }
2072 ],
2073 output: vec![
2074 TxOut {
2075 value: Amount::from_sat(200_000_000),
2076 script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
2077 },
2078 TxOut {
2079 value: Amount::from_sat(190_303_501_938),
2080 script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
2081 },
2082 ],
2083 }),
2084 ..Default::default()
2085 },
2086 ],
2087 outputs: vec![
2088 Output {
2089 ..Default::default()
2090 },
2091 Output {
2092 ..Default::default()
2093 },
2094 ],
2095 };
2096 unserialized.inputs[0].hash160_preimages = hash160_preimages;
2097 unserialized.inputs[0].sha256_preimages = sha256_preimages;
2098
2099 let rtt: Psbt = hex_psbt(&unserialized.serialize_hex()).unwrap();
2100 assert_eq!(rtt, unserialized);
2101
2102 let mut ripemd160_preimages = BTreeMap::new();
2104 ripemd160_preimages.insert(ripemd160::Hash::hash(&[17u8]), vec![18u8]);
2105 unserialized.inputs[0].ripemd160_preimages = ripemd160_preimages;
2106
2107 let rtt: Result<Psbt, _> = hex_psbt(&unserialized.serialize_hex());
2109 assert!(rtt.is_err());
2110 }
2111
2112 #[test]
2113 fn serialize_and_deserialize_proprietary() {
2114 let mut psbt: Psbt = hex_psbt("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
2115 psbt.proprietary.insert(
2116 raw::ProprietaryKey { prefix: b"test".to_vec(), subtype: 0u8, key: b"test".to_vec() },
2117 b"test".to_vec(),
2118 );
2119 assert!(!psbt.proprietary.is_empty());
2120 let rtt: Psbt = hex_psbt(&psbt.serialize_hex()).unwrap();
2121 assert!(!rtt.proprietary.is_empty());
2122 }
2123
2124 #[test]
2126 fn combine_psbts() {
2127 let mut psbt1 = hex_psbt(include_str!("../tests/data/psbt1.hex")).unwrap();
2128 let psbt2 = hex_psbt(include_str!("../tests/data/psbt2.hex")).unwrap();
2129 let psbt_combined = hex_psbt(include_str!("../tests/data/psbt2.hex")).unwrap();
2130
2131 psbt1.combine(psbt2).expect("psbt combine to succeed");
2132 assert_eq!(psbt1, psbt_combined);
2133 }
2134
2135 #[test]
2136 fn combine_psbts_commutative() {
2137 let mut psbt1 = hex_psbt(include_str!("../tests/data/psbt1.hex")).unwrap();
2138 let mut psbt2 = hex_psbt(include_str!("../tests/data/psbt2.hex")).unwrap();
2139
2140 let psbt1_clone = psbt1.clone();
2141 let psbt2_clone = psbt2.clone();
2142
2143 psbt1.combine(psbt2_clone).expect("psbt1 combine to succeed");
2144 psbt2.combine(psbt1_clone).expect("psbt2 combine to succeed");
2145
2146 assert_eq!(psbt1, psbt2);
2147 }
2148
2149 #[cfg(feature = "rand-std")]
2150 fn gen_keys() -> (PrivateKey, PublicKey, Secp256k1<All>) {
2151 use bitcoin::secp256k1::rand::thread_rng;
2152
2153 let secp = Secp256k1::new();
2154
2155 let sk = SecretKey::new(&mut thread_rng());
2156 let priv_key = PrivateKey::new(sk, NetworkKind::Test);
2157 let pk = PublicKey::from_private_key(&secp, &priv_key);
2158
2159 (priv_key, pk, secp)
2160 }
2161
2162 #[test]
2163 #[cfg(feature = "rand-std")]
2164 fn get_key_btree_map() {
2165 let (priv_key, pk, secp) = gen_keys();
2166
2167 let mut key_map = BTreeMap::new();
2168 key_map.insert(pk, priv_key);
2169
2170 let got = key_map.get_key(KeyRequest::Pubkey(pk), &secp).expect("failed to get key");
2171 assert_eq!(got.unwrap(), priv_key)
2172 }
2173
2174 #[test]
2175 fn test_fee() {
2176 let output_0_val = Amount::from_sat(99_999_699);
2177 let output_1_val = Amount::from_sat(100_000_000);
2178 let prev_output_val = Amount::from_sat(200_000_000);
2179
2180 let mut t = Psbt {
2181 unsigned_tx: Transaction {
2182 version: transaction::Version::TWO,
2183 lock_time: absolute::LockTime::from_consensus(1257139),
2184 input: vec![
2185 TxIn {
2186 previous_output: OutPoint {
2187 txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(),
2188 vout: 0,
2189 },
2190 sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
2191 ..Default::default()
2192 }
2193 ],
2194 output: vec![
2195 TxOut {
2196 value: output_0_val,
2197 script_pubkey: ScriptBuf::new()
2198 },
2199 TxOut {
2200 value: output_1_val,
2201 script_pubkey: ScriptBuf::new()
2202 },
2203 ],
2204 },
2205 xpub: Default::default(),
2206 version: 0,
2207 proprietary: BTreeMap::new(),
2208 unknown: BTreeMap::new(),
2209
2210 inputs: vec![
2211 Input {
2212 non_witness_utxo: Some(Transaction {
2213 version: transaction::Version::ONE,
2214 lock_time: absolute::LockTime::ZERO,
2215 input: vec![
2216 TxIn {
2217 previous_output: OutPoint {
2218 txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
2219 vout: 1,
2220 },
2221 sequence: Sequence::MAX,
2222 ..Default::default()
2223 },
2224 TxIn {
2225 previous_output: OutPoint {
2226 txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
2227 vout: 1,
2228 },
2229 sequence: Sequence::MAX,
2230 ..Default::default()
2231 }
2232 ],
2233 output: vec![
2234 TxOut {
2235 value: prev_output_val,
2236 script_pubkey: ScriptBuf::new()
2237 },
2238 TxOut {
2239 value: Amount::from_sat(190_303_501_938),
2240 script_pubkey: ScriptBuf::new()
2241 },
2242 ],
2243 }),
2244 ..Default::default()
2245 },
2246 ],
2247 outputs: vec![
2248 Output {
2249 ..Default::default()
2250 },
2251 Output {
2252 ..Default::default()
2253 },
2254 ],
2255 };
2256 assert_eq!(
2257 t.fee().expect("fee calculation"),
2258 prev_output_val - (output_0_val + output_1_val)
2259 );
2260 let mut t2 = t.clone();
2262 t2.inputs[0].non_witness_utxo = None;
2263 match t2.fee().unwrap_err() {
2264 Error::MissingUtxo => {}
2265 e => panic!("unexpected error: {:?}", e),
2266 }
2267 let mut t3 = t.clone();
2269 t3.unsigned_tx.output[0].value = prev_output_val;
2270 match t3.fee().unwrap_err() {
2271 Error::NegativeFee => {}
2272 e => panic!("unexpected error: {:?}", e),
2273 }
2274 t.unsigned_tx.output[0].value = Amount::MAX;
2276 t.unsigned_tx.output[1].value = Amount::MAX;
2277 match t.fee().unwrap_err() {
2278 Error::FeeOverflow => {}
2279 e => panic!("unexpected error: {:?}", e),
2280 }
2281 }
2282
2283 #[test]
2284 #[cfg(feature = "rand-std")]
2285 fn sign_psbt() {
2286 use bitcoin::bip32::{DerivationPath, Fingerprint};
2287 use bitcoin::witness_version::WitnessVersion;
2288 use bitcoin::{WPubkeyHash, WitnessProgram};
2289
2290 let unsigned_tx = Transaction {
2291 version: transaction::Version::TWO,
2292 lock_time: absolute::LockTime::ZERO,
2293 input: vec![TxIn::default(), TxIn::default()],
2294 output: vec![TxOut::NULL],
2295 };
2296 let mut psbt = Psbt::from_unsigned_tx(unsigned_tx).unwrap();
2297
2298 let (priv_key, pk, secp) = gen_keys();
2299
2300 let mut key_map = BTreeMap::new();
2303 key_map.insert(pk, priv_key);
2304
2305 let txout_wpkh = TxOut {
2307 value: Amount::from_sat(10),
2308 script_pubkey: ScriptBuf::new_p2wpkh(&WPubkeyHash::hash(&pk.to_bytes())),
2309 };
2310 psbt.inputs[0].witness_utxo = Some(txout_wpkh);
2311
2312 let mut map = BTreeMap::new();
2313 map.insert(pk.inner, (Fingerprint::default(), DerivationPath::default()));
2314 psbt.inputs[0].bip32_derivation = map;
2315
2316 let unknown_prog = WitnessProgram::new(WitnessVersion::V4, &[0xaa; 34]).unwrap();
2318 let txout_unknown_future = TxOut {
2319 value: Amount::from_sat(10),
2320 script_pubkey: ScriptBuf::new_witness_program(&unknown_prog),
2321 };
2322 psbt.inputs[1].witness_utxo = Some(txout_unknown_future);
2323
2324 let (signing_keys, _) = psbt.sign(&key_map, &secp).unwrap_err();
2325
2326 assert_eq!(signing_keys.len(), 1);
2327 assert_eq!(signing_keys[&0], SigningKeys::Ecdsa(vec![pk]));
2328 }
2329}