diff --git a/src/script/interpreter.h b/src/script/interpreter.h --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -23,6 +23,7 @@ SIGHASH_ALL = 1, SIGHASH_NONE = 2, SIGHASH_SINGLE = 3, + SIGHASH_SPENDANYOUTPUT = 0x20, SIGHASH_FORKID = 0x40, SIGHASH_ANYONECANPAY = 0x80, }; @@ -115,6 +116,10 @@ // Do we accept signature using SIGHASH_FORKID // SCRIPT_ENABLE_SIGHASH_FORKID = (1U << 16), + + // Do we accept signature using SIGHASH_SPENDANYOUTPUT + // + SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT = (1U << 17), }; bool CheckSignatureEncoding(const std::vector &vchSig, uint32_t flags, @@ -122,7 +127,7 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, uint32_t nHashType, - const Amount &amount, + const Amount &amount, const CScript &scriptPubKey, const PrecomputedTransactionData *cache = nullptr, uint32_t flags = SCRIPT_ENABLE_SIGHASH_FORKID); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -209,7 +209,8 @@ return false; } uint32_t nHashType = - GetHashType(vchSig) & ~(SIGHASH_ANYONECANPAY | SIGHASH_FORKID); + GetHashType(vchSig) & + ~(SIGHASH_SPENDANYOUTPUT | SIGHASH_ANYONECANPAY | SIGHASH_FORKID); if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) { return false; } @@ -238,6 +239,23 @@ if (!IsDefinedHashtypeSignature(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); } + + bool usesAnyOneCanPay = GetHashType(vchSig) & SIGHASH_ANYONECANPAY; + bool usesSpendAnyOutput = GetHashType(vchSig) & SIGHASH_SPENDANYOUTPUT; + bool spendAnyOutputEnabled = + flags & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT; + + if (!spendAnyOutputEnabled && usesSpendAnyOutput) { + return set_error(serror, SCRIPT_ERR_SPENDANYOUTPUT_NOT_ENABLED); + } + + // spend-any-output MUST use any-one-can-pay (otherwise, you'd need all + // pubkeys) + if (usesSpendAnyOutput && !usesAnyOneCanPay) { + return set_error(serror, + SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY); + } + bool usesForkId = GetHashType(vchSig) & SIGHASH_FORKID; bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; if (!forkIdEnabled && usesForkId) { @@ -1350,7 +1368,7 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, uint32_t nHashType, - const Amount &amount, + const Amount &amount, const CScript &scriptPubKey, const PrecomputedTransactionData *cache, uint32_t flags) { if ((nHashType & SIGHASH_FORKID) && (flags & SCRIPT_ENABLE_SIGHASH_FORKID)) { @@ -1384,12 +1402,24 @@ // Input prevouts/nSequence (none/all, depending on flags) ss << hashPrevouts; ss << hashSequence; - // The input being signed (replacing the scriptSig with scriptCode + - // amount). The prevout may already be contained in hashPrevout, and the - // nSequence may already be contain in hashSequence. - ss << txTo.vin[nIn].prevout; - ss << static_cast(scriptCode); - ss << amount.GetSatoshis(); + + if ((nHashType & SIGHASH_SPENDANYOUTPUT) && + (flags & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)) { + // SPENDANYOUTPUT includes the scriptcode and pubkey, but not the + // amount and prevout + ss << static_cast(scriptPubKey); + ss << static_cast(scriptCode); + + } else { + // The input being signed (replacing the scriptSig with scriptCode + + // amount). The prevout may already be contained in hashPrevout, and + // the + // nSequence may already be contain in hashSequence. + ss << txTo.vin[nIn].prevout; + ss << static_cast(scriptCode); + ss << amount.GetSatoshis(); + } + ss << txTo.vin[nIn].nSequence; // Outputs (none/one/all, depending on flags) ss << hashOutputs; @@ -1449,7 +1479,7 @@ vchSig.pop_back(); uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, - this->txdata, flags); + CScript(vchPubKey), this->txdata, flags); if (!VerifySignature(vchSig, pubkey, sighash)) { return false; diff --git a/src/script/script_error.h b/src/script/script_error.h --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -61,6 +61,10 @@ SCRIPT_ERR_ILLEGAL_FORKID, SCRIPT_ERR_MUST_USE_FORKID, + /* spend-any-output flags */ + SCRIPT_ERR_SPENDANYOUTPUT_NOT_ENABLED, + SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY, + SCRIPT_ERR_ERROR_COUNT } ScriptError; diff --git a/src/script/sign.cpp b/src/script/sign.cpp --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -28,7 +28,8 @@ return false; } - uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount); + uint256 hash = + SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, CScript()); if (!key.Sign(hash, vchSig)) { return false; } diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -21,8 +21,8 @@ CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, int whichIn) { - uint256 hash = - SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0); + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, + SIGHASH_ALL, 0, CScript()); CScript result; // CHECKMULTISIG bug workaround diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -273,9 +273,9 @@ CScript scriptPubKey = script; if (P2SH) { redeemscript = scriptPubKey; - scriptPubKey = CScript() << OP_HASH160 - << ToByteVector(CScriptID(redeemscript)) - << OP_EQUAL; + scriptPubKey = CScript() + << OP_HASH160 + << ToByteVector(CScriptID(redeemscript)) << OP_EQUAL; } creditTx = MakeTransactionRef(BuildCreditingTransaction(scriptPubKey, nValue)); @@ -312,7 +312,8 @@ TestBuilder &PushSig(const CKey &key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, CAmount amount = 0) { - uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount); + uint256 hash = + SignatureHash(script, spendTx, 0, nHashType, amount, CScript()); std::vector vchSig, r, s; uint32_t iter = 0; do { @@ -582,8 +583,8 @@ .DamagePush(10) .ScriptError(SCRIPT_ERR_SIG_DER)); tests.push_back( - TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG - << OP_NOT, + TestBuilder(CScript() + << ToByteVector(keys.pubkey2C) << OP_CHECKSIG << OP_NOT, "P2PK NOT with too much R padding but no DERSIG", 0) .PushSig(keys.key2, SIGHASH_ALL, 31, 32) .EditPush(1, "43021F", "44022000") @@ -814,8 +815,8 @@ .PushSig(keys.key0, SIGHASH_ALL) .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); tests.push_back( - TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKSIG - << OP_NOT, + TestBuilder(CScript() + << ToByteVector(keys.pubkey0H) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0) .PushSig(keys.key0, SIGHASH_ALL) .DamagePush(10)); @@ -867,8 +868,8 @@ .PushSig(keys.key1, 5) .DamagePush(10)); tests.push_back( - TestBuilder(CScript() << ToByteVector(keys.pubkey1) << OP_CHECKSIG - << OP_NOT, + TestBuilder(CScript() + << ToByteVector(keys.pubkey1) << OP_CHECKSIG << OP_NOT, "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC) .PushSig(keys.key1, 5) @@ -1057,8 +1058,8 @@ std::string str = JSONPrettyPrint(test.GetJSON()); #ifndef UPDATE_JSON_TESTS if (tests_set.count(str) == 0) { - BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + - test.GetComment()); + BOOST_CHECK_MESSAGE( + false, "Missing auto script_valid test: " + test.GetComment()); } #endif strGen += str + ",\n"; @@ -1151,7 +1152,8 @@ CScript sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0); + uint256 hash = + SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, CScript()); CScript result; // @@ -1422,15 +1424,18 @@ // A couple of partially-signed versions: std::vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0); + uint256 hash1 = + SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, CScript()); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0); + uint256 hash2 = + SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, CScript()); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0); + uint256 hash3 = + SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, CScript()); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -145,7 +145,7 @@ uint256 sh, sho; sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); - sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0); + sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, CScript()); #if defined(PRINT_SIGHASH_JSON) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << txTo; @@ -212,9 +212,217 @@ continue; } - sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0); + sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, CScript()); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } +// Check the variance/invariance of different input fields under signature +// hashing +BOOST_AUTO_TEST_CASE(sighash_invariance) { + + // tx with 2 inputs + CMutableTransaction tx1; + tx1.vin.resize(2); + tx1.vin[0].prevout = COutPoint(GetRandHash(), insecure_rand()); + tx1.vin[0].nSequence = insecure_rand(); + RandomScript(tx1.vin[0].scriptSig); + tx1.vin[1].prevout = COutPoint(GetRandHash(), insecure_rand()); + tx1.vin[1].nSequence = insecure_rand(); + RandomScript(tx1.vin[1].scriptSig); + + CScript pubKey1, pubKey2; + RandomScript(pubKey1); + RandomScript(pubKey2); + + // all valid hashtypes + std::vector sighashtypes; + for (int n = SIGHASH_ALL; n <= SIGHASH_SINGLE; n++) { + sighashtypes.push_back(n | SIGHASH_FORKID); + sighashtypes.push_back(n | SIGHASH_FORKID | SIGHASH_ANYONECANPAY); + sighashtypes.push_back(n | SIGHASH_FORKID | SIGHASH_ANYONECANPAY | + SIGHASH_SPENDANYOUTPUT); + } + const uint32_t flags[] = {SCRIPT_ENABLE_SIGHASH_FORKID, + SCRIPT_ENABLE_SIGHASH_FORKID | + SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT}; + + // we'll test invariance through these sighashes and flags + for (uint8_t hashtype : sighashtypes) { + + for (uint32_t flag : flags) { + + bool expectedInvariant; + uint256 h1, h2; + CMutableTransaction tx2 = tx1; + + // Amount invariance + expectedInvariant = (hashtype & SIGHASH_SPENDANYOUTPUT) && + (flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT); + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 132, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // PubKey invariance + expectedInvariant = + !((hashtype & SIGHASH_SPENDANYOUTPUT) && + (flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)); + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey2, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // THIS prevout.hash + tx2 = tx1; + tx2.vin[1].prevout.hash = GetRandHash(); + expectedInvariant = (hashtype & SIGHASH_SPENDANYOUTPUT) && + (flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT); + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // THIS prevout.n + tx2 = tx1; + tx2.vin[1].prevout.n += 1; + expectedInvariant = (hashtype & SIGHASH_SPENDANYOUTPUT) && + (flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT); + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // THIS prevout.sequence + tx2 = tx1; + tx2.vin[1].nSequence += 1; + expectedInvariant = false; + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // OTHER prevout.hash + tx2 = tx1; + tx2.vin[0].prevout.hash = GetRandHash(); + expectedInvariant = + ((hashtype & SIGHASH_SPENDANYOUTPUT) && + (flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)) || + (hashtype & SIGHASH_ANYONECANPAY); + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // OTHER prevout.n + tx2 = tx1; + tx2.vin[0].prevout.n += 1; + expectedInvariant = + ((hashtype & SIGHASH_SPENDANYOUTPUT) && + (flag & SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT)) || + (hashtype & SIGHASH_ANYONECANPAY); + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + + // OTHER prevout.sequence + tx2 = tx1; + tx2.vin[0].nSequence += 1; + expectedInvariant = (hashtype & SIGHASH_ANYONECANPAY) || + (hashtype & 0x1f) == SIGHASH_NONE || + (hashtype & 0x1f) == SIGHASH_SINGLE; + h1 = SignatureHash(tx1.vin[0].scriptSig, tx1, 1, hashtype, 133, + pubKey1, nullptr, flag); + h2 = SignatureHash(tx2.vin[0].scriptSig, tx2, 1, hashtype, 133, + pubKey1, nullptr, flag); + BOOST_CHECK((h1 == h2) == expectedInvariant); + } + } +} + +static void TestCheckSignatureEncoding(std::vector sig, + uint8_t hashtype, uint32_t flags, + ScriptError expected_error) { + sig.back() = hashtype; + ScriptError err = SCRIPT_ERR_OK; + const bool result = CheckSignatureEncoding(sig, flags, &err); + BOOST_CHECK(result == (expected_error == SCRIPT_ERR_OK)); + BOOST_CHECK_EQUAL(err, expected_error); +} + +// Check the allowed sighash flags under different verify flags +BOOST_AUTO_TEST_CASE(sighash_flags_allowed) { + + CKey key; + std::vector sig; + + // create a random valid signature + key.MakeNewKey(false); + BOOST_CHECK(key.Sign(GetRandHash(), sig, insecure_rand())); + + sig.push_back(SIGHASH_ALL); + TestCheckSignatureEncoding(sig, SIGHASH_ALL, 0, SCRIPT_ERR_OK); + + TestCheckSignatureEncoding(sig, SIGHASH_ALL, SCRIPT_VERIFY_STRICTENC, + SCRIPT_ERR_OK); + + // test forkid + TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_FORKID, + SCRIPT_VERIFY_STRICTENC, + SCRIPT_ERR_ILLEGAL_FORKID); + + TestCheckSignatureEncoding( + sig, SIGHASH_ALL | SIGHASH_FORKID, + SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_FORKID, SCRIPT_ERR_OK); + + TestCheckSignatureEncoding(sig, SIGHASH_ALL, + SCRIPT_VERIFY_STRICTENC | + SCRIPT_ENABLE_SIGHASH_FORKID, + SCRIPT_ERR_MUST_USE_FORKID); + + TestCheckSignatureEncoding(sig, SIGHASH_ALL, SCRIPT_ENABLE_SIGHASH_FORKID, + SCRIPT_ERR_OK); // No checks without strictenc + + // test spendanyoutput + TestCheckSignatureEncoding(sig, SIGHASH_SPENDANYOUTPUT | SIGHASH_SINGLE, + SCRIPT_VERIFY_STRICTENC, + SCRIPT_ERR_SPENDANYOUTPUT_NOT_ENABLED); + + TestCheckSignatureEncoding(sig, SIGHASH_SPENDANYOUTPUT | SIGHASH_SINGLE, + SCRIPT_VERIFY_STRICTENC | + SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, + SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY); + + TestCheckSignatureEncoding(sig, SIGHASH_ALL, + SCRIPT_VERIFY_STRICTENC | + SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, + SCRIPT_ERR_OK); // spend-any-output not mandatory + + // test combination + TestCheckSignatureEncoding( + sig, SIGHASH_ALL | SIGHASH_ANYONECANPAY | SIGHASH_SPENDANYOUTPUT, + SCRIPT_VERIFY_STRICTENC | SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, + SCRIPT_ERR_OK); + + TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_ANYONECANPAY, + SCRIPT_VERIFY_STRICTENC | + SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, + SCRIPT_ERR_OK); + + TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_SPENDANYOUTPUT, + SCRIPT_VERIFY_STRICTENC | + SCRIPT_ENABLE_SIGHASH_SPENDANYOUTPUT, + SCRIPT_ERR_SPENDANYOUTPUT_WITHOUT_ANYONECANPAY); + TestCheckSignatureEncoding(sig, SIGHASH_ALL | SIGHASH_SPENDANYOUTPUT, 0, + SCRIPT_ERR_OK); // No checks without strictenc +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -54,7 +54,7 @@ std::vector vchSig; uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL | SIGHASH_FORKID, - coinbaseTxns[0].vout[0].nValue); + coinbaseTxns[0].vout[0].nValue, CScript()); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); spends[i].vin[0].scriptSig << vchSig; @@ -192,7 +192,7 @@ std::vector vchSig; uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL | SIGHASH_FORKID, - coinbaseTxns[0].vout[0].nValue); + coinbaseTxns[0].vout[0].nValue, CScript()); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); // Negate S to ensure the signature is valid but non standard. NegateSignatureS(vchSig); @@ -276,7 +276,7 @@ std::vector vchSig; uint256 hash = SignatureHash( spend_tx.vout[1].scriptPubKey, invalid_with_cltv_tx, 0, - SIGHASH_ALL | SIGHASH_FORKID, spend_tx.vout[1].nValue); + SIGHASH_ALL | SIGHASH_FORKID, spend_tx.vout[1].nValue, CScript()); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; @@ -311,7 +311,7 @@ std::vector vchSig; uint256 hash = SignatureHash( spend_tx.vout[2].scriptPubKey, invalid_with_csv_tx, 0, - SIGHASH_ALL | SIGHASH_FORKID, spend_tx.vout[2].nValue); + SIGHASH_ALL | SIGHASH_FORKID, spend_tx.vout[2].nValue, CScript()); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back(uint8_t(SIGHASH_ALL | SIGHASH_FORKID)); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101;