mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-05 14:06:27 -05:00
Merge #18401: Refactor: Initialize PrecomputedTransactionData in CheckInputScripts
f63dec189c
[REFACTOR] Initialize PrecomputedTransactionData in CheckInputScripts (Pieter Wuille) Pull request description: This is a single commit taken from the Schnorr/Taproot PR #17977. 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. The spent UTXOs are required for the schnorr signature hash, since it commits to the scriptPubKeys. See https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message for details. By itself, this isn't really an improvement to the code, but I think it makes sense to separate out the refactor/moveonly commits from PR #17977 so that PR is only the logical changes needed for Schnorr/Taproot. ACKs for top commit: jonatack: Re-ACKf63dec1
`git diff 851908d f63dec1` shows no change since last ACK. sipa: utACKf63dec189c
theStack: re-ACKf63dec189c
fjahr: Re-ACKf63dec189c
ariard: Code Review ACKf63dec1
Tree-SHA512: ecf9154077824ae4c274b4341e985797f3648c0cb0c31cb25ce382163b923a3acbc7048683720be4ae3663501801129cd0f48c441a36f049cc304ebe9f30994e
This commit is contained in:
commit
e16718a8b3
3 changed files with 32 additions and 9 deletions
|
@ -1291,18 +1291,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);
|
||||||
|
|
||||||
|
@ -1315,7 +1326,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;
|
||||||
|
|
||||||
|
@ -1516,6 +1516,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);
|
||||||
|
@ -2079,15 +2083,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]);
|
||||||
|
@ -2134,13 +2142,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…
Add table
Reference in a new issue