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