mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
[validation/refactor] store precomputed txdata in workspace
We want to be able to re-use the precomputed transaction data between PolicyScriptChecks and ConsensusScriptChecks in AcceptMultipleTransactions.
This commit is contained in:
parent
0a79eaba72
commit
cbb3598b5c
1 changed files with 17 additions and 18 deletions
|
@ -513,6 +513,9 @@ private:
|
||||||
const CTransactionRef& m_ptx;
|
const CTransactionRef& m_ptx;
|
||||||
const uint256& m_hash;
|
const uint256& m_hash;
|
||||||
TxValidationState m_state;
|
TxValidationState m_state;
|
||||||
|
/** A temporary cache containing serialized transaction data for signature verification.
|
||||||
|
* Reused across PolicyScriptChecks and ConsensusScriptChecks. */
|
||||||
|
PrecomputedTransactionData m_precomputed_txdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run the policy checks on a given transaction, excluding any script checks.
|
// Run the policy checks on a given transaction, excluding any script checks.
|
||||||
|
@ -523,13 +526,13 @@ private:
|
||||||
|
|
||||||
// Run the script checks using our policy flags. As this can be slow, we should
|
// Run the script checks using our policy flags. As this can be slow, we should
|
||||||
// only invoke this on transactions that have otherwise passed policy checks.
|
// only invoke this on transactions that have otherwise passed policy checks.
|
||||||
bool PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
bool PolicyScriptChecks(const 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
|
// Re-run the script checks, using consensus flags, and try to cache the
|
||||||
// result in the scriptcache. This should be done after
|
// result in the scriptcache. This should be done after
|
||||||
// PolicyScriptChecks(). This requires that all inputs either be in our
|
// PolicyScriptChecks(). This requires that all inputs either be in our
|
||||||
// utxo set or in the mempool.
|
// utxo set or in the mempool.
|
||||||
bool ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
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.
|
// Try to add the transaction to the mempool, removing any conflicts first.
|
||||||
// Returns true if the transaction is in the mempool after any size
|
// Returns true if the transaction is in the mempool after any size
|
||||||
|
@ -842,7 +845,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata)
|
bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
|
||||||
{
|
{
|
||||||
const CTransaction& tx = *ws.m_ptx;
|
const CTransaction& tx = *ws.m_ptx;
|
||||||
TxValidationState& state = ws.m_state;
|
TxValidationState& state = ws.m_state;
|
||||||
|
@ -851,13 +854,13 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, Prec
|
||||||
|
|
||||||
// Check input scripts and signatures.
|
// Check input scripts and signatures.
|
||||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||||
if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) {
|
if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, ws.m_precomputed_txdata)) {
|
||||||
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
||||||
// need to turn both off, and compare against just turning off CLEANSTACK
|
// need to turn both off, and compare against just turning off CLEANSTACK
|
||||||
// to see if the failure is specifically due to witness validation.
|
// to see if the failure is specifically due to witness validation.
|
||||||
TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts
|
TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts
|
||||||
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
|
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, ws.m_precomputed_txdata) &&
|
||||||
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
|
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, ws.m_precomputed_txdata)) {
|
||||||
// Only the witness is missing, so the transaction itself may be fine.
|
// Only the witness is missing, so the transaction itself may be fine.
|
||||||
state.Invalid(TxValidationResult::TX_WITNESS_STRIPPED,
|
state.Invalid(TxValidationResult::TX_WITNESS_STRIPPED,
|
||||||
state.GetRejectReason(), state.GetDebugMessage());
|
state.GetRejectReason(), state.GetDebugMessage());
|
||||||
|
@ -868,7 +871,7 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws, Prec
|
||||||
return true;
|
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 CTransaction& tx = *ws.m_ptx;
|
||||||
const uint256& hash = ws.m_hash;
|
const uint256& hash = ws.m_hash;
|
||||||
|
@ -891,7 +894,8 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, P
|
||||||
// invalid blocks (using TestBlockValidity), however allowing such
|
// invalid blocks (using TestBlockValidity), however allowing such
|
||||||
// transactions into the mempool can be exploited as a DoS attack.
|
// transactions into the mempool can be exploited as a DoS attack.
|
||||||
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(m_active_chainstate.m_chain.Tip(), chainparams.GetConsensus());
|
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(m_active_chainstate.m_chain.Tip(), chainparams.GetConsensus());
|
||||||
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata, m_active_chainstate.CoinsTip())) {
|
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags,
|
||||||
|
ws.m_precomputed_txdata, m_active_chainstate.CoinsTip())) {
|
||||||
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s",
|
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s",
|
||||||
__func__, hash.ToString(), state.ToString());
|
__func__, hash.ToString(), state.ToString());
|
||||||
}
|
}
|
||||||
|
@ -952,15 +956,11 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
||||||
|
|
||||||
if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
|
if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
|
||||||
|
|
||||||
// Only compute the precomputed transaction data if we need to verify
|
// Perform the inexpensive checks first and avoid hashing and signature verification unless
|
||||||
// scripts (ie, other policy checks pass). We perform the inexpensive
|
// those checks pass, to mitigate CPU exhaustion denial-of-service attacks.
|
||||||
// checks first and avoid hashing and signature verification unless those
|
if (!PolicyScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
|
||||||
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
|
|
||||||
PrecomputedTransactionData txdata;
|
|
||||||
|
|
||||||
if (!PolicyScriptChecks(args, ws, txdata)) return MempoolAcceptResult::Failure(ws.m_state);
|
if (!ConsensusScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
|
||||||
|
|
||||||
if (!ConsensusScriptChecks(args, ws, txdata)) return MempoolAcceptResult::Failure(ws.m_state);
|
|
||||||
|
|
||||||
// Tx was accepted, but not added
|
// Tx was accepted, but not added
|
||||||
if (args.m_test_accept) {
|
if (args.m_test_accept) {
|
||||||
|
@ -1020,8 +1020,7 @@ PackageMempoolAcceptResult MemPoolAccept::AcceptMultipleTransactions(const std::
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Workspace& ws : workspaces) {
|
for (Workspace& ws : workspaces) {
|
||||||
PrecomputedTransactionData txdata;
|
if (!PolicyScriptChecks(args, ws)) {
|
||||||
if (!PolicyScriptChecks(args, ws, txdata)) {
|
|
||||||
// Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished.
|
// Exit early to avoid doing pointless work. Update the failed tx result; the rest are unfinished.
|
||||||
package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
|
package_state.Invalid(PackageValidationResult::PCKG_TX, "transaction failed");
|
||||||
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
|
results.emplace(ws.m_ptx->GetWitnessHash(), MempoolAcceptResult::Failure(ws.m_state));
|
||||||
|
|
Loading…
Add table
Reference in a new issue