2

I'm trying to broadcast a transaction to my RPC provider:

curl https://my-quicknode-rpc-provider/ \
    -X POST \
    -H "Content-Type: application/json" \
    --data '{"method": "sendrawtransaction", "params": ["02000000000101cc0fc61320a04525c8dabf30241fe9a64b3f8c28ebf61a9700b8a57a76306bac0000000000ffffffff01ea100000000000002251208dace6f04076ca1ea4eb168dcdad6ad61f695ca1c16a3df6b9586cdca1c71db8034025871482b0c7bb14b8c72d5ac44ce069991505a1aeca1c4de5b8d1857831ca87e6f43a3e784c755595574c798892ecf58c7ae525bccba441cdf46862dd405bb47e208dace6f04076ca1ea4eb168dcdad6ad61f695ca1c16a3df6b9586cdca1c71db8ac0063036f7264010118746578742f706c61696e3b636861727365743d7574662d3800387b2270223a226272632d3230222c226f70223a227472616e73666572222c227469636b223a2270657065222c22616d74223a22313030227d6821c18dace6f04076ca1ea4eb168dcdad6ad61f695ca1c16a3df6b9586cdca1c71db800000000"]}'

but I keep getting this error response from the RPC:

{"result":null,"error":{"code":-26,"message":"non-mandatory-script-verify-flag (Witness program hash mismatch)"},"id":null}

I've verified multiple times that I'm signing with the correct private key. On top of that, this occurs when broadcasting to the network, not during signing my PSBT inputs so I've been having trouble debugging.

For some context, I'm trying to attach a Taproot script to my input UTXO. Here is a code snippet of what I'm doing:

const hexData = Buffer.from(
  `{"p":"brc-20","op":"transfer","tick":"${tick}","amt":"${amount.toString()}"}`
).toString("hex");
const publicKeyHex = toXOnly(tweakedSigner.publicKey).toString("hex");
let inscribeLockScript = bitcoin.script.fromASM(
  `${publicKeyHex} OP_CHECKSIG OP_0 OP_IF ${Buffer.from("ord").toString(
    "hex"
  )} OP_1 ${Buffer.from("text/plain;charset=utf-8").toString(
    "hex"
  )} OP_0 ${splitByNChars(hexData, 1040).join(" ")} OP_ENDIF`
);
inscribeLockScript = Buffer.from(
  inscribeLockScript.toString("hex").replace("6f726451", "6f72640101"),
  "hex"
);

const scriptTree: Taptree = {
  output: inscribeLockScript,
};

const inscribeLockRedeem = {
  output: inscribeLockScript,
  redeemVersion: 192,
};

const inscribeP2tr = bitcoin.payments.p2tr({
  internalPubkey: toXOnly(tweakedSigner.publicKey),
  scriptTree,
  network: bitcoin.networks.bitcoin,
  redeem: inscribeLockRedeem,
});

const tapLeafScript = {
  leafVersion: inscribeLockRedeem.redeemVersion!,
  script: inscribeLockRedeem.output || Buffer.from(""),
  controlBlock: inscribeP2tr.witness![inscribeP2tr.witness!.length - 1],
};

psbt.addInput({
  hash: utxo.hash,
  index: utxo.index,
  witnessUtxo: {
    script: inscribeP2tr.output!,
    value: utxo.value,
  },
  tapInternalKey: toXOnly(tweakedSigner.publicKey),
  tapLeafScript: [tapLeafScript],
});

I'm fairly new to this so any help would be appreciated!

1 Answer 1

3

"Witness program hash mismatch" in a Taproot script path spend means the Taproot commitment wasn't successfully verified, in other words the internal key tweaked with the taptweak hash (constructed from the script, leaf version, merkle tree hashing partners and the internal key itself) didn't match the taproot output key (see BIP341).

This could be for many reasons, but here are the more likely ones:

  • You're saying you're "trying to attach a Taproot script" to your UTXO, but you can't attach a script to which the previous output doesn't commit. You need to know before constructing the output what scripts (and their positions in the script tree) will be allowed when spending.
  • The variable name tweakedSigner suggests it is the internal private/public key pair tweaked with the taptweak hash, which is something you would use for key path spending. For script path spending you need the untweaked internal key.
1
  • Awesome, thank you for clarifying!
    – Sherwin Li
    Oct 9, 2023 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.