P2WSH-MultiSig 失敗並記錄了 OP_0 解決方法
根據Developer Guide - MultiSig and BIP147 when using OP_CHECKMULTISIG 中的註釋,需要在 scriptSig 前面加上 OP_0 以適應原始比特幣實現中的錯誤。
如果在見證程序中應用相同的解決方法,則腳本似乎無法通過 SCRIPT_FLAGS_VERIFY_NULLDUMMY 檢查。將 OP_0 添加到 MultiSig Witness Program 的正確方法是什麼?根據下面的範例添加 OP_0 會導致最終的堆棧元素包含 0x00 ,但檢查失敗。
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{} << OP_1 << ToByteVector(alicePubkey) << ToByteVector(bobPubKey) << OP_2 << OP_CHECKMULTISIG; uint256 redeemScriptHash{}; CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(redeemScriptHash.begin()); CScript scriptPubkey = CScript{} << OP_0 << 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{} << OP_0; std::vector<uint8_t> coinZeroBobSig{}; bobKey.Sign(coinZeroSigHash, coinZeroBobSig, 0); coinZeroBobSig.push_back(SIGHASH_ALL); CScriptWitness& witness = tx.vin[0].scriptWitness; witness.stack.push_back(ToByteVector(op0Script)); // <-- 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 << tx; std::cout << "Spending Tx: " << CTransaction(tx).ToString() << std::endl; bitcoinconsensus_error err; auto spendCoinZeroResult = bitcoinconsensus_verify_script_with_amount(scriptPubkey.data(), scriptPubkey.size(), amount, (const unsigned char*)&txSpendingStm[0], txSpendingStm.size(), 0, bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL, &err); std::cout << "Spend Coin Zero result: " << spendCoinZeroResult << ", error code " << err << std::endl;
一個簡單的解決方法是將空向量添加到見證程序堆棧而不是 OP_0,例如使用witness.stack.emplace_back()而不是witness.stack.push_back(ToByteVector(op0Script)),但這可能會導致還有其他問題嗎?
真正的要求是額外的輸入
OP_CHECKMULTISIG
為零(即:空字節數組)。對於非 SegWit 輸入,在堆棧上獲得這樣一個零的唯一規範方法是
OP_0
在scriptSig
.OP_0
只是將一個空字節數組推入堆棧。在 SegWit 輸入中,不再有建構該堆棧的腳本。相反,您直接指定堆棧。結果,不僅是推薦的方法,而且唯一的方法是將空數組添加到
scriptWitness
.
對於在核心測試框架中工作的任何人,我使用此程式碼創建了一個 2 of 2 多重簽名見證堆棧,其中一個空虛擬對像作為堆棧上的第一個元素:
見證程序 = CScript([OP_2, pubkey1, pubkey2, OP_2,OP_CHECKMULTISIG]
tx.wit.vtxinwit[0].scriptWitness.stack = [b’’, sig1, sig2, witness_program]
我不是 Python 程序員,所以我花了一些時間才發現我需要的只是 b’’ 來創建一個空字節數組元素。