@ -1016,7 +1016,7 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
// scripts (ie, other policy checks pass). We perform the inexpensive
// scripts (ie, other policy checks pass). We perform the inexpensive
// checks first and avoid hashing and signature verification unless those
// checks first and avoid hashing and signature verification unless those
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
// checks pass, to mitigate CPU exhaustion denial-of-service attacks.
PrecomputedTransactionData txdata ( * ptx ) ;
PrecomputedTransactionData txdata ;
if ( ! PolicyScriptChecks ( args , workspace , txdata ) ) return false ;
if ( ! PolicyScriptChecks ( args , workspace , txdata ) ) return false ;
@ -1512,6 +1512,10 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
return true ;
return true ;
}
}
if ( ! txdata . m_ready ) {
txdata . Init ( tx ) ;
}
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + ) {
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + ) {
const COutPoint & prevout = tx . vin [ i ] . prevout ;
const COutPoint & prevout = tx . vin [ i ] . prevout ;
const Coin & coin = inputs . AccessCoin ( prevout ) ;
const Coin & coin = inputs . AccessCoin ( prevout ) ;
@ -2075,15 +2079,19 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
CBlockUndo blockundo ;
CBlockUndo blockundo ;
// Precomputed transaction data pointers must not be invalidated
// until after `control` has run the script checks (potentially
// in multiple threads). Preallocate the vector size so a new allocation
// doesn't invalidate pointers into the vector, and keep txsdata in scope
// for as long as `control`.
CCheckQueueControl < CScriptCheck > control ( fScriptChecks & & g_parallel_script_checks ? & scriptcheckqueue : nullptr ) ;
CCheckQueueControl < CScriptCheck > control ( fScriptChecks & & g_parallel_script_checks ? & scriptcheckqueue : nullptr ) ;
std : : vector < PrecomputedTransactionData > txsdata ( block . vtx . size ( ) ) ;
std : : vector < int > prevheights ;
std : : vector < int > prevheights ;
CAmount nFees = 0 ;
CAmount nFees = 0 ;
int nInputs = 0 ;
int nInputs = 0 ;
int64_t nSigOpsCost = 0 ;
int64_t nSigOpsCost = 0 ;
blockundo . vtxundo . reserve ( block . vtx . size ( ) - 1 ) ;
blockundo . vtxundo . reserve ( block . vtx . size ( ) - 1 ) ;
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 + + )
for ( unsigned int i = 0 ; i < block . vtx . size ( ) ; i + + )
{
{
const CTransaction & tx = * ( block . vtx [ i ] ) ;
const CTransaction & tx = * ( block . vtx [ i ] ) ;
@ -2130,13 +2138,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
return state . Invalid ( BlockValidationResult : : BLOCK_CONSENSUS , " bad-blk-sigops " ) ;
return state . Invalid ( BlockValidationResult : : BLOCK_CONSENSUS , " bad-blk-sigops " ) ;
}
}
txdata . emplace_back ( tx ) ;
if ( ! tx . IsCoinBase ( ) )
if ( ! tx . IsCoinBase ( ) )
{
{
std : : vector < CScriptCheck > vChecks ;
std : : vector < CScriptCheck > vChecks ;
bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
bool fCacheResults = fJustCheck ; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
TxValidationState tx_state ;
TxValidationState tx_state ;
if ( fScriptChecks & & ! CheckInputScripts ( tx , tx_state , view , flags , fCacheResults , fCacheResults , tx data[ i ] , g_parallel_script_checks ? & vChecks : nullptr ) ) {
if ( fScriptChecks & & ! CheckInputScripts ( tx , tx_state , view , flags , fCacheResults , fCacheResults , tx s data[ i ] , g_parallel_script_checks ? & vChecks : nullptr ) ) {
// Any transaction validation failure in ConnectBlock is a block consensus failure
// Any transaction validation failure in ConnectBlock is a block consensus failure
state . Invalid ( BlockValidationResult : : BLOCK_CONSENSUS ,
state . Invalid ( BlockValidationResult : : BLOCK_CONSENSUS ,
tx_state . GetRejectReason ( ) , tx_state . GetDebugMessage ( ) ) ;
tx_state . GetRejectReason ( ) , tx_state . GetDebugMessage ( ) ) ;