Use tap_key_origins in PSBTs to derive descriptors
This commit is contained in:
@@ -26,7 +26,8 @@ use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::consensus::encode::serialize;
|
||||
use bitcoin::util::{psbt, taproot};
|
||||
use bitcoin::{
|
||||
Address, EcdsaSighashType, Network, OutPoint, Script, Transaction, TxOut, Txid, Witness,
|
||||
Address, EcdsaSighashType, Network, OutPoint, SchnorrSighashType, Script, Transaction, TxOut,
|
||||
Txid, Witness,
|
||||
};
|
||||
|
||||
use miniscript::descriptor::DescriptorTrait;
|
||||
@@ -1013,23 +1014,27 @@ 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 but finalized one
|
||||
// If we aren't allowed to use `witness_utxo`, ensure that every input (except p2tr and finalized ones)
|
||||
// has the `non_witness_utxo`
|
||||
if !sign_options.trust_witness_utxo
|
||||
&& psbt
|
||||
.inputs
|
||||
.iter()
|
||||
.filter(|i| i.final_script_witness.is_none() && i.final_script_sig.is_none())
|
||||
.filter(|i| i.tap_internal_key.is_none() && i.tap_merkle_root.is_none())
|
||||
.any(|i| i.non_witness_utxo.is_none())
|
||||
{
|
||||
return Err(Error::Signer(signer::SignerError::MissingNonWitnessUtxo));
|
||||
}
|
||||
|
||||
// If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
|
||||
// is using `SIGHASH_ALL`
|
||||
// is using `SIGHASH_ALL` or `SIGHASH_DEFAULT` for taproot
|
||||
if !sign_options.allow_all_sighashes
|
||||
&& !psbt.inputs.iter().all(|i| {
|
||||
i.sighash_type.is_none() || i.sighash_type == Some(EcdsaSighashType::All.into())
|
||||
i.sighash_type.is_none()
|
||||
|| i.sighash_type == Some(EcdsaSighashType::All.into())
|
||||
|| i.sighash_type == Some(SchnorrSighashType::All.into())
|
||||
|| i.sighash_type == Some(SchnorrSighashType::Default.into())
|
||||
})
|
||||
{
|
||||
return Err(Error::Signer(signer::SignerError::NonStandardSighash));
|
||||
@@ -1854,7 +1859,7 @@ pub(crate) mod test {
|
||||
}
|
||||
|
||||
pub(crate) fn get_test_tr_with_taptree() -> &'static str {
|
||||
"tr(cPZzKuNmpuUjD1e8jUU4PVzy2b5LngbSip8mBsxf4e7rSFZVb4Uh,{pk(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
|
||||
"tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{pk(cPZzKuNmpuUjD1e8jUU4PVzy2b5LngbSip8mBsxf4e7rSFZVb4Uh),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
|
||||
}
|
||||
|
||||
pub(crate) fn get_test_tr_repeated_key() -> &'static str {
|
||||
@@ -4218,7 +4223,7 @@ pub(crate) mod test {
|
||||
let (wallet, _, _) = get_funded_wallet(get_test_tr_repeated_key());
|
||||
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
||||
|
||||
let path = vec![("rn4nre9c".to_string(), vec![0])]
|
||||
let path = vec![("u6ugnnck".to_string(), vec![0])]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
@@ -4290,7 +4295,7 @@ pub(crate) mod test {
|
||||
psbt.inputs[0].tap_merkle_root,
|
||||
Some(
|
||||
FromHex::from_hex(
|
||||
"d9ca24475ed2c4081ae181d8faa7461649961237bee7bc692f1de448d2d62031"
|
||||
"61f81509635053e52d9d1217545916167394490da2287aca4693606e43851986"
|
||||
)
|
||||
.unwrap()
|
||||
),
|
||||
@@ -4298,8 +4303,8 @@ pub(crate) mod test {
|
||||
assert_eq!(
|
||||
psbt.inputs[0].tap_scripts.clone().into_iter().collect::<Vec<_>>(),
|
||||
vec![
|
||||
(taproot::ControlBlock::from_slice(&Vec::<u8>::from_hex("c151494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef3452012958b0afded0ee3149dbf6710d349dc30e55ae30c319c30efbc79efe19cf70f46a8").unwrap()).unwrap(), (from_str!("208aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642ac"), taproot::LeafVersion::TapScript)),
|
||||
(taproot::ControlBlock::from_slice(&Vec::<u8>::from_hex("c151494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef345201295b9a515f7be31a70186e3c5937ee4a70cc4b4e1efe876c1d38e408222ffc64834").unwrap()).unwrap(), (from_str!("20b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55ac"), taproot::LeafVersion::TapScript)),
|
||||
(taproot::ControlBlock::from_slice(&Vec::<u8>::from_hex("c0b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55b7ef769a745e625ed4b9a4982a4dc08274c59187e73e6f07171108f455081cb2").unwrap()).unwrap(), (from_str!("208aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642ac"), taproot::LeafVersion::TapScript)),
|
||||
(taproot::ControlBlock::from_slice(&Vec::<u8>::from_hex("c0b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55b9a515f7be31a70186e3c5937ee4a70cc4b4e1efe876c1d38e408222ffc64834").unwrap()).unwrap(), (from_str!("2051494dc22e24a32fe9dcfbd7e85faf345fa1df296fb49d156e859ef345201295ac"), taproot::LeafVersion::TapScript)),
|
||||
],
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -4356,4 +4361,34 @@ pub(crate) mod test {
|
||||
"foreign_utxo should be in there"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_taproot_key_spend() {
|
||||
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
||||
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
||||
|
||||
let mut builder = wallet.build_tx();
|
||||
builder.add_recipient(addr.script_pubkey(), 25_000);
|
||||
let (mut psbt, _) = builder.finish().unwrap();
|
||||
|
||||
assert!(
|
||||
wallet.sign(&mut psbt, Default::default()).unwrap(),
|
||||
"Unable to finalize taproot key spend"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_taproot_script_spend() {
|
||||
let (wallet, _, _) = get_funded_wallet(get_test_tr_with_taptree());
|
||||
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
||||
|
||||
let mut builder = wallet.build_tx();
|
||||
builder.add_recipient(addr.script_pubkey(), 25_000);
|
||||
let (mut psbt, _) = builder.finish().unwrap();
|
||||
|
||||
assert!(
|
||||
wallet.sign(&mut psbt, Default::default()).unwrap(),
|
||||
"Unable to finalize taproot script spend"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user