1use alloc::collections::BTreeMap;
8use core::fmt;
9
10use bitcoin::hashes::hash160;
11use bitcoin::secp256k1::{Secp256k1, Verification};
12use bitcoin::taproot::LeafVersion;
13use bitcoin::{sighash, Address, Network, Script, ScriptBuf, Txid, Witness, XOnlyPublicKey};
14use miniscript::{
15 interpreter, BareCtx, Descriptor, ExtParams, Legacy, Miniscript, Satisfier, Segwitv0, SigType,
16 Tap, ToPublicKey,
17};
18
19use crate::error::{write_err, FundingUtxoError};
20use crate::prelude::*;
21use crate::v2::map::input::{self, Input};
22use crate::v2::miniscript::satisfy::InputSatisfier;
23use crate::v2::miniscript::InterpreterCheckError;
24use crate::v2::{DetermineLockTimeError, PartialSigsSighashTypeError, Psbt};
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub struct Finalizer(Psbt);
30
31impl Finalizer {
32 pub fn new(psbt: Psbt) -> Result<Self, Error> {
36 for input in psbt.inputs.iter() {
38 let _ = input.funding_utxo()?;
39 }
40 let _ = psbt.determine_lock_time()?;
41 psbt.check_partial_sigs_sighash_type()?;
42
43 Ok(Self(psbt))
44 }
45
46 pub fn id(&self) -> Txid {
48 self.0.id().expect("Finalizer guarantees lock time can be determined")
49 }
50
51 #[must_use = "returns the finalized PSBT without modifying the original"]
57 pub fn finalize<C: Verification>(&self, secp: &Secp256k1<C>) -> Result<Psbt, FinalizeError> {
58 let mut inputs = vec![];
59 for (input_index, input) in self.0.inputs.iter().enumerate() {
60 match self.finalize_input(input) {
61 Ok(input) => inputs.push(input),
62 Err(error) => return Err(FinalizeError::FinalizeInput { input_index, error }),
64 }
65 }
66
67 let finalized =
68 Psbt { global: self.0.global.clone(), inputs, outputs: self.0.outputs.to_vec() };
69
70 finalized.interpreter_check(secp)?;
71 Ok(finalized)
72 }
73
74 fn finalize_input(&self, input: &Input) -> Result<Input, FinalizeInputError> {
76 let allow_mall = true; let (script_sig, witness) = self.final_script_sig_and_witness(input, allow_mall)?;
78
79 Ok(input.finalize(script_sig, witness)?.clone())
80 }
81
82 fn final_script_sig_and_witness(
102 &self,
103 input: &Input,
104 allow_mall: bool,
105 ) -> Result<(ScriptBuf, Witness), InputError> {
106 let (witness, script_sig) = {
107 let spk =
108 &input.funding_utxo().expect("guaranteed by Finalizer invariant").script_pubkey;
109 let sat = InputSatisfier { input };
110
111 if spk.is_p2tr() {
112 let wit = construct_tap_witness(spk, sat, allow_mall)?;
114 (wit, ScriptBuf::new())
115 } else {
116 let desc = self.get_descriptor(input)?;
118
119 if !allow_mall {
121 desc.get_satisfaction(sat)?
122 } else {
123 desc.get_satisfaction_mall(sat)?
124 }
125 }
126 };
127
128 let witness = Witness::from_slice(&witness);
129 Ok((script_sig, witness))
130 }
131
132 fn get_descriptor(&self, input: &Input) -> Result<Descriptor<bitcoin::PublicKey>, InputError> {
139 let mut map: BTreeMap<hash160::Hash, bitcoin::PublicKey> = BTreeMap::new();
140
141 let psbt_inputs = &self.0.inputs;
143 for psbt_input in psbt_inputs {
144 let public_keys = psbt_input.bip32_derivations.keys();
146 for key in public_keys {
147 let bitcoin_key = *key;
148 let hash = bitcoin_key.pubkey_hash().to_raw_hash();
149 map.insert(hash, bitcoin_key);
150 }
151 }
152
153 let script_pubkey = &input.funding_utxo().expect("guaranteed by Finalizer").script_pubkey;
155 if script_pubkey.is_p2pk() {
157 let script_pubkey_len = script_pubkey.len();
158 let pk_bytes = &script_pubkey.to_bytes();
159 match bitcoin::PublicKey::from_slice(&pk_bytes[1..script_pubkey_len - 1]) {
160 Ok(pk) => Ok(Descriptor::new_pk(pk)),
161 Err(e) => Err(InputError::from(e)),
162 }
163 } else if script_pubkey.is_p2pkh() {
164 let partial_sig_contains_pk = input.partial_sigs.iter().find(|&(&pk, _sig)| {
166 let addr = Address::p2pkh(pk, Network::Bitcoin);
173 *script_pubkey == addr.script_pubkey()
174 });
175 match partial_sig_contains_pk {
176 Some((pk, _sig)) => Descriptor::new_pkh(*pk).map_err(InputError::from),
177 None => Err(InputError::MissingPubkey),
178 }
179 } else if script_pubkey.is_p2wpkh() {
180 let partial_sig_contains_pk = input.partial_sigs.iter().find(|&(&pk, _sig)| {
182 match bitcoin::key::CompressedPublicKey::try_from(pk) {
183 Ok(compressed) => {
184 let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin);
187 *script_pubkey == addr.script_pubkey()
188 }
189 Err(_) => false,
190 }
191 });
192 match partial_sig_contains_pk {
193 Some((pk, _sig)) => Ok(Descriptor::new_wpkh(*pk)?),
194 None => Err(InputError::MissingPubkey),
195 }
196 } else if script_pubkey.is_p2wsh() {
197 if input.redeem_script.is_some() {
199 return Err(InputError::NonEmptyRedeemScript);
200 }
201 if let Some(ref witness_script) = input.witness_script {
202 if witness_script.to_p2wsh() != *script_pubkey {
203 return Err(InputError::InvalidWitnessScript {
204 witness_script: witness_script.clone(),
205 p2wsh_expected: script_pubkey.clone(),
206 });
207 }
208 let ms = Miniscript::<bitcoin::PublicKey, Segwitv0>::parse_with_ext(
209 witness_script,
210 &ExtParams::allow_all(),
211 )?;
212 Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&map))?)
213 } else {
214 Err(InputError::MissingWitnessScript)
215 }
216 } else if script_pubkey.is_p2sh() {
217 match input.redeem_script {
218 None => Err(InputError::MissingRedeemScript),
219 Some(ref redeem_script) => {
220 if redeem_script.to_p2sh() != *script_pubkey {
221 return Err(InputError::InvalidRedeemScript {
222 redeem: redeem_script.clone(),
223 p2sh_expected: script_pubkey.clone(),
224 });
225 }
226 if redeem_script.is_p2wsh() {
227 if let Some(ref witness_script) = input.witness_script {
229 if witness_script.to_p2wsh() != *redeem_script {
230 return Err(InputError::InvalidWitnessScript {
231 witness_script: witness_script.clone(),
232 p2wsh_expected: redeem_script.clone(),
233 });
234 }
235 let ms = Miniscript::<bitcoin::PublicKey, Segwitv0>::parse_with_ext(
236 witness_script,
237 &ExtParams::allow_all(),
238 )?;
239 Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&map))?)
240 } else {
241 Err(InputError::MissingWitnessScript)
242 }
243 } else if redeem_script.is_p2wpkh() {
244 let partial_sig_contains_pk =
246 input.partial_sigs.iter().find(|&(&pk, _sig)| {
247 match bitcoin::key::CompressedPublicKey::try_from(pk) {
248 Ok(compressed) => {
249 let addr = bitcoin::Address::p2wpkh(
250 &compressed,
251 bitcoin::Network::Bitcoin,
252 );
253 *redeem_script == addr.script_pubkey()
254 }
255 Err(_) => false,
256 }
257 });
258 match partial_sig_contains_pk {
259 Some((pk, _sig)) => Ok(Descriptor::new_sh_wpkh(*pk)?),
260 None => Err(InputError::MissingPubkey),
261 }
262 } else {
263 if input.witness_script.is_some() {
265 return Err(InputError::NonEmptyWitnessScript);
266 }
267 if let Some(ref redeem_script) = input.redeem_script {
268 let ms = Miniscript::<bitcoin::PublicKey, Legacy>::parse_with_ext(
269 redeem_script,
270 &ExtParams::allow_all(),
271 )?;
272 Ok(Descriptor::new_sh(ms)?)
273 } else {
274 Err(InputError::MissingWitnessScript)
275 }
276 }
277 }
278 }
279 } else {
280 if input.witness_script.is_some() {
282 return Err(InputError::NonEmptyWitnessScript);
283 }
284 if input.redeem_script.is_some() {
285 return Err(InputError::NonEmptyRedeemScript);
286 }
287 let ms = Miniscript::<bitcoin::PublicKey, BareCtx>::parse_with_ext(
288 script_pubkey,
289 &ExtParams::allow_all(),
290 )?;
291 Ok(Descriptor::new_bare(ms.substitute_raw_pkh(&map))?)
292 }
293 }
294}
295
296fn construct_tap_witness(
300 spk: &Script,
301 sat: InputSatisfier,
302 allow_mall: bool,
303) -> Result<Vec<Vec<u8>>, InputError> {
304 assert!(spk.is_p2tr());
305 let mut map: BTreeMap<hash160::Hash, XOnlyPublicKey> = BTreeMap::new();
309
310 let public_keys = sat.input.tap_key_origins.keys();
313 for key in public_keys {
314 let bitcoin_key = *key;
317 let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr);
318
319 map.insert(hash, *key);
320 }
321
322 if let Some(sig) = <InputSatisfier as Satisfier<XOnlyPublicKey>>::lookup_tap_key_spend_sig(&sat)
324 {
325 return Ok(vec![sig.to_vec()]);
326 }
327 let (mut min_wit, mut min_wit_len) = (None, None);
329 if let Some(block_map) =
330 <InputSatisfier as Satisfier<XOnlyPublicKey>>::lookup_tap_control_block_map(&sat)
331 {
332 for (control_block, (script, ver)) in block_map {
333 if *ver != LeafVersion::TapScript {
334 continue;
336 }
337 let ms = match Miniscript::<XOnlyPublicKey, Tap>::parse_with_ext(
338 script,
339 &ExtParams::allow_all(),
340 ) {
341 Ok(ms) => ms.substitute_raw_pkh(&map),
342 Err(..) => continue, };
344 let mut wit = if allow_mall {
345 match ms.satisfy_malleable(&sat) {
346 Ok(ms) => ms,
347 Err(..) => continue,
348 }
349 } else {
350 match ms.satisfy(&sat) {
351 Ok(ms) => ms,
352 Err(..) => continue,
353 }
354 };
355 wit.push(ms.encode().into_bytes());
356 wit.push(control_block.serialize());
357 let wit_len = Some(super::witness_size(&wit));
358 if min_wit_len.is_some() && wit_len > min_wit_len {
359 continue;
360 } else {
361 min_wit = Some(wit);
363 min_wit_len = wit_len;
364 }
365 }
366 min_wit.ok_or(InputError::CouldNotSatisfyTr)
367 } else {
368 Err(InputError::CouldNotSatisfyTr)
370 }
371}
372
373#[derive(Debug)]
375pub enum Error {
376 FundingUtxo(FundingUtxoError),
378 DetermineLockTime(DetermineLockTimeError),
380 PartialSigsSighashType(PartialSigsSighashTypeError),
382}
383
384impl fmt::Display for Error {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 use Error::*;
387
388 match *self {
389 FundingUtxo(ref e) => write_err!(f, "Finalizer missing funding UTXO"; e),
391 DetermineLockTime(ref e) =>
392 write_err!(f, "finalizer must be able to determine the lock time"; e),
393 PartialSigsSighashType(ref e) => write_err!(f, "Finalizer sighash type error"; e),
394 }
395 }
396}
397
398#[cfg(feature = "std")]
399impl std::error::Error for Error {
400 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
401 use Error::*;
402
403 match *self {
404 FundingUtxo(ref e) => Some(e),
405 DetermineLockTime(ref e) => Some(e),
406 PartialSigsSighashType(ref e) => Some(e),
407 }
408 }
409}
410
411impl From<FundingUtxoError> for Error {
412 fn from(e: FundingUtxoError) -> Self { Self::FundingUtxo(e) }
413}
414
415impl From<DetermineLockTimeError> for Error {
416 fn from(e: DetermineLockTimeError) -> Self { Self::DetermineLockTime(e) }
417}
418
419impl From<PartialSigsSighashTypeError> for Error {
420 fn from(e: PartialSigsSighashTypeError) -> Self { Self::PartialSigsSighashType(e) }
421}
422
423#[derive(Debug)]
425pub enum FinalizeError {
426 FinalizeInput {
428 input_index: usize,
430 error: FinalizeInputError,
432 },
433 InterpreterCheck(InterpreterCheckError),
435}
436
437impl fmt::Display for FinalizeError {
438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 use FinalizeError::*;
440
441 match *self {
442 FinalizeInput { input_index, ref error } =>
443 write_err!(f, "failed to finalize input at index {}", input_index; error),
444 InterpreterCheck(ref e) => write_err!(f, "error running the interpreter checks"; e),
445 }
446 }
447}
448
449#[cfg(feature = "std")]
450impl std::error::Error for FinalizeError {
451 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
452 use FinalizeError::*;
453
454 match *self {
455 FinalizeInput { input_index: _, ref error } => Some(error),
456 InterpreterCheck(ref error) => Some(error),
457 }
458 }
459}
460
461impl From<InterpreterCheckError> for FinalizeError {
462 fn from(e: InterpreterCheckError) -> Self { Self::InterpreterCheck(e) }
463}
464
465#[derive(Debug)]
467pub enum FinalizeInputError {
468 Final(InputError),
470 Input(input::FinalizeError),
472}
473
474impl fmt::Display for FinalizeInputError {
475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476 use FinalizeInputError::*;
477
478 match *self {
479 Final(ref e) => write_err!(f, "final"; e),
480 Input(ref e) => write_err!(f, "input"; e),
481 }
482 }
483}
484
485#[cfg(feature = "std")]
486impl std::error::Error for FinalizeInputError {
487 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
488 use FinalizeInputError::*;
489
490 match *self {
491 Final(ref e) => Some(e),
492 Input(ref e) => Some(e),
493 }
494 }
495}
496
497impl From<InputError> for FinalizeInputError {
498 fn from(e: InputError) -> Self { Self::Final(e) }
499}
500
501impl From<input::FinalizeError> for FinalizeInputError {
502 fn from(e: input::FinalizeError) -> Self { Self::Input(e) }
503}
504
505#[derive(Debug)]
507pub enum InputError {
508 SecpErr(bitcoin::secp256k1::Error),
510 KeyErr(bitcoin::key::FromSliceError),
512 CouldNotSatisfyTr,
517 Interpreter(interpreter::Error),
519 InvalidRedeemScript {
521 redeem: ScriptBuf,
523 p2sh_expected: ScriptBuf,
525 },
526 InvalidWitnessScript {
528 witness_script: ScriptBuf,
530 p2wsh_expected: ScriptBuf,
532 },
533 InvalidSignature {
535 pubkey: bitcoin::PublicKey,
537 sig: Vec<u8>,
539 },
540 MiniscriptError(miniscript::Error),
542 MissingRedeemScript,
544 MissingWitness,
546 MissingPubkey,
548 MissingWitnessScript,
550 MissingUtxo,
552 NonEmptyWitnessScript,
554 NonEmptyRedeemScript,
556 NonStandardSighashType(sighash::NonStandardSighashTypeError),
558 WrongSighashFlag {
560 required: sighash::EcdsaSighashType,
562 got: sighash::EcdsaSighashType,
564 pubkey: bitcoin::PublicKey,
566 },
567}
568
569#[cfg(feature = "std")]
570impl std::error::Error for InputError {
571 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
572 use self::InputError::*;
573
574 match self {
575 CouldNotSatisfyTr
576 | InvalidRedeemScript { .. }
577 | InvalidWitnessScript { .. }
578 | InvalidSignature { .. }
579 | MissingRedeemScript
580 | MissingWitness
581 | MissingPubkey
582 | MissingWitnessScript
583 | MissingUtxo
584 | NonEmptyWitnessScript
585 | NonEmptyRedeemScript
586 | NonStandardSighashType(_)
587 | WrongSighashFlag { .. } => None,
588 SecpErr(e) => Some(e),
589 KeyErr(e) => Some(e),
590 Interpreter(e) => Some(e),
591 MiniscriptError(e) => Some(e),
592 }
593 }
594}
595
596impl fmt::Display for InputError {
597 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
598 match *self {
599 InputError::InvalidSignature { ref pubkey, ref sig } => {
600 write!(f, "PSBT: bad signature {} for key {:?}", pubkey, sig)
601 }
602 InputError::KeyErr(ref e) => write!(f, "Key Err: {}", e),
603 InputError::Interpreter(ref e) => write!(f, "Interpreter: {}", e),
604 InputError::SecpErr(ref e) => write!(f, "Secp Err: {}", e),
605 InputError::InvalidRedeemScript { ref redeem, ref p2sh_expected } => write!(
606 f,
607 "Redeem script {} does not match the p2sh script {}",
608 redeem, p2sh_expected
609 ),
610 InputError::InvalidWitnessScript { ref witness_script, ref p2wsh_expected } => write!(
611 f,
612 "Witness script {} does not match the p2wsh script {}",
613 witness_script, p2wsh_expected
614 ),
615 InputError::MiniscriptError(ref e) => write!(f, "Miniscript Error: {}", e),
616 InputError::MissingWitness => write!(f, "PSBT is missing witness"),
617 InputError::MissingRedeemScript => write!(f, "PSBT is Redeem script"),
618 InputError::MissingUtxo => {
619 write!(f, "PSBT is missing both witness and non-witness UTXO")
620 }
621 InputError::MissingWitnessScript => write!(f, "PSBT is missing witness script"),
622 InputError::MissingPubkey => write!(f, "Missing pubkey for a pkh/wpkh"),
623 InputError::NonEmptyRedeemScript => {
624 write!(f, "PSBT has non-empty redeem script at for legacy transactions")
625 }
626 InputError::NonEmptyWitnessScript => {
627 write!(f, "PSBT has non-empty witness script at for legacy input")
628 }
629 InputError::WrongSighashFlag { required, got, pubkey } => write!(
630 f,
631 "PSBT: signature with key {:?} had \
632 sighashflag {:?} rather than required {:?}",
633 pubkey, got, required
634 ),
635 InputError::CouldNotSatisfyTr => write!(f, "Could not satisfy Tr descriptor"),
636 InputError::NonStandardSighashType(ref e) =>
637 write!(f, "Non-standard sighash type {}", e),
638 }
639 }
640}
641
642impl From<crate::miniscript::Error> for InputError {
643 fn from(e: crate::miniscript::Error) -> Self { Self::MiniscriptError(e) }
644}
645
646impl From<interpreter::Error> for InputError {
647 fn from(e: interpreter::Error) -> Self { Self::Interpreter(e) }
648}
649
650impl From<bitcoin::secp256k1::Error> for InputError {
651 fn from(e: bitcoin::secp256k1::Error) -> Self { Self::SecpErr(e) }
652}
653
654impl From<bitcoin::key::FromSliceError> for InputError {
655 fn from(e: bitcoin::key::FromSliceError) -> Self { Self::KeyErr(e) }
656}