Skip to main content

psbt_v2/v2/miniscript/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Implementation of the Finalizer role as defined in [BIP-174].
4//!
5//! # Finalizer Role
6//!
7//! > For each input, the Input Finalizer determines if the input has enough data to pass validation.
8//!
9//! Determining if a PSBT has enough data to satisfy the spending conditions of all its inputs
10//! requires usage of `rust-miniscript`.
11//!
12//! # Extractor Role
13//!
14//! > The Transaction Extractor does not need to know how to interpret scripts in order
15//! > to extract the network serialized transaction.
16//!
17//! The Extractor role does not technically require `rust-miniscript` but since a PSBT must be  
18
19//! [BIP-174]: <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>
20
21mod finalize;
22mod satisfy;
23
24use core::fmt;
25
26use bitcoin::consensus::encode::VarInt;
27use bitcoin::secp256k1::{Secp256k1, Verification};
28use bitcoin::sighash::Prevouts;
29use bitcoin::{Script, Sequence, Transaction, TxOut, Witness};
30use miniscript::miniscript::satisfy::Placeholder;
31use miniscript::{interpreter, Interpreter, MiniscriptKey};
32
33use crate::error::write_err;
34use crate::prelude::*;
35use crate::v2::map::input::Input;
36use crate::v2::{DetermineLockTimeError, Psbt};
37
38#[rustfmt::skip]                // Keep public exports separate.
39pub use self::finalize::{InputError, Finalizer, FinalizeError, FinalizeInputError};
40
41impl Psbt {
42    // TODO: Should this be on a Role? Finalizer/Extractor? Then we can remove the debug_assert
43    /// Interprets all PSBT inputs and checks whether the script is correctly interpreted according
44    /// to the context.
45    ///
46    /// The psbt must have included final script sig and final witness. In other words, this checks
47    /// whether the finalized psbt interprets correctly
48    pub fn interpreter_check<C: Verification>(
49        &self,
50        secp: &Secp256k1<C>,
51    ) -> Result<(), InterpreterCheckError> {
52        debug_assert!(self.is_finalized());
53
54        let unsigned_tx = self.unsigned_tx()?; // Used to verify signatures.
55
56        let utxos: Vec<&TxOut> = self
57            .iter_funding_utxos()
58            .map(|res| res.expect("finalized PSBT has funding utxos"))
59            .collect();
60        let utxos = &Prevouts::All(&utxos);
61        for (index, input) in self.inputs.iter().enumerate() {
62            self.interpreter_check_input(
63                secp,
64                &unsigned_tx,
65                index,
66                input,
67                utxos,
68                input.final_script_witness.as_ref().expect("checked in is_finalized"),
69                input.final_script_sig.as_ref().expect("checked in is_finalized"),
70            )?;
71        }
72        Ok(())
73    }
74
75    /// Runs the miniscript interpreter on a single psbt input.
76    #[allow(clippy::too_many_arguments)] // TODO: Remove this.
77    fn interpreter_check_input<C: Verification, T: Borrow<TxOut>>(
78        &self,
79        secp: &Secp256k1<C>,
80        unsigned_tx: &Transaction,
81        index: usize,
82        input: &Input,
83        utxos: &Prevouts<T>,
84        witness: &Witness,
85        script_sig: &Script,
86    ) -> Result<(), InterpreterCheckInputError> {
87        use InterpreterCheckInputError::*;
88
89        let spk = &input.funding_utxo().expect("have funding utxo").script_pubkey;
90
91        // TODO: Check that this is correct?
92        let cltv = input.lock_time();
93        // TODO: is this usage of MAX correct?
94        let csv = input.sequence.unwrap_or(Sequence::MAX);
95
96        let interpreter = Interpreter::from_txdata(spk, script_sig, witness, csv, cltv)
97            .map_err(|error| Constructor { input_index: index, error })?;
98
99        let iter = interpreter.iter(secp, unsigned_tx, index, utxos);
100        // TODO: Ok to just return the first satisfaction error?
101        if let Some(error) = iter.filter_map(Result::err).next() {
102            return Err(Satisfaction { input_index: index, error });
103        };
104
105        Ok(())
106    }
107}
108
109pub(crate) trait ItemSize {
110    fn size(&self) -> usize;
111}
112
113impl<Pk: MiniscriptKey> ItemSize for Placeholder<Pk> {
114    fn size(&self) -> usize {
115        match self {
116            Placeholder::Pubkey(_, size) => *size,
117            Placeholder::PubkeyHash(_, size) => *size,
118            Placeholder::EcdsaSigPk(_) | Placeholder::EcdsaSigPkHash(_) => 73,
119            Placeholder::SchnorrSigPk(_, _, size) | Placeholder::SchnorrSigPkHash(_, _, size) =>
120                size + 1, // +1 for the OP_PUSH
121            Placeholder::HashDissatisfaction
122            | Placeholder::Sha256Preimage(_)
123            | Placeholder::Hash256Preimage(_)
124            | Placeholder::Ripemd160Preimage(_)
125            | Placeholder::Hash160Preimage(_) => 33,
126            Placeholder::PushOne => 2, // On legacy this should be 1 ?
127            Placeholder::PushZero => 1,
128            Placeholder::TapScript(s) => s.len(),
129            Placeholder::TapControlBlock(cb) => cb.serialize().len(),
130        }
131    }
132}
133
134impl ItemSize for Vec<u8> {
135    fn size(&self) -> usize { self.len() }
136}
137
138// Helper function to calculate witness size
139pub(crate) fn witness_size<T: ItemSize>(wit: &[T]) -> usize {
140    wit.iter().map(T::size).sum::<usize>() + varint_len(wit.len())
141}
142
143pub(crate) fn varint_len(n: usize) -> usize { VarInt(n as u64).size() }
144
145/// Error type for Pbst Input
146#[derive(Debug)]
147pub enum InterpreterCheckError {
148    /// Failed to determine lock time for unsigned transaction.
149    DetermineLockTime(DetermineLockTimeError),
150    /// Interpreter check failed for an input.
151    InterpreterCheckInput(InterpreterCheckInputError),
152}
153
154impl fmt::Display for InterpreterCheckError {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        use InterpreterCheckError::*;
157
158        match *self {
159            DetermineLockTime(ref e) => write_err!(f, "interpreter check determine locktime"; e),
160            InterpreterCheckInput(ref e) => write_err!(f, "interpreter check failed for input"; e),
161        }
162    }
163}
164
165#[cfg(feature = "std")]
166impl std::error::Error for InterpreterCheckError {
167    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
168        use InterpreterCheckError::*;
169
170        match *self {
171            DetermineLockTime(ref e) => Some(e),
172            InterpreterCheckInput(ref e) => Some(e),
173        }
174    }
175}
176
177impl From<DetermineLockTimeError> for InterpreterCheckError {
178    fn from(e: DetermineLockTimeError) -> Self { Self::DetermineLockTime(e) }
179}
180
181impl From<InterpreterCheckInputError> for InterpreterCheckError {
182    fn from(e: InterpreterCheckInputError) -> Self { Self::InterpreterCheckInput(e) }
183}
184
185/// Error type for Pbst Input
186#[derive(Debug)]
187pub enum InterpreterCheckInputError {
188    /// Failed to construct a [`miniscript::Interpreter`].
189    Constructor {
190        /// Index of the input causing this error.
191        input_index: usize,
192        /// The interpreter error returned from `rust-miniscript`.
193        error: interpreter::Error,
194    },
195    /// Interpreter satisfaction failed for input.
196    Satisfaction {
197        /// Index of the input causing this error.
198        input_index: usize,
199        /// The interpreter error returned from `rust-miniscript`.
200        error: interpreter::Error,
201    },
202}
203
204impl fmt::Display for InterpreterCheckInputError {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        use InterpreterCheckInputError::*;
207
208        match *self {
209            Constructor { input_index, ref error } =>
210                write_err!(f, "Interpreter constructor failed for input {}", input_index; error),
211            Satisfaction { input_index, ref error } =>
212                write_err!(f, "Interpreter satisfaction failed for input {}", input_index; error),
213        }
214    }
215}
216
217#[cfg(feature = "std")]
218impl std::error::Error for InterpreterCheckInputError {
219    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
220        use InterpreterCheckInputError::*;
221
222        match *self {
223            Constructor { input_index: _, ref error } => Some(error),
224            Satisfaction { input_index: _, ref error } => Some(error),
225        }
226    }
227}