@@ -1016,7 +1016,7 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
1016
1016
// scripts (ie, other policy checks pass). We perform the inexpensive
1017
1017
// checks first and avoid hashing and signature verification unless those
1018
1018
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
1019
- PrecomputedTransactionData txdata (*ptx) ;
1019
+ PrecomputedTransactionData txdata;
1020
1020
1021
1021
if (!PolicyScriptChecks (args, workspace, txdata)) return false ;
1022
1022
@@ -1512,6 +1512,10 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
1512
1512
return true ;
1513
1513
}
1514
1514
1515
+ if (!txdata.m_ready ) {
1516
+ txdata.Init (tx);
1517
+ }
1518
+
1515
1519
for (unsigned int i = 0 ; i < tx.vin .size (); i++) {
1516
1520
const COutPoint &prevout = tx.vin [i].prevout ;
1517
1521
const Coin& coin = inputs.AccessCoin (prevout);
@@ -2075,15 +2079,19 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2075
2079
2076
2080
CBlockUndo blockundo;
2077
2081
2082
+ // Precomputed transaction data pointers must not be invalidated
2083
+ // until after `control` has run the script checks (potentially
2084
+ // in multiple threads). Preallocate the vector size so a new allocation
2085
+ // doesn't invalidate pointers into the vector, and keep txsdata in scope
2086
+ // for as long as `control`.
2078
2087
CCheckQueueControl<CScriptCheck> control (fScriptChecks && g_parallel_script_checks ? &scriptcheckqueue : nullptr );
2088
+ std::vector<PrecomputedTransactionData> txsdata (block.vtx .size ());
2079
2089
2080
2090
std::vector<int > prevheights;
2081
2091
CAmount nFees = 0 ;
2082
2092
int nInputs = 0 ;
2083
2093
int64_t nSigOpsCost = 0 ;
2084
2094
blockundo.vtxundo .reserve (block.vtx .size () - 1 );
2085
- std::vector<PrecomputedTransactionData> txdata;
2086
- txdata.reserve (block.vtx .size ()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
2087
2095
for (unsigned int i = 0 ; i < block.vtx .size (); i++)
2088
2096
{
2089
2097
const CTransaction &tx = *(block.vtx [i]);
@@ -2130,13 +2138,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2130
2138
return state.Invalid (BlockValidationResult::BLOCK_CONSENSUS, " bad-blk-sigops" );
2131
2139
}
2132
2140
2133
- txdata.emplace_back (tx);
2134
2141
if (!tx.IsCoinBase ())
2135
2142
{
2136
2143
std::vector<CScriptCheck> vChecks;
2137
2144
bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
2138
2145
TxValidationState tx_state;
2139
- if (fScriptChecks && !CheckInputScripts (tx, tx_state, view, flags, fCacheResults , fCacheResults , txdata [i], g_parallel_script_checks ? &vChecks : nullptr )) {
2146
+ if (fScriptChecks && !CheckInputScripts (tx, tx_state, view, flags, fCacheResults , fCacheResults , txsdata [i], g_parallel_script_checks ? &vChecks : nullptr )) {
2140
2147
// Any transaction validation failure in ConnectBlock is a block consensus failure
2141
2148
state.Invalid (BlockValidationResult::BLOCK_CONSENSUS,
2142
2149
tx_state.GetRejectReason (), tx_state.GetDebugMessage ());
0 commit comments