diff --git a/src/psbt/mod.rs b/src/psbt/mod.rs index d83f18a3..ff950db7 100644 --- a/src/psbt/mod.rs +++ b/src/psbt/mod.rs @@ -99,4 +99,23 @@ mod test { }; let _ = wallet.sign(&mut psbt, options).unwrap(); } + + #[test] + fn test_psbt_sign_with_finalized() { + let psbt_bip: PSBT = deserialize(&base64::decode(PSBT_STR).unwrap()).unwrap(); + let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); + let send_to = wallet.get_address(AddressIndex::New).unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(send_to.script_pubkey(), 10_000); + let (mut psbt, _) = builder.finish().unwrap(); + + // add a finalized input + psbt.inputs.push(psbt_bip.inputs[0].clone()); + psbt.global + .unsigned_tx + .input + .push(psbt_bip.global.unsigned_tx.input[0].clone()); + + let _ = wallet.sign(&mut psbt, SignOptions::default()).unwrap(); + } } diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index ac32cb63..53522695 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -861,10 +861,14 @@ where // this helps us doing our job later self.add_input_hd_keypaths(psbt)?; - // If we aren't allowed to use `witness_utxo`, ensure that every input has the - // `non_witness_utxo` + // If we aren't allowed to use `witness_utxo`, ensure that every input but finalized one + // has the `non_witness_utxo` if !sign_options.trust_witness_utxo - && psbt.inputs.iter().any(|i| i.non_witness_utxo.is_none()) + && psbt + .inputs + .iter() + .filter(|i| i.final_script_witness.is_none() && i.final_script_sig.is_none()) + .any(|i| i.non_witness_utxo.is_none()) { return Err(Error::Signer(signer::SignerError::MissingNonWitnessUtxo)); } diff --git a/src/wallet/signer.rs b/src/wallet/signer.rs index 04f4d2ad..76ffc3d7 100644 --- a/src/wallet/signer.rs +++ b/src/wallet/signer.rs @@ -206,6 +206,12 @@ impl Signer for DescriptorXKey { return Err(SignerError::InputIndexOutOfRange); } + if psbt.inputs[input_index].final_script_sig.is_some() + || psbt.inputs[input_index].final_script_witness.is_some() + { + return Ok(()); + } + let (public_key, full_path) = match psbt.inputs[input_index] .bip32_derivation .iter() @@ -261,10 +267,16 @@ impl Signer for PrivateKey { secp: &SecpCtx, ) -> Result<(), SignerError> { let input_index = input_index.unwrap(); - if input_index >= psbt.inputs.len() { + if input_index >= psbt.inputs.len() || input_index >= psbt.global.unsigned_tx.input.len() { return Err(SignerError::InputIndexOutOfRange); } + if psbt.inputs[input_index].final_script_sig.is_some() + || psbt.inputs[input_index].final_script_witness.is_some() + { + return Ok(()); + } + let pubkey = self.public_key(&secp); if psbt.inputs[input_index].partial_sigs.contains_key(&pubkey) { return Ok(());