Hi everyone!
I'm trying to create a transaction programmatically (in Rust) that spends an output associated with a P2WPKH address. This is the relevant code snippet:
fn sign_transaction<SignFun>(
own_public_key: &[u8],
own_address: &Address,
own_utxos: &[Utxo],
mut transaction: Transaction,
key_name: String,
derivation_path: Vec<Vec<u8>>,
signer: SignFun,
) -> Transaction
where
SignFun: Fn(String, Vec<Vec<u8>>, Vec<u8>) -> Fut,
{
let txclone = transaction.clone();
let mut hash_cache = sighash::SighashCache::new(&txclone);
for (index, input) in transaction.input.iter_mut().enumerate() {
let value = get_value(input, own_utxos); // Look up the value by finding the corresponding UTXO
let sighash = hash_cache
.segwit_signature_hash(index, &own_address.script_pubkey(), value, SIG_HASH_TYPE)
.expect("Creating the segwit signature hash failed.");
let signature = signer(key_name.clone(), derivation_path.clone(), sighash.to_vec()).await;
// Convert signature to DER.
let der_signature = sec1_to_der(signature);
let mut sig_with_hashtype = der_signature;
sig_with_hashtype.push(SIG_HASH_TYPE.to_u32() as u8);
let witness_bytes = vec![sig_with_hashtype, own_public_key.to_vec()];
input.witness = Witness::from_vec(witness_bytes);
}
transaction
}
SIG_HASH_TYPE is simply EcdsaSighashType::All.
I get the following serialized transaction:
010000000001016e97eae878274b6663923994bf7622c72ed41ce71d9d5d4091905378eeb0e5fa0000000000ffffffff0200e1f505000000001976a9148f7918f50cfd908ff82294a12c926f0fc52b0d1d88ac3e160d8f000000001600148be949ae15ee4b5da9af0ce2bf8d3f3c43c582da02483045022100999dd2a10b036d6b599d7d6b205f62b4dd14aca4b4c0d12224c0daa35c34bbea022025702dd922f94bd5b9444f798ab4ad7bcdbdd53568d7a45c6086a3e6f81b20d4012103366e75877b80252ff39e76229fe6d88d14e1150256bfdd27e7726b6b2cb23c0200000000
When trying to submit it, I get the following error:
error code: -26
error message:
non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)
When decoding the transaction (using decoderawtransaction), everything looks okay as far as I can tell but I might be missing something.
Note that I adapted the code from the following
working example that signs a P2PKH input:
...
let sighash = txclone.signature_hash(index, &own_address.script_pubkey(), SIG_HASH_TYPE.to_u32());
let signature = signer(key_name.clone(), derivation_path.clone(), sighash.to_vec()).await;
// Convert signature to DER.
let der_signature = sec1_to_der(signature);
let mut sig_with_hashtype = der_signature;
sig_with_hashtype.push(SIG_HASH_TYPE.to_u32() as u8);
input.script_sig = Builder::new()
.push_slice(sig_with_hashtype.as_slice())
.push_slice(own_public_key)
.into_script();
input.witness.clear();
Can anybody spot a mistake in the code? Am I signing the wrong data?
If you need additional information, just let me know.
Thanks!