I am making an attempt to brush funds from an handle generated with the next descriptor:
tr(ff13a3311d3e14239bcbb9dfd5d304f4b57c32c0b35d313cb5255f93d7b2dc68,and_v(v:pk(b064bd37b71b7c39355f866e022287097757b05bb1790ecffc5de5fbf07cff69),sha256(a02e93b3dce9cb6031055905d94b04516819ef8fdae4c498777350469e6352dd)))#pygtzret
I’ve set the funds up on a neighborhood regtest utilizing nigiri to check this example and am utilizing rust-bitcoin to assemble the transaction. So far as I can inform, I’m setting up the witness for the enter appropriately. Nonetheless, when checking the output transaction utilizing testmempoolaccept, I regularly get mandatory-script-verify-flag-failed (Invalid Schnorr signature). The important thing I am utilizing seems to be proper. I noticed the remark below this reply suggesting it was the serialization of my signature though I am utilizing the default. Nonetheless, utilizing what now appears to be at bitcoin::taproot::Signature does not remedy my difficulty.
I am positive I am doing one thing subtly incorrect right here. So any nudge within the appropriate route can be tremendously appreciated. My program in its entirety is under:
use std::str::FromStr;
use anyhow::{Consequence, anyhow, bail};
use bitcoin::absolute::LockTime;
use bitcoin::consensus::Encodable;
use bitcoin::hashes::{Hash, sha256};
use bitcoin::hex::prelude::*;
use bitcoin::key::Keypair;
use bitcoin::secp256k1::{Message, Secp256k1};
use bitcoin::sighash::{Prevouts, SighashCache};
use bitcoin::transaction::Model;
use bitcoin::{
Deal with, Quantity, Community, OutPoint, TapSighashType, Transaction, TxIn, TxOut, Witness,
XOnlyPublicKey, taproot,
};
use miniscript::Descriptor;
const DESCRIPTOR: &str = "tr(ff13a3311d3e14239bcbb9dfd5d304f4b57c32c0b35d313cb5255f93d7b2dc68,and_v(v:pk(b064bd37b71b7c39355f866e022287097757b05bb1790ecffc5de5fbf07cff69),sha256(a02e93b3dce9cb6031055905d94b04516819ef8fdae4c498777350469e6352dd)))#pygtzret";
const PREIMAGE: &str = "366d2eff102fd290e7be0226f3dd746f4657bce85f08eeef55d0a7777d1a313f";
const PRIVATE_KEY: &str = "0301e0480b374b32851a9462db29dc19fe830a7f7d7a88b81612b9d42099c0ae";
fn foremost() -> Consequence<()> {
let Descriptor::Tr(taproot) = Descriptor::::from_str(DESCRIPTOR)? else {
bail!("not a taproot descriptor");
};
assert_eq!(
taproot.handle(Community::Regtest).to_string(),
"bcrt1prg82xfnv265zvl0mt6q2rr39mpmskrf2nyum4hqnmdwen3kzsn3slts4sh"
);
let whole = Quantity::from_str("0.0025 BTC")?;
let previous_output =
OutPoint::from_str("44afabb1b631d2cd265910dc6befef7e3962df486ad4a4a12f83668c58c9c22c:0")?;
let txin = TxIn {
previous_output,
..Default::default()
};
let to_address = Deal with::from_str("bcrt1q9th3z6mknxp60avl9xq8vac05q4xgvygx7r7jz")?
.require_network(Community::Regtest)?;
let txout = TxOut {
worth: Quantity::ZERO,
script_pubkey: to_address.script_pubkey(),
};
let outputs = vec![txout];
let mut tx = Transaction {
model: Model::TWO,
lock_time: LockTime::ZERO,
enter: vec![txin],
output: outputs.clone(),
};
// Primary 5 sats/vbyte charge
let charge = Quantity::from_sat(tx.vsize() as u64 * 5);
tx.output[0].worth = whole - charge;
let preimage: [u8; 32] = FromHex::from_hex(PREIMAGE)?;
let preimage_hash = sha256::Hash::hash(&preimage);
assert!(
preimage_hash.to_string()
== "a02e93b3dce9cb6031055905d94b04516819ef8fdae4c498777350469e6352dd"
);
let secp = Secp256k1::new();
let keypair = Keypair::from_seckey_str(&secp, PRIVATE_KEY)?;
let public_key = XOnlyPublicKey::from(keypair.public_key());
assert_eq!(
public_key.to_string(),
"b064bd37b71b7c39355f866e022287097757b05bb1790ecffc5de5fbf07cff69"
);
let spend_info = taproot.spend_info();
let leaf = spend_info
.leaves()
.subsequent()
.ok_or(anyhow!("taptree leaf lacking"))?;
let mut sighash_cache = SighashCache::new(&tx);
let prevouts = Prevouts::All(&outputs);
let sighash = sighash_cache.taproot_script_spend_signature_hash(
0,
&prevouts,
leaf.leaf_hash(),
TapSighashType::Default,
)?;
let message = Message::from_digest(*sighash.as_ref());
let signature = taproot::Signature {
signature: secp.sign_schnorr(&message, &keypair),
sighash_type: TapSighashType::Default,
};
let mut witness = Witness::new();
witness.push(preimage);
witness.push(signature.serialize());
witness.push(leaf.script());
witness.push(leaf.into_control_block().serialize());
tx.enter[0].witness = witness;
let mut bytes = Vec::new();
tx.consensus_encode(&mut bytes)?;
println!("{}", bytes.to_lower_hex_string());
Okay(())
}
