mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-13 11:40:42 +02:00
[REFACTOR] Initialize PrecomputedTransactionData in CheckInputScripts
Add a default constructor to `PrecomputedTransactionData`, which doesn't initialize the struct's members. Instead they're initialized inside the `CheckInputScripts()` function. This allows a later commit to add the spent UTXOs to that structure.
This commit is contained in:
parent
5504703a9f
commit
f63dec189c
@ -1279,18 +1279,29 @@ uint256 GetOutputsHash(const T& txTo)
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
|
void PrecomputedTransactionData::Init(const T& txTo)
|
||||||
{
|
{
|
||||||
|
assert(!m_ready);
|
||||||
|
|
||||||
// Cache is calculated only for transactions with witness
|
// Cache is calculated only for transactions with witness
|
||||||
if (txTo.HasWitness()) {
|
if (txTo.HasWitness()) {
|
||||||
hashPrevouts = GetPrevoutHash(txTo);
|
hashPrevouts = GetPrevoutHash(txTo);
|
||||||
hashSequence = GetSequenceHash(txTo);
|
hashSequence = GetSequenceHash(txTo);
|
||||||
hashOutputs = GetOutputsHash(txTo);
|
hashOutputs = GetOutputsHash(txTo);
|
||||||
ready = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
|
||||||
|
{
|
||||||
|
Init(txTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicit instantiation
|
// explicit instantiation
|
||||||
|
template void PrecomputedTransactionData::Init(const CTransaction& txTo);
|
||||||
|
template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo);
|
||||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
||||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
||||||
|
|
||||||
@ -1303,7 +1314,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
|
|||||||
uint256 hashPrevouts;
|
uint256 hashPrevouts;
|
||||||
uint256 hashSequence;
|
uint256 hashSequence;
|
||||||
uint256 hashOutputs;
|
uint256 hashOutputs;
|
||||||
const bool cacheready = cache && cache->ready;
|
const bool cacheready = cache && cache->m_ready;
|
||||||
|
|
||||||
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
||||||
hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
|
hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
|
||||||
|
@ -121,7 +121,12 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
|||||||
struct PrecomputedTransactionData
|
struct PrecomputedTransactionData
|
||||||
{
|
{
|
||||||
uint256 hashPrevouts, hashSequence, hashOutputs;
|
uint256 hashPrevouts, hashSequence, hashOutputs;
|
||||||
bool ready = false;
|
bool m_ready = false;
|
||||||
|
|
||||||
|
PrecomputedTransactionData() = default;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Init(const T& tx);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
explicit PrecomputedTransactionData(const T& tx);
|
explicit PrecomputedTransactionData(const T& tx);
|
||||||
|
@ -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, txdata[i], g_parallel_script_checks ? &vChecks : nullptr)) {
|
if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[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());
|
||||||
|
Loading…
Reference in New Issue
Block a user