diff --git a/src/checkqueue.h b/src/checkqueue.h --- a/src/checkqueue.h +++ b/src/checkqueue.h @@ -145,14 +145,14 @@ void Add(std::vector &vChecks) { boost::unique_lock lock(mutex); for (T &check : vChecks) { - queue.push_back(T()); - check.swap(queue.back()); + queue.push_back(std::move(check)); } nTodo += vChecks.size(); - if (vChecks.size() == 1) + if (vChecks.size() == 1) { condWorker.notify_one(); - else if (vChecks.size() > 1) + } else if (vChecks.size() > 1) { condWorker.notify_all(); + } } ~CCheckQueue() {} diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -348,4 +348,18 @@ /** Compute the size of a transaction */ int64_t GetTransactionSize(const CTransaction &tx); +/** Precompute sighash midstate to avoid quadratic hashing */ +struct PrecomputedTransactionData { + uint256 hashPrevouts, hashSequence, hashOutputs; + + PrecomputedTransactionData() + : hashPrevouts(), hashSequence(), hashOutputs() {} + + PrecomputedTransactionData(const PrecomputedTransactionData &txdata) + : hashPrevouts(txdata.hashPrevouts), hashSequence(txdata.hashSequence), + hashOutputs(txdata.hashOutputs) {} + + PrecomputedTransactionData(const CTransaction &tx); +}; + #endif // BITCOIN_PRIMITIVES_TRANSACTION_H diff --git a/src/script/interpreter.h b/src/script/interpreter.h --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -9,7 +9,7 @@ #include "primitives/transaction.h" #include "script_error.h" -#include +#include #include #include @@ -121,12 +121,6 @@ bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError *serror); -struct PrecomputedTransactionData { - uint256 hashPrevouts, hashSequence, hashOutputs; - - PrecomputedTransactionData(const CTransaction &tx); -}; - uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo, unsigned int nIn, uint32_t nHashType, const CAmount &amount, diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -111,7 +111,7 @@ 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)(); + SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false, txdata)(); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -442,8 +442,8 @@ bool CheckInputs(const CTransaction &tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, unsigned int flags, bool cacheStore, - PrecomputedTransactionData &txdata, - std::vector *pvChecks = NULL); + const PrecomputedTransactionData &txdata, + std::vector *pvChecks = nullptr); /** Apply the effects of this transaction on the UTXO set represented by view */ void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs, int nHeight); @@ -513,15 +513,15 @@ unsigned int nFlags; bool cacheStore; ScriptError error; - PrecomputedTransactionData *txdata; + PrecomputedTransactionData txdata; public: CScriptCheck() : amount(0), ptxTo(0), nIn(0), nFlags(0), cacheStore(false), - error(SCRIPT_ERR_UNKNOWN_ERROR) {} + error(SCRIPT_ERR_UNKNOWN_ERROR), txdata() {} CScriptCheck(const CCoins &txFromIn, const CTransaction &txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, - PrecomputedTransactionData *txdataIn) + const 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), @@ -678,9 +678,10 @@ int32_t ComputeBlockVersion(const CBlockIndex *pindexPrev, const Consensus::Params ¶ms); -/** Reject codes greater or equal to this can be returned by AcceptToMemPool - * for transactions, to signal internal conditions. They cannot and should not - * be sent over the P2P network. +/** + * Reject codes greater or equal to this can be returned by AcceptToMemPool for + * transactions, to signal internal conditions. They cannot and should not be + * sent over the P2P network. */ static const unsigned int REJECT_INTERNAL = 0x100; /** Too high fee. Can not be triggered by P2P transactions */ diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1272,7 +1272,7 @@ const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, - cacheStore, *txdata), + cacheStore, txdata), &error)) { return false; } @@ -1338,7 +1338,7 @@ bool CheckInputs(const CTransaction &tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, - PrecomputedTransactionData &txdata, + const PrecomputedTransactionData &txdata, std::vector *pvChecks) { assert(!tx.IsCoinBase()); @@ -1369,10 +1369,9 @@ assert(coins); // Verify signature - CScriptCheck check(*coins, tx, i, flags, cacheStore, &txdata); + CScriptCheck check(*coins, tx, i, flags, cacheStore, txdata); if (pvChecks) { - pvChecks->push_back(CScriptCheck()); - check.swap(pvChecks->back()); + pvChecks->push_back(std::move(check)); } else if (!check()) { if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { // Check whether the failure was caused by a non-mandatory @@ -1382,7 +1381,7 @@ // and non-upgraded nodes. CScriptCheck check2( *coins, tx, i, flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, - cacheStore, &txdata); + cacheStore, txdata); if (check2()) { return state.Invalid( false, REJECT_NONSTANDARD, @@ -1869,11 +1868,6 @@ std::vector> vPos; vPos.reserve(block.vtx.size()); blockundo.vtxundo.reserve(block.vtx.size() - 1); - std::vector txdata; - - // Required so that pointers to individual PrecomputedTransactionData don't - // get invalidated. - txdata.reserve(block.vtx.size()); for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = *(block.vtx[i]); @@ -1917,7 +1911,6 @@ REJECT_INVALID, "bad-blk-sigops"); } - txdata.emplace_back(tx); if (!tx.IsCoinBase()) { nFees += view.GetValueIn(tx) - tx.GetValueOut(); @@ -1927,7 +1920,7 @@ std::vector vChecks; if (!CheckInputs(tx, state, view, fScriptChecks, flags, - fCacheResults, txdata[i], + fCacheResults, PrecomputedTransactionData(tx), nScriptCheckThreads ? &vChecks : nullptr)) { return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetId().ToString(), FormatStateMessage(state)); @@ -2439,8 +2432,8 @@ } /** - * Return the tip of the chain with the most work in it, that isn't - * known to be invalid (it's however far from certain to be valid). + * Return the tip of the chain with the most work in it, that isn't known to be + * invalid (it's however far from certain to be valid). */ static CBlockIndex *FindMostWorkChain() { do {