mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 14:38:29 +01:00
Merge #15976: refactor: move methods under CChainState (pt. 1)
403e677c9refactoring: IsInitialBlockDownload -> CChainState (James O'Beirne)3ccbc376drefactoring: FlushStateToDisk -> CChainState (James O'Beirne)4d6688603refactoring: introduce ChainstateActive() (James O'Beirne)d7c97edeemove-only: make the CChainState interface public (James O'Beirne) Pull request description: This is part of the [assumeutxo project](https://github.com/bitcoin/bitcoin/projects/11): Parent PR: #15606 Issue: #15605 Specification: https://github.com/jamesob/assumeutxo-docs/tree/2019-04-proposal/proposal --- This changeset starts moving functionality intimately related to CChainState into methods. Parameterizing these functions by a particular CChainState is necessary for the use of multiple chainstates simultaneously (e.g. for asynchronous background validation). In this change, we - make the CChainState interface public - since other units will start to invoke its methods directly, - introduce `::ChainstateActive()`, the CChainState equivalent for `::ChainActive()`, - and move `IsInitialBlockDownload()` and `FlushStateToDisk()` into methods on CChainState. Independent of assumeutxo, these changes better encapsulate chainstate behavior and allow easier use from a testing context. There are more methods that we'll move in the future, but they require other substantial changes (i.e. moving ownership of the `CCoinsView*` hierarchy into CChainState) so we'll save them for future PRs. --- The first move-only commit is most easily reviewed with `git diff ... --color-moved=dimmed_zebra`. ACKs for commit 403e67: Empact: utACK403e677c9eno need to address my nits herein Sjors: utACK403e677ryanofsky: utACK403e677c9e. Only change since previous review is removing global state comment as suggested. MarcoFalke: utACK403e677c9e, though the diff still seems a bit bloated with some unnecessary changes in the second commit. promag: utACK403e677and rebased with current [master](c7cfd20a7). Tree-SHA512: 6fcf260bb2dc201361170c0b4547405366f5f331fcc3a2bac29b24442814b7b244ca1b58aac5af716885f9a130c343b544590dff780da0bf835c7c5b3ccb2257
This commit is contained in:
191
src/validation.h
191
src/validation.h
@@ -31,6 +31,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class CChainState;
|
||||
class CBlockIndex;
|
||||
class CBlockTreeDB;
|
||||
class CBlockUndo;
|
||||
@@ -44,6 +45,7 @@ class CTxMemPool;
|
||||
class CValidationState;
|
||||
struct ChainTxData;
|
||||
|
||||
struct DisconnectedBlockTransactions;
|
||||
struct PrecomputedTransactionData;
|
||||
struct LockPoints;
|
||||
|
||||
@@ -247,8 +249,6 @@ bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_m
|
||||
void UnloadBlockIndex();
|
||||
/** Run an instance of the script checking thread */
|
||||
void ThreadScriptCheck(int worker_num);
|
||||
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
|
||||
bool IsInitialBlockDownload();
|
||||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
|
||||
/**
|
||||
@@ -276,10 +276,6 @@ void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
*/
|
||||
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
|
||||
|
||||
/** Flush all state, indexes and buffers to disk. */
|
||||
void FlushStateToDisk();
|
||||
/** Prune block files and flush state to disk. */
|
||||
void PruneAndFlush();
|
||||
/** Prune block files up to a given height */
|
||||
void PruneBlockFilesManual(int nManualPruneHeight);
|
||||
|
||||
@@ -422,6 +418,186 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIR
|
||||
/** Find the last common block between the parameter chain and a locator. */
|
||||
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
enum DisconnectResult
|
||||
{
|
||||
DISCONNECT_OK, // All good.
|
||||
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
|
||||
DISCONNECT_FAILED // Something else went wrong.
|
||||
};
|
||||
|
||||
class ConnectTrace;
|
||||
|
||||
/** @see CChainState::FlushStateToDisk */
|
||||
enum class FlushStateMode {
|
||||
NONE,
|
||||
IF_NEEDED,
|
||||
PERIODIC,
|
||||
ALWAYS
|
||||
};
|
||||
|
||||
struct CBlockIndexWorkComparator
|
||||
{
|
||||
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* CChainState stores and provides an API to update our local knowledge of the
|
||||
* current best chain and header tree.
|
||||
*
|
||||
* It generally provides access to the current block tree, as well as functions
|
||||
* to provide new data, which it will appropriately validate and incorporate in
|
||||
* its state as necessary.
|
||||
*
|
||||
* Eventually, the API here is targeted at being exposed externally as a
|
||||
* consumable libconsensus library, so any functions added must only call
|
||||
* other class member functions, pure functions in other parts of the consensus
|
||||
* library, callbacks via the validation interface, or read/write-to-disk
|
||||
* functions (eventually this will also be via callbacks).
|
||||
*/
|
||||
class CChainState {
|
||||
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, though, and pruning nodes may be
|
||||
* missing the data for the block.
|
||||
*/
|
||||
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
|
||||
|
||||
/**
|
||||
* Every received block is assigned a unique and increasing identifier, so we
|
||||
* know which one to give priority in case of a fork.
|
||||
*/
|
||||
CCriticalSection cs_nBlockSequenceId;
|
||||
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
|
||||
int32_t nBlockSequenceId = 1;
|
||||
/** Decreasing counter (used by subsequent preciousblock calls). */
|
||||
int32_t nBlockReverseSequenceId = -1;
|
||||
/** chainwork for the last block that preciousblock has been applied to. */
|
||||
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;
|
||||
|
||||
/**
|
||||
* the ChainState CriticalSection
|
||||
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
|
||||
*/
|
||||
CCriticalSection m_cs_chainstate;
|
||||
|
||||
/**
|
||||
* Whether this chainstate is undergoing initial block download.
|
||||
*
|
||||
* Mutable because we need to be able to mark IsInitialBlockDownload()
|
||||
* const, which latches this for caching purposes.
|
||||
*/
|
||||
mutable std::atomic<bool> m_cached_finished_ibd{false};
|
||||
|
||||
public:
|
||||
//! The current chain of blockheaders we consult and build on.
|
||||
//! @see CChain, CBlockIndex.
|
||||
CChain m_chain;
|
||||
BlockMap mapBlockIndex GUARDED_BY(cs_main);
|
||||
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
|
||||
CBlockIndex *pindexBestInvalid = nullptr;
|
||||
|
||||
bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
/**
|
||||
* Update the on-disk chain state.
|
||||
* 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 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 anything
|
||||
* besides checking if we need to prune.
|
||||
*/
|
||||
bool FlushStateToDisk(
|
||||
const CChainParams& chainparams,
|
||||
CValidationState &state,
|
||||
FlushStateMode mode,
|
||||
int nManualPruneHeight = 0);
|
||||
|
||||
//! Unconditionally flush all changes to disk.
|
||||
void ForceFlushStateToDisk();
|
||||
|
||||
//! Prune blockfiles from the disk if necessary and then flush chainstate changes
|
||||
//! if we pruned.
|
||||
void PruneAndFlush();
|
||||
|
||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) 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 CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
// Block (dis)connection on a given view:
|
||||
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
|
||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
|
||||
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
// Block disconnection on our pcoinsTip:
|
||||
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
// Manual block validity manipulation:
|
||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
|
||||
bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
|
||||
bool LoadGenesisBlock(const CChainParams& chainparams);
|
||||
|
||||
void PruneBlockIndexCandidates();
|
||||
|
||||
void UnloadBlockIndex();
|
||||
|
||||
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
|
||||
bool IsInitialBlockDownload() const;
|
||||
|
||||
private:
|
||||
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) 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 uint256& 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, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
//! Mark a block as not having block data
|
||||
void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
};
|
||||
|
||||
/** Mark a block as precious and reorganize.
|
||||
*
|
||||
* May not be called in a
|
||||
@@ -435,6 +611,9 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
|
||||
/** Remove invalidity status from a block and its descendants. */
|
||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
/** @returns the most-work valid chainstate. */
|
||||
CChainState& ChainstateActive();
|
||||
|
||||
/** @returns the most-work chain. */
|
||||
CChain& ChainActive();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user