diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -13,8 +13,10 @@ #include #include +#include #include #include +#include #include #include #include // For CMessageHeader::MessageMagic @@ -48,9 +50,10 @@ class CTxMemPool; class CTxUndo; class CValidationState; +class DisconnectedBlockTransactions; -struct FlatFilePos; struct ChainTxData; +struct FlatFilePos; struct PrecomputedTransactionData; struct LockPoints; @@ -475,6 +478,8 @@ } }; +class ConnectTrace; + /** * Check whether all inputs of this transaction are valid (no double spends, * scripts & sigs, amounts). This does not modify the UTXO set. @@ -706,6 +711,176 @@ const CBlockLocator &locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main); +/** + * 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 or parked though, and pruning nodes may be missing + * the data for the block; these will get cleaned during FindMostWorkChain. + */ + std::set setBlockIndexCandidates; + + /** + * the ChainState CriticalSection + * A lock that must be held when modifying this ChainState - held in + * ActivateBestChain() + */ + RecursiveMutex m_cs_chainstate; + + /** + * Every received block is assigned a unique and increasing identifier, so + * 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. + */ + std::atomic 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 m_failed_blocks; + +public: + CChain m_chain; + BlockMap mapBlockIndex GUARDED_BY(cs_main); + std::multimap mapBlocksUnlinked; + CBlockIndex *pindexBestInvalid = nullptr; + CBlockIndex *pindexBestParked = nullptr; + CBlockIndex const *pindexFinalized = nullptr; + + bool LoadBlockIndex(const Config &config, CBlockTreeDB &blocktree) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + bool ActivateBestChain( + const Config &config, CValidationState &state, + std::shared_ptr pblock = std::shared_ptr()); + + /** + * 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, + CValidationState &state, CBlockIndex **ppindex) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool AcceptBlock(const Config &config, + const std::shared_ptr &pblock, + CValidationState &state, 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 ¶ms, + BlockValidationOptions options, bool fJustCheck = false) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + // Block disconnection on our pcoinsTip: + bool DisconnectTip(const CChainParams ¶ms, CValidationState &state, + DisconnectedBlockTransactions *disconnectpool) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + // Manual block validity manipulation: + bool PreciousBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main); + bool UnwindBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex, bool invalidate); + void ResetBlockFailureFlags(CBlockIndex *pindex) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + template + bool UpdateFlagsForBlock(CBlockIndex *pindexBase, CBlockIndex *pindex, F f) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + template + void UpdateFlags(CBlockIndex *pindex, CBlockIndex *&pindexReset, F f, + C fChild, AC fAncestorWasChanged) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + /** Remove parked status from a block and its descendants. */ + void UnparkBlockImpl(CBlockIndex *pindex, bool fClearChildren) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view); + bool LoadGenesisBlock(const CChainParams &chainparams); + + void PruneBlockIndexCandidates(); + + void UnloadBlockIndex(); + +private: + bool ActivateBestChainStep(const Config &config, CValidationState &state, + CBlockIndex *pindexMostWork, + const std::shared_ptr &pblock, + bool &fInvalidFound, ConnectTrace &connectTrace) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + bool ConnectTip(const Config &config, CValidationState &state, + CBlockIndex *pindexNew, + const std::shared_ptr &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 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, 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) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); + + bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, + const Consensus::Params ¶ms) + EXCLUSIVE_LOCKS_REQUIRED(cs_main); +}; + /** * Mark a block as precious and reorganize. * diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -65,177 +64,8 @@ #define MICRO 0.000001 #define MILLI 0.001 -class ConnectTrace; -/** - * 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 or parked though, and pruning nodes may be missing - * the data for the block; these will get cleaned during FindMostWorkChain. - */ - std::set setBlockIndexCandidates; - - /** - * the ChainState CriticalSection - * A lock that must be held when modifying this ChainState - held in - * ActivateBestChain() - */ - RecursiveMutex m_cs_chainstate; - - /** - * Every received block is assigned a unique and increasing identifier, so - * 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. - */ - std::atomic 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 m_failed_blocks; - -public: - CChain m_chain; - BlockMap mapBlockIndex GUARDED_BY(cs_main); - std::multimap mapBlocksUnlinked; - CBlockIndex *pindexBestInvalid = nullptr; - CBlockIndex *pindexBestParked = nullptr; - CBlockIndex const *pindexFinalized = nullptr; - - bool LoadBlockIndex(const Config &config, CBlockTreeDB &blocktree) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - bool ActivateBestChain( - const Config &config, CValidationState &state, - std::shared_ptr pblock = std::shared_ptr()); - - /** - * 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, - CValidationState &state, CBlockIndex **ppindex) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - bool AcceptBlock(const Config &config, - const std::shared_ptr &pblock, - CValidationState &state, 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 ¶ms, - BlockValidationOptions options, bool fJustCheck = false) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - // Block disconnection on our pcoinsTip: - bool DisconnectTip(const CChainParams ¶ms, CValidationState &state, - DisconnectedBlockTransactions *disconnectpool) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - // Manual block validity manipulation: - bool PreciousBlock(const Config &config, CValidationState &state, - CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main); - bool UnwindBlock(const Config &config, CValidationState &state, - CBlockIndex *pindex, bool invalidate); - void ResetBlockFailureFlags(CBlockIndex *pindex) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - template - bool UpdateFlagsForBlock(CBlockIndex *pindexBase, CBlockIndex *pindex, F f) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - template - void UpdateFlags(CBlockIndex *pindex, CBlockIndex *&pindexReset, F f, - C fChild, AC fAncestorWasChanged) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - /** Remove parked status from a block and its descendants. */ - void UnparkBlockImpl(CBlockIndex *pindex, bool fClearChildren) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - bool ReplayBlocks(const Consensus::Params ¶ms, CCoinsView *view); - bool LoadGenesisBlock(const CChainParams &chainparams); - - void PruneBlockIndexCandidates(); - - void UnloadBlockIndex(); - -private: - bool ActivateBestChainStep(const Config &config, CValidationState &state, - CBlockIndex *pindexMostWork, - const std::shared_ptr &pblock, - bool &fInvalidFound, ConnectTrace &connectTrace) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - bool ConnectTip(const Config &config, CValidationState &state, - CBlockIndex *pindexNew, - const std::shared_ptr &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 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, 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) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); - - bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, - const Consensus::Params ¶ms) - EXCLUSIVE_LOCKS_REQUIRED(cs_main); -} g_chainstate; +CChainState g_chainstate; CChain &ChainActive() { return g_chainstate.m_chain;