diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -399,6 +399,12 @@ const CTransactionRef &m_ptx; TxValidationState m_state; + /** + * A temporary cache containing serialized transaction data for + * signature verification. + * Reused across PolicyScriptChecks and ConsensusScriptChecks. + */ + PrecomputedTransactionData m_precomputed_txdata; // ABC specific flags that are used in both PreChecks and // ConsensusScriptChecks @@ -411,16 +417,14 @@ // evaluates package limits, etc. As this function can be invoked for "free" // by a peer, only tests that are fast should be done here (to avoid CPU // DoS). - bool PreChecks(ATMPArgs &args, Workspace &ws, - PrecomputedTransactionData &txdata) + bool PreChecks(ATMPArgs &args, Workspace &ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Re-run the script checks, using consensus flags, and try to cache the // result in the scriptcache. This should be done after // PolicyScriptChecks(). This requires that all inputs either be in our // utxo set or in the mempool. - bool ConsensusScriptChecks(const ATMPArgs &args, Workspace &ws, - PrecomputedTransactionData &txdata) + bool ConsensusScriptChecks(const ATMPArgs &args, Workspace &ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); // Try to add the transaction to the mempool, removing any conflicts first. @@ -446,8 +450,7 @@ size_t m_limit_descendant_size; }; -bool MemPoolAccept::PreChecks(ATMPArgs &args, Workspace &ws, - PrecomputedTransactionData &txdata) { +bool MemPoolAccept::PreChecks(ATMPArgs &args, Workspace &ws) { const CTransactionRef &ptx = ws.m_ptx; const CTransaction &tx = *ws.m_ptx; const TxId &txid = ws.m_ptx->GetId(); @@ -609,9 +612,9 @@ // Validate input scripts against standard script flags. const uint32_t scriptVerifyFlags = ws.m_next_block_script_verify_flags | STANDARD_SCRIPT_VERIFY_FLAGS; - txdata = PrecomputedTransactionData{tx}; + ws.m_precomputed_txdata = PrecomputedTransactionData{tx}; if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, - txdata, ws.m_sig_checks_standard)) { + ws.m_precomputed_txdata, ws.m_sig_checks_standard)) { // State filled in by CheckInputScripts return false; } @@ -646,8 +649,7 @@ return true; } -bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs &args, Workspace &ws, - PrecomputedTransactionData &txdata) { +bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs &args, Workspace &ws) { const CTransaction &tx = *ws.m_ptx; const TxId &txid = tx.GetId(); TxValidationState &state = ws.m_state; @@ -666,7 +668,8 @@ int nSigChecksConsensus; if (!CheckInputsFromMempoolAndCache( tx, state, m_view, m_pool, ws.m_next_block_script_verify_flags, - txdata, nSigChecksConsensus, m_active_chainstate.CoinsTip())) { + ws.m_precomputed_txdata, nSigChecksConsensus, + m_active_chainstate.CoinsTip())) { // This can occur under some circumstances, if the node receives an // unrequested tx which is invalid due to new consensus rules not // being activated yet (during IBD). @@ -725,16 +728,14 @@ args.m_config.GetChainParams().GetConsensus(), m_active_chainstate.m_chain.Tip())); - // Only compute the precomputed transaction data if we need to verify - // scripts (ie, other policy checks pass). We perform the inexpensive - // checks first and avoid hashing and signature verification unless those - // checks pass, to mitigate CPU exhaustion denial-of-service attacks. - PrecomputedTransactionData txdata; - if (!PreChecks(args, ws, txdata)) { + // We perform the inexpensive checks first and avoid hashing and signature + // verification unless those checks pass, to mitigate CPU exhaustion + // denial-of-service attacks. + if (!PreChecks(args, ws)) { return MempoolAcceptResult::Failure(ws.m_state); } - if (!ConsensusScriptChecks(args, ws, txdata)) { + if (!ConsensusScriptChecks(args, ws)) { return MempoolAcceptResult::Failure(ws.m_state); } @@ -781,8 +782,7 @@ // Do all PreChecks first and fail fast to avoid running expensive script // checks when unnecessary. for (Workspace &ws : workspaces) { - PrecomputedTransactionData txdata; - if (!PreChecks(args, ws, txdata)) { + if (!PreChecks(args, ws)) { package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed"); // Exit early to avoid doing pointless work. Update the failed tx