CCoinsViewCache view(&fakeDB);
CValidationState state;
- CachedHashes cachedHashes(tx);
- EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, cachedHashes, Params(CBaseChainParams::MAIN).GetConsensus()));
+ PrecomputedTransactionData txdata(tx);
+ EXPECT_TRUE(ContextualCheckInputs(tx, state, view, false, 0, false, txdata, Params(CBaseChainParams::MAIN).GetConsensus()));
}
TEST(Validation, ReceivedBlockTransactions) {
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- CachedHashes cachedHashes(tx);
- if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, cachedHashes, Params().GetConsensus()))
+ PrecomputedTransactionData txdata(tx);
+ if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus()))
{
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
}
// 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, cachedHashes, Params().GetConsensus()))
+ if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus()))
{
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
}
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
- if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *cachedHashes), &error)) {
+ if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), &error)) {
return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
}
return true;
}
}// namespace Consensus
-bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, CachedHashes& cachedHashes, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
+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<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
assert(coins);
// Verify signature
- CScriptCheck check(*coins, tx, i, flags, cacheStore, &cachedHashes);
+ CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata);
if (pvChecks) {
pvChecks->push_back(CScriptCheck());
check.swap(pvChecks->back());
// avoid splitting the network between upgraded and
// non-upgraded nodes.
CScriptCheck check2(*coins, tx, i,
- flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &cachedHashes);
+ flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
if (check2())
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
}
assert(tree.root() == old_tree_root);
}
- std::vector<CachedHashes> cachedHashes;
- cachedHashes.reserve(block.vtx.size()); // Required so that pointers to individual CachedHashes don't get invalidated
+ std::vector<PrecomputedTransactionData> 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++)
{
const CTransaction &tx = block.vtx[i];
REJECT_INVALID, "bad-blk-sigops");
}
- cachedHashes.emplace_back(tx);
+ txdata.emplace_back(tx);
if (!tx.IsCoinBase())
{
nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks;
- if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, cachedHashes[i], chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
+ if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, txdata[i], chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
return false;
control.Add(vChecks);
}
class CScriptCheck;
class CValidationInterface;
class CValidationState;
-class CachedHashes;
+class PrecomputedTransactionData;
struct CNodeStateStats;
* instead of being performed inline.
*/
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks,
- unsigned int flags, bool cacheStore, CachedHashes& cachedHashes, const Consensus::Params& consensusParams,
+ unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, const Consensus::Params& consensusParams,
std::vector<CScriptCheck> *pvChecks = NULL);
/** Check a transaction contextually against a set of consensus rules */
unsigned int nFlags;
bool cacheStore;
ScriptError error;
- CachedHashes *cachedHashes;
+ 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, CachedHashes* cachedHashesIn) :
+ CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, 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), cachedHashes(cachedHashesIn) { }
+ ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR), txdata(txdataIn) { }
bool operator()();
std::swap(nFlags, check.nFlags);
std::swap(cacheStore, check.cacheStore);
std::swap(error, check.error);
- std::swap(cachedHashes, check.cachedHashes);
+ std::swap(txdata, check.txdata);
}
ScriptError GetScriptError() const { return error; }
// policy here, but we still have to ensure that the block we
// create only contains transactions that are valid in new blocks.
CValidationState state;
- CachedHashes cachedHashes(tx);
- if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, cachedHashes, Params().GetConsensus()))
+ PrecomputedTransactionData txdata(tx);
+ if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata, Params().GetConsensus()))
continue;
UpdateCoins(tx, view, nHeight);
} // anon namespace
-CachedHashes::CachedHashes(const CTransaction& txTo)
+PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo)
{
hashPrevouts = GetPrevoutHash(txTo);
hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo);
}
-uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const CachedHashes* cache)
+uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
// nIn out of range
uint256 sighash;
try {
- sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->cachedHashes);
+ sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
} catch (logic_error ex) {
return false;
}
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
};
-struct CachedHashes
+struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs;
- CachedHashes(const CTransaction& tx);
+ PrecomputedTransactionData(const CTransaction& tx);
};
enum SigVersion
SIGVERSION_WITNESS_V0 = 1,
};
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const CachedHashes* cache = NULL);
+uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = NULL);
class BaseSignatureChecker
{
const CTransaction* txTo;
unsigned int nIn;
const CAmount amount;
- const CachedHashes* cachedHashes;
+ const PrecomputedTransactionData* txdata;
protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public:
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), cachedHashes(NULL) {}
- TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const CachedHashes& cachedHashesIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), cachedHashes(&cachedHashesIn) {}
+ 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<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const;
bool CheckLockTime(const CScriptNum& nLockTime) const;
};
bool store;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, CachedHashes& cachedHashesIn) : TransactionSignatureChecker(txToIn, nInIn, amount, cachedHashesIn), store(storeIn) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {}
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
};
// Regardless of the verification result, the tx did not error.
set_error(err, zcashconsensus_ERR_OK);
- CachedHashes cachedHashes(tx);
+ PrecomputedTransactionData txdata(tx);
CAmount am(0);
- return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, cachedHashes), NULL);
+ return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn, am, txdata), NULL);
} catch (const std::exception&) {
return set_error(err, zcashconsensus_ERR_TX_DESERIALIZE); // Error deserializing
}
// 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:
for (int i = 0; i < 8; i++) {
- CachedHashes cachedHashes(txTo[i]);
+ PrecomputedTransactionData txdata(txTo[i]);
for (int j = 0; j < 8; j++)
{
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, &cachedHashes)();
+ bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, &txdata)();
if (i == j)
BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j));
else
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest + comment);
BOOST_CHECK_MESSAGE(state.IsValid(), comment);
- CachedHashes cachedHashes(tx);
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
CAmount amount = 0;
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- verify_flags, TransactionSignatureChecker(&tx, i, amount, cachedHashes), &err),
+ verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err),
strTest + comment);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
}
CValidationState state;
fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
- CachedHashes cachedHashes(tx);
+ PrecomputedTransactionData txdata(tx);
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{
if (!mapprevOutScriptPubKeys.count(tx.vin[i].prevout))
unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
CAmount amount = 0;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
- verify_flags, TransactionSignatureChecker(&tx, i, amount, cachedHashes), &err);
+ verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), &err);
}
BOOST_CHECK_MESSAGE(!fValid, strTest + comment);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment);
ssout >> tx;
// check all inputs concurrently, with the cache
- CachedHashes cachedHashes(tx);
+ PrecomputedTransactionData txdata(tx);
boost::thread_group threadGroup;
CCheckQueue<CScriptCheck> scriptcheckqueue(128);
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
for(uint32_t i = 0; i < mtx.vin.size(); i++) {
std::vector<CScriptCheck> vChecks;
- CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, &cachedHashes);
+ CScriptCheck check(coins, tx, i, SCRIPT_VERIFY_P2SH, false, &txdata);
vChecks.push_back(CScriptCheck());
check.swap(vChecks.back());
control.Add(vChecks);