Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 4,074 Lines • ▼ Show 20 Lines | static bool ContextualCheckBlock(const CBlock &block, | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* If the provided block header is valid, add it to the block index. | * If the provided block header is valid, add it to the block index. | ||||
* | * | ||||
* Returns true if the block is successfully added to the block index. | * Returns true if the block is successfully added to the block index. | ||||
*/ | */ | ||||
bool ChainstateManager::AcceptBlockHeader(const Config &config, | bool ChainstateManager::AcceptBlockHeader(const CBlockHeader &block, | ||||
const CBlockHeader &block, | |||||
BlockValidationState &state, | BlockValidationState &state, | ||||
CBlockIndex **ppindex, | CBlockIndex **ppindex, | ||||
bool min_pow_checked) { | bool min_pow_checked) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
const Config &config = this->GetConfig(); | |||||
const CChainParams &chainparams = config.GetChainParams(); | const CChainParams &chainparams = config.GetChainParams(); | ||||
// Check for duplicate | // Check for duplicate | ||||
BlockHash hash = block.GetHash(); | BlockHash hash = block.GetHash(); | ||||
BlockMap::iterator miSelf{m_blockman.m_block_index.find(hash)}; | BlockMap::iterator miSelf{m_blockman.m_block_index.find(hash)}; | ||||
if (hash != chainparams.GetConsensus().hashGenesisBlock) { | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
if (miSelf != m_blockman.m_block_index.end()) { | if (miSelf != m_blockman.m_block_index.end()) { | ||||
// Block header is already known. | // Block header is already known. | ||||
▲ Show 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | if (ppindex) { | ||||
*ppindex = pindex; | *ppindex = pindex; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
// Exposed wrapper for AcceptBlockHeader | // Exposed wrapper for AcceptBlockHeader | ||||
bool ChainstateManager::ProcessNewBlockHeaders( | bool ChainstateManager::ProcessNewBlockHeaders( | ||||
const Config &config, const std::vector<CBlockHeader> &headers, | const std::vector<CBlockHeader> &headers, bool min_pow_checked, | ||||
bool min_pow_checked, BlockValidationState &state, | BlockValidationState &state, const CBlockIndex **ppindex) { | ||||
const CBlockIndex **ppindex) { | |||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
for (const CBlockHeader &header : headers) { | for (const CBlockHeader &header : headers) { | ||||
// Use a temp pindex instead of ppindex to avoid a const_cast | // Use a temp pindex instead of ppindex to avoid a const_cast | ||||
CBlockIndex *pindex = nullptr; | CBlockIndex *pindex = nullptr; | ||||
bool accepted = AcceptBlockHeader(config, header, state, &pindex, | bool accepted = | ||||
min_pow_checked); | AcceptBlockHeader(header, state, &pindex, min_pow_checked); | ||||
ActiveChainstate().CheckBlockIndex(); | ActiveChainstate().CheckBlockIndex(); | ||||
if (!accepted) { | if (!accepted) { | ||||
return false; | return false; | ||||
} | } | ||||
if (ppindex) { | if (ppindex) { | ||||
*ppindex = pindex; | *ppindex = pindex; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (NotifyHeaderTip(ActiveChainstate())) { | if (NotifyHeaderTip(ActiveChainstate())) { | ||||
if (ActiveChainstate().IsInitialBlockDownload() && ppindex && | if (ActiveChainstate().IsInitialBlockDownload() && ppindex && | ||||
*ppindex) { | *ppindex) { | ||||
const CBlockIndex &last_accepted{**ppindex}; | const CBlockIndex &last_accepted{**ppindex}; | ||||
const int64_t blocks_left{ | const int64_t blocks_left{ | ||||
(GetTime() - last_accepted.GetBlockTime()) / | (GetTime() - last_accepted.GetBlockTime()) / | ||||
config.GetChainParams().GetConsensus().nPowTargetSpacing}; | this->GetConsensus().nPowTargetSpacing}; | ||||
const double progress{100.0 * last_accepted.nHeight / | const double progress{100.0 * last_accepted.nHeight / | ||||
(last_accepted.nHeight + blocks_left)}; | (last_accepted.nHeight + blocks_left)}; | ||||
LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", | LogPrintf("Synchronizing blockheaders, height: %d (~%.2f%%)\n", | ||||
last_accepted.nHeight, progress); | last_accepted.nHeight, progress); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | bool Chainstate::AcceptBlock(const Config &config, | ||||
const CBlock &block = *pblock; | const CBlock &block = *pblock; | ||||
if (fNewBlock) { | if (fNewBlock) { | ||||
*fNewBlock = false; | *fNewBlock = false; | ||||
} | } | ||||
CBlockIndex *pindex = nullptr; | CBlockIndex *pindex = nullptr; | ||||
bool accepted_header{m_chainman.AcceptBlockHeader( | bool accepted_header{ | ||||
config, block, state, &pindex, min_pow_checked)}; | m_chainman.AcceptBlockHeader(block, state, &pindex, min_pow_checked)}; | ||||
CheckBlockIndex(); | CheckBlockIndex(); | ||||
if (!accepted_header) { | if (!accepted_header) { | ||||
return false; | return false; | ||||
} | } | ||||
// Try to process all requested blocks that we don't have, but only | // Try to process all requested blocks that we don't have, but only | ||||
// process an unrequested block if it's new and has enough work to | // process an unrequested block if it's new and has enough work to | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | bool Chainstate::AcceptBlock(const Config &config, | ||||
FlushStateToDisk(state, FlushStateMode::NONE); | FlushStateToDisk(state, FlushStateMode::NONE); | ||||
CheckBlockIndex(); | CheckBlockIndex(); | ||||
return true; | return true; | ||||
} | } | ||||
bool ChainstateManager::ProcessNewBlock( | bool ChainstateManager::ProcessNewBlock( | ||||
const Config &config, const std::shared_ptr<const CBlock> &block, | const std::shared_ptr<const CBlock> &block, bool force_processing, | ||||
bool force_processing, bool min_pow_checked, bool *new_block) { | bool min_pow_checked, bool *new_block) { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
{ | { | ||||
if (new_block) { | if (new_block) { | ||||
*new_block = false; | *new_block = false; | ||||
} | } | ||||
BlockValidationState state; | BlockValidationState state; | ||||
// CheckBlock() does not support multi-threaded block validation | // CheckBlock() does not support multi-threaded block validation | ||||
// because CBlock::fChecked can cause data race. | // because CBlock::fChecked can cause data race. | ||||
// Therefore, the following critical section must include the | // Therefore, the following critical section must include the | ||||
// CheckBlock() call as well. | // CheckBlock() call as well. | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Skipping AcceptBlock() for CheckBlock() failures means that we will | // Skipping AcceptBlock() for CheckBlock() failures means that we will | ||||
// never mark a block as invalid if CheckBlock() fails. This is | // never mark a block as invalid if CheckBlock() fails. This is | ||||
// protective against consensus failure if there are any unknown form | // protective against consensus failure if there are any unknown form | ||||
// s of block malleability that cause CheckBlock() to fail; see e.g. | // s of block malleability that cause CheckBlock() to fail; see e.g. | ||||
// CVE-2012-2459 and | // CVE-2012-2459 and | ||||
// https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-February/016697.html. | // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-February/016697.html. | ||||
// Because CheckBlock() is not very expensive, the anti-DoS benefits of | // Because CheckBlock() is not very expensive, the anti-DoS benefits of | ||||
// caching failure (of a definitely-invalid block) are not substantial. | // caching failure (of a definitely-invalid block) are not substantial. | ||||
bool ret = | bool ret = CheckBlock(*block, state, this->GetConsensus(), | ||||
CheckBlock(*block, state, config.GetChainParams().GetConsensus(), | BlockValidationOptions(this->GetConfig())); | ||||
BlockValidationOptions(config)); | |||||
if (ret) { | if (ret) { | ||||
// Store to disk | // Store to disk | ||||
ret = ActiveChainstate().AcceptBlock(config, block, state, | ret = ActiveChainstate().AcceptBlock( | ||||
force_processing, nullptr, | this->GetConfig(), block, state, force_processing, nullptr, | ||||
new_block, min_pow_checked); | new_block, min_pow_checked); | ||||
} | } | ||||
if (!ret) { | if (!ret) { | ||||
GetMainSignals().BlockChecked(*block, state); | GetMainSignals().BlockChecked(*block, state); | ||||
return error("%s: AcceptBlock FAILED (%s)", __func__, | return error("%s: AcceptBlock FAILED (%s)", __func__, | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,033 Lines • Show Last 20 Lines |