Skip to content

Commit 40cc0c9

Browse files
committed
Merge #311: Cleanups on Psbt APIs
358fcd3 Re-order code such that psbt input only mutates if the finalization succeeds (sanket1729) 46d9dd2 Update API docs (sanket1729) Pull request description: - Cleanly separate the mutating part of the code such that if the psbt input finalization errors, that input is not mutated. - Update API docs ACKs for top commit: dr-orlovsky: utACK 358fcd3 apoelstra: ACK 358fcd3 Tree-SHA512: 5eec31680a3f016eebf1f5106e9857b1462e81be6f79762067613e170561583bda360987b8d2ccd07ea625155caeca215eb5589a4b65627653dd3a63b74530b4
2 parents bc2d097 + 358fcd3 commit 40cc0c9

File tree

2 files changed

+55
-18
lines changed

2 files changed

+55
-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
}

src/psbt/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,13 +435,22 @@ pub trait PsbtExt {
435435
/// See [finalizer::finalize_mall] if you want to allow malleable satisfactions
436436
///
437437
/// For finalizing individual inputs, see also [`PsbtExt::finalize_inp`]
438+
///
439+
/// # Errors:
440+
///
441+
/// - A vector of errors, one of each of failed finalized input
438442
fn finalize_mut<C: secp256k1::Verification>(
439443
&mut self,
440444
secp: &secp256k1::Secp256k1<C>,
441445
) -> Result<(), Vec<Error>>;
442446

443447
/// Same as [`PsbtExt::finalize_mut`], but does not mutate the input psbt and
444448
/// returns a new psbt
449+
///
450+
/// # Errors:
451+
///
452+
/// - Returns a mutated psbt with all inputs `finalize_mut` could finalize
453+
/// - A vector of input errors, one of each of failed finalized input
445454
fn finalize<C: secp256k1::Verification>(
446455
self,
447456
secp: &secp256k1::Secp256k1<C>,
@@ -462,13 +471,22 @@ pub trait PsbtExt {
462471
/// Same as [`PsbtExt::finalize_mut`], but only tries to finalize a single input leaving other
463472
/// inputs as is. Use this when not all of inputs that you are trying to
464473
/// satisfy are miniscripts
474+
///
475+
/// # Errors:
476+
///
477+
/// - Input error detailing why the finalization failed. The psbt is not mutated when the finalization fails
465478
fn finalize_inp_mut<C: secp256k1::Verification>(
466479
&mut self,
467480
secp: &secp256k1::Secp256k1<C>,
468481
index: usize,
469482
) -> Result<(), Error>;
470483

471484
/// Same as [`PsbtExt::finalize_inp_mut`], but does not mutate the psbt and returns a new one
485+
///
486+
/// # Errors:
487+
/// Returns a tuple containing
488+
/// - Original psbt
489+
/// - Input Error detailing why the input finalization failed
472490
fn finalize_inp<C: secp256k1::Verification>(
473491
self,
474492
secp: &secp256k1::Secp256k1<C>,

0 commit comments

Comments
 (0)