Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 324 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
assert(txFrom->vout[txin.prevout.GetN()] == coin.GetTxOut()); | assert(txFrom->vout[txin.prevout.GetN()] == coin.GetTxOut()); | ||||
} else { | } else { | ||||
const Coin &coinFromDisk = pcoinsTip->AccessCoin(txin.prevout); | const Coin &coinFromDisk = pcoinsTip->AccessCoin(txin.prevout); | ||||
assert(!coinFromDisk.IsSpent()); | assert(!coinFromDisk.IsSpent()); | ||||
assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | ||||
} | } | ||||
} | } | ||||
return CheckInputs(tx, state, view, true, flags, cacheSigStore, true, | return CheckInputs(tx, state, view, flags, cacheSigStore, true, txdata, | ||||
txdata, nSigChecksOut); | nSigChecksOut); | ||||
} | } | ||||
/** | /** | ||||
* @param[out] coins_to_uncache Return any outpoints which were not previously | * @param[out] coins_to_uncache Return any outpoints which were not previously | ||||
* present in the coins cache, but were added as a result of validating the tx | * present in the coins cache, but were added as a result of validating the tx | ||||
* for mempool acceptance. This allows the caller | * for mempool acceptance. This allows the caller | ||||
* to optionally remove the cache additions if the associated transaction ends | * to optionally remove the cache additions if the associated transaction ends | ||||
* up being rejected by the mempool. | * up being rejected by the mempool. | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
strprintf("%d > %d", nFees, nAbsurdFee)); | strprintf("%d > %d", nFees, nAbsurdFee)); | ||||
} | } | ||||
// Validate input scripts against standard script flags. | // Validate input scripts against standard script flags. | ||||
const uint32_t scriptVerifyFlags = | const uint32_t scriptVerifyFlags = | ||||
nextBlockScriptVerifyFlags | STANDARD_SCRIPT_VERIFY_FLAGS; | nextBlockScriptVerifyFlags | STANDARD_SCRIPT_VERIFY_FLAGS; | ||||
PrecomputedTransactionData txdata(tx); | PrecomputedTransactionData txdata(tx); | ||||
int nSigChecksStandard; | int nSigChecksStandard; | ||||
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, | if (!CheckInputs(tx, state, view, scriptVerifyFlags, true, false, | ||||
txdata, nSigChecksStandard)) { | txdata, nSigChecksStandard)) { | ||||
// State filled in by CheckInputs. | // State filled in by CheckInputs. | ||||
return false; | return false; | ||||
} | } | ||||
CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), | CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), | ||||
fSpendsCoinbase, nSigChecksStandard, lp); | fSpendsCoinbase, nSigChecksStandard, lp); | ||||
▲ Show 20 Lines • Show All 494 Lines • ▼ Show 20 Lines | |||||
int GetSpendHeight(const CCoinsViewCache &inputs) { | int GetSpendHeight(const CCoinsViewCache &inputs) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CBlockIndex *pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | CBlockIndex *pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | ||||
return pindexPrev->nHeight + 1; | return pindexPrev->nHeight + 1; | ||||
} | } | ||||
bool CheckInputs(const CTransaction &tx, TxValidationState &state, | bool CheckInputs(const CTransaction &tx, TxValidationState &state, | ||||
const CCoinsViewCache &inputs, bool fScriptChecks, | const CCoinsViewCache &inputs, const uint32_t flags, | ||||
const uint32_t flags, bool sigCacheStore, | bool sigCacheStore, bool scriptCacheStore, | ||||
bool scriptCacheStore, | |||||
const PrecomputedTransactionData &txdata, int &nSigChecksOut, | const PrecomputedTransactionData &txdata, int &nSigChecksOut, | ||||
TxSigCheckLimiter &txLimitSigChecks, | TxSigCheckLimiter &txLimitSigChecks, | ||||
CheckInputsLimiter *pBlockLimitSigChecks, | CheckInputsLimiter *pBlockLimitSigChecks, | ||||
std::vector<CScriptCheck> *pvChecks) { | std::vector<CScriptCheck> *pvChecks) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(!tx.IsCoinBase()); | assert(!tx.IsCoinBase()); | ||||
if (pvChecks) { | if (pvChecks) { | ||||
pvChecks->reserve(tx.vin.size()); | pvChecks->reserve(tx.vin.size()); | ||||
} | } | ||||
// Skip script verification when connecting blocks under the assumevalid | |||||
// block. Assuming the assumevalid block is valid this is safe because | |||||
// block merkle hashes are still computed and checked, of course, if an | |||||
// assumed valid block is invalid due to false scriptSigs this optimization | |||||
// would allow an invalid chain to be accepted. | |||||
if (!fScriptChecks) { | |||||
return true; | |||||
} | |||||
// First check if script executions have been cached with the same flags. | // First check if script executions have been cached with the same flags. | ||||
// Note that this assumes that the inputs provided are correct (ie that the | // Note that this assumes that the inputs provided are correct (ie that the | ||||
// transaction hash which is in tx's prevouts properly commits to the | // transaction hash which is in tx's prevouts properly commits to the | ||||
// scriptPubKey in the inputs view of that transaction). | // scriptPubKey in the inputs view of that transaction). | ||||
ScriptCacheKey hashCacheEntry(tx, flags); | ScriptCacheKey hashCacheEntry(tx, flags); | ||||
if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | ||||
if (!txLimitSigChecks.consume_and_check(nSigChecksOut) || | if (!txLimitSigChecks.consume_and_check(nSigChecksOut) || | ||||
(pBlockLimitSigChecks && | (pBlockLimitSigChecks && | ||||
▲ Show 20 Lines • Show All 504 Lines • ▼ Show 20 Lines | if (!hashAssumeValid.IsNull()) { | ||||
// effectively caching the result of part of the verification. | // effectively caching the result of part of the verification. | ||||
BlockMap::const_iterator it = | BlockMap::const_iterator it = | ||||
m_blockman.m_block_index.find(hashAssumeValid); | m_blockman.m_block_index.find(hashAssumeValid); | ||||
if (it != m_blockman.m_block_index.end()) { | if (it != m_blockman.m_block_index.end()) { | ||||
if (it->second->GetAncestor(pindex->nHeight) == pindex && | if (it->second->GetAncestor(pindex->nHeight) == pindex && | ||||
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | ||||
pindexBestHeader->nChainWork >= nMinimumChainWork) { | pindexBestHeader->nChainWork >= nMinimumChainWork) { | ||||
// This block is a member of the assumed verified chain and an | // This block is a member of the assumed verified chain and an | ||||
// ancestor of the best header. The equivalent time check | // ancestor of the best header. | ||||
// discourages hash power from extorting the network via DOS | // Script verification is skipped when connecting blocks under | ||||
// attack into accepting an invalid block through telling users | // the assumevalid block. Assuming the assumevalid block is | ||||
// they must manually set assumevalid. Requiring a software | // valid this is safe because block merkle hashes are still | ||||
// change or burying the invalid block, regardless of the | // computed and checked, Of course, if an assumed valid block is | ||||
// setting, makes it hard to hide the implication of the demand. | // invalid due to false scriptSigs this optimization would allow | ||||
// This also avoids having release candidates that are hardly | // an invalid chain to be accepted. | ||||
// doing any signature verification at all in testing without | // The equivalent time check discourages hash power from | ||||
// having to artificially set the default assumed verified block | // extorting the network via DOS attack into accepting an | ||||
// further back. The test against nMinimumChainWork prevents the | // invalid block through telling users they must manually set | ||||
// skipping when denied access to any chain at least as good as | // assumevalid. Requiring a software change or burying the | ||||
// the expected chain. | // invalid block, regardless of the setting, makes it hard to | ||||
// hide the implication of the demand. This also avoids having | |||||
// release candidates that are hardly doing any signature | |||||
// verification at all in testing without having to artificially | |||||
// set the default assumed verified block further back. The test | |||||
// against nMinimumChainWork prevents the skipping when denied | |||||
// access to any chain at least as good as the expected chain. | |||||
fScriptChecks = | fScriptChecks = | ||||
(GetBlockProofEquivalentTime( | (GetBlockProofEquivalentTime( | ||||
*pindexBestHeader, *pindex, *pindexBestHeader, | *pindexBestHeader, *pindex, *pindexBestHeader, | ||||
consensusParams) <= 60 * 60 * 24 * 7 * 2); | consensusParams) <= 60 * 60 * 24 * 7 * 2); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | for (const auto &ptx : block.vtx) { | ||||
nSigChecksTxLimiters[txIndex] = TxSigCheckLimiter::getDisabled(); | nSigChecksTxLimiters[txIndex] = TxSigCheckLimiter::getDisabled(); | ||||
} | } | ||||
std::vector<CScriptCheck> vChecks; | std::vector<CScriptCheck> vChecks; | ||||
// nSigChecksRet may be accurate (found in cache) or 0 (checks were | // nSigChecksRet may be accurate (found in cache) or 0 (checks were | ||||
// deferred into vChecks). | // deferred into vChecks). | ||||
int nSigChecksRet; | int nSigChecksRet; | ||||
TxValidationState tx_state; | TxValidationState tx_state; | ||||
if (!CheckInputs(tx, tx_state, view, fScriptChecks, flags, | if (fScriptChecks && | ||||
fCacheResults, fCacheResults, | !CheckInputs(tx, tx_state, view, flags, fCacheResults, | ||||
PrecomputedTransactionData(tx), nSigChecksRet, | fCacheResults, PrecomputedTransactionData(tx), | ||||
nSigChecksTxLimiters[txIndex], &nSigChecksBlockLimiter, | nSigChecksRet, nSigChecksTxLimiters[txIndex], | ||||
&vChecks)) { | &nSigChecksBlockLimiter, &vChecks)) { | ||||
// Any transaction validation failure in ConnectBlock is a block | // Any transaction validation failure in ConnectBlock is a block | ||||
// consensus failure | // consensus failure | ||||
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | ||||
tx_state.GetRejectCode(), tx_state.GetRejectReason(), | tx_state.GetRejectCode(), tx_state.GetRejectReason(), | ||||
tx_state.GetDebugMessage()); | tx_state.GetDebugMessage()); | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 4,018 Lines • Show Last 20 Lines |