taproot-tests: Add test coverage for tx signing
This commit is contained in:
parent
461397e590
commit
89cb425e69
@ -1855,7 +1855,7 @@ pub(crate) mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_test_tr_single_sig() -> &'static str {
|
pub(crate) fn get_test_tr_single_sig() -> &'static str {
|
||||||
"tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*)"
|
"tr(cNJmN3fH9DDbDt131fQNkVakkpzawJBSeybCUNmP1BovpmGQ45xG)"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_test_tr_with_taptree() -> &'static str {
|
pub(crate) fn get_test_tr_with_taptree() -> &'static str {
|
||||||
@ -1866,6 +1866,14 @@ pub(crate) mod test {
|
|||||||
"tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100)),and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(200))})"
|
"tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100)),and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(200))})"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_test_tr_single_sig_xprv() -> &'static str {
|
||||||
|
"tr(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*)"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_test_tr_with_taptree_xprv() -> &'static str {
|
||||||
|
"tr(b511bd5771e47ee27558b1765e87b541668304ec567721c7b880edc0a010da55,{pk(tprv8ZgxMBicQKsPdDArR4xSAECuVxeX1jwwSXR4ApKbkYgZiziDc4LdBy2WvJeGDfUSE4UT4hHhbgEwbdq8ajjUHiKDegkwrNU6V55CxcxonVN/*),pk(8aee2b8120a5f157f1223f72b5e62b825831a27a9fdf427db7cc697494d4a642)})"
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! assert_fee_rate {
|
macro_rules! assert_fee_rate {
|
||||||
($tx:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
|
($tx:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
|
||||||
let mut tx = $tx.clone();
|
let mut tx = $tx.clone();
|
||||||
@ -4185,7 +4193,7 @@ pub(crate) mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_taproot_psbt_populate_tap_key_origins() {
|
fn test_taproot_psbt_populate_tap_key_origins() {
|
||||||
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig_xprv());
|
||||||
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
||||||
|
|
||||||
let mut builder = wallet.build_tx();
|
let mut builder = wallet.build_tx();
|
||||||
@ -4322,6 +4330,52 @@ pub(crate) mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_taproot_sign_missing_witness_utxo() {
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
||||||
|
let addr = wallet.get_address(New).unwrap();
|
||||||
|
let mut builder = wallet.build_tx();
|
||||||
|
builder.drain_to(addr.script_pubkey()).drain_wallet();
|
||||||
|
let (mut psbt, _) = builder.finish().unwrap();
|
||||||
|
let witness_utxo = psbt.inputs[0].witness_utxo.take();
|
||||||
|
|
||||||
|
let result = wallet.sign(
|
||||||
|
&mut psbt,
|
||||||
|
SignOptions {
|
||||||
|
allow_all_sighashes: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result.is_err(),
|
||||||
|
"Signing should have failed because the witness_utxo is missing"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
result.unwrap_err(),
|
||||||
|
Error::Signer(SignerError::MissingWitnessUtxo)
|
||||||
|
),
|
||||||
|
"Signing failed with the wrong error type"
|
||||||
|
);
|
||||||
|
|
||||||
|
// restore the witness_utxo
|
||||||
|
psbt.inputs[0].witness_utxo = witness_utxo;
|
||||||
|
|
||||||
|
let result = wallet.sign(
|
||||||
|
&mut psbt,
|
||||||
|
SignOptions {
|
||||||
|
allow_all_sighashes: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(result.is_ok(), "Signing should have worked");
|
||||||
|
assert!(
|
||||||
|
result.unwrap(),
|
||||||
|
"Should finalize the input since we can produce signatures"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_taproot_foreign_utxo() {
|
fn test_taproot_foreign_utxo() {
|
||||||
let (wallet1, _, _) = get_funded_wallet(get_test_wpkh());
|
let (wallet1, _, _) = get_funded_wallet(get_test_wpkh());
|
||||||
@ -4362,9 +4416,7 @@ pub(crate) mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn test_spend_from_wallet(wallet: Wallet<AnyDatabase>) {
|
||||||
fn test_taproot_key_spend() {
|
|
||||||
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
|
||||||
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
||||||
|
|
||||||
let mut builder = wallet.build_tx();
|
let mut builder = wallet.build_tx();
|
||||||
@ -4373,22 +4425,143 @@ pub(crate) mod test {
|
|||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
wallet.sign(&mut psbt, Default::default()).unwrap(),
|
wallet.sign(&mut psbt, Default::default()).unwrap(),
|
||||||
"Unable to finalize taproot key spend"
|
"Unable to finalize tx"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_taproot_key_spend() {
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
||||||
|
test_spend_from_wallet(wallet);
|
||||||
|
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig_xprv());
|
||||||
|
test_spend_from_wallet(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_taproot_script_spend() {
|
fn test_taproot_script_spend() {
|
||||||
let (wallet, _, _) = get_funded_wallet(get_test_tr_with_taptree());
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_with_taptree());
|
||||||
|
test_spend_from_wallet(wallet);
|
||||||
|
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_with_taptree_xprv());
|
||||||
|
test_spend_from_wallet(wallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_taproot_sign_derive_index_from_psbt() {
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig_xprv());
|
||||||
|
|
||||||
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
let addr = wallet.get_address(AddressIndex::New).unwrap();
|
||||||
|
|
||||||
let mut builder = wallet.build_tx();
|
let mut builder = wallet.build_tx();
|
||||||
builder.add_recipient(addr.script_pubkey(), 25_000);
|
builder.add_recipient(addr.script_pubkey(), 25_000);
|
||||||
let (mut psbt, _) = builder.finish().unwrap();
|
let (mut psbt, _) = builder.finish().unwrap();
|
||||||
|
|
||||||
|
// re-create the wallet with an empty db
|
||||||
|
let wallet_empty = Wallet::new(
|
||||||
|
get_test_tr_single_sig_xprv(),
|
||||||
|
None,
|
||||||
|
Network::Regtest,
|
||||||
|
AnyDatabase::Memory(MemoryDatabase::new()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// signing with an empty db means that we will only look at the psbt to infer the
|
||||||
|
// derivation index
|
||||||
assert!(
|
assert!(
|
||||||
wallet.sign(&mut psbt, Default::default()).unwrap(),
|
wallet_empty.sign(&mut psbt, Default::default()).unwrap(),
|
||||||
"Unable to finalize taproot script spend"
|
"Unable to finalize tx"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_taproot_sign_explicit_sighash_all() {
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
||||||
|
let addr = wallet.get_address(New).unwrap();
|
||||||
|
let mut builder = wallet.build_tx();
|
||||||
|
builder
|
||||||
|
.drain_to(addr.script_pubkey())
|
||||||
|
.sighash(SchnorrSighashType::All.into())
|
||||||
|
.drain_wallet();
|
||||||
|
let (mut psbt, _) = builder.finish().unwrap();
|
||||||
|
|
||||||
|
let result = wallet.sign(&mut psbt, Default::default());
|
||||||
|
assert!(
|
||||||
|
result.is_ok(),
|
||||||
|
"Signing should work because SIGHASH_ALL is safe"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_taproot_sign_non_default_sighash() {
|
||||||
|
let sighash = SchnorrSighashType::NonePlusAnyoneCanPay;
|
||||||
|
|
||||||
|
let (wallet, _, _) = get_funded_wallet(get_test_tr_single_sig());
|
||||||
|
let addr = wallet.get_address(New).unwrap();
|
||||||
|
let mut builder = wallet.build_tx();
|
||||||
|
builder
|
||||||
|
.drain_to(addr.script_pubkey())
|
||||||
|
.sighash(sighash.into())
|
||||||
|
.drain_wallet();
|
||||||
|
let (mut psbt, _) = builder.finish().unwrap();
|
||||||
|
|
||||||
|
let witness_utxo = psbt.inputs[0].witness_utxo.take();
|
||||||
|
|
||||||
|
let result = wallet.sign(&mut psbt, Default::default());
|
||||||
|
assert!(
|
||||||
|
result.is_err(),
|
||||||
|
"Signing should have failed because the TX uses non-standard sighashes"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
result.unwrap_err(),
|
||||||
|
Error::Signer(SignerError::NonStandardSighash)
|
||||||
|
),
|
||||||
|
"Signing failed with the wrong error type"
|
||||||
|
);
|
||||||
|
|
||||||
|
// try again after opting-in
|
||||||
|
let result = wallet.sign(
|
||||||
|
&mut psbt,
|
||||||
|
SignOptions {
|
||||||
|
allow_all_sighashes: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
result.is_err(),
|
||||||
|
"Signing should have failed because the witness_utxo is missing"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
result.unwrap_err(),
|
||||||
|
Error::Signer(SignerError::MissingWitnessUtxo)
|
||||||
|
),
|
||||||
|
"Signing failed with the wrong error type"
|
||||||
|
);
|
||||||
|
|
||||||
|
// restore the witness_utxo
|
||||||
|
psbt.inputs[0].witness_utxo = witness_utxo;
|
||||||
|
|
||||||
|
let result = wallet.sign(
|
||||||
|
&mut psbt,
|
||||||
|
SignOptions {
|
||||||
|
allow_all_sighashes: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(result.is_ok(), "Signing should have worked");
|
||||||
|
assert!(
|
||||||
|
result.unwrap(),
|
||||||
|
"Should finalize the input since we can produce signatures"
|
||||||
|
);
|
||||||
|
|
||||||
|
let extracted = psbt.extract_tx();
|
||||||
|
assert_eq!(
|
||||||
|
*extracted.input[0].witness.to_vec()[0].last().unwrap(),
|
||||||
|
sighash as u8,
|
||||||
|
"The signature should have been made with the right sighash"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user