P2WSH-MultiSig fails with documented OP_0 workaround As per the note at Developer Guide - MultiSig and BIP147 when using OP_CHECKMULTISIG an OP_0 needs to be prefaced to the scriptSig to accommodate a bug in the original Bitcoin implementation.

If the same workaround is applied in a Witness Program the script seems to fail the SCRIPT_FLAGS_VERIFY_NULLDUMMY check. What's the correct way to add the OP_0 to a MultiSig Witness Program? Adding an OP_0 as per the sample below results in a final stack element containing 0x00 which fails the check. 



auto aliceKeyData = ParseHex("bbc27228ddcb9209d7fd6f36b02f7dfa6252af40bb2f1cbc7a557da8027ff866");
CKey aliceKey{};
aliceKey.Set(aliceKeyData.begin(), aliceKeyData.end(), true);
CPubKey alicePubkey = aliceKey.GetPubKey();

auto keyData = ParseHex("619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9");
CKey bobKey{};
bobKey.Set(keyData.begin(), keyData.end(), true);
CPubKey bobPubKey = bobKey.GetPubKey();

CScript redeemScript = CScript{} &lt;&lt; OP_1 &lt;&lt; ToByteVector(alicePubkey) &lt;&lt; ToByteVector(bobPubKey) &lt;&lt; OP_2 &lt;&lt; OP_CHECKMULTISIG;
uint256 redeemScriptHash{};
CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(redeemScriptHash.begin());
CScript scriptPubkey = CScript{} &lt;&lt; OP_0 &lt;&lt; ToByteVector(redeemScriptHash); // P2WSH

int amount = 600000000;

CScript scriptSig;
CScriptWitness scriptWitness;
CMutableTransaction tx = BuildFundingTransaction(scriptSig, scriptWitness, amount);

uint256 coinZeroSigHash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0);

CScript op0Script = CScript{} &lt;&lt; OP_0;

std::vector&lt;uint8_t&gt; coinZeroBobSig{};
bobKey.Sign(coinZeroSigHash, coinZeroBobSig, 0);
coinZeroBobSig.push_back(SIGHASH_ALL);

CScriptWitness&amp; witness = tx.vin[0].scriptWitness;
witness.stack.push_back(ToByteVector(op0Script));  // &lt;-- Results in 0x00 stack element in Witness Program.
witness.stack.push_back(ToByteVector(coinZeroBobSig));
witness.stack.push_back(ToByteVector(redeemScript));

CDataStream txSpendingStm(SER_NETWORK, PROTOCOL_VERSION);
txSpendingStm &lt;&lt; tx;
std::cout &lt;&lt; "Spending Tx: " &lt;&lt; CTransaction(tx).ToString() &lt;&lt; std::endl;

bitcoinconsensus_error err;
auto spendCoinZeroResult = bitcoinconsensus_verify_script_with_amount(scriptPubkey.data(), scriptPubkey.size(), amount, (const unsigned char*)&amp;txSpendingStm[0], txSpendingStm.size(), 0, bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL, &amp;err);
std::cout &lt;&lt; "Spend Coin Zero result: " &lt;&lt; spendCoinZeroResult &lt;&lt; ", error code " &lt;&lt; err &lt;&lt; std::endl;


One trivial fix is to add an empty vector to the Witness Program stack rather than an OP_0, such as by using witness.stack.emplace_back() instead of witness.stack.push_back(ToByteVector(op0Script)), but is that likely to cause any other issues?
The real requirement is that the extra input to OP_CHECKMULTISIG is a zero (that is: the empty byte array).

For non-SegWit inputs, the only canonical way to get such a zero on the stack is by including an OP_0 in the scriptSig. OP_0 just pushes an empty byte array onto the stack.

In SegWit inputs there is no longer a script to build that stack. Instead, you specify the stack directly. As a result, not just the recommended way, but the only way is adding an empty array to the scriptWitness.