Skip to content

Commit d9c5c99

Browse files
committed
Add PsbtInputExt::update_with_descriptor
This populates all relevant fields in a PSBT input according to a descriptor. Includes previously not yet implemented logic for populating bip32_derivation and tap_key_origins. Also optionally checks the witness_utxo and non_witness_utxo. I renamed "PsbtExt::update_desc" to "PsbtExt::update_inp_with_descriptor" which calls update_with_descriptor internally but retrieves the vout for the input for the non_witness_utxo check automatically. I removed the derivation range functionality because it didn't feel useful (and if it is then it probably belongs in a separate function).
1 parent ef8c048 commit d9c5c99

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

integration_test/src/test_desc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub fn test_desc_satisfy(cl: &Client, testdata: &TestData, desc: &str) -> Witnes
112112
input.witness_utxo = Some(witness_utxo.clone());
113113
psbt.inputs.push(input);
114114
psbt.outputs.push(psbt::Output::default());
115-
psbt.update_desc(0, &desc, None).unwrap();
115+
psbt.update_inp_with_descriptor(0, &desc, true, false).unwrap();
116116

117117
// --------------------------------------------
118118
// Sign the transactions with all keys

src/psbt/mod.rs

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -516,14 +516,20 @@ pub trait PsbtExt {
516516
secp: &Secp256k1<C>,
517517
) -> Result<bitcoin::Transaction, Error>;
518518

519-
/// Update a PSBT with the derived descriptor.
519+
/// Update PSBT input with a descriptor.
520520
///
521-
/// Internally, uses [`PsbtInputExt::update_with_descriptor`] and checks that the `witness_utxo`
522-
/// and `non_witness_utxo` have the correct `script_pubkey` if applicable.
521+
/// This is a convienient wrapper around [`PsbtInputExt::update_with_descriptor`] which avoids
522+
/// looking up the inputs previous outupt index. Consult that function for further
523+
/// documentation.
524+
///
525+
/// The `descriptor` **must not have any wildcards** in it otherwise an error will be returned
526+
/// however it can (and should) have extended keys in it.
523527
fn update_inp_with_descriptor(
524528
&mut self,
525529
input_index: usize,
526-
desc: &Descriptor<DescriptorPublicKey>,
530+
descriptor: &Descriptor<DescriptorPublicKey>,
531+
check_witness_utxo: bool,
532+
check_non_witness_utxo: bool,
527533
) -> Result<(), UtxoUpdateError>;
528534

529535
/// Get the sighash message(data to sign) at input index `idx` based on the sighash
@@ -689,21 +695,28 @@ impl PsbtExt for Psbt {
689695
&mut self,
690696
input_index: usize,
691697
desc: &Descriptor<DescriptorPublicKey>,
698+
check_witness_utxo: bool,
699+
check_non_witness_utxo: bool,
692700
) -> Result<(), UtxoUpdateError> {
693701
let n_inputs = self.inputs.len();
694702
let input = self
695703
.inputs
696704
.get_mut(input_index)
697705
.ok_or(UtxoUpdateError::IndexOutOfBounds(input_index, n_inputs))?;
698-
let vout = self
699-
.unsigned_tx
700-
.input
701-
.get(input_index)
702-
.ok_or(UtxoUpdateError::MissingInputUtxo)?
703-
.previous_output
704-
.vout;
706+
let check_non_witness_utxo = if check_non_witness_utxo {
707+
Some(
708+
self.unsigned_tx
709+
.input
710+
.get(input_index)
711+
.ok_or(UtxoUpdateError::MissingInputUtxo)?
712+
.previous_output
713+
.vout,
714+
)
715+
} else {
716+
None
717+
};
705718
input
706-
.update_with_descriptor(desc, true, Some(vout))
719+
.update_with_descriptor(desc, check_witness_utxo, check_non_witness_utxo)
707720
.map_err(UtxoUpdateError::InputUpdate)?;
708721
Ok(())
709722
}
@@ -806,12 +819,22 @@ pub trait PsbtInputExt {
806819
/// spend it.
807820
///
808821
/// If the descriptor contains wilcards or otherwise cannot be transformed into a concrete
809-
/// descriptor an error will returned.
822+
/// descriptor an error will returned. The descriptor *can* (and should) have extended keys in
823+
/// it so PSBT fields like `bip32_derivation` and `tap_key_origins` can be populated.
810824
///
811825
/// You can make sure the descriptor is consistent with the `witness_utxo` and/or
812826
/// `non_witness_utxo` fields of the PSBT by setting `check_witness_utxo` and
813-
/// `check_non_witness_utxo` respectively. You should set `check_non_witness_utxo` to inputs the
814-
/// output index in the transaction being spent.
827+
/// `check_non_witness_utxo` respectively. You should set `check_non_witness_utxo` to input's
828+
/// output index in the transaction being spent. Note that `witness_utxo` or
829+
/// `check_non_witness_utxo` being absent also counts as a check failure unless the field is
830+
/// strictly not relevent to the descriptor. The two cases where the absence of a field will be
831+
/// ignored are `witness_utxo` missing on a non-segwit descriptor and `non_witness_utxo` missing
832+
/// on a taproot descriptor.
833+
///
834+
/// Note that it may be suprising that `non_witness_utxo` would ever be required on a segwit
835+
/// output but some PSBT signers require it to be set because of the [*segwit
836+
/// bug*](https://bitcoinhackers.org/@lukedashjr/104287698361196952) which was fixed in the
837+
/// design of segwitv1 (taproot).
815838
fn update_with_descriptor(
816839
&mut self,
817840
descriptor: &Descriptor<DescriptorPublicKey>,

0 commit comments

Comments
 (0)