1use std::collections::BTreeSet;
24
25use amplify::num::u5;
26use amplify::{ByteArray, Bytes20, Bytes32};
27use derive::{
28 Bip340Sig, ByteStr, ControlBlock, InternalPk, KeyOrigin, LeafScript, LegacyPk, LegacySig,
29 LockHeight, LockTime, LockTimestamp, Outpoint, RedeemScript, Sats, ScriptCode, ScriptPubkey,
30 SeqNo, SigScript, SighashType, TapDerivation, TapLeafHash, TapNodeHash, TapTree, Terminal, Tx,
31 TxIn, TxOut, TxVer, Txid, VarIntArray, Vout, Witness, WitnessScript, XOnlyPk, XkeyOrigin, Xpub,
32};
33use descriptors::{Descriptor, LegacyKeySig, TaprootKeySig};
34use indexmap::IndexMap;
35
36pub use self::display_from_str::PsbtParseError;
37use crate::{KeyData, PropKey, PsbtError, PsbtVer, ValueData};
38
39#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
40#[display("PSBT can't be modified")]
41pub struct Unmodifiable;
42
43#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
44#[display(
45 "can't extract signed transaction from PSBT since it still contains {0} non-finalized inputs"
46)]
47pub struct UnfinalizedInputs(pub usize);
48
49#[derive(Copy, Clone, Eq, PartialEq, Debug)]
50pub struct Prevout {
51 pub txid: Txid,
52 pub vout: Vout,
53 pub value: Sats,
54}
55
56impl Prevout {
57 pub fn new(outpoint: Outpoint, value: Sats) -> Self {
58 Prevout {
59 txid: outpoint.txid,
60 vout: outpoint.vout,
61 value,
62 }
63 }
64
65 pub fn outpoint(&self) -> Outpoint { Outpoint::new(self.txid, self.vout) }
66}
67
68#[derive(Clone, Eq, PartialEq, Hash, Debug)]
79#[cfg_attr(
80 feature = "strict_encoding",
81 derive(StrictType, StrictDumb, StrictEncode, StrictDecode),
82 strict_type(lib = crate::LIB_NAME_PSBT)
83)]
84#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
85pub struct UnsignedTx {
86 pub version: TxVer,
87 pub inputs: VarIntArray<UnsignedTxIn>,
88 pub outputs: VarIntArray<TxOut>,
89 pub lock_time: LockTime,
90}
91
92impl From<Tx> for UnsignedTx {
93 #[inline]
94 fn from(tx: Tx) -> UnsignedTx { UnsignedTx::with_sigs_removed(tx) }
95}
96
97impl From<UnsignedTx> for Tx {
98 #[inline]
99 fn from(unsigned_tx: UnsignedTx) -> Tx {
100 Tx {
101 version: unsigned_tx.version,
102 inputs: VarIntArray::from_checked(
103 unsigned_tx.inputs.into_iter().map(TxIn::from).collect(),
104 ),
105 outputs: unsigned_tx.outputs,
106 lock_time: unsigned_tx.lock_time,
107 }
108 }
109}
110
111impl UnsignedTx {
112 #[inline]
113 pub fn with_sigs_removed(tx: Tx) -> UnsignedTx {
114 UnsignedTx {
115 version: tx.version,
116 inputs: VarIntArray::from_checked(
117 tx.inputs.into_iter().map(UnsignedTxIn::with_sigs_removed).collect(),
118 ),
119 outputs: tx.outputs,
120 lock_time: tx.lock_time,
121 }
122 }
123
124 pub fn txid(&self) -> Txid { Tx::from(self.clone()).txid() }
125}
126
127#[derive(Clone, Eq, PartialEq, Hash, Debug)]
128#[cfg_attr(
129 feature = "strict_encoding",
130 derive(StrictType, StrictDumb, StrictEncode, StrictDecode),
131 strict_type(lib = crate::LIB_NAME_PSBT)
132)]
133#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
134pub struct UnsignedTxIn {
135 pub prev_output: Outpoint,
136 pub sequence: SeqNo,
137}
138
139impl From<TxIn> for UnsignedTxIn {
140 #[inline]
141 fn from(txin: TxIn) -> UnsignedTxIn { UnsignedTxIn::with_sigs_removed(txin) }
142}
143
144impl From<UnsignedTxIn> for TxIn {
145 #[inline]
146 fn from(unsigned_txin: UnsignedTxIn) -> TxIn {
147 TxIn {
148 prev_output: unsigned_txin.prev_output,
149 sig_script: none!(),
150 sequence: unsigned_txin.sequence,
151 witness: empty!(),
152 }
153 }
154}
155
156impl UnsignedTxIn {
157 #[inline]
158 pub fn with_sigs_removed(txin: TxIn) -> UnsignedTxIn {
159 UnsignedTxIn {
160 prev_output: txin.prev_output,
161 sequence: txin.sequence,
162 }
163 }
164}
165
166#[derive(Clone, Eq, PartialEq, Debug)]
167#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
168pub struct Psbt {
172 pub version: PsbtVer,
174
175 pub tx_version: TxVer,
177
178 pub fallback_locktime: Option<LockTime>,
180
181 pub(crate) inputs: Vec<Input>,
183
184 pub(crate) outputs: Vec<Output>,
186
187 pub xpubs: IndexMap<Xpub, XkeyOrigin>,
190
191 pub(crate) tx_modifiable: Option<ModifiableFlags>,
193
194 pub proprietary: IndexMap<PropKey, ValueData>,
196
197 pub unknown: IndexMap<u8, IndexMap<KeyData, ValueData>>,
199}
200
201impl Default for Psbt {
202 fn default() -> Self { Psbt::create(PsbtVer::V2) }
203}
204
205impl Psbt {
206 pub fn create(version: PsbtVer) -> Psbt {
207 Psbt {
208 version,
209 tx_version: TxVer::V2,
210 fallback_locktime: None,
211 inputs: vec![],
212 outputs: vec![],
213 xpubs: none!(),
214 tx_modifiable: Some(ModifiableFlags::modifiable()),
215 proprietary: none!(),
216 unknown: none!(),
217 }
218 }
219
220 pub fn from_tx(tx: impl Into<UnsignedTx>) -> Self {
221 let unsigned_tx = tx.into();
222 let mut psbt = Psbt::create(PsbtVer::V0);
223 psbt.reset_from_unsigned_tx(unsigned_tx);
224 psbt
225 }
226
227 pub(crate) fn reset_from_unsigned_tx(&mut self, unsigned_tx: UnsignedTx) {
228 self.version = PsbtVer::V0;
229 self.tx_version = unsigned_tx.version;
230 self.fallback_locktime = Some(unsigned_tx.lock_time);
231 self.inputs =
232 unsigned_tx.inputs.into_iter().enumerate().map(Input::from_unsigned_txin).collect();
233 self.outputs =
234 unsigned_tx.outputs.into_iter().enumerate().map(Output::from_txout).collect();
235 }
236
237 pub(crate) fn reset_inputs(&mut self, input_count: usize) {
238 self.inputs = (0..input_count).map(Input::new).collect();
239 }
240
241 pub(crate) fn reset_outputs(&mut self, output_count: usize) {
242 self.outputs = (0..output_count).map(Output::new).collect();
243 }
244
245 pub fn to_unsigned_tx(&self) -> UnsignedTx {
246 UnsignedTx {
247 version: self.tx_version,
248 inputs: VarIntArray::from_iter_checked(self.inputs().map(Input::to_unsigned_txin)),
249 outputs: VarIntArray::from_iter_checked(self.outputs().map(Output::to_txout)),
250 lock_time: self.lock_time(),
251 }
252 }
253
254 pub fn txid(&self) -> Txid { self.to_unsigned_tx().txid() }
255
256 pub fn input(&self, index: usize) -> Option<&Input> { self.inputs.get(index) }
257
258 pub fn input_mut(&mut self, index: usize) -> Option<&mut Input> { self.inputs.get_mut(index) }
259
260 pub fn inputs(&self) -> impl Iterator<Item = &Input> { self.inputs.iter() }
261
262 pub fn inputs_mut(&mut self) -> impl Iterator<Item = &mut Input> { self.inputs.iter_mut() }
263
264 pub fn output(&self, index: usize) -> Option<&Output> { self.outputs.get(index) }
265
266 pub fn output_mut(&mut self, index: usize) -> Option<&mut Output> {
267 self.outputs.get_mut(index)
268 }
269
270 pub fn outputs(&self) -> impl Iterator<Item = &Output> { self.outputs.iter() }
271
272 pub fn outputs_mut(&mut self) -> impl Iterator<Item = &mut Output> { self.outputs.iter_mut() }
273
274 pub fn lock_time(&self) -> LockTime {
275 self.fallback_locktime.unwrap_or(LockTime::ZERO)
277 }
278
279 #[inline]
280 pub fn input_sum(&self) -> Sats { self.inputs().map(Input::value).sum() }
281
282 #[inline]
283 pub fn output_sum(&self) -> Sats { self.outputs().map(Output::value).sum() }
284
285 #[inline]
286 pub fn fee(&self) -> Option<Sats> { self.input_sum().checked_sub(self.output_sum()) }
287
288 pub fn xpubs(&self) -> impl Iterator<Item = (&Xpub, &XkeyOrigin)> { self.xpubs.iter() }
289
290 pub fn is_modifiable(&self) -> bool {
291 self.tx_modifiable.as_ref().map(ModifiableFlags::is_modifiable).unwrap_or_default()
292 }
293
294 pub fn are_inputs_modifiable(&self) -> bool {
295 self.tx_modifiable
296 .as_ref()
297 .map(|flags| flags.inputs_modifiable && !flags.sighash_single)
298 .unwrap_or_default()
299 }
300
301 pub fn are_outputs_modifiable(&self) -> bool {
302 self.tx_modifiable
303 .as_ref()
304 .map(|flags| flags.inputs_modifiable && !flags.sighash_single)
305 .unwrap_or_default()
306 }
307
308 pub fn append_input<K, D: Descriptor<K>>(
312 &mut self,
313 prevout: Prevout,
314 descriptor: &D,
315 terminal: Terminal,
316 script_pubkey: ScriptPubkey,
317 sequence: SeqNo,
318 ) -> Result<&mut Input, Unmodifiable> {
319 if !self.are_inputs_modifiable() {
320 return Err(Unmodifiable);
321 }
322
323 let script = descriptor
324 .derive(terminal.keychain, terminal.index)
325 .find(|script| script.to_script_pubkey() == script_pubkey)
326 .expect("unable to generate input matching prevout");
327 let input = Input {
328 index: self.inputs.len(),
329 previous_outpoint: prevout.outpoint(),
330 sequence_number: Some(sequence),
331 required_time_lock: None,
332 required_height_lock: None,
333 non_witness_tx: None,
334 witness_utxo: Some(TxOut::new(script.to_script_pubkey(), prevout.value)),
335 partial_sigs: none!(),
336 sighash_type: None,
337 redeem_script: script.to_redeem_script(),
338 witness_script: script.to_witness_script(),
339 bip32_derivation: descriptor.legacy_keyset(terminal),
340 final_script_sig: None,
342 final_witness: None,
343 proof_of_reserves: None,
344 ripemd160: none!(),
345 sha256: none!(),
346 hash160: none!(),
347 hash256: none!(),
348 tap_key_sig: None,
349 tap_script_sig: none!(),
350 tap_leaf_script: script.to_leaf_scripts(),
351 tap_bip32_derivation: descriptor.xonly_keyset(terminal),
352 tap_internal_key: script.to_internal_pk(),
353 tap_merkle_root: script.to_tap_root(),
354 proprietary: none!(),
355 unknown: none!(),
356 };
357 self.inputs.push(input);
358 Ok(self.inputs.last_mut().expect("just inserted"))
359 }
360
361 pub fn append_input_expect<K, D: Descriptor<K>>(
362 &mut self,
363 prevout: Prevout,
364 descriptor: &D,
365 terminal: Terminal,
366 script_pubkey: ScriptPubkey,
367 sequence: SeqNo,
368 ) -> &mut Input {
369 self.append_input(prevout, descriptor, terminal, script_pubkey, sequence)
370 .expect("PSBT inputs are expected to be modifiable")
371 }
372
373 pub fn insert_output(
374 &mut self,
375 pos: usize,
376 script_pubkey: ScriptPubkey,
377 value: Sats,
378 ) -> Result<&mut Output, Unmodifiable> {
379 if !self.are_outputs_modifiable() {
380 return Err(Unmodifiable);
381 }
382
383 let output = Output {
384 amount: value,
385 script: script_pubkey,
386 ..Output::new(pos)
387 };
388 self.outputs.insert(pos, output);
389 for no in pos..self.outputs.len() {
390 self.outputs[no].index = no;
391 }
392 Ok(&mut self.outputs[pos])
393 }
394
395 pub fn append_output(
396 &mut self,
397 script_pubkey: ScriptPubkey,
398 value: Sats,
399 ) -> Result<&mut Output, Unmodifiable> {
400 self.insert_output(self.outputs.len(), script_pubkey, value)
401 }
402
403 pub fn append_output_expect(
404 &mut self,
405 script_pubkey: ScriptPubkey,
406 value: Sats,
407 ) -> &mut Output {
408 self.append_output(script_pubkey, value)
409 .expect("PSBT outputs are expected to be modifiable")
410 }
411
412 pub fn append_change<K, D: Descriptor<K>>(
416 &mut self,
417 descriptor: &D,
418 change_terminal: Terminal,
419 value: Sats,
420 ) -> Result<&mut Output, Unmodifiable> {
421 if !self.are_outputs_modifiable() {
422 return Err(Unmodifiable);
423 }
424
425 let script = descriptor
426 .derive(change_terminal.keychain, change_terminal.index)
427 .next()
428 .expect("unable to generate change script");
429 let output = Output {
430 index: self.outputs.len(),
431 amount: value,
432 script: script.to_script_pubkey(),
433 redeem_script: script.to_redeem_script(),
434 witness_script: script.to_witness_script(),
435 bip32_derivation: descriptor.legacy_keyset(change_terminal),
436 tap_internal_key: script.to_internal_pk(),
437 tap_tree: script.to_tap_tree(),
438 tap_bip32_derivation: descriptor.xonly_keyset(change_terminal),
439 proprietary: none!(),
440 unknown: none!(),
441 };
442 self.outputs.push(output);
443 Ok(self.outputs.last_mut().expect("just inserted"))
444 }
445
446 pub fn append_change_expect<K, D: Descriptor<K>>(
447 &mut self,
448 descriptor: &D,
449 change_terminal: Terminal,
450 value: Sats,
451 ) -> &mut Output {
452 self.append_change(descriptor, change_terminal, value)
453 .expect("PSBT outputs are expected to be modifiable")
454 }
455
456 pub fn sort_outputs_by<K: Ord>(
457 &mut self,
458 f: impl FnMut(&Output) -> K,
459 ) -> Result<(), Unmodifiable> {
460 if !self.are_outputs_modifiable() {
461 return Err(Unmodifiable);
462 }
463
464 self.outputs.sort_by_key(f);
465 for (index, output) in self.outputs.iter_mut().enumerate() {
466 output.index = index;
467 }
468
469 Ok(())
470 }
471
472 pub fn complete_construction(&mut self) {
473 self.tx_modifiable = Some(ModifiableFlags::unmodifiable())
475 }
476
477 pub fn is_finalized(&self) -> bool { self.inputs.iter().all(Input::is_finalized) }
478
479 pub fn finalize<D: Descriptor<K, V>, K, V>(&mut self, descriptor: &D) -> usize {
480 self.inputs.iter_mut().map(|input| input.finalize(descriptor) as usize).sum()
481 }
482
483 pub fn extract(&self) -> Result<Tx, UnfinalizedInputs> {
484 let finalized = self.inputs.iter().filter(|i| i.is_finalized()).count();
485 let unfinalized = self.inputs.len() - finalized;
486 if unfinalized > 0 {
487 return Err(UnfinalizedInputs(unfinalized));
488 }
489
490 Ok(Tx {
491 version: self.tx_version,
492 inputs: VarIntArray::from_iter_checked(self.inputs.iter().map(Input::to_signed_txin)),
493 outputs: VarIntArray::from_iter_checked(self.outputs.iter().map(Output::to_txout)),
494 lock_time: self.lock_time(),
495 })
496 }
497}
498
499mod display_from_str {
500 use std::fmt::{self, Display, Formatter, LowerHex};
501 use std::str::FromStr;
502
503 use amplify::hex::{self, FromHex, ToHex};
504 use base64::display::Base64Display;
505 use base64::prelude::BASE64_STANDARD;
506 use base64::Engine;
507
508 use super::*;
509
510 #[derive(Clone, Debug, Display, Error, From)]
511 #[display(inner)]
512 pub enum PsbtParseError {
513 #[from]
514 Hex(hex::Error),
515
516 #[from]
517 Base64(base64::DecodeError),
518
519 #[from]
520 Psbt(PsbtError),
521 }
522
523 impl Psbt {
524 pub fn from_base64(s: &str) -> Result<Psbt, PsbtParseError> {
525 Psbt::deserialize(BASE64_STANDARD.decode(s)?).map_err(PsbtParseError::from)
526 }
527
528 pub fn from_base16(s: &str) -> Result<Psbt, PsbtParseError> {
529 let data = Vec::<u8>::from_hex(s)?;
530 Psbt::deserialize(data).map_err(PsbtParseError::from)
531 }
532
533 pub fn to_base64(&self) -> String { self.to_base64_ver(self.version) }
534
535 pub fn to_base64_ver(&self, version: PsbtVer) -> String {
536 BASE64_STANDARD.encode(self.serialize(version))
537 }
538
539 pub fn to_base16(&self) -> String { self.to_base16_ver(self.version) }
540
541 pub fn to_base16_ver(&self, version: PsbtVer) -> String { self.serialize(version).to_hex() }
542 }
543
544 impl FromStr for Psbt {
546 type Err = PsbtParseError;
547
548 #[inline]
549 fn from_str(s: &str) -> Result<Self, Self::Err> {
550 Self::from_base16(s).or_else(|_| Self::from_base64(s))
551 }
552 }
553
554 impl Display for Psbt {
564 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
565 let ver = match (f.width(), f.sign_aware_zero_pad()) {
566 (None, true) => PsbtVer::V0,
567 (Some(1), _) => PsbtVer::V0,
568 (Some(ver), _) => PsbtVer::try_from(ver).map_err(|_| fmt::Error)?,
569 _ => self.version,
570 };
571 write!(f, "{}", Base64Display::new(&self.serialize(ver), &BASE64_STANDARD))
572 }
573 }
574
575 impl LowerHex for Psbt {
585 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
586 let ver = match (f.width(), f.sign_aware_zero_pad()) {
587 (None, true) => PsbtVer::V0,
588 (Some(1), _) => PsbtVer::V0,
589 (Some(ver), _) => PsbtVer::try_from(ver).map_err(|_| fmt::Error)?,
590 _ => self.version,
591 };
592 f.write_str(&self.to_base16_ver(ver))
593 }
594 }
595}
596
597#[derive(Clone, Eq, PartialEq, Debug)]
616#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
617pub struct Input {
618 #[cfg_attr(feature = "serde", serde(skip))]
620 pub(crate) index: usize,
621
622 pub previous_outpoint: Outpoint,
624
625 pub sequence_number: Option<SeqNo>,
628
629 pub required_time_lock: Option<LockTimestamp>,
633
634 pub required_height_lock: Option<LockHeight>,
638
639 pub non_witness_tx: Option<Tx>,
643
644 pub witness_utxo: Option<TxOut>,
647
648 pub partial_sigs: IndexMap<LegacyPk, LegacySig>,
652
653 pub sighash_type: Option<SighashType>,
656
657 pub redeem_script: Option<RedeemScript>,
659
660 pub witness_script: Option<WitnessScript>,
662
663 pub bip32_derivation: IndexMap<LegacyPk, KeyOrigin>,
666
667 pub final_script_sig: Option<SigScript>,
670
671 pub final_witness: Option<Witness>,
674
675 pub proof_of_reserves: Option<String>,
678
679 pub ripemd160: IndexMap<Bytes20, ByteStr>,
682
683 pub sha256: IndexMap<Bytes32, ByteStr>,
686
687 pub hash160: IndexMap<Bytes20, ByteStr>,
690
691 pub hash256: IndexMap<Bytes32, ByteStr>,
694
695 pub tap_key_sig: Option<Bip340Sig>,
698
699 pub tap_script_sig: IndexMap<(XOnlyPk, TapLeafHash), Bip340Sig>,
702
703 pub tap_leaf_script: IndexMap<ControlBlock, LeafScript>,
708
709 pub tap_bip32_derivation: IndexMap<XOnlyPk, TapDerivation>,
717
718 pub tap_internal_key: Option<InternalPk>,
721
722 pub tap_merkle_root: Option<TapNodeHash>,
725
726 pub proprietary: IndexMap<PropKey, ValueData>,
728
729 pub unknown: IndexMap<u8, IndexMap<KeyData, ValueData>>,
731}
732
733impl Input {
734 pub fn new(index: usize) -> Input {
735 Input {
736 index,
737 previous_outpoint: Outpoint::coinbase(),
738 sequence_number: None,
739 required_time_lock: None,
740 required_height_lock: None,
741 non_witness_tx: None,
742 witness_utxo: None,
743 partial_sigs: none!(),
744 sighash_type: None,
745 redeem_script: None,
746 witness_script: None,
747 bip32_derivation: none!(),
748 final_script_sig: None,
749 final_witness: None,
750 proof_of_reserves: None,
751 ripemd160: none!(),
752 sha256: none!(),
753 hash160: none!(),
754 hash256: none!(),
755 tap_key_sig: None,
756 tap_script_sig: none!(),
757 tap_leaf_script: none!(),
758 tap_bip32_derivation: none!(),
759 tap_internal_key: None,
760 tap_merkle_root: None,
761 proprietary: none!(),
762 unknown: none!(),
763 }
764 }
765
766 pub fn with_txin(txin: impl Into<UnsignedTxIn>, index: usize) -> Input {
767 let txin = txin.into();
768 let mut input = Input::new(index);
769 input.previous_outpoint = txin.prev_output;
770 input.sequence_number = Some(txin.sequence);
771 input
772 }
773
774 pub fn from_unsigned_txin((index, txin): (usize, UnsignedTxIn)) -> Input {
775 Input::with_txin(txin, index)
776 }
777
778 fn to_signed_txin(&self) -> TxIn {
779 TxIn {
780 prev_output: self.previous_outpoint,
781 sig_script: self.final_script_sig.clone().expect("non-finalized input"),
783 sequence: self.sequence_number.unwrap_or(SeqNo::from_consensus_u32(0)),
784 witness: self.final_witness.clone().expect("non-finalized input"),
785 }
786 }
787
788 pub fn to_unsigned_txin(&self) -> UnsignedTxIn {
789 UnsignedTxIn {
790 prev_output: self.previous_outpoint,
791 sequence: self.sequence_number.unwrap_or(SeqNo::from_consensus_u32(0)),
793 }
794 }
795
796 #[inline]
797 pub fn prev_txout(&self) -> &TxOut {
798 match (&self.witness_utxo, None::<&Tx>) {
800 (Some(txout), _) => txout,
801 (None, Some(tx)) => &tx.outputs[self.index],
802 (None, None) => unreachable!(
803 "PSBT input must contain either witness UTXO or a non-witness transaction"
804 ),
805 }
806 }
807
808 #[inline]
809 pub fn prevout(&self) -> Prevout {
810 Prevout {
811 txid: self.previous_outpoint.txid,
812 vout: self.previous_outpoint.vout,
813 value: self.value(),
814 }
815 }
816
817 #[inline]
818 pub fn value(&self) -> Sats { self.prev_txout().value }
819
820 #[inline]
821 pub fn index(&self) -> usize { self.index }
822
823 pub fn script_code(&self) -> Option<ScriptCode> {
831 let spk = &self.prev_txout().script_pubkey;
832 Some(match (&self.witness_script, &self.redeem_script) {
833 (None, None) if spk.is_p2wpkh() => ScriptCode::with_p2wpkh(spk),
834 (Some(witness_script), None) if spk.is_p2wsh() => {
835 ScriptCode::with_p2wsh(witness_script)
836 }
837 (_, Some(redeem_script)) if redeem_script.is_p2sh_wpkh() => {
838 ScriptCode::with_p2sh_wpkh(spk)
839 }
840 (Some(witness_script), Some(redeem_script)) if redeem_script.is_p2sh_wsh() => {
841 ScriptCode::with_p2sh_wsh(witness_script)
842 }
843 _ => return None,
844 })
845 }
846
847 #[inline]
848 pub fn is_segwit_v0(&self) -> bool {
849 self.witness_script.is_some()
850 || self.witness_utxo.is_some()
851 || self.prev_txout().script_pubkey.is_p2wpkh()
852 || self.prev_txout().script_pubkey.is_p2wsh()
853 }
854
855 #[must_use]
856 pub fn is_bip340(&self) -> bool { self.tap_internal_key.is_some() }
857
858 #[must_use]
859 pub fn is_finalized(&self) -> bool {
860 self.final_witness.is_some() || self.final_script_sig.is_some()
861 }
862
863 pub fn finalize<D: Descriptor<K, V>, K, V>(&mut self, descriptor: &D) -> bool {
864 if self.is_finalized() {
865 return false;
866 }
867
868 let satisfaction = if descriptor.is_taproot() {
869 self.tap_internal_key
870 .map(XOnlyPk::from)
871 .and_then(|pk| self.tap_bip32_derivation.get(&pk).map(|d| (&d.origin, pk)))
872 .zip(self.tap_key_sig)
873 .and_then(|((origin, pk), sig)| {
874 descriptor.taproot_witness(map! { origin => TaprootKeySig::new(pk, sig) })
876 })
877 .or_else(|| {
878 self.tap_leaf_script
880 .keys()
881 .filter_map(|cb| cb.merkle_branch.first())
882 .copied()
883 .map(|hash| TapLeafHash::from_byte_array(hash.to_byte_array()))
884 .find_map(|leafhash| {
885 let keysigs = self
886 .tap_script_sig
887 .iter()
888 .filter(|((_, lh), _)| *lh == leafhash)
889 .map(|((pk, _), sig)| TaprootKeySig::new(*pk, *sig))
890 .filter_map(|ks| {
891 self.tap_bip32_derivation
892 .get(&ks.key)
893 .filter(|d| d.leaf_hashes.contains(&leafhash))
894 .map(|d| (&d.origin, ks))
895 })
896 .collect();
897 descriptor.taproot_witness(keysigs)
898 })
899 })
900 .map(|witness| (empty!(), witness))
901 } else {
902 let keysigs = self
903 .partial_sigs
904 .iter()
905 .map(|(pk, sig)| LegacyKeySig::new(*pk, *sig))
906 .filter_map(|ks| self.bip32_derivation.get(&ks.key).map(|origin| (origin, ks)))
907 .collect();
908 descriptor.legacy_witness(keysigs)
909 };
910 let Some((sig_script, witness)) = satisfaction else {
911 return false;
912 };
913
914 self.final_script_sig = Some(sig_script);
915 self.final_witness = Some(witness);
916 self.partial_sigs.clear(); self.sighash_type = None; self.redeem_script = None; self.witness_script = None; self.bip32_derivation.clear(); self.ripemd160.clear(); self.sha256.clear(); self.hash160.clear(); self.hash256.clear(); self.tap_key_sig = None; self.tap_script_sig.clear(); self.tap_leaf_script.clear(); self.tap_bip32_derivation.clear(); self.tap_internal_key = None; self.tap_merkle_root = None; true
937 }
938}
939
940#[derive(Clone, Eq, PartialEq, Debug)]
941#[cfg_attr(feature = "serde", derive(Serialize), serde(rename_all = "camelCase"))]
942pub struct Output {
943 #[cfg_attr(feature = "serde", serde(skip))]
945 pub(crate) index: usize,
946
947 pub amount: Sats,
949
950 pub script: ScriptPubkey,
952
953 pub redeem_script: Option<RedeemScript>,
955
956 pub witness_script: Option<WitnessScript>,
958
959 pub bip32_derivation: IndexMap<LegacyPk, KeyOrigin>,
962
963 pub tap_internal_key: Option<InternalPk>,
966
967 pub tap_tree: Option<TapTree>,
974
975 pub tap_bip32_derivation: IndexMap<XOnlyPk, TapDerivation>,
983
984 pub proprietary: IndexMap<PropKey, ValueData>,
986
987 pub unknown: IndexMap<u8, IndexMap<KeyData, ValueData>>,
989}
990
991impl Output {
992 pub fn new(index: usize) -> Self {
993 Output {
994 index,
995 amount: Sats::ZERO,
996 script: ScriptPubkey::new(),
997 redeem_script: None,
998 witness_script: None,
999 bip32_derivation: none!(),
1000 tap_internal_key: None,
1001 tap_tree: None,
1002 tap_bip32_derivation: none!(),
1003 proprietary: none!(),
1004 unknown: none!(),
1005 }
1006 }
1007
1008 pub fn with_txout(txout: TxOut, index: usize) -> Self {
1009 let mut output = Output::new(index);
1010 output.amount = txout.value;
1011 output.script = txout.script_pubkey;
1012 output
1013 }
1014
1015 pub fn from_txout((index, txout): (usize, TxOut)) -> Self { Output::with_txout(txout, index) }
1016
1017 pub fn to_txout(&self) -> TxOut {
1018 TxOut {
1019 value: self.amount,
1020 script_pubkey: self.script.clone(),
1021 }
1022 }
1023
1024 #[inline]
1025 pub fn value(&self) -> Sats { self.amount }
1026
1027 #[inline]
1028 pub fn index(&self) -> usize { self.index }
1029
1030 #[inline]
1031 pub fn vout(&self) -> Vout { Vout::from_u32(self.index as u32) }
1032
1033 pub fn terminal_derivation(&self) -> Option<Terminal> {
1034 if self.bip32_derivation.is_empty() && self.tap_bip32_derivation.is_empty() {
1035 return None;
1036 }
1037 let terminal = self
1038 .bip32_derivation
1039 .values()
1040 .flat_map(|origin| origin.derivation().terminal())
1041 .chain(
1042 self.tap_bip32_derivation
1043 .values()
1044 .flat_map(|derivation| derivation.origin.derivation().terminal()),
1045 )
1046 .collect::<BTreeSet<_>>();
1047 if terminal.len() != 1 {
1048 return None;
1049 }
1050 terminal.first().copied()
1051 }
1052}
1053
1054#[derive(Clone, Eq, PartialEq, Hash, Debug)]
1055#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
1056pub struct ModifiableFlags {
1057 pub inputs_modifiable: bool,
1058 pub outputs_modifiable: bool,
1059 pub sighash_single: bool,
1060 pub unknown: u5,
1061}
1062
1063impl ModifiableFlags {
1064 pub const fn unmodifiable() -> Self {
1065 ModifiableFlags {
1066 inputs_modifiable: false,
1067 outputs_modifiable: false,
1068 sighash_single: false,
1069 unknown: u5::ZERO,
1070 }
1071 }
1072
1073 pub const fn modifiable() -> Self {
1074 ModifiableFlags {
1075 inputs_modifiable: true,
1076 outputs_modifiable: true,
1077 sighash_single: false,
1078 unknown: u5::ZERO,
1079 }
1080 }
1081
1082 pub const fn modifiable_sighash_single() -> Self {
1083 ModifiableFlags {
1084 inputs_modifiable: true,
1085 outputs_modifiable: true,
1086 sighash_single: true,
1087 unknown: u5::ZERO,
1088 }
1089 }
1090
1091 pub fn from_standard_u8(val: u8) -> Self {
1092 let inputs_modifiable = val & 0x01 == 0x01;
1093 let outputs_modifiable = val & 0x02 == 0x02;
1094 let sighash_single = val & 0x04 == 0x04;
1095 let unknown = u5::with(val >> 3);
1096 Self {
1097 inputs_modifiable,
1098 outputs_modifiable,
1099 sighash_single,
1100 unknown,
1101 }
1102 }
1103
1104 pub const fn to_standard_u8(&self) -> u8 {
1105 (self.inputs_modifiable as u8)
1106 | ((self.outputs_modifiable as u8) << 1)
1107 | ((self.sighash_single as u8) << 2)
1108 }
1109
1110 pub const fn is_modifiable(&self) -> bool {
1111 self.inputs_modifiable | self.outputs_modifiable | self.sighash_single
1112 }
1113}
1114
1115#[cfg(test)]
1116mod tests {
1117 use super::*;
1118
1119 #[test]
1120 fn psbt_formats() {
1121 let v0_psbt = Psbt {
1122 version: PsbtVer::V0,
1123 tx_version: TxVer::default(),
1124 fallback_locktime: None,
1125 inputs: Vec::new(),
1126 outputs: Vec::new(),
1127 xpubs: IndexMap::new(),
1128 tx_modifiable: None,
1129 proprietary: IndexMap::new(),
1130 unknown: IndexMap::new(),
1131 };
1132 let v2_psbt = Psbt {
1133 version: PsbtVer::V2,
1134 tx_version: TxVer::default(),
1135 fallback_locktime: None,
1136 inputs: Vec::new(),
1137 outputs: Vec::new(),
1138 xpubs: IndexMap::new(),
1139 tx_modifiable: None,
1140 proprietary: IndexMap::new(),
1141 unknown: IndexMap::new(),
1142 };
1143
1144 assert_eq!(format!("{v0_psbt}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1145 assert_eq!(format!("{v2_psbt}"), "cHNidP8BAgQCAAAAAQQBAAEFAQAB+wQCAAAAAA==");
1146
1147 assert_eq!(format!("{v0_psbt:#}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1148 assert_eq!(format!("{v2_psbt:#}"), "cHNidP8BAgQCAAAAAQQBAAEFAQAB+wQCAAAAAA==");
1149
1150 assert_eq!(format!("{v0_psbt:x}"), "70736274ff01000a0200000000000000000001fb040000000000");
1151 assert_eq!(
1152 format!("{v2_psbt:x}"),
1153 "70736274ff01020402000000010401000105010001fb040200000000"
1154 );
1155
1156 assert_eq!(format!("{v0_psbt:#x}"), "70736274ff01000a0200000000000000000001fb040000000000");
1157 assert_eq!(
1158 format!("{v2_psbt:#x}"),
1159 "70736274ff01020402000000010401000105010001fb040200000000"
1160 );
1161
1162 assert_eq!(format!("{v2_psbt:00}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1164 assert_eq!(format!("{v2_psbt:01}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1165 assert_eq!(format!("{v0_psbt:02}"), "cHNidP8BAgQCAAAAAQQBAAEFAQAB+wQCAAAAAA==");
1166
1167 assert_eq!(format!("{v2_psbt:0}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1168 assert_eq!(format!("{v2_psbt:1}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1169 assert_eq!(format!("{v0_psbt:2}"), "cHNidP8BAgQCAAAAAQQBAAEFAQAB+wQCAAAAAA==");
1170
1171 assert_eq!(format!("{v2_psbt:#0}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1172 assert_eq!(format!("{v2_psbt:#1}"), "cHNidP8BAAoCAAAAAAAAAAAAAfsEAAAAAAA=");
1173 assert_eq!(format!("{v0_psbt:#2}"), "cHNidP8BAgQCAAAAAQQBAAEFAQAB+wQCAAAAAA==");
1174
1175 let result = std::panic::catch_unwind(|| format!("{v0_psbt:03}"));
1177 assert!(result.is_err(), "Should fail on unsupported psbt version");
1178
1179 let result = std::panic::catch_unwind(|| format!("{v0_psbt:3}"));
1180 assert!(result.is_err(), "Should fail on unsupported psbt version");
1181
1182 let result = std::panic::catch_unwind(|| format!("{v0_psbt:#03}"));
1183 assert!(result.is_err(), "Should fail on unsupported psbt version");
1184
1185 let result = std::panic::catch_unwind(|| format!("{v0_psbt:#3}"));
1186 assert!(result.is_err(), "Should fail on unsupported psbt version");
1187
1188 let result = std::panic::catch_unwind(|| format!("{v0_psbt:#3x}"));
1189 assert!(result.is_err(), "Should fail on unsupported psbt version");
1190
1191 let result = std::panic::catch_unwind(|| format!("{v0_psbt:#03x}"));
1192 assert!(result.is_err(), "Should fail on unsupported psbt version");
1193 }
1194}