From be12669982b86313e76500908400bcc98f8c2a97 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Feb 2018 01:49:42 +0000 Subject: [PATCH] Add consensus branch ID parameter to SignatureHash, remove SigVersion parameter We do not need to be able to calculate multiple SignatureHash versions for a single transaction format; instead, we use the transaction format to determine the SigVersion. The consensus branch ID *does* need to be passed in from the outside, as only the caller knows the context in which the SignatureHash is being calculated (ie. mempool acceptance vs. block validation). JoinSplit signature verification has been moved into ContextualCheckTransaction, where the consensus branch ID can be obtained. The argument to the sign command for zcash-tx has been modified to take a height in addition to the optional sigtype flags. --- src/bitcoin-tx.cpp | 33 +++- src/gtest/test_checktransaction.cpp | 14 +- src/gtest/test_validation.cpp | 4 +- src/main.cpp | 77 ++++----- src/main.h | 13 +- src/miner.cpp | 4 +- src/rpcrawtransaction.cpp | 10 +- src/script/interpreter.cpp | 33 ++-- src/script/interpreter.h | 14 +- src/script/sign.cpp | 59 +++---- src/script/sign.h | 14 +- src/script/zcashconsensus.cpp | 4 +- src/test/DoS_tests.cpp | 7 +- src/test/data/bitcoin-util-test.json | 2 +- src/test/multisig_tests.cpp | 36 +++-- src/test/script_P2SH_tests.cpp | 28 ++-- src/test/script_tests.cpp | 152 ++++++++++-------- src/test/sighash_tests.cpp | 21 ++- src/test/transaction_tests.cpp | 29 ++-- src/utiltest.cpp | 10 +- src/wallet/asyncrpcoperation_sendmany.cpp | 9 +- src/wallet/asyncrpcoperation_sendmany.h | 1 + .../asyncrpcoperation_shieldcoinbase.cpp | 6 +- src/wallet/rpcwallet.cpp | 4 +- src/wallet/wallet.cpp | 8 +- src/zcbenchmarks.cpp | 5 +- 26 files changed, 360 insertions(+), 237 deletions(-) diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 72efd2282..710d0082f 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -6,6 +6,7 @@ #include "clientversion.h" #include "coins.h" #include "consensus/consensus.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "keystore.h" #include "primitives/transaction.h" @@ -70,7 +71,7 @@ static bool AppInitRawTx(int argc, char* argv[]) strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N")); strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX")); strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX")); - strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " + + strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " + _("This command requires JSON registers:") + _("prevtxs=JSON object") + ", " + _("privatekeys=JSON object") + ". " + @@ -334,10 +335,27 @@ static CAmount AmountFromValue(const UniValue& value) return amount; } -static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) +static void MutateTxSign(CMutableTransaction& tx, const string& strInput) { - int nHashType = SIGHASH_ALL; + // separate HEIGHT:SIGHASH-FLAGS in string + size_t pos = strInput.find(':'); + if ((pos == 0) || + (pos == (strInput.size() - 1))) + throw runtime_error("Invalid sighash flag separator"); + // extract and validate HEIGHT + string strHeight = strInput.substr(0, pos); + int nHeight = atoi(strHeight); + if (nHeight <= 0) { + throw runtime_error("invalid height"); + } + + // extract and validate SIGHASH-FLAGS + int nHashType = SIGHASH_ALL; + string flagStr; + if (pos != string::npos) { + flagStr = strInput.substr(pos + 1, string::npos); + } if (flagStr.size() > 0) if (!findSighashFlags(nHashType, flagStr)) throw runtime_error("unknown sighash flag/sign option"); @@ -427,6 +445,9 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Grab the consensus branch ID for the given height + auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); + // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; @@ -441,14 +462,14 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); // ... and merge in other signatures: BOOST_FOREACH(const CTransaction& txv, txVariants) - sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i)); + sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); UpdateTransaction(mergedTx, i, sigdata); - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount))) + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId)) fComplete = false; } diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index ec7f45342..bec9cdd6f 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -45,6 +45,8 @@ public: CMutableTransaction GetValidTransaction() { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + CMutableTransaction mtx; mtx.vin.resize(2); mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); @@ -74,7 +76,7 @@ CMutableTransaction GetValidTransaction() { // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); if (dataToBeSigned == one) { throw std::runtime_error("SignatureHash failed"); } @@ -352,23 +354,27 @@ TEST(checktransaction_tests, bad_txns_prevout_null) { } TEST(checktransaction_tests, bad_txns_invalid_joinsplit_signature) { + SelectParams(CBaseChainParams::REGTEST); + CMutableTransaction mtx = GetValidTransaction(); mtx.joinSplitSig[0] += 1; CTransaction tx(mtx); MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - CheckTransactionWithoutProofVerification(tx, state); + ContextualCheckTransaction(tx, state, 0, 100); } TEST(checktransaction_tests, non_canonical_ed25519_signature) { + SelectParams(CBaseChainParams::REGTEST); + CMutableTransaction mtx = GetValidTransaction(); // Check that the signature is valid before we add L { CTransaction tx(mtx); MockCValidationState state; - EXPECT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + EXPECT_TRUE(ContextualCheckTransaction(tx, state, 0, 100)); } // Copied from libsodium/crypto_sign/ed25519/ref10/open.c @@ -389,7 +395,7 @@ TEST(checktransaction_tests, non_canonical_ed25519_signature) { MockCValidationState state; EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false)).Times(1); - CheckTransactionWithoutProofVerification(tx, state); + ContextualCheckTransaction(tx, state, 0, 100); } TEST(checktransaction_tests, OverwinterConstructors) { diff --git a/src/gtest/test_validation.cpp b/src/gtest/test_validation.cpp index 508616e8a..db382e96b 100644 --- a/src/gtest/test_validation.cpp +++ b/src/gtest/test_validation.cpp @@ -1,5 +1,6 @@ #include +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "main.h" #include "utiltest.h" @@ -70,9 +71,10 @@ TEST(Validation, ContextualCheckInputsPassesWithCoinbase) { FakeCoinsViewDB fakeDB; CCoinsViewCache view(&fakeDB); + auto consensusBranchId = SPROUT_BRANCH_ID; CValidationState state; PrecomputedTransactionData txdata(tx); - EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus())); + EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus(), consensusBranchId)); } TEST(Validation, ReceivedBlockTransactions) { diff --git a/src/main.cpp b/src/main.cpp index b5dac6595..28bc4acf5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -758,7 +758,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) * 2. P2SH scripts with a crazy number of expensive * CHECKSIG/CHECKMULTISIG operations */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId) { if (tx.IsCoinBase()) return true; // Coinbases don't use vin normally @@ -784,7 +784,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // IsStandardTx() will have already returned false // and this method isn't called. vector > stack; - if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE)) + if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), consensusBranchId)) return false; if (whichType == TX_SCRIPTHASH) @@ -886,6 +886,30 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state, } } + if (!(tx.IsCoinBase() || tx.vjoinsplit.empty())) { + auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus()); + // Empty output script. + CScript scriptCode; + uint256 dataToBeSigned; + try { + dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + } catch (std::logic_error ex) { + return state.DoS(100, error("CheckTransaction(): error computing signature hash"), + REJECT_INVALID, "error-computing-signature-hash"); + } + + BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); + + // We rely on libsodium to check that the signature is canonical. + // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 + if (crypto_sign_verify_detached(&tx.joinSplitSig[0], + dataToBeSigned.begin(), 32, + tx.joinSplitPubKey.begin() + ) != 0) { + return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), + REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); + } + } return true; } @@ -1082,30 +1106,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio if (txin.prevout.IsNull()) return state.DoS(10, error("CheckTransaction(): prevout is null"), REJECT_INVALID, "bad-txns-prevout-null"); - - if (tx.vjoinsplit.size() > 0) { - // Empty output script. - CScript scriptCode; - uint256 dataToBeSigned; - try { - dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); - } catch (std::logic_error ex) { - return state.DoS(100, error("CheckTransaction(): error computing signature hash"), - REJECT_INVALID, "error-computing-signature-hash"); - } - - BOOST_STATIC_ASSERT(crypto_sign_PUBLICKEYBYTES == 32); - - // We rely on libsodium to check that the signature is canonical. - // https://github.com/jedisct1/libsodium/commit/62911edb7ff2275cccd74bf1c8aefcc4d76924e0 - if (crypto_sign_verify_detached(&tx.joinSplitSig[0], - dataToBeSigned.begin(), 32, - tx.joinSplitPubKey.begin() - ) != 0) { - return state.DoS(100, error("CheckTransaction(): invalid joinsplit signature"), - REJECT_INVALID, "bad-txns-invalid-joinsplit-signature"); - } - } } return true; @@ -1148,6 +1148,9 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (pfMissingInputs) *pfMissingInputs = false; + int nextBlockHeight = chainActive.Height() + 1; + auto consensusBranchId = CurrentEpochBranchId(nextBlockHeight, Params().GetConsensus()); + // Node operator can choose to reject tx by number of transparent inputs static_assert(std::numeric_limits::max() >= std::numeric_limits::max(), "size_t too small"); size_t limit = (size_t) GetArg("-mempooltxinputlimit", 0); @@ -1165,7 +1168,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // DoS level set to 10 to be more forgiving. // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. - int nextBlockHeight = chainActive.Height() + 1; if (!ContextualCheckTransaction(tx, state, nextBlockHeight, 10)) { return error("AcceptToMemoryPool: ContextualCheckTransaction failed"); } @@ -1260,7 +1262,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // Check for non-standard pay-to-script-hash in inputs - if (Params().RequireStandard() && !AreInputsStandard(tx, view)) + if (Params().RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId)) return error("AcceptToMemoryPool: nonstandard transaction input"); // Check that the transaction doesn't have an excessive number of @@ -1348,7 +1350,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. PrecomputedTransactionData txdata(tx); - if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus())) + if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) { return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); } @@ -1362,7 +1364,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks, however allowing such transactions into the mempool // can be exploited as a DoS attack. - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus())) + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) { return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } @@ -1727,7 +1729,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; - if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) { + if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) { return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error)); } return true; @@ -1810,7 +1812,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins } }// namespace Consensus -bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams, std::vector *pvChecks) +bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams, uint32_t consensusBranchId, std::vector *pvChecks) { if (!tx.IsCoinBase()) { @@ -1835,7 +1837,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons assert(coins); // Verify signature - CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata); + CScriptCheck check(*coins, tx, i, flags, cacheStore, consensusBranchId, &txdata); if (pvChecks) { pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); @@ -1848,7 +1850,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons // avoid splitting the network between upgraded and // non-upgraded nodes. CScriptCheck check2(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata); + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, consensusBranchId, &txdata); if (check2()) return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); } @@ -2238,6 +2240,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin assert(tree.root() == old_tree_root); } + // Grab the consensus branch ID for the block's height + auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus()); + std::vector txdata; txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated for (unsigned int i = 0; i < block.vtx.size(); i++) @@ -2277,7 +2282,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector vChecks; - if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL)) + if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) return false; control.Add(vChecks); } @@ -3721,7 +3726,7 @@ bool static LoadBlockIndexDB() pindex->nCachedBranchId = pindex->pprev->nCachedBranchId; } } else { - pindex->nCachedBranchId = NetworkUpgradeInfo[Consensus::BASE_SPROUT].nBranchId; + pindex->nCachedBranchId = SPROUT_BRANCH_ID; } if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) setBlockIndexCandidates.insert(pindex); diff --git a/src/main.h b/src/main.h index e2a386e62..d868f032b 100644 --- a/src/main.h +++ b/src/main.h @@ -306,7 +306,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF * @param[in] mapInputs Map of previous transactions that have outputs we're spending * @return True if all inputs (scriptSigs) use only standard transaction forms */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, uint32_t consensusBranchId); /** * Count ECDSA signature operations the old-fashioned (pre-0.6) way @@ -331,7 +331,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma * instead of being performed inline. */ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams, + unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, + const Consensus::Params& consensusParams, uint32_t consensusBranchId, std::vector *pvChecks = NULL); /** Check a transaction contextually against a set of consensus rules */ @@ -390,14 +391,15 @@ private: unsigned int nIn; unsigned int nFlags; bool cacheStore; + uint32_t consensusBranchId; ScriptError error; PrecomputedTransactionData *txdata; public: - CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) : + CScriptCheck(): amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), consensusBranchId(0), error(SCRIPT_ERR_UNKNOWN_ERROR) {} + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, uint32_t consensusBranchIdIn, PrecomputedTransactionData* txdataIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), amount(txFromIn.vout[txToIn.vin[nInIn].prevout.n].nValue), - ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), consensusBranchId(consensusBranchIdIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { } bool operator()(); @@ -408,6 +410,7 @@ public: std::swap(nIn, check.nIn); std::swap(nFlags, check.nFlags); std::swap(cacheStore, check.cacheStore); + std::swap(consensusBranchId, check.consensusBranchId); std::swap(error, check.error); std::swap(txdata, check.txdata); } diff --git a/src/miner.cpp b/src/miner.cpp index 3d7a67329..d87205c64 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -12,6 +12,7 @@ #include "base58.h" #include "chainparams.h" #include "consensus/consensus.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #ifdef ENABLE_MINING #include "crypto/equihash.h" @@ -143,6 +144,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); const int nHeight = pindexPrev->nHeight + 1; + uint32_t consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus()); pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); CCoinsViewCache view(pcoinsTip); @@ -294,7 +296,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // create only contains transactions that are valid in new blocks. CValidationState state; PrecomputedTransactionData txdata(tx); - if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus())) + if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus(), consensusBranchId)) continue; UpdateCoins(tx, view, nHeight); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 42e162b08..2f89529de 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "base58.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "core_io.h" #include "init.h" @@ -839,6 +840,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Grab the current consensus branch ID + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + // Script verification errors UniValue vErrors(UniValue::VARR); @@ -859,17 +863,17 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); // ... and merge in other signatures: BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { - sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i)); + sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); } UpdateTransaction(mergedTx, i, sigdata); ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), &serror)) { + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); } } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 75edd4941..beb16ebef 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -232,7 +232,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { return true; } -bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror) +bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* serror) { static const CScriptNum bnZero(0); static const CScriptNum bnOne(1); @@ -828,7 +828,7 @@ bool EvalScript(vector >& stack, const CScript& script, un //serror is set return false; } - bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, sigversion); + bool fSuccess = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId); popstack(stack); popstack(stack); @@ -886,7 +886,7 @@ bool EvalScript(vector >& stack, const CScript& script, un } // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, script, sigversion); + bool fOk = checker.CheckSig(vchSig, vchPubKey, script, consensusBranchId); if (fOk) { isig++; @@ -1083,14 +1083,25 @@ PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo) hashOutputs = GetOutputsHash(txTo); } -uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) +SigVersion SignatureHashVersion(const CTransaction& txTo) +{ + if (txTo.fOverwintered) { + return SIGVERSION_OVERWINTER; + } else { + return SIGVERSION_SPROUT; + } +} + +uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, uint32_t consensusBranchId, const PrecomputedTransactionData* cache) { if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) { // nIn out of range throw logic_error("input index is out of range"); } - if (sigversion == SIGVERSION_WITNESS_V0) { + auto sigversion = SignatureHashVersion(txTo); + + if (sigversion == SIGVERSION_OVERWINTER) { uint256 hashPrevouts; uint256 hashSequence; uint256 hashOutputs; @@ -1159,7 +1170,7 @@ bool TransactionSignatureChecker::VerifySignature(const std::vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn, const vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1174,7 +1185,7 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn uint256 sighash; try { - sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata); + sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata); } catch (logic_error ex) { return false; } @@ -1222,7 +1233,7 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* serror) { set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); @@ -1231,12 +1242,12 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne } vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, scriptPubKey, flags, checker, consensusBranchId, serror)) // serror is set return false; if (stack.empty()) @@ -1263,7 +1274,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); - if (!EvalScript(stack, pubKey2, flags, checker, SIGVERSION_BASE, serror)) + if (!EvalScript(stack, pubKey2, flags, checker, consensusBranchId, serror)) // serror is set return false; if (stack.empty()) diff --git a/src/script/interpreter.h b/src/script/interpreter.h index fe97bd63c..7d4ed974b 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -97,16 +97,16 @@ struct PrecomputedTransactionData enum SigVersion { - SIGVERSION_BASE = 0, - SIGVERSION_WITNESS_V0 = 1, + SIGVERSION_SPROUT = 0, + SIGVERSION_OVERWINTER = 1, }; -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL); +uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, uint32_t consensusBranchId, const PrecomputedTransactionData* cache = NULL); class BaseSignatureChecker { public: - virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const { return false; } @@ -133,7 +133,7 @@ protected: public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {} TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const; + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckLockTime(const CScriptNum& nLockTime) const; }; @@ -146,7 +146,7 @@ public: MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {} }; -bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = NULL); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = NULL); +bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* error = NULL); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, uint32_t consensusBranchId, ScriptError* serror = NULL); #endif // BITCOIN_SCRIPT_INTERPRETER_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 790d03b63..0fe89ece8 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -19,7 +19,7 @@ typedef vector valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} -bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const +bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const { CKey key; if (!keystore->GetKey(address, key)) @@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, uint256 hash; try { - hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); + hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId); } catch (logic_error ex) { return false; } @@ -38,16 +38,16 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, return true; } -static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) +static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, uint32_t consensusBranchId) { vector vchSig; - if (!creator.CreateSig(vchSig, address, scriptCode, sigversion)) + if (!creator.CreateSig(vchSig, address, scriptCode, consensusBranchId)) return false; ret.push_back(vchSig); return true; } -static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, SigVersion sigversion) +static bool SignN(const vector& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, std::vector& ret, uint32_t consensusBranchId) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -55,7 +55,7 @@ static bool SignN(const vector& multisigdata, const BaseSignatureCreato { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); - if (Sign1(keyID, creator, scriptCode, ret, sigversion)) + if (Sign1(keyID, creator, scriptCode, ret, consensusBranchId)) ++nSigned; } return nSigned==nRequired; @@ -68,7 +68,7 @@ static bool SignN(const vector& multisigdata, const BaseSignatureCreato * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, - std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion) + std::vector& ret, txnouttype& whichTypeRet, uint32_t consensusBranchId) { CScript scriptRet; uint160 h160; @@ -86,10 +86,10 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return Sign1(keyID, creator, scriptPubKey, ret, sigversion); + return Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (!Sign1(keyID, creator, scriptPubKey, ret, sigversion)) + if (!Sign1(keyID, creator, scriptPubKey, ret, consensusBranchId)) return false; else { @@ -107,7 +107,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP case TX_MULTISIG: ret.push_back(valtype()); // workaround CHECKMULTISIG bug - return (SignN(vSolutions, creator, scriptPubKey, ret, sigversion)); + return (SignN(vSolutions, creator, scriptPubKey, ret, consensusBranchId)); default: return false; @@ -129,13 +129,13 @@ static CScript PushAll(const vector& values) return result; } -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata) +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, SignatureData& sigdata, uint32_t consensusBranchId) { CScript script = fromPubKey; bool solved = true; std::vector result; txnouttype whichType; - solved = SignStep(creator, script, result, whichType, SIGVERSION_BASE); + solved = SignStep(creator, script, result, whichType, consensusBranchId); CScript subscript; if (solved && whichType == TX_SCRIPTHASH) @@ -144,14 +144,14 @@ bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPu // the final scriptSig is the signatures from that // and then the serialized subscript: script = subscript = CScript(result[0].begin(), result[0].end()); - solved = solved && SignStep(creator, script, result, whichType, SIGVERSION_BASE) && whichType != TX_SCRIPTHASH; + solved = solved && SignStep(creator, script, result, whichType, consensusBranchId) && whichType != TX_SCRIPTHASH; result.push_back(std::vector(subscript.begin(), subscript.end())); } sigdata.scriptSig = PushAll(result); // Test solution - return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); + return solved && VerifyScript(sigdata.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker(), consensusBranchId); } SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn) @@ -168,7 +168,7 @@ void UpdateTransaction(CMutableTransaction& tx, unsigned int nIn, const Signatur tx.vin[nIn].scriptSig = data.scriptSig; } -bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType) +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, uint32_t consensusBranchId) { assert(nIn < txTo.vin.size()); @@ -176,24 +176,24 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); SignatureData sigdata; - bool ret = ProduceSignature(creator, fromPubKey, sigdata); + bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId); UpdateTransaction(txTo, nIn, sigdata); return ret; } -bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) +bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, uint32_t consensusBranchId) { assert(nIn < txTo.vin.size()); CTxIn& txin = txTo.vin[nIn]; assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; - return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType); + return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId); } static vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const vector& vSolutions, - const vector& sigs1, const vector& sigs2, SigVersion sigversion) + const vector& sigs1, const vector& sigs2, uint32_t consensusBranchId) { // Combine all the signatures we've got: set allsigs; @@ -221,7 +221,7 @@ static vector CombineMultisig(const CScript& scriptPubKey, const BaseSi if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (checker.CheckSig(sig, pubkey, scriptPubKey, sigversion)) + if (checker.CheckSig(sig, pubkey, scriptPubKey, consensusBranchId)) { sigs[pubkey] = sig; break; @@ -254,8 +254,8 @@ struct Stacks Stacks() {} explicit Stacks(const std::vector& scriptSigStack_) : script(scriptSigStack_) {} - explicit Stacks(const SignatureData& data) { - EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), SIGVERSION_BASE); + explicit Stacks(const SignatureData& data, uint32_t consensusBranchId) { + EvalScript(script, data.scriptSig, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker(), consensusBranchId); } SignatureData Output() const { @@ -268,7 +268,7 @@ struct Stacks static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const txnouttype txType, const vector& vSolutions, - Stacks sigs1, Stacks sigs2, SigVersion sigversion) + Stacks sigs1, Stacks sigs2, uint32_t consensusBranchId) { switch (txType) { @@ -300,25 +300,26 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature Solver(pubKey2, txType2, vSolutions2); sigs1.script.pop_back(); sigs2.script.pop_back(); - Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, sigversion); + Stacks result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2, consensusBranchId); result.script.push_back(spk); return result; } case TX_MULTISIG: - return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, sigversion)); + return Stacks(CombineMultisig(scriptPubKey, checker, vSolutions, sigs1.script, sigs2.script, consensusBranchId)); default: return Stacks(); } } SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, - const SignatureData& scriptSig1, const SignatureData& scriptSig2) + const SignatureData& scriptSig1, const SignatureData& scriptSig2, + uint32_t consensusBranchId) { txnouttype txType; vector > vSolutions; Solver(scriptPubKey, txType, vSolutions); - return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1), Stacks(scriptSig2), SIGVERSION_BASE).Output(); + return CombineSignatures(scriptPubKey, checker, txType, vSolutions, Stacks(scriptSig1, consensusBranchId), Stacks(scriptSig2, consensusBranchId), consensusBranchId).Output(); } namespace { @@ -328,7 +329,7 @@ class DummySignatureChecker : public BaseSignatureChecker public: DummySignatureChecker() {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const { return true; } @@ -341,7 +342,7 @@ const BaseSignatureChecker& DummySignatureCreator::Checker() const return dummyChecker; } -bool DummySignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const +bool DummySignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const { // Create a dummy signature that is a valid DER-encoding vchSig.assign(72, '\000'); diff --git a/src/script/sign.h b/src/script/sign.h index 5ec0f0b0f..1e9bde118 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -27,7 +27,7 @@ public: virtual const BaseSignatureChecker& Checker() const =0; /** Create a singular (non-script) signature. */ - virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0; + virtual bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const =0; }; /** A signature creator for transactions. */ @@ -41,7 +41,7 @@ class TransactionSignatureCreator : public BaseSignatureCreator { public: TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); const BaseSignatureChecker& Checker() const { return checker; } - bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const; + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const; }; class MutableTransactionSignatureCreator : public TransactionSignatureCreator { @@ -56,7 +56,7 @@ class DummySignatureCreator : public BaseSignatureCreator { public: DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {} const BaseSignatureChecker& Checker() const; - bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const; + bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const; }; struct SignatureData { @@ -67,14 +67,14 @@ struct SignatureData { }; /** Produce a script signature using a generic signature creator. */ -bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata); +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, SignatureData& sigdata, uint32_t consensusBranchId); /** Produce a script signature for a transaction. */ -bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType); -bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType); +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, uint32_t consensusBranchId); +bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, uint32_t consensusBranchId); /** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ -SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2); +SignatureData CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const SignatureData& scriptSig1, const SignatureData& scriptSig2, uint32_t consensusBranchId); /** Extract signature data from a transaction, and insert it. */ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn); diff --git a/src/script/zcashconsensus.cpp b/src/script/zcashconsensus.cpp index 6a85c79f6..ec494d966 100644 --- a/src/script/zcashconsensus.cpp +++ b/src/script/zcashconsensus.cpp @@ -5,6 +5,7 @@ #include "zcashconsensus.h" +#include "consensus/upgrades.h" #include "primitives/transaction.h" #include "pubkey.h" #include "script/interpreter.h" @@ -86,7 +87,8 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int set_error(err, zcashconsensus_ERR_OK); PrecomputedTransactionData txdata(tx); CAmount am(0); - return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), NULL); + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), consensusBranchId, NULL); } catch (const std::exception&) { return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing } diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 271a37260..7641b8b2d 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -8,6 +8,7 @@ +#include "consensus/upgrades.h" #include "keystore.h" #include "main.h" #include "net.h" @@ -119,6 +120,8 @@ CTransaction RandomOrphan() BOOST_AUTO_TEST_CASE(DoS_mapOrphans) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + CKey key; key.MakeNewKey(true); CBasicKeyStore keystore; @@ -151,7 +154,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL); + SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId); AddOrphanTx(tx, i); } @@ -171,7 +174,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) tx.vin[j].prevout.n = j; tx.vin[j].prevout.hash = txPrev.GetHash(); } - SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL); + SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId); // Re-use same signature for other inputs // (they don't have to be valid for this test) for (unsigned int j = 1; j < tx.vin.size(); j++) diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index c23befe23..3e9874157 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -53,7 +53,7 @@ "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", - "sign=ALL", + "sign=1:ALL", "outaddr=0.001:t1Ruz6gK4QPZoPPGpHaieupnnh62mktjQE7"], "output_cmp": "txcreatesign.hex" } diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index db19b4ce0..a7decc94e 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "consensus/upgrades.h" #include "key.h" #include "keystore.h" #include "main.h" @@ -26,9 +27,9 @@ typedef vector valtype; BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript -sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn) +sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn, uint32_t consensusBranchId) { - uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, consensusBranchId); CScript result; result << OP_0; // CHECKMULTISIG bug workaround @@ -44,6 +45,7 @@ sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, BOOST_AUTO_TEST_CASE(multisig_verify) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; ScriptError err; @@ -83,21 +85,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify) // Test a AND b: keys.assign(1,key[0]); keys.push_back(key[1]); - s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err)); + s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); + BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); for (int i = 0; i < 4; i++) { keys.assign(1,key[i]); - s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 1: %d", i)); + s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); keys.assign(1,key[1]); keys.push_back(key[i]); - s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), &err), strprintf("a&b 2: %d", i)); + s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } @@ -105,21 +107,21 @@ BOOST_AUTO_TEST_CASE(multisig_verify) for (int i = 0; i < 4; i++) { keys.assign(1,key[i]); - s = sign_multisig(a_or_b, keys, txTo[1], 0); + s = sign_multisig(a_or_b, keys, txTo[1], 0, consensusBranchId); if (i == 0 || i == 1) { - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), &err)); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); @@ -128,15 +130,15 @@ BOOST_AUTO_TEST_CASE(multisig_verify) { keys.assign(1,key[i]); keys.push_back(key[j]); - s = sign_multisig(escrow, keys, txTo[2], 0); + s = sign_multisig(escrow, keys, txTo[2], 0, consensusBranchId); if (i < j && i < 3 && j < 3) { - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), &err), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } @@ -277,6 +279,8 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1) BOOST_AUTO_TEST_CASE(multisig_Sign) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + // Test SignSignature() (and therefore the version of Solver() that signs transactions) CBasicKeyStore keystore; CKey key[4]; @@ -313,7 +317,7 @@ BOOST_AUTO_TEST_CASE(multisig_Sign) for (int i = 0; i < 3; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); } } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index 8be86ce73..209ff06c9 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "consensus/upgrades.h" #include "core_io.h" #include "key.h" #include "keystore.h" @@ -32,6 +33,8 @@ Serialize(const CScript& s) static bool Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + // Create dummy to/from transactions: CMutableTransaction txFrom; txFrom.vout.resize(1); @@ -45,7 +48,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), &err); + return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), consensusBranchId, &err); } @@ -54,6 +57,7 @@ BOOST_FIXTURE_TEST_SUITE(script_P2SH_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sign) { LOCK(cs_main); + uint32_t consensusBranchId = SPROUT_BRANCH_ID; // Pay-to-script-hash looks like this: // scriptSig: // scriptPubKey: HASH160 EQUAL @@ -107,7 +111,7 @@ BOOST_AUTO_TEST_CASE(sign) } for (int i = 0; i < 8; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); } // All of the above should be OK, and the txTos have valid signatures // Check to make sure signature verification fails if we use the wrong ScriptSig: @@ -117,7 +121,7 @@ BOOST_AUTO_TEST_CASE(sign) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)(); + bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, consensusBranchId, &txdata)(); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else @@ -157,6 +161,7 @@ BOOST_AUTO_TEST_CASE(norecurse) BOOST_AUTO_TEST_CASE(set) { LOCK(cs_main); + uint32_t consensusBranchId = SPROUT_BRANCH_ID; // Test the CScript::Set* methods CBasicKeyStore keystore; CKey key[4]; @@ -206,7 +211,7 @@ BOOST_AUTO_TEST_CASE(set) } for (int i = 0; i < 4; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i)); } } @@ -265,6 +270,7 @@ BOOST_AUTO_TEST_CASE(switchover) BOOST_AUTO_TEST_CASE(AreInputsStandard) { LOCK(cs_main); + uint32_t consensusBranchId = SPROUT_BRANCH_ID; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); CBasicKeyStore keystore; @@ -335,16 +341,16 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txTo.vin[i].prevout.n = i; txTo.vin[i].prevout.hash = txFrom.GetHash(); } - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL)); - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL)); - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL, consensusBranchId)); // SignSignature doesn't know how to sign these. We're // not testing validating signatures, so just create // dummy signatures that DO include the correct P2SH scripts: txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast >(oneAndTwo); txTo.vin[4].scriptSig << static_cast >(fifteenSigops); - BOOST_CHECK(::AreInputsStandard(txTo, coins)); + BOOST_CHECK(::AreInputsStandard(txTo, coins, consensusBranchId)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txTo, coins), 22U); @@ -353,7 +359,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) { CScript t = txTo.vin[i].scriptSig; txTo.vin[i].scriptSig = (CScript() << 11) + t; - BOOST_CHECK(!::AreInputsStandard(txTo, coins)); + BOOST_CHECK(!::AreInputsStandard(txTo, coins, consensusBranchId)); txTo.vin[i].scriptSig = t; } @@ -366,7 +372,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); txToNonStd1.vin[0].scriptSig << static_cast >(sixteenSigops); - BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins)); + BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins, consensusBranchId)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); CMutableTransaction txToNonStd2; @@ -378,7 +384,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); txToNonStd2.vin[0].scriptSig << static_cast >(twentySigops); - BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins)); + BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins, consensusBranchId)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index d089816c8..bb363be41 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -5,6 +5,7 @@ #include "data/script_invalid.json.h" #include "data/script_valid.json.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "key.h" #include "keystore.h" @@ -87,13 +88,13 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu return txSpend; } -void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) +void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, uint32_t consensusBranchId, bool expect, const std::string& message) { ScriptError err; CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx2 = tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), &err) == expect, message); + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), consensusBranchId, &err) == expect, message); BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); #if defined(HAVE_CONSENSUS_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); @@ -188,6 +189,7 @@ private: std::vector push; std::string comment; int flags; + uint32_t consensusBranchId; void DoPush() { @@ -205,7 +207,7 @@ private: } public: - TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_) + TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_), consensusBranchId(0) { if (P2SH) { creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL); @@ -237,7 +239,7 @@ public: TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32) { - uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId); std::vector vchSig, r, s; uint32_t iter = 0; do { @@ -289,7 +291,7 @@ public: { TestBuilder copy = *this; // Make a copy so we can rollback the push. DoPush(); - DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment); + DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, consensusBranchId, expect, comment); *this = copy; return *this; } @@ -577,6 +579,7 @@ BOOST_AUTO_TEST_CASE(script_build) BOOST_AUTO_TEST_CASE(script_valid) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; // Read tests from test/data/script_valid.json // Format is an array of arrays // Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ] @@ -600,12 +603,13 @@ BOOST_AUTO_TEST_CASE(script_valid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, consensusBranchId, true, strTest); } } BOOST_AUTO_TEST_CASE(script_invalid) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; // Scripts that should evaluate as invalid UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); @@ -625,12 +629,14 @@ BOOST_AUTO_TEST_CASE(script_invalid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, consensusBranchId, false, strTest); } } BOOST_AUTO_TEST_CASE(script_PushData) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + // Check that PUSHDATA1, PUSHDATA2, and PUSHDATA4 create the same value on // the stack as the 1-75 opcodes do. static const unsigned char direct[] = { 1, 0x5a }; @@ -640,29 +646,29 @@ BOOST_AUTO_TEST_CASE(script_PushData) ScriptError err; vector > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err)); BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err)); BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); vector > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), SIGVERSION_BASE, &err)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), SCRIPT_VERIFY_P2SH, BaseSignatureChecker(), consensusBranchId, &err)); BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } CScript -sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction) +sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, uint32_t consensusBranchId) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, consensusBranchId); CScript result; // @@ -684,15 +690,17 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac return result; } CScript -sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction) +sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, uint32_t consensusBranchId) { std::vector keys; keys.push_back(key); - return sign_multisig(scriptPubKey, keys, transaction); + return sign_multisig(scriptPubKey, keys, transaction, consensusBranchId); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + ScriptError err; CKey key1, key2, key3; key1.MakeNewKey(true); @@ -705,24 +713,26 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); - CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); - CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), &err)); + CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + ScriptError err; CKey key1, key2, key3, key4; key1.MakeNewKey(true); @@ -738,60 +748,62 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) std::vector keys; keys.push_back(key1); keys.push_back(key2); - CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); - CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); - CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig - CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order - CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order - CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys - CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys - CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures - CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), &err)); + CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } BOOST_AUTO_TEST_CASE(script_combineSigs) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + // Test the CombineSignatures function CAmount amount = 0; CBasicKeyStore keystore; @@ -812,61 +824,61 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript& scriptSig = txTo.vin[0].scriptSig; SignatureData empty; - SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty); + SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty, consensusBranchId); BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); // changes scriptSig - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: scriptSigCopy = CScript() << OP_0 << static_cast >(pkSingle); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty); + SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, consensusBranchId); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SIGVERSION_BASE); + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, consensusBranchId); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SIGVERSION_BASE); + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, consensusBranchId); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); @@ -882,32 +894,34 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId); BOOST_CHECK(combined.scriptSig == partial1a); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete12); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete12); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete12); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete13); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete23); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete23); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a)); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId); BOOST_CHECK(combined.scriptSig == partial3c); } BOOST_AUTO_TEST_CASE(script_standard_push) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + ScriptError err; for (int i=0; i<67000; i++) { CScript script; script << i; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); - BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), consensusBranchId, &err), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } @@ -916,7 +930,7 @@ BOOST_AUTO_TEST_CASE(script_standard_push) CScript script; script << data; BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); - BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data."); + BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), consensusBranchId, &err), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 6a3b2e855..f591b80c7 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -93,7 +93,7 @@ void static RandomScript(CScript &script) { script << oplist[insecure_rand() % (sizeof(oplist)/sizeof(oplist[0]))]; } -void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { +void static RandomTransaction(CMutableTransaction &tx, bool fSingle, uint32_t consensusBranchId) { tx.fOverwintered = insecure_rand() % 2; if (tx.fOverwintered) { // Versions outside known ranges throw an exception during parsing @@ -160,7 +160,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { // Empty output script. CScript scriptCode; CTransaction signTx(tx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); assert(crypto_sign_detached(&tx.joinSplitSig[0], NULL, dataToBeSigned.begin(), 32, @@ -173,11 +173,12 @@ BOOST_FIXTURE_TEST_SUITE(sighash_tests, JoinSplitTestingSetup) BOOST_AUTO_TEST_CASE(sighash_test) { + uint32_t overwinterBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; seed_insecure_rand(false); #if defined(PRINT_SIGHASH_JSON) std::cout << "[\n"; - std::cout << "\t[\"raw_transaction, script, input_index, hashType, signature_hash (result)\"],\n"; + std::cout << "\t[\"raw_transaction, script, input_index, hashType, branchId, signature_hash (result)\"],\n"; #endif int nRandomTests = 50000; @@ -186,15 +187,16 @@ BOOST_AUTO_TEST_CASE(sighash_test) #endif for (int i=0; inullifiers[0] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash(); - BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state)); + BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); + BOOST_CHECK(!ContextualCheckTransaction(newTx, state, 0, 100)); BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature"); // Empty output script. CScript scriptCode; CTransaction signTx(newTx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); assert(crypto_sign_detached(&newTx.joinSplitSig[0], NULL, dataToBeSigned.begin(), 32, @@ -436,6 +443,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity) ) == 0); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); + BOOST_CHECK(ContextualCheckTransaction(newTx, state, 0, 100)); } { // Ensure that values within the joinsplit are well-formed. @@ -525,6 +533,8 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity) BOOST_AUTO_TEST_CASE(test_Get) { + uint32_t consensusBranchId = SPROUT_BRANCH_ID; + CBasicKeyStore keystore; CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); @@ -545,19 +555,20 @@ BOOST_AUTO_TEST_CASE(test_Get) t1.vout[0].nValue = 90*CENT; t1.vout[0].scriptPubKey << OP_1; - BOOST_CHECK(AreInputsStandard(t1, coins)); + BOOST_CHECK(AreInputsStandard(t1, coins, consensusBranchId)); BOOST_CHECK_EQUAL(coins.GetValueIn(t1), (50+21+22)*CENT); // Adding extra junk to the scriptSig should make it non-standard: t1.vin[0].scriptSig << OP_11; - BOOST_CHECK(!AreInputsStandard(t1, coins)); + BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId)); // ... as should not having enough: t1.vin[0].scriptSig = CScript(); - BOOST_CHECK(!AreInputsStandard(t1, coins)); + BOOST_CHECK(!AreInputsStandard(t1, coins, consensusBranchId)); } BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { + uint32_t consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; CMutableTransaction mtx; mtx.fOverwintered = true; mtx.nVersion = 3; @@ -596,7 +607,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { // sign all inputs for(uint32_t i = 0; i < mtx.vin.size(); i++) { - bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size())); + bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()), consensusBranchId); assert(hashSigned); } @@ -626,7 +637,7 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { for(uint32_t i = 0; i < mtx.vin.size(); i++) { std::vector vChecks; - CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, &txdata); + CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, consensusBranchId, &txdata); vChecks.push_back(CScriptCheck()); check.swap(vChecks.back()); control.Add(vChecks); diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 15a88e678..4599cec3c 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -4,6 +4,8 @@ #include "utiltest.h" +#include "consensus/upgrades.h" + CWalletTx GetValidReceive(ZCJoinSplit& params, const libzcash::SpendingKey& sk, CAmount value, bool randomInputs) { @@ -45,11 +47,10 @@ CWalletTx GetValidReceive(ZCJoinSplit& params, mtx.vjoinsplit.push_back(jsdesc); // Empty output script. + uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); - //fifth parameter amount will not be used for joinsplit signing, value arbitrary, also arbitrary decision what to use for sigverion - //This is just to get this merge commit to compile later will remove sigversion parameter as choosing sigversion by block height - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL,0, SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, @@ -131,9 +132,10 @@ CWalletTx GetValidSpend(ZCJoinSplit& params, mtx.vjoinsplit.push_back(jsdesc); // Empty output script. + uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL,0,SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index a1200e30c..b69bef0de 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -5,6 +5,7 @@ #include "asyncrpcoperation_sendmany.h" #include "asyncrpcqueue.h" #include "amount.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -337,6 +338,12 @@ bool AsyncRPCOperation_sendmany::main_impl() { LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total)); LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee)); + // Grab the current consensus branch ID + { + LOCK(cs_main); + consensusBranchId_ = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + } + /** * SCENARIO #1 * @@ -994,7 +1001,7 @@ UniValue AsyncRPCOperation_sendmany::perform_joinsplit( // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_); // Add the signature if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 83a976af9..113f11f49 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -73,6 +73,7 @@ private: UniValue contextinfo_; // optional data to include in return value from getStatus() + uint32_t consensusBranchId_; CAmount fee_; int mindepth_; std::string fromaddress_; diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 61a02ffe9..527f810bc 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -4,6 +4,7 @@ #include "asyncrpcqueue.h" #include "amount.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -302,12 +303,15 @@ void AsyncRPCOperation_shieldcoinbase::sign_send_raw_transaction(UniValue obj) UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) { + uint32_t consensusBranchId; uint256 anchor; { LOCK(cs_main); + consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); anchor = pcoinsTip->GetBestAnchor(); } + if (anchor.IsNull()) { throw std::runtime_error("anchor is null"); } @@ -369,7 +373,7 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 62fe40cde..90651ea74 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5,6 +5,7 @@ #include "amount.h" #include "base58.h" +#include "consensus/upgrades.h" #include "core_io.h" #include "init.h" #include "main.h" @@ -2840,7 +2841,8 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, SIGVERSION_BASE); + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); // Add the signature assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 3730430b7..8dd52a0b0 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -8,6 +8,7 @@ #include "base58.h" #include "checkpoints.h" #include "coincontrol.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "init.h" #include "main.h" @@ -2768,6 +2769,9 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt } } + // Grab the current consensus branch ID + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + // Sign int nIn = 0; CTransaction txNewConst(txNew); @@ -2777,9 +2781,9 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; SignatureData sigdata; if (sign) - signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata); + signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, consensusBranchId); else - signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata); + signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) { diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index c061fd797..4b17e57bf 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -13,6 +13,7 @@ #include "crypto/equihash.h" #include "chain.h" #include "chainparams.h" +#include "consensus/upgrades.h" #include "consensus/validation.h" #include "main.h" #include "miner.h" @@ -251,8 +252,9 @@ double benchmark_large_tx() } // Sign for all the inputs + auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId; for (size_t i = 0; i < NUM_INPUTS; i++) { - SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL); + SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId); } // Serialize: @@ -278,6 +280,7 @@ double benchmark_large_tx() prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&final_spending_tx, i, 1000000), + consensusBranchId, &serror)); } return timer_stop(tv_start);