Skip to content

Commit 358fcd3

Browse files
committed
Re-order code such that psbt input only mutates if the finalization
succeeds
1 parent 46d9dd2 commit 358fcd3

File tree

1 file changed

+37
-18
lines changed

1 file changed

+37
-18
lines changed

src/psbt/finalizer.rs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,17 @@ pub fn interpreter_check<C: secp256k1::Verification>(
284284
) -> Result<(), Error> {
285285
let utxos = prevouts(&psbt)?;
286286
let utxos = &Prevouts::All(&utxos);
287-
for (index, _input) in psbt.inputs.iter().enumerate() {
288-
interpreter_inp_check(psbt, secp, index, utxos)?;
287+
for (index, input) in psbt.inputs.iter().enumerate() {
288+
let empty_script_sig = Script::new();
289+
let empty_witness = Witness::default();
290+
let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig);
291+
let witness = input
292+
.final_script_witness
293+
.as_ref()
294+
.map(|wit_slice| Witness::from_vec(wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness
295+
.unwrap_or(empty_witness);
296+
297+
interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?;
289298
}
290299
Ok(())
291300
}
@@ -296,17 +305,10 @@ fn interpreter_inp_check<C: secp256k1::Verification>(
296305
secp: &Secp256k1<C>,
297306
index: usize,
298307
utxos: &Prevouts,
308+
witness: &Witness,
309+
script_sig: &Script,
299310
) -> Result<(), Error> {
300-
let input = &psbt.inputs[index];
301311
let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?;
302-
let empty_script_sig = Script::new();
303-
let empty_witness = Witness::default();
304-
let script_sig = input.final_script_sig.as_ref().unwrap_or(&empty_script_sig);
305-
let witness = input
306-
.final_script_witness
307-
.as_ref()
308-
.map(|wit_slice| Witness::from_vec(wit_slice.to_vec())) // TODO: Update rust-bitcoin psbt API to use witness
309-
.unwrap_or(empty_witness);
310312

311313
// Now look at all the satisfied constraints. If everything is filled in
312314
// corrected, there should be no errors
@@ -365,12 +367,14 @@ pub fn finalize_helper<C: secp256k1::Verification>(
365367
Ok(())
366368
}
367369

368-
pub(super) fn finalize_input<C: secp256k1::Verification>(
369-
psbt: &mut Psbt,
370+
// Helper function to obtain psbt final_witness/final_script_sig.
371+
// Does not add fields to the psbt, only returns the values.
372+
fn finalize_input_helper<C: secp256k1::Verification>(
373+
psbt: &Psbt,
370374
index: usize,
371375
secp: &Secp256k1<C>,
372376
allow_mall: bool,
373-
) -> Result<(), super::Error> {
377+
) -> Result<(Witness, Script), super::Error> {
374378
let (witness, script_sig) = {
375379
let spk = get_scriptpubkey(psbt, index).map_err(|e| Error::InputError(e, index))?;
376380
let sat = PsbtInputSatisfier::new(&psbt, index);
@@ -395,6 +399,24 @@ pub(super) fn finalize_input<C: secp256k1::Verification>(
395399
}
396400
};
397401

402+
let witness = bitcoin::Witness::from_vec(witness);
403+
let utxos = prevouts(&psbt)?;
404+
let utxos = &Prevouts::All(&utxos);
405+
interpreter_inp_check(psbt, secp, index, utxos, &witness, &script_sig)?;
406+
407+
Ok((witness, script_sig))
408+
}
409+
410+
pub(super) fn finalize_input<C: secp256k1::Verification>(
411+
psbt: &mut Psbt,
412+
index: usize,
413+
secp: &Secp256k1<C>,
414+
allow_mall: bool,
415+
) -> Result<(), super::Error> {
416+
let (witness, script_sig) = finalize_input_helper(psbt, index, secp, allow_mall)?;
417+
418+
// Now mutate the psbt input. Note that we cannot error after this point.
419+
// If the input is mutated, it means that the finalization succeeded.
398420
{
399421
let input = &mut psbt.inputs[index];
400422
//Fill in the satisfactions
@@ -406,7 +428,7 @@ pub(super) fn finalize_input<C: secp256k1::Verification>(
406428
input.final_script_witness = if witness.is_empty() {
407429
None
408430
} else {
409-
Some(bitcoin::Witness::from_vec(witness))
431+
Some(witness)
410432
};
411433
//reset everything
412434
input.partial_sigs.clear(); // 0x02
@@ -428,9 +450,6 @@ pub(super) fn finalize_input<C: secp256k1::Verification>(
428450
input.tap_internal_key = None; // x017
429451
input.tap_merkle_root = None; // 0x018
430452
}
431-
let utxos = prevouts(&psbt)?;
432-
let utxos = &Prevouts::All(&utxos);
433-
interpreter_inp_check(psbt, secp, index, utxos)?;
434453

435454
Ok(())
436455
}

0 commit comments

Comments
 (0)