Changeset View
Changeset View
Standalone View
Standalone View
src/validation.h
Show First 20 Lines • Show All 685 Lines • ▼ Show 20 Lines | |||||
CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | CBlockIndex *FindForkInGlobalIndex(const CChain &chain, | ||||
const CBlockLocator &locator) | const CBlockLocator &locator) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
/** @see CChainState::FlushStateToDisk */ | /** @see CChainState::FlushStateToDisk */ | ||||
enum class FlushStateMode { NONE, IF_NEEDED, PERIODIC, ALWAYS }; | enum class FlushStateMode { NONE, IF_NEEDED, PERIODIC, ALWAYS }; | ||||
/** | /** | ||||
* CChainState stores and provides an API to update our local knowledge of the | * Maintains a tree of blocks (stored in `m_block_index`) which is consulted | ||||
* current best chain and header tree. | * to determine where the most-work tip is. | ||||
* | |||||
* This data is used mostly in `CChainState` - information about, e.g., | |||||
* candidate tips is not maintained here. | |||||
*/ | |||||
class BlockManager { | |||||
public: | |||||
BlockMap m_block_index GUARDED_BY(cs_main); | |||||
/** | |||||
* In order to efficiently track invalidity of headers, we keep the set of | |||||
* blocks which we tried to connect and found to be invalid here (ie which | |||||
* were set to BLOCK_FAILED_VALID since the last restart). We can then | |||||
* walk this set and check if a new header is a descendant of something in | |||||
* this set, preventing us from having to walk m_block_index when we try | |||||
* to connect a bad block and fail. | |||||
* | |||||
* While this is more complicated than marking everything which descends | |||||
* from an invalid block as invalid at the time we discover it to be | |||||
* invalid, doing so would require walking all of m_block_index to find all | |||||
* descendants. Since this case should be very rare, keeping track of all | |||||
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as | |||||
* well. | |||||
* | * | ||||
* It generally provides access to the current block tree, as well as functions | * Because we already walk m_block_index in height-order at startup, we go | ||||
* to provide new data, which it will appropriately validate and incorporate in | * ahead and mark descendants of invalid blocks as FAILED_CHILD at that | ||||
* its state as necessary. | * time, instead of putting things in this set. | ||||
*/ | |||||
std::set<CBlockIndex *> m_failed_blocks; | |||||
/** | |||||
* All pairs A->B, where A (or one of its ancestors) misses transactions, | |||||
* but B has transactions. Pruned nodes may have entries where B is missing | |||||
* data. | |||||
*/ | |||||
std::multimap<CBlockIndex *, CBlockIndex *> m_blocks_unlinked; | |||||
bool LoadBlockIndex(const Consensus::Params &consensus_params, | |||||
CBlockTreeDB &blocktree) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
/** Clear all data members. */ | |||||
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
CBlockIndex *AddToBlockIndex(const CBlockHeader &block) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
/** Create a new block index entry for a given block hash */ | |||||
CBlockIndex *InsertBlockIndex(const BlockHash &hash) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
/** | |||||
* If a block header hasn't already been seen, call CheckBlockHeader on it, | |||||
* ensure that it doesn't descend from an invalid block, and then add it to | |||||
* mapBlockIndex. | |||||
*/ | |||||
bool AcceptBlockHeader(const Config &config, const CBlockHeader &block, | |||||
BlockValidationState &state, CBlockIndex **ppindex) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
}; | |||||
/** | |||||
* CChainState stores and provides an API to update our local knowledge of the | |||||
* current best chain. | |||||
* | * | ||||
* Eventually, the API here is targeted at being exposed externally as a | * Eventually, the API here is targeted at being exposed externally as a | ||||
* consumable libconsensus library, so any functions added must only call | * consumable libconsensus library, so any functions added must only call | ||||
* other class member functions, pure functions in other parts of the consensus | * other class member functions, pure functions in other parts of the consensus | ||||
* library, callbacks via the validation interface, or read/write-to-disk | * library, callbacks via the validation interface, or read/write-to-disk | ||||
* functions (eventually this will also be via callbacks). | * functions (eventually this will also be via callbacks). | ||||
* | |||||
* Anything that is contingent on the current tip of the chain is stored here, | |||||
* whereas block information and metadata independent of the current tip is | |||||
* kept in `BlockMetadataManager`. | |||||
*/ | */ | ||||
class CChainState { | class CChainState { | ||||
private: | private: | ||||
/** | /** | ||||
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for | |||||
* itself and all ancestors) and as good as our current tip or better. | |||||
* Entries may be failed or parked though, and pruning nodes may be missing | |||||
* the data for the block; these will get cleaned during FindMostWorkChain. | |||||
*/ | |||||
std::set<CBlockIndex *, CBlockIndexWorkComparator> setBlockIndexCandidates; | |||||
/** | |||||
* the ChainState CriticalSection | * the ChainState CriticalSection | ||||
* A lock that must be held when modifying this ChainState - held in | * A lock that must be held when modifying this ChainState - held in | ||||
* ActivateBestChain() | * ActivateBestChain() | ||||
*/ | */ | ||||
RecursiveMutex m_cs_chainstate; | RecursiveMutex m_cs_chainstate; | ||||
/** | /** | ||||
* Every received block is assigned a unique and increasing identifier, so | * Every received block is assigned a unique and increasing identifier, so | ||||
* we know which one to give priority in case of a fork. | * we know which one to give priority in case of a fork. | ||||
* Blocks loaded from disk are assigned id 0, so start the counter at 1. | * Blocks loaded from disk are assigned id 0, so start the counter at 1. | ||||
*/ | */ | ||||
std::atomic<int32_t> nBlockSequenceId{1}; | std::atomic<int32_t> nBlockSequenceId{1}; | ||||
/** Decreasing counter (used by subsequent preciousblock calls). */ | /** Decreasing counter (used by subsequent preciousblock calls). */ | ||||
int32_t nBlockReverseSequenceId = -1; | int32_t nBlockReverseSequenceId = -1; | ||||
/** chainwork for the last block that preciousblock has been applied to. */ | /** chainwork for the last block that preciousblock has been applied to. */ | ||||
arith_uint256 nLastPreciousChainwork = 0; | arith_uint256 nLastPreciousChainwork = 0; | ||||
/** | /** | ||||
* In order to efficiently track invalidity of headers, we keep the set of | |||||
* blocks which we tried to connect and found to be invalid here (ie which | |||||
* were set to BLOCK_FAILED_VALID since the last restart). We can then | |||||
* walk this set and check if a new header is a descendant of something in | |||||
* this set, preventing us from having to walk mapBlockIndex when we try | |||||
* to connect a bad block and fail. | |||||
* | |||||
* While this is more complicated than marking everything which descends | |||||
* from an invalid block as invalid at the time we discover it to be | |||||
* invalid, doing so would require walking all of mapBlockIndex to find all | |||||
* descendants. Since this case should be very rare, keeping track of all | |||||
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as | |||||
* well. | |||||
* | |||||
* Because we already walk mapBlockIndex in height-order at startup, we go | |||||
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that | |||||
* time, instead of putting things in this set. | |||||
*/ | |||||
std::set<CBlockIndex *> m_failed_blocks; | |||||
/** | |||||
* Whether this chainstate is undergoing initial block download. | * Whether this chainstate is undergoing initial block download. | ||||
* | * | ||||
* Mutable because we need to be able to mark IsInitialBlockDownload() | * Mutable because we need to be able to mark IsInitialBlockDownload() | ||||
* const, which latches this for caching purposes. | * const, which latches this for caching purposes. | ||||
*/ | */ | ||||
mutable std::atomic<bool> m_cached_finished_ibd{false}; | mutable std::atomic<bool> m_cached_finished_ibd{false}; | ||||
//! Reference to a BlockManager instance which itself is shared across all | |||||
//! CChainState instances. Keeping a local reference allows us to test more | |||||
//! easily as opposed to referencing a global. | |||||
BlockManager &m_blockman; | |||||
public: | public: | ||||
explicit CChainState(BlockManager &blockman) : m_blockman(blockman) {} | |||||
//! The current chain of blockheaders we consult and build on. | |||||
//! @see CChain, CBlockIndex. | |||||
CChain m_chain; | CChain m_chain; | ||||
BlockMap mapBlockIndex GUARDED_BY(cs_main); | |||||
std::multimap<CBlockIndex *, CBlockIndex *> mapBlocksUnlinked; | |||||
CBlockIndex *pindexBestInvalid = nullptr; | CBlockIndex *pindexBestInvalid = nullptr; | ||||
CBlockIndex *pindexBestParked = nullptr; | CBlockIndex *pindexBestParked = nullptr; | ||||
CBlockIndex const *pindexFinalized = nullptr; | CBlockIndex const *pindexFinalized = nullptr; | ||||
/** | |||||
bool LoadBlockIndex(const Consensus::Params ¶ms, | * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for | ||||
CBlockTreeDB &blocktree) | * itself and all ancestors) and as good as our current tip or better. | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | * Entries may be failed, though, and pruning nodes may be missing the data | ||||
* for the block. | |||||
*/ | |||||
std::set<CBlockIndex *, CBlockIndexWorkComparator> setBlockIndexCandidates; | |||||
/** | /** | ||||
* Update the on-disk chain state. | * Update the on-disk chain state. | ||||
* The caches and indexes are flushed depending on the mode we're called | * The caches and indexes are flushed depending on the mode we're called | ||||
* with if they're too large, if it's been a while since the last write, or | * with if they're too large, if it's been a while since the last write, or | ||||
* always and in all cases if we're in prune mode and are deleting files. | * always and in all cases if we're in prune mode and are deleting files. | ||||
* | * | ||||
* If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do | * If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do | ||||
Show All 10 Lines | public: | ||||
//! changes if we pruned. | //! changes if we pruned. | ||||
void PruneAndFlush(); | void PruneAndFlush(); | ||||
bool ActivateBestChain( | bool ActivateBestChain( | ||||
const Config &config, BlockValidationState &state, | const Config &config, BlockValidationState &state, | ||||
std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>()) | std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>()) | ||||
LOCKS_EXCLUDED(cs_main); | LOCKS_EXCLUDED(cs_main); | ||||
/** | |||||
* If a block header hasn't already been seen, call CheckBlockHeader on it, | |||||
* ensure that it doesn't descend from an invalid block, and then add it to | |||||
* mapBlockIndex. | |||||
*/ | |||||
bool AcceptBlockHeader(const Config &config, const CBlockHeader &block, | |||||
BlockValidationState &state, CBlockIndex **ppindex) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
bool AcceptBlock(const Config &config, | bool AcceptBlock(const Config &config, | ||||
const std::shared_ptr<const CBlock> &pblock, | const std::shared_ptr<const CBlock> &pblock, | ||||
BlockValidationState &state, bool fRequested, | BlockValidationState &state, bool fRequested, | ||||
const FlatFilePos *dbp, bool *fNewBlock) | const FlatFilePos *dbp, bool *fNewBlock) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
// Block (dis)connection on a given view: | // Block (dis)connection on a given view: | ||||
DisconnectResult DisconnectBlock(const CBlock &block, | DisconnectResult DisconnectBlock(const CBlock &block, | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | public: | ||||
void UnloadBlockIndex(); | void UnloadBlockIndex(); | ||||
/** | /** | ||||
* Check whether we are doing an initial block download (synchronizing from | * Check whether we are doing an initial block download (synchronizing from | ||||
* disk or network) | * disk or network) | ||||
*/ | */ | ||||
bool IsInitialBlockDownload() const; | bool IsInitialBlockDownload() const; | ||||
/** | |||||
* Make various assertions about the state of the block index. | |||||
* | |||||
* By default this only executes fully when using the Regtest chain; see: | |||||
* fCheckBlockIndex. | |||||
*/ | |||||
void CheckBlockIndex(const Consensus::Params &consensusParams); | |||||
private: | private: | ||||
bool ActivateBestChainStep(const Config &config, | bool ActivateBestChainStep(const Config &config, | ||||
BlockValidationState &state, | BlockValidationState &state, | ||||
CBlockIndex *pindexMostWork, | CBlockIndex *pindexMostWork, | ||||
const std::shared_ptr<const CBlock> &pblock, | const std::shared_ptr<const CBlock> &pblock, | ||||
bool &fInvalidFound, ConnectTrace &connectTrace) | bool &fInvalidFound, ConnectTrace &connectTrace) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
bool ConnectTip(const Config &config, BlockValidationState &state, | bool ConnectTip(const Config &config, BlockValidationState &state, | ||||
CBlockIndex *pindexNew, | CBlockIndex *pindexNew, | ||||
const std::shared_ptr<const CBlock> &pblock, | const std::shared_ptr<const CBlock> &pblock, | ||||
ConnectTrace &connectTrace, | ConnectTrace &connectTrace, | ||||
DisconnectedBlockTransactions &disconnectpool) | DisconnectedBlockTransactions &disconnectpool) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
CBlockIndex *AddToBlockIndex(const CBlockHeader &block) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
bool MarkBlockAsFinal(const Config &config, BlockValidationState &state, | |||||
const CBlockIndex *pindex) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
/** Create a new block index entry for a given block hash */ | |||||
CBlockIndex *InsertBlockIndex(const BlockHash &hash) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
/** | |||||
* Make various assertions about the state of the block index. | |||||
* | |||||
* By default this only executes fully when using the Regtest chain; see: | |||||
* fCheckBlockIndex. | |||||
*/ | |||||
void CheckBlockIndex(const Consensus::Params &consensusParams); | |||||
void InvalidBlockFound(CBlockIndex *pindex, | void InvalidBlockFound(CBlockIndex *pindex, | ||||
const BlockValidationState &state) | const BlockValidationState &state) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
CBlockIndex *FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main); | CBlockIndex *FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
bool MarkBlockAsFinal(const Config &config, BlockValidationState &state, | |||||
const CBlockIndex *pindex) | |||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||
void ReceivedBlockTransactions(const CBlock &block, CBlockIndex *pindexNew, | void ReceivedBlockTransactions(const CBlock &block, CBlockIndex *pindexNew, | ||||
const FlatFilePos &pos) | const FlatFilePos &pos) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, | bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, | ||||
const Consensus::Params ¶ms) | const Consensus::Params ¶ms) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main); | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | ||||
bool UnwindBlock(const Config &config, BlockValidationState &state, | bool UnwindBlock(const Config &config, BlockValidationState &state, | ||||
▲ Show 20 Lines • Show All 93 Lines • Show Last 20 Lines |