Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 272 Lines • ▼ Show 20 Lines | |||||
/** Dirty block index entries. */ | /** Dirty block index entries. */ | ||||
std::set<const CBlockIndex *> setDirtyBlockIndex; | std::set<const CBlockIndex *> setDirtyBlockIndex; | ||||
/** Dirty block file entries. */ | /** Dirty block file entries. */ | ||||
std::set<int> setDirtyFileInfo; | std::set<int> setDirtyFileInfo; | ||||
} // namespace | } // namespace | ||||
BlockValidationOptions::BlockValidationOptions(const Config &config) | |||||
: checkPoW(true), checkMerkleRoot(true), | |||||
excessiveBlockSize(config.GetMaxBlockSize()) {} | |||||
CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | ||||
const CBlockLocator &locator) { | const CBlockLocator &locator) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// Find the first block the caller has in the main chain | // Find the first block the caller has in the main chain | ||||
for (const uint256 &hash : locator.vHave) { | for (const uint256 &hash : locator.vHave) { | ||||
CBlockIndex *pindex = LookupBlockIndex(hash); | CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
if (pindex) { | if (pindex) { | ||||
▲ Show 20 Lines • Show All 1,381 Lines • ▼ Show 20 Lines | bool CChainState::ConnectBlock(const Config &config, const CBlock &block, | ||||
// software, and we would NOT be enforcing the rule here. Fully solving | // software, and we would NOT be enforcing the rule here. Fully solving | ||||
// upgrade from one software version to the next after a consensus rule | // upgrade from one software version to the next after a consensus rule | ||||
// change is potentially tricky and issue-specific (see RewindBlockIndex() | // change is potentially tricky and issue-specific (see RewindBlockIndex() | ||||
// for one general approach that was used for BIP 141 deployment). | // for one general approach that was used for BIP 141 deployment). | ||||
// Also, currently the rule against blocks more than 2 hours in the future | // Also, currently the rule against blocks more than 2 hours in the future | ||||
// is enforced in ContextualCheckBlockHeader(); we wouldn't want to | // is enforced in ContextualCheckBlockHeader(); we wouldn't want to | ||||
// re-enforce that rule here (at least until we make it impossible for | // re-enforce that rule here (at least until we make it impossible for | ||||
// GetAdjustedTime() to go backward). | // GetAdjustedTime() to go backward). | ||||
BlockValidationOptions validationOptions = | if (!CheckBlock(config, block, state, | ||||
BlockValidationOptions(!fJustCheck, !fJustCheck); | BlockValidationOptions(config) | ||||
if (!CheckBlock(config, block, state, validationOptions)) { | .withCheckPoW(!fJustCheck) | ||||
.withCheckMerkleRoot(!fJustCheck))) { | |||||
if (state.CorruptionPossible()) { | if (state.CorruptionPossible()) { | ||||
// We don't write down blocks to disk if they may have been | // We don't write down blocks to disk if they may have been | ||||
// corrupted, so this should be impossible unless we're having | // corrupted, so this should be impossible unless we're having | ||||
// hardware problems. | // hardware problems. | ||||
return AbortNode(state, "Corrupt block found indicating potential " | return AbortNode(state, "Corrupt block found indicating potential " | ||||
"hardware failure; shutting down"); | "hardware failure; shutting down"); | ||||
} | } | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
▲ Show 20 Lines • Show All 1,744 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Return true if the provided block header is valid. | * Return true if the provided block header is valid. | ||||
* Only verify PoW if blockValidationOptions is configured to do so. | * Only verify PoW if blockValidationOptions is configured to do so. | ||||
* This allows validation of headers on which the PoW hasn't been done. | * This allows validation of headers on which the PoW hasn't been done. | ||||
* For example: to validate template handed to mining software. | * For example: to validate template handed to mining software. | ||||
* Do not call this for any check that depends on the context. | * Do not call this for any check that depends on the context. | ||||
* For context-dependent calls, see ContextualCheckBlockHeader. | * For context-dependent calls, see ContextualCheckBlockHeader. | ||||
*/ | */ | ||||
static bool CheckBlockHeader( | static bool CheckBlockHeader(const Config &config, const CBlockHeader &block, | ||||
const Config &config, const CBlockHeader &block, CValidationState &state, | CValidationState &state, | ||||
BlockValidationOptions validationOptions = BlockValidationOptions()) { | BlockValidationOptions validationOptions) { | ||||
// Check proof of work matches claimed amount | // Check proof of work matches claimed amount | ||||
if (validationOptions.shouldValidatePoW() && | if (validationOptions.shouldValidatePoW() && | ||||
!CheckProofOfWork(block.GetHash(), block.nBits, | !CheckProofOfWork(block.GetHash(), block.nBits, | ||||
config.GetChainParams().GetConsensus())) { | config.GetChainParams().GetConsensus())) { | ||||
return state.DoS(50, false, REJECT_INVALID, "high-hash", false, | return state.DoS(50, false, REJECT_INVALID, "high-hash", false, | ||||
"proof of work failed"); | "proof of work failed"); | ||||
} | } | ||||
Show All 38 Lines | bool CheckBlock(const Config &config, const CBlock &block, | ||||
// First transaction must be coinbase. | // First transaction must be coinbase. | ||||
if (block.vtx.empty()) { | if (block.vtx.empty()) { | ||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, | return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, | ||||
"first tx is not coinbase"); | "first tx is not coinbase"); | ||||
} | } | ||||
// Size limits. | // Size limits. | ||||
auto nMaxBlockSize = config.GetMaxBlockSize(); | auto nMaxBlockSize = validationOptions.getExcessiveBlockSize(); | ||||
// Bail early if there is no way this block is of reasonable size. | // Bail early if there is no way this block is of reasonable size. | ||||
if ((block.vtx.size() * MIN_TRANSACTION_SIZE) > nMaxBlockSize) { | if ((block.vtx.size() * MIN_TRANSACTION_SIZE) > nMaxBlockSize) { | ||||
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, | return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, | ||||
"size limits failed"); | "size limits failed"); | ||||
} | } | ||||
auto currentBlockSize = | auto currentBlockSize = | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
return state.Invalid(error("%s: block %s is marked invalid", | return state.Invalid(error("%s: block %s is marked invalid", | ||||
__func__, hash.ToString()), | __func__, hash.ToString()), | ||||
0, "duplicate"); | 0, "duplicate"); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (!CheckBlockHeader(config, block, state)) { | if (!CheckBlockHeader(config, block, state, | ||||
BlockValidationOptions(config))) { | |||||
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | ||||
hash.ToString(), FormatStateMessage(state)); | hash.ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
// Get prev block index | // Get prev block index | ||||
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); | BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); | ||||
if (mi == mapBlockIndex.end()) { | if (mi == mapBlockIndex.end()) { | ||||
return state.DoS(10, error("%s: prev block not found", __func__), 0, | return state.DoS(10, error("%s: prev block not found", __func__), 0, | ||||
▲ Show 20 Lines • Show All 205 Lines • ▼ Show 20 Lines | if (!fRequested) { | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
if (fNewBlock) { | if (fNewBlock) { | ||||
*fNewBlock = true; | *fNewBlock = true; | ||||
} | } | ||||
if (!CheckBlock(config, block, state) || | if (!CheckBlock(config, block, state, BlockValidationOptions(config)) || | ||||
!ContextualCheckBlock(config, block, state, pindex->pprev)) { | !ContextualCheckBlock(config, block, state, pindex->pprev)) { | ||||
if (state.IsInvalid() && !state.CorruptionPossible()) { | if (state.IsInvalid() && !state.CorruptionPossible()) { | ||||
pindex->nStatus = pindex->nStatus.withFailed(); | pindex->nStatus = pindex->nStatus.withFailed(); | ||||
setDirtyBlockIndex.insert(pindex); | setDirtyBlockIndex.insert(pindex); | ||||
} | } | ||||
return error("%s: %s (block %s)", __func__, FormatStateMessage(state), | return error("%s: %s (block %s)", __func__, FormatStateMessage(state), | ||||
block.GetHash().ToString()); | block.GetHash().ToString()); | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | AssertLockNotHeld(cs_main); | ||||
// 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); | ||||
// Ensure that CheckBlock() passes before calling AcceptBlock, as | // Ensure that CheckBlock() passes before calling AcceptBlock, as | ||||
// belt-and-suspenders. | // belt-and-suspenders. | ||||
bool ret = CheckBlock(config, *pblock, state); | bool ret = | ||||
CheckBlock(config, *pblock, state, BlockValidationOptions(config)); | |||||
if (ret) { | if (ret) { | ||||
// Store to disk | // Store to disk | ||||
ret = g_chainstate.AcceptBlock( | ret = g_chainstate.AcceptBlock( | ||||
config, pblock, state, fForceProcessing, nullptr, fNewBlock); | config, pblock, state, fForceProcessing, nullptr, fNewBlock); | ||||
} | } | ||||
if (!ret) { | if (!ret) { | ||||
GetMainSignals().BlockChecked(*pblock, state); | GetMainSignals().BlockChecked(*pblock, state); | ||||
▲ Show 20 Lines • Show All 534 Lines • ▼ Show 20 Lines | for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev; | ||||
// check level 0: read from disk | // check level 0: read from disk | ||||
if (!ReadBlockFromDisk(block, pindex, consensusParams)) { | if (!ReadBlockFromDisk(block, pindex, consensusParams)) { | ||||
return error( | return error( | ||||
"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", | "VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
// check level 1: verify block validity | // check level 1: verify block validity | ||||
if (nCheckLevel >= 1 && !CheckBlock(config, block, state)) { | if (nCheckLevel >= 1 && | ||||
!CheckBlock(config, block, state, BlockValidationOptions(config))) { | |||||
return error("%s: *** found bad block at %d, hash=%s (%s)\n", | return error("%s: *** found bad block at %d, hash=%s (%s)\n", | ||||
__func__, pindex->nHeight, | __func__, pindex->nHeight, | ||||
pindex->GetBlockHash().ToString(), | pindex->GetBlockHash().ToString(), | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
// check level 2: verify undo validity | // check level 2: verify undo validity | ||||
if (nCheckLevel >= 2 && pindex) { | if (nCheckLevel >= 2 && pindex) { | ||||
▲ Show 20 Lines • Show All 1,056 Lines • Show Last 20 Lines |