Inside Bitcoin
Opening the selected file…
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.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <node/blockstorage.h>7#include <arith_uint256.h>8#include <chain.h>9#include <consensus/params.h>10#include <crypto/hex_base.h>11#include <dbwrapper.h>12#include <flatfile.h>13#include <hash.h>14#include <kernel/blockmanager_opts.h>15#include <kernel/chainparams.h>16#include <kernel/messagestartchars.h>17#include <kernel/notifications_interface.h>18#include <kernel/types.h>19#include <pow.h>20#include <primitives/block.h>21#include <primitives/transaction.h>22#include <random.h>23#include <serialize.h>24#include <signet.h>25#include <streams.h>26#include <sync.h>27#include <tinyformat.h>28#include <uint256.h>29#include <undo.h>30#include <util/check.h>31#include <util/expected.h>32#include <util/fs.h>33#include <util/log.h>34#include <util/obfuscation.h>35#include <util/overflow.h>36#include <util/result.h>37#include <util/signalinterrupt.h>38#include <util/strencodings.h>39#include <util/syserror.h>40#include <util/time.h>41#include <util/translation.h>42#include <validation.h>44#include <cerrno>45#include <compare>46#include <cstddef>47#include <cstdio>48#include <exception>49#include <map>50#include <optional>51#include <ostream>52#include <span>53#include <stdexcept>54#include <system_error>55#include <unordered_map>57namespace kernel {58static constexpr uint8_t DB_BLOCK_FILES{'f'};59static constexpr uint8_t DB_BLOCK_INDEX{'b'};60static constexpr uint8_t DB_FLAG{'F'};61static constexpr uint8_t DB_REINDEX_FLAG{'R'};62static constexpr uint8_t DB_LAST_BLOCK{'l'};63// Keys used in previous version that might still be found in the DB:64// BlockTreeDB::DB_TXINDEX_BLOCK{'T'};65// BlockTreeDB::DB_TXINDEX{'t'}66// BlockTreeDB::ReadFlag("txindex")68bool BlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo& info)69{70return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);71}73void BlockTreeDB::WriteReindexing(bool fReindexing)74{75if (fReindexing) {76Write(DB_REINDEX_FLAG, uint8_t{'1'});77} else {78Erase(DB_REINDEX_FLAG);79}80}82void BlockTreeDB::ReadReindexing(bool& fReindexing)83{84fReindexing = Exists(DB_REINDEX_FLAG);85}87bool BlockTreeDB::ReadLastBlockFile(int& nFile)88{89return Read(DB_LAST_BLOCK, nFile);90}92void BlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*>>& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo)93{94CDBBatch batch(*this);95for (const auto& [file, info] : fileInfo) {96batch.Write(std::make_pair(DB_BLOCK_FILES, file), *info);97}98batch.Write(DB_LAST_BLOCK, nLastFile);99for (const CBlockIndex* bi : blockinfo) {100batch.Write(std::make_pair(DB_BLOCK_INDEX, bi->GetBlockHash()), CDiskBlockIndex{bi});101}102WriteBatch(batch, true);103}105void BlockTreeDB::WriteFlag(const std::string& name, bool fValue)106{107Write(std::make_pair(DB_FLAG, name), fValue ? uint8_t{'1'} : uint8_t{'0'});108}110bool BlockTreeDB::ReadFlag(const std::string& name, bool& fValue)111{112uint8_t ch;113if (!Read(std::make_pair(DB_FLAG, name), ch)) {114return false;115}116fValue = ch == uint8_t{'1'};117return true;118}120bool BlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex, const util::SignalInterrupt& interrupt)121{122AssertLockHeld(::cs_main);123std::unique_ptr<CDBIterator> pcursor(NewIterator());124pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));126// Load m_block_index127while (pcursor->Valid()) {128if (interrupt) return false;129std::pair<uint8_t, uint256> key;130if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {131CDiskBlockIndex diskindex;132if (pcursor->GetValue(diskindex)) {133// Construct block index object134CBlockIndex* pindexNew = insertBlockIndex(diskindex.ConstructBlockHash());135pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);136pindexNew->nHeight = diskindex.nHeight;137pindexNew->nFile = diskindex.nFile;138pindexNew->nDataPos = diskindex.nDataPos;139pindexNew->nUndoPos = diskindex.nUndoPos;140pindexNew->nVersion = diskindex.nVersion;141pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;142pindexNew->nTime = diskindex.nTime;143pindexNew->nBits = diskindex.nBits;144pindexNew->nNonce = diskindex.nNonce;145pindexNew->nStatus = diskindex.nStatus;146pindexNew->nTx = diskindex.nTx;148if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) {149LogError("%s: CheckProofOfWork failed: %s\n", __func__, pindexNew->ToString());150return false;151}153pcursor->Next();154} else {155LogError("%s: failed to read value\n", __func__);156return false;157}158} else {159break;160}161}163return true;164}166std::string CBlockFileInfo::ToString() const167{168return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, FormatISO8601Date(nTimeFirst), FormatISO8601Date(nTimeLast));169}170} // namespace kernel172namespace node {174bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const175{176// First sort by most total work, ...177if (pa->nChainWork > pb->nChainWork) return false;178if (pa->nChainWork < pb->nChainWork) return true;180// ... then by earliest activatable time, ...181if (pa->nSequenceId < pb->nSequenceId) return false;182if (pa->nSequenceId > pb->nSequenceId) return true;184// Use pointer address as tie breaker (should only happen with blocks185// loaded from disk, as those share the same id: 0 for blocks on the186// best chain, 1 for all others).187if (pa < pb) return false;188if (pa > pb) return true;190// Identical blocks.191return false;192}194bool CBlockIndexHeightOnlyComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const195{196return pa->nHeight < pb->nHeight;197}199std::vector<CBlockIndex*> BlockManager::GetAllBlockIndices()200{201AssertLockHeld(cs_main);202std::vector<CBlockIndex*> rv;203rv.reserve(m_block_index.size());204for (auto& [_, block_index] : m_block_index) {205rv.push_back(&block_index);206}207return rv;208}210CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash)211{212AssertLockHeld(cs_main);213BlockMap::iterator it = m_block_index.find(hash);214return it == m_block_index.end() ? nullptr : &it->second;215}217const CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash) const218{219AssertLockHeld(cs_main);220BlockMap::const_iterator it = m_block_index.find(hash);221return it == m_block_index.end() ? nullptr : &it->second;222}224CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header)225{226AssertLockHeld(cs_main);228auto [mi, inserted] = m_block_index.try_emplace(block.GetHash(), block);229if (!inserted) {230return &mi->second;231}232CBlockIndex* pindexNew = &(*mi).second;234// We assign the sequence id to blocks only when the full data is available,235// to avoid miners withholding blocks but broadcasting headers, to get a236// competitive advantage.237pindexNew->nSequenceId = SEQ_ID_INIT_FROM_DISK;239pindexNew->phashBlock = &((*mi).first);240BlockMap::iterator miPrev = m_block_index.find(block.hashPrevBlock);241if (miPrev != m_block_index.end()) {242pindexNew->pprev = &(*miPrev).second;243pindexNew->nHeight = pindexNew->pprev->nHeight + 1;244pindexNew->BuildSkip();245}246pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);247pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);248pindexNew->RaiseValidity(BLOCK_VALID_TREE);249if (best_header == nullptr || best_header->nChainWork < pindexNew->nChainWork) {250best_header = pindexNew;