Skip to main content

miniscript/psbt/
finalizer.rs

1// Written in 2020 by Sanket Kanjalkar <sanket1729@gmail.com>
2// SPDX-License-Identifier: CC0-1.0
3
4//! Partially-Signed Bitcoin Transactions
5//!
6//! This module implements the Finalizer and Extractor roles defined in
7//! BIP 174, PSBT, described at
8//! `https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki`
9//!
10
11use core::convert::TryFrom;
12use core::mem;
13
14use bitcoin::hashes::hash160;
15use bitcoin::key::XOnlyPublicKey;
16#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/121684
17use bitcoin::secp256k1;
18use bitcoin::secp256k1::Secp256k1;
19use bitcoin::sighash::Prevouts;
20use bitcoin::taproot::LeafVersion;
21use bitcoin::{PublicKey, Script, ScriptBuf, TxOut, Witness};
22
23use super::{sanity_check, Error, InputError, Psbt, PsbtInputSatisfier};
24use crate::prelude::*;
25use crate::util::witness_size;
26use crate::{
27    interpreter, BareCtx, Descriptor, Legacy, Miniscript, Satisfier, Segwitv0, SigType, Tap,
28    ToPublicKey,
29};
30
31// Satisfy the taproot descriptor. It is not possible to infer the complete
32// descriptor from psbt because the information about all the scripts might not
33// be present. Also, currently the spec does not support hidden branches, so
34// inferring a descriptor is not possible
35fn construct_tap_witness(
36    spk: &Script,
37    sat: &PsbtInputSatisfier,
38    allow_mall: bool,
39) -> Result<Vec<Vec<u8>>, InputError> {
40    // When miniscript tries to finalize the PSBT, it doesn't have the full descriptor (which contained a pkh() fragment)
41    // and instead resorts to parsing the raw script sig, which is translated into a "expr_raw_pkh" internally.
42    let mut map: BTreeMap<hash160::Hash, bitcoin::key::XOnlyPublicKey> = BTreeMap::new();
43    let psbt_inputs = &sat.psbt.inputs;
44    for psbt_input in psbt_inputs {
45        // We need to satisfy or dissatisfy any given key. `tap_key_origin` is the only field of PSBT Input which consist of
46        // all the keys added on a descriptor and thus we get keys from it.
47        let public_keys = psbt_input.tap_key_origins.keys();
48        for key in public_keys {
49            let bitcoin_key = *key;
50            let hash = bitcoin_key.to_pubkeyhash(SigType::Schnorr);
51            map.insert(hash, bitcoin_key);
52        }
53    }
54    assert!(spk.is_p2tr());
55
56    // try the key spend path firsti
57    if let Some(ref key) = sat.psbt_input().tap_internal_key {
58        if let Some(sig) =
59            <PsbtInputSatisfier as Satisfier<XOnlyPublicKey>>::lookup_tap_key_spend_sig(sat, key)
60        {
61            return Ok(vec![sig.to_vec()]);
62        }
63    }
64    // Next script spends
65    let (mut min_wit, mut min_wit_len) = (None, None);
66    if let Some(block_map) =
67        <PsbtInputSatisfier as Satisfier<XOnlyPublicKey>>::lookup_tap_control_block_map(sat)
68    {
69        for (control_block, (script, ver)) in block_map {
70            if *ver != LeafVersion::TapScript {
71                // We don't know how to satisfy non default version scripts yet
72                continue;
73            }
74            let ms = match Miniscript::<XOnlyPublicKey, Tap>::decode_consensus(script) {
75                Ok(ms) => ms.substitute_raw_pkh(&map),
76                Err(..) => continue, // try another script
77            };
78            let mut wit = if allow_mall {
79                match ms.satisfy_malleable(sat) {
80                    Ok(ms) => ms,
81                    Err(..) => continue,
82                }
83            } else {
84                match ms.satisfy(sat) {
85                    Ok(ms) => ms,
86                    Err(..) => continue,
87                }
88            };
89            wit.push(ms.encode().into_bytes());
90            wit.push(control_block.serialize());
91            let wit_len = Some(witness_size(&wit));
92            if min_wit_len.is_some() && wit_len > min_wit_len {
93                continue;
94            } else {
95                // store the minimum
96                min_wit = Some(wit);
97                min_wit_len = wit_len;
98            }
99        }
100        min_wit.ok_or(InputError::CouldNotSatisfyTr)
101    } else {
102        // No control blocks found
103        Err(InputError::CouldNotSatisfyTr)
104    }
105}
106
107// Get the scriptpubkey for the psbt input
108pub(super) fn get_scriptpubkey(psbt: &Psbt, index: usize) -> Result<ScriptBuf, InputError> {
109    get_utxo(psbt, index).map(|utxo| utxo.script_pubkey.clone())
110}
111
112// Get the spending utxo for this psbt input
113pub(super) fn get_utxo(psbt: &Psbt, index: usize) -> Result<&bitcoin::TxOut, InputError> {
114    let inp = &psbt.inputs[index];
115    let utxo = if let Some(ref witness_utxo) = inp.witness_utxo {
116        witness_utxo
117    } else if let Some(ref non_witness_utxo) = inp.non_witness_utxo {
118        let vout = psbt.unsigned_tx.input[index].previous_output.vout;
119        &non_witness_utxo.output[vout as usize]
120    } else {
121        return Err(InputError::MissingUtxo);
122    };
123    Ok(utxo)
124}
125
126/// Get the Prevouts for the psbt
127pub(super) fn prevouts(psbt: &Psbt) -> Result<Vec<&bitcoin::TxOut>, super::Error> {
128    let mut utxos = vec![];
129    for i in 0..psbt.inputs.len() {
130        let utxo_ref = get_utxo(psbt, i).map_err(|e| Error::InputError(e, i))?;
131        utxos.push(utxo_ref);
132    }
133    Ok(utxos)
134}
135
136// Create a descriptor from unfinalized PSBT input.
137// Panics on out of bound input index for psbt
138// Also sanity checks that the witness script and
139// redeem script are consistent with the script pubkey.
140// Does *not* check signatures
141// We parse the insane version while satisfying because
142// we want to move the script is probably already created
143// and we want to satisfy it in any way possible.
144fn get_descriptor(psbt: &Psbt, index: usize) -> Result<Descriptor<PublicKey>, InputError> {
145    let mut map: BTreeMap<hash160::Hash, PublicKey> = BTreeMap::new();
146    let psbt_inputs = &psbt.inputs;
147    for psbt_input in psbt_inputs {
148        // Use BIP32 Derviation to get set of all possible keys.
149        let public_keys = psbt_input.bip32_derivation.keys();
150        for key in public_keys {
151            let bitcoin_key = bitcoin::PublicKey::new(*key);
152            let hash = bitcoin_key.pubkey_hash().to_raw_hash();
153            map.insert(hash, bitcoin_key);
154        }
155    }
156
157    // Figure out Scriptpubkey
158    let script_pubkey = get_scriptpubkey(psbt, index)?;
159    let inp = &psbt.inputs[index];
160    // 1. `PK`: creates a `Pk` descriptor(does not check if partial sig is given)
161    if script_pubkey.is_p2pk() {
162        let script_pubkey_len = script_pubkey.len();
163        let pk_bytes = &script_pubkey.to_bytes();
164        match bitcoin::PublicKey::from_slice(&pk_bytes[1..script_pubkey_len - 1]) {
165            Ok(pk) => Ok(Descriptor::new_pk(pk)),
166            Err(e) => Err(InputError::from(e)),
167        }
168    } else if script_pubkey.is_p2pkh() {
169        // 2. `Pkh`: creates a `PkH` descriptor if partial_sigs has the corresponding pk
170        let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
171            // Indirect way to check the equivalence of pubkey-hashes.
172            // Create a pubkey hash and check if they are the same.
173            // THIS IS A BUG AND *WILL* PRODUCE WRONG SATISFACTIONS FOR UNCOMPRESSED KEYS
174            // Partial sigs loses the compressed flag that is necessary
175            // TODO: See https://github.com/rust-bitcoin/rust-bitcoin/pull/836
176            // The type checker will fail again after we update to 0.28 and this can be removed
177            let addr = bitcoin::Address::p2pkh(pk, bitcoin::Network::Bitcoin);
178            *script_pubkey == addr.script_pubkey()
179        });
180        match partial_sig_contains_pk {
181            Some((pk, _sig)) => Descriptor::new_pkh(*pk).map_err(InputError::from),
182            None => Err(InputError::MissingPubkey),
183        }
184    } else if script_pubkey.is_p2wpkh() {
185        // 3. `Wpkh`: creates a `wpkh` descriptor if the partial sig has corresponding pk.
186        let partial_sig_contains_pk = inp.partial_sigs.iter().find(|&(&pk, _sig)| {
187            match bitcoin::key::CompressedPublicKey::try_from(pk) {
188                Ok(compressed) => {
189                    // Indirect way to check the equivalence of pubkey-hashes.
190                    // Create a pubkey hash and check if they are the same.
191                    let addr = bitcoin::Address::p2wpkh(&compressed, bitcoin::Network::Bitcoin);
192                    *script_pubkey == addr.script_pubkey()
193                }
194                Err(_) => false,
195            }
196        });
197        match partial_sig_contains_pk {
198            Some((pk, _sig)) => Ok(Descriptor::new_wpkh(*pk)?),
199            None => Err(InputError::MissingPubkey),
200        }
201    } else if script_pubkey.is_p2wsh() {
202        // 4. `Wsh`: creates a `Wsh` descriptor
203        if inp.redeem_script.is_some() {
204            return Err(InputError::NonEmptyRedeemScript);
205        }
206        if let Some(ref witness_script) = inp.witness_script {
207            if witness_script.to_p2wsh() != *script_pubkey {
208                return Err(InputError::InvalidWitnessScript {
209                    witness_script: witness_script.clone(),
210                    p2wsh_expected: script_pubkey.clone(),
211                });
212            }
213            let ms = Miniscript::<bitcoin::PublicKey, Segwitv0>::decode_consensus(witness_script)?;
214            Ok(Descriptor::new_wsh(ms.substitute_raw_pkh(&map))?)
215        } else {
216            Err(InputError::MissingWitnessScript)
217        }
218    } else if script_pubkey.is_p2sh() {
219        match inp.redeem_script {
220            None => Err(InputError::MissingRedeemScript),
221            Some(ref redeem_script) => {
222                if redeem_script.to_p2sh() != *script_pubkey {
223                    return Err(InputError::InvalidRedeemScript {
224                        redeem: redeem_script.clone(),
225                        p2sh_expected: script_pubkey.clone(),
226                    });
227                }
228                if redeem_script.is_p2wsh() {
229                    // 5. `ShWsh` case
230                    if let Some(ref witness_script) = inp.witness_script {
231                        if witness_script.to_p2wsh() != *redeem_script {
232                            return Err(InputError::InvalidWitnessScript {
233                                witness_script: witness_script.clone(),
234                                p2wsh_expected: redeem_script.clone(),
235                            });
236                        }
237                        let ms = Miniscript::<bitcoin::PublicKey, Segwitv0>::decode_consensus(
238                            witness_script,
239                        )?;
240                        Ok(Descriptor::new_sh_wsh(ms.substitute_raw_pkh(&map))?)
241                    } else {
242                        Err(InputError::MissingWitnessScript)
243                    }
244                } else if redeem_script.is_p2wpkh() {
245                    // 6. `ShWpkh` case
246                    let partial_sig_contains_pk = inp.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                    //7. regular p2sh
264                    if inp.witness_script.is_some() {
265                        return Err(InputError::NonEmptyWitnessScript);
266                    }
267                    if let Some(ref redeem_script) = inp.redeem_script {
268                        let ms = Miniscript::<bitcoin::PublicKey, Legacy>::decode_consensus(
269                            redeem_script,
270                        )?;
271                        Ok(Descriptor::new_sh(ms)?)
272                    } else {
273                        Err(InputError::MissingWitnessScript)
274                    }
275                }
276            }
277        }
278    } else {
279        // 8. Bare case
280        if inp.witness_script.is_some() {
281            return Err(InputError::NonEmptyWitnessScript);
282        }
283        if inp.redeem_script.is_some() {
284            return Err(InputError::NonEmptyRedeemScript);
285        }
286        let ms = Miniscript::<bitcoin::PublicKey, BareCtx>::decode_consensus(&script_pubkey)?;
287        Ok(Descriptor::new_bare(ms.substitute_raw_pkh(&map))?)
288    }
289}
290
291/// Interprets all psbt inputs and checks whether the
292/// script is correctly interpreted according to the context.
293///
294/// The psbt must have included final script sig and final witness.
295/// In other words, this checks whether the finalized psbt interprets
296/// correctly
297pub fn interpreter_check<C: secp256k1::Verification>(
298    psbt: &Psbt,
299    secp: &Secp256k1<C>,
300) -> Result<(), Error> {
301    let utxos = prevouts(psbt)?;
302    let utxos = &Prevouts::All(&utxos);
303    for (index, input) in psbt.inputs.iter().enumerate() {
304        let empty_script_sig = ScriptBuf::new();
305        let empty_witness = Witness::default();
306        let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig);
307        let witness = input
308            .final_script_witness
309            .as_ref()
310            .map(|wit_slice| Witness::from_slice(&wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness
311            .unwrap_or(empty_witness);
312
313        interpreter_inp_check(psbt, secp, index, utxos, &witness, script_sig)?;
314    }
315    Ok(())
316}
317
318// Run the miniscript interpreter on a single psbt input
319fn interpreter_inp_check<C: secp256k1::Verification, T: Borrow<TxOut>>(
320    psbt: &Psbt,
321    secp: &Secp256k1<C>,
322    index: usize,
323    utxos: &Prevouts<T>,
324    witness: &Witness,
325    script_sig: &Script,
326) -> Result<(), Error> {
327    let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?;
328
329    // Now look at all the satisfied constraints. If everything is filled in
330    // corrected, there should be no errors
331    // Interpreter check
332    {
333        let cltv = psbt.unsigned_tx.lock_time;
334        let csv = psbt.unsigned_tx.input[index].sequence;
335        let interpreter =
336            interpreter::Interpreter::from_txdata(&spk, script_sig, witness, csv, cltv)
337                .map_err(|e| Error::InputError(InputError::Interpreter(e), index))?;
338        let iter = interpreter.iter(secp, &psbt.unsigned_tx, index, utxos);
339        if let Some(error) = iter.filter_map(Result::err).next() {
340            return Err(Error::InputError(InputError::Interpreter(error), index));
341        };
342    }
343    Ok(())
344}
345
346/// Finalize the psbt.
347///
348/// This function takes in a mutable reference to psbt
349/// and populates the final_witness and final_scriptsig
350/// of the psbt assuming all of the inputs are miniscript as per BIP174.
351/// If any of the inputs is not miniscript, this returns a parsing error
352/// For satisfaction of individual inputs, use the satisfy API.
353/// This function also performs a sanity interpreter check on the
354/// finalized psbt which involves checking the signatures/ preimages/timelocks.
355/// The functions fails it is not possible to satisfy any of the inputs non-malleably
356/// See [finalize_mall] if you want to allow malleable satisfactions
357#[deprecated(since = "7.0.0", note = "Please use PsbtExt::finalize instead")]
358pub fn finalize<C: secp256k1::Verification>(
359    psbt: &mut Psbt,
360    secp: &Secp256k1<C>,
361) -> Result<(), super::Error> {
362    finalize_helper(psbt, secp, false)
363}
364
365/// Same as [finalize], but allows for malleable satisfactions
366pub fn finalize_mall<C: secp256k1::Verification>(
367    psbt: &mut Psbt,
368    secp: &Secp256k1<C>,
369) -> Result<(), super::Error> {
370    finalize_helper(psbt, secp, true)
371}
372
373pub fn finalize_helper<C: secp256k1::Verification>(
374    psbt: &mut Psbt,
375    secp: &Secp256k1<C>,
376    allow_mall: bool,
377) -> Result<(), super::Error> {
378    sanity_check(psbt)?;
379
380    // Actually construct the witnesses
381    for index in 0..psbt.inputs.len() {
382        finalize_input(psbt, index, secp, allow_mall)?;
383    }
384    // Interpreter is already run inside finalize_input for each input
385    Ok(())
386}
387
388// Helper function to obtain psbt final_witness/final_script_sig.
389// Does not add fields to the psbt, only returns the values.
390fn finalize_input_helper<C: secp256k1::Verification>(
391    psbt: &Psbt,
392    index: usize,
393    secp: &Secp256k1<C>,
394    allow_mall: bool,
395) -> Result<(Witness, ScriptBuf), super::Error> {
396    let (witness, script_sig) = {
397        let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?;
398        let sat = PsbtInputSatisfier::new(psbt, index);
399
400        if spk.is_p2tr() {
401            // Deal with tr case separately, unfortunately we cannot infer the full descriptor for Tr
402            let wit = construct_tap_witness(&spk, &sat, allow_mall)
403                .map_err(|e| Error::InputError(e, index))?;
404            (wit, ScriptBuf::new())
405        } else {
406            // Get a descriptor for this input.
407            let desc = get_descriptor(psbt, index).map_err(|e| Error::InputError(e, index))?;
408
409            //generate the satisfaction witness and scriptsig
410            let sat = PsbtInputSatisfier::new(psbt, index);
411            if !allow_mall {
412                desc.get_satisfaction(sat)
413            } else {
414                desc.get_satisfaction_mall(sat)
415            }
416            .map_err(|e| Error::InputError(InputError::MiniscriptError(e), index))?
417        }
418    };
419
420    let witness = bitcoin::Witness::from_slice(&witness);
421    let utxos = prevouts(psbt)?;
422    let utxos = &Prevouts::All(&utxos);
423    interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?;
424
425    Ok((witness, script_sig))
426}
427
428pub(super) fn finalize_input<C: secp256k1::Verification>(
429    psbt: &mut Psbt,
430    index: usize,
431    secp: &Secp256k1<C>,
432    allow_mall: bool,
433) -> Result<(), super::Error> {
434    // Preserve previously finalized inputs
435    if psbt.inputs[index].final_script_sig.is_some()
436        || psbt.inputs[index].final_script_witness.is_some()
437    {
438        return Ok(());
439    }
440
441    let (witness, script_sig) = finalize_input_helper(psbt, index, secp, allow_mall)?;
442
443    // Now mutate the psbt input. Note that we cannot error after this point.
444    // If the input is mutated, it means that the finalization succeeded.
445    {
446        let original = mem::take(&mut psbt.inputs[index]);
447        let input = &mut psbt.inputs[index];
448        input.non_witness_utxo = original.non_witness_utxo;
449        input.witness_utxo = original.witness_utxo;
450        input.final_script_sig = if script_sig.is_empty() {
451            None
452        } else {
453            Some(script_sig)
454        };
455        input.final_script_witness = if witness.is_empty() {
456            None
457        } else {
458            Some(witness)
459        };
460    }
461
462    Ok(())
463}
464
465#[cfg(test)]
466mod tests {
467    use bitcoin::{absolute, transaction, Transaction, TxIn};
468    use hex;
469
470    use super::*;
471    use crate::psbt::PsbtExt;
472
473    #[test]
474    fn tests_from_bip174() {
475        let mut psbt = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f012202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap();
476
477        let secp = Secp256k1::verification_only();
478        psbt.finalize_mut(&secp).unwrap();
479
480        let expected = Psbt::deserialize(&hex::decode_to_vec("70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000").unwrap()).unwrap();
481        assert_eq!(psbt, expected);
482    }
483
484    #[test]
485    fn finalize_skips_already_finalized_input() {
486        let tx = Transaction {
487            version: transaction::Version::ONE,
488            lock_time: absolute::LockTime::ZERO,
489            input: vec![TxIn::default()],
490            output: vec![],
491        };
492        let mut psbt = Psbt::from_unsigned_tx(tx).unwrap();
493        psbt.inputs[0].final_script_witness = Some(Witness::from_slice(&[vec![1]]));
494
495        let expected_input = psbt.inputs[0].clone();
496        let secp = Secp256k1::verification_only();
497
498        psbt.finalize_mut(&secp).unwrap();
499
500        assert_eq!(psbt.inputs[0], expected_input);
501    }
502}