Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
4251{4252AssertLockNotHeld(cs_main);4253{4254LOCK(cs_main);4255for (const CBlockHeader& header : headers) {4256CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast4257bool accepted{AcceptBlockHeader(header, state, &pindex, min_pow_checked)};4258CheckBlockIndex();4260if (!accepted) {4261return false;4262}4263if (ppindex) {4264*ppindex = pindex;4265}4266}4267}4268if (NotifyHeaderTip()) {4269if (IsInitialBlockDownload() && ppindex && *ppindex) {4270const CBlockIndex& last_accepted{**ppindex};4271int64_t blocks_left{(NodeClock::now() - last_accepted.Time()) / GetConsensus().PowTargetSpacing()};4272blocks_left = std::max<int64_t>(0, blocks_left);4273const double progress{100.0 * last_accepted.nHeight / (last_accepted.nHeight + blocks_left)};4274LogInfo("Synchronizing blockheaders, height: %d (~%.2f%%)\n", last_accepted.nHeight, progress);4275}4276}4277return true;4278}4280void ChainstateManager::ReportHeadersPresync(int64_t height, int64_t timestamp)4281{4282AssertLockNotHeld(GetMutex());4283{4284LOCK(GetMutex());4285// Don't report headers presync progress if we already have a post-minchainwork header chain.4286// This means we lose reporting for potentially legitimate, but unlikely, deep reorgs, but4287// prevent attackers that spam low-work headers from filling our logs.4288if (m_best_header->nChainWork >= UintToArith256(GetConsensus().nMinimumChainWork)) return;4289// Rate limit headers presync updates to 4 per second, as these are not subject to DoS4290// protection.4291auto now = MockableSteadyClock::now();4292if (now < m_last_presync_update + std::chrono::milliseconds{250}) return;4293m_last_presync_update = now;4294}4295bool initial_download = IsInitialBlockDownload();4296GetNotifications().headerTip(GetSynchronizationState(initial_download, m_blockman.m_blockfiles_indexed), height, timestamp, /*presync=*/true);4297if (initial_download) {4298int64_t blocks_left{(NodeClock::now() - NodeSeconds{std::chrono::seconds{timestamp}}) / GetConsensus().PowTargetSpacing()};4299blocks_left = std::max<int64_t>(0, blocks_left);4300const double progress{100.0 * height / (height + blocks_left)};4301LogInfo("Pre-synchronizing blockheaders, height: %d (~%.2f%%)\n", height, progress);4302}4303}4305/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */4306bool ChainstateManager::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked)4307{4308const CBlock& block = *pblock;4310if (fNewBlock) *fNewBlock = false;4311AssertLockHeld(cs_main);4313CBlockIndex *pindexDummy = nullptr;4314CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;4316bool accepted_header{AcceptBlockHeader(block, state, &pindex, min_pow_checked)};4317CheckBlockIndex();4319if (!accepted_header)4320return false;4322// Check all requested blocks that we do not already have for validity and4323// save them to disk. Skip processing of unrequested blocks as an anti-DoS4324// measure, unless the blocks have more work than the active chain tip, and4325// aren't too far ahead of it, so are likely to be attached soon.4326bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;4327bool fHasMoreOrSameWork = (ActiveTip() ? pindex->nChainWork >= ActiveTip()->nChainWork : true);4328// Blocks that are too out-of-order needlessly limit the effectiveness of4329// pruning, because pruning will not delete block files that contain any4330// blocks which are too close in height to the tip. Apply this test4331// regardless of whether pruning is enabled; it should generally be safe to4332// not process unrequested blocks.4333bool fTooFarAhead{pindex->nHeight > ActiveHeight() + int(MIN_BLOCKS_TO_KEEP)};4335// TODO: Decouple this function from the block download logic by removing fRequested4336// This requires some new chain data structure to efficiently look up if a4337// block is in a chain leading to a candidate for best tip, despite not4338// being such a candidate itself.4339// Note that this would break the getblockfrompeer RPC4341// TODO: deal better with return value and error conditions for duplicate4342// and unrequested blocks.4343if (fAlreadyHave) return true;4344if (!fRequested) { // If we didn't ask for it:4345if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned4346if (!fHasMoreOrSameWork) return true; // Don't process less-work chains4347if (fTooFarAhead) return true; // Block height is too high4349// Protect against DoS attacks from low-work chains.4350// If our tip is behind, a peer could try to send us4351// low-work blocks on a fake chain that we would never4352// request; don't process these.4353if (pindex->nChainWork < MinimumChainWork()) return true;4354}4356const CChainParams& params{GetParams()};4358if (!CheckBlock(block, state, params.GetConsensus()) ||4359!ContextualCheckBlock(block, state, *this, pindex->pprev)) {4360if (Assume(state.IsInvalid())) {4361ActiveChainstate().InvalidBlockFound(pindex, state);4362}4363LogError("%s: %s\n", __func__, state.ToString());4364return false;4365}4367// Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW4368// (but if it does not build on our best tip, let the SendMessages loop relay it)4369if (!IsInitialBlockDownload() && ActiveTip() == pindex->pprev && m_options.signals) {4370m_options.signals->NewPoWValidBlock(pindex, pblock);4371}4373// Write block to history file4374if (fNewBlock) *fNewBlock = true;4375try {4376FlatFilePos blockPos{};4377if (dbp) {4378blockPos = *dbp;4379m_blockman.UpdateBlockInfo(block, pindex->nHeight, blockPos);4380} else {4381blockPos = m_blockman.WriteBlock(block, pindex->nHeight);4382if (blockPos.IsNull()) {4383state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));4384return false;4385}4386}4387ReceivedBlockTransactions(block, pindex, blockPos);4388} catch (const std::runtime_error& e) {4389return FatalError(GetNotifications(), state, strprintf(_("System error while saving block to disk: %s"), e.what()));4390}4392// TODO: FlushStateToDisk() handles flushing of both block and chainstate4393// data, so we should move this to ChainstateManager so that we can be more4394// intelligent about how we flush.4395// For now, since FlushStateMode::NONE is used, all that can happen is that4396// the block files may be pruned, so we can just call this on one4397// chainstate (particularly if we haven't implemented pruning with4398// background validation yet).4399//4400// Flush errors (e.g. low disk space during pruning) are ignored, so that4401// callers can't mistreat a flush failure as a block validation failure.4402// The fatal error notification inside FlushStateToDisk still fires,4403// so the node will shut down on unrecoverable flush errors regardless.4404// For state a dummy value is used, and the return value is ignored.4405BlockValidationState flush_state_ignore;4406(void)ActiveChainstate().FlushStateToDisk(flush_state_ignore, FlushStateMode::NONE);4408CheckBlockIndex();4410return true;4411}4413bool ChainstateManager::ProcessNewBlock(const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked, bool* new_block)4414{4415AssertLockNotHeld(cs_main);4417{4418CBlockIndex *pindex = nullptr;4419if (new_block) *new_block = false;4420BlockValidationState state;4422// CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race.4423// Therefore, the following critical section must include the CheckBlock() call as well.4424LOCK(cs_main);4426// Skipping AcceptBlock() for CheckBlock() failures means that we will never mark a block as invalid if4427// CheckBlock() fails. This is protective against consensus failure if there are any unknown forms of block4428// malleability that cause CheckBlock() to fail; see e.g. CVE-2012-2459 and4429// https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-February/016697.html. Because CheckBlock() is4430// not very expensive, the anti-DoS benefits of caching failure (of a definitely-invalid block) are not substantial.4431bool ret = CheckBlock(*block, state, GetConsensus());4432if (ret) {4433// Store to disk4434ret = AcceptBlock(block, state, &pindex, force_processing, nullptr, new_block, min_pow_checked);4435}4436if (!ret) {4437if (m_options.signals) {4438m_options.signals->BlockChecked(block, state);4439}4440LogError("%s: AcceptBlock FAILED (%s)\n", __func__, state.ToString());4441return false;4442}4443}4445NotifyHeaderTip();4447BlockValidationState state; // Only used to report errors, not invalidity - ignore it4448if (!ActiveChainstate().ActivateBestChain(state, block)) {4449LogError("%s: ActivateBestChain failed (%s)\n", __func__, state.ToString());4450return false;4451}4453Chainstate* bg_chain{WITH_LOCK(cs_main, return HistoricalChainstate())};4454BlockValidationState bg_state;4455if (bg_chain && !bg_chain->ActivateBestChain(bg_state, block)) {4456LogError("%s: [background] ActivateBestChain failed (%s)\n", __func__, bg_state.ToString());4457return false;4458}4460return true;4461}4463MempoolAcceptResult ChainstateManager::ProcessTransaction(const CTransactionRef& tx, bool test_accept)4464{4465AssertLockHeld(cs_main);4466Chainstate& active_chainstate = ActiveChainstate();4467if (!active_chainstate.GetMempool()) {4468TxValidationState state;4469state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool");4470return MempoolAcceptResult::Failure(state);4471}4472auto result = AcceptToMemoryPool(active_chainstate, tx, GetTime(), /*bypass_limits=*/ false, test_accept);4473active_chainstate.GetMempool()->check(active_chainstate.CoinsTip(), active_chainstate.m_chain.Height() + 1);4474return result;4475}4478BlockValidationState TestBlockValidity(4479Chainstate& chainstate,4480const CBlock& block,4481const bool check_pow,4482const bool check_merkle_root)4483{4484// Lock must be held throughout this function for two reasons:4485// 1. We don't want the tip to change during several of the validation steps4486// 2. To prevent a CheckBlock() race condition for fChecked, see ProcessNewBlock()4487AssertLockHeld(chainstate.m_chainman.GetMutex());4489BlockValidationState state;4490CBlockIndex* tip{Assert(chainstate.m_chain.Tip())};4492if (block.hashPrevBlock != *Assert(tip->phashBlock)) {4493state.Invalid({}, "inconclusive-not-best-prevblk");4494return state;4495}4497// For signets CheckBlock() verifies the challenge iff fCheckPow is set.4498if (!CheckBlock(block, state, chainstate.m_chainman.GetConsensus(), /*fCheckPow=*/check_pow, /*fCheckMerkleRoot=*/check_merkle_root)) {4499// This should never happen, but belt-and-suspenders don't approve the4500// block if it does.