diff --git a/src/chain.h b/src/chain.h --- a/src/chain.h +++ b/src/chain.h @@ -243,7 +243,7 @@ }; typedef std::unordered_map BlockMap; -extern BlockMap mapBlockIndex; +extern BlockMap &mapBlockIndex; arith_uint256 GetBlockProof(const CBlockIndex &block); diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -202,7 +202,7 @@ extern CConditionVariable g_best_block_cv; extern uint256 g_best_block; extern std::atomic_bool fImporting; -extern bool fReindex; +extern std::atomic_bool fReindex; extern int nScriptCheckThreads; extern bool fTxIndex; extern bool fIsBareMultisigStd; @@ -433,8 +433,6 @@ */ void UnlinkPrunedFiles(const std::set &setFilesToPrune); -/** Create a new block index entry for a given block hash */ -CBlockIndex *InsertBlockIndex(uint256 hash); /** Flush all state, indexes and buffers to disk. */ void FlushStateToDisk(); /** Prune block files and flush state to disk. */ @@ -629,18 +627,18 @@ bool InvalidateBlock(const Config &config, CValidationState &state, CBlockIndex *pindex); +/** Remove invalidity status from a block and its descendants. */ +bool ResetBlockFailureFlags(CBlockIndex *pindex); + /** Park a block. */ bool ParkBlock(const Config &config, CValidationState &state, CBlockIndex *pindex); -/** Remove invalidity status from a block and its descendants. */ -bool ResetBlockFailureFlags(CBlockIndex *pindex); - /** Remove parked status from a block and its descendants. */ bool UnparkBlock(CBlockIndex *pindex); /** The currently-connected chain of blocks (protected by cs_main). */ -extern CChain chainActive; +extern CChain &chainActive; /** * Global variable that points to the coins database (protected by cs_main) diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -56,20 +56,127 @@ #error "Bitcoin cannot be compiled without assertions." #endif +class ConnectTrace; + /** - * Global state + * 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 setBlockIndexCandidates; + +public: + CChain chainActive; + BlockMap mapBlockIndex; + std::multimap mapBlocksUnlinked; + CBlockIndex *pindexBestInvalid = nullptr; + CBlockIndex *pindexBestParked = nullptr; + + bool LoadBlockIndex(const Config &config, CBlockTreeDB &blocktree); + + bool ActivateBestChain( + const Config &config, CValidationState &state, + std::shared_ptr pblock = std::shared_ptr()); + + bool AcceptBlockHeader(const Config &config, const CBlockHeader &block, + CValidationState &state, CBlockIndex **ppindex); + bool AcceptBlock(const Config &config, + const std::shared_ptr &pblock, + CValidationState &state, CBlockIndex **ppindex, + bool fRequested, const CDiskBlockPos *dbp, + bool *fNewBlock); + + // Block (dis)connection on a given view: + DisconnectResult DisconnectBlock(const CBlock &block, + const CBlockIndex *pindex, + CCoinsViewCache &view); + bool ConnectBlock(const Config &config, const CBlock &block, + CValidationState &state, CBlockIndex *pindex, + CCoinsViewCache &view, bool fJustCheck = false); + + // Block disconnection on our pcoinsTip: + bool DisconnectTip(const Config &config, CValidationState &state, + DisconnectedBlockTransactions *disconnectpool); + + // Manual block validity manipulation: + bool PreciousBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex); + bool UnwindBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex, bool invalidate); + bool ResetBlockFailureFlags(CBlockIndex *pindex); + + template bool UpdateFlags(CBlockIndex *pindex, F f); + + /** Park a block. */ + bool ParkBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex); + + /** Remove parked status from a block and its descendants. */ + bool UnparkBlock(CBlockIndex *pindex); + + bool ReplayBlocks(const Config &config, CCoinsView *view); + bool RewindBlockIndex(const Config &config); + 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); + bool ConnectTip(const Config &config, CValidationState &state, + CBlockIndex *pindexNew, + const std::shared_ptr &pblock, + ConnectTrace &connectTrace, + DisconnectedBlockTransactions &disconnectpool); + + CBlockIndex *AddToBlockIndex(const CBlockHeader &block); + /** Create a new block index entry for a given block hash */ + CBlockIndex *InsertBlockIndex(const uint256 &hash); + void CheckBlockIndex(const Consensus::Params &consensusParams); + + void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state); + CBlockIndex *FindMostWorkChain(); + bool ReceivedBlockTransactions(const CBlock &block, CValidationState &state, + CBlockIndex *pindexNew, + const CDiskBlockPos &pos); + + bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &inputs, + const Config &config); +} g_chainstate; + CCriticalSection cs_main; -BlockMap mapBlockIndex; -CChain chainActive; +BlockMap &mapBlockIndex = g_chainstate.mapBlockIndex; +CChain &chainActive = g_chainstate.chainActive; CBlockIndex *pindexBestHeader = nullptr; CWaitableCriticalSection g_best_block_mutex; CConditionVariable g_best_block_cv; uint256 g_best_block; int nScriptCheckThreads = 0; std::atomic_bool fImporting(false); -bool fReindex = false; +std::atomic_bool fReindex(false); bool fTxIndex = false; bool fHavePruned = false; bool fPruneMode = false; @@ -88,8 +195,6 @@ CTxMemPool mempool; -static void CheckBlockIndex(const Consensus::Params &consensusParams); - /** Constant stuff for coinbase transactions we create: */ CScript COINBASE_FLAGS; @@ -97,49 +202,63 @@ // Internal stuff namespace { +CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid; +CBlockIndex *&pindexBestParked = g_chainstate.pindexBestParked; -CBlockIndex *pindexBestInvalid; -CBlockIndex *pindexBestParked; - -/** - * 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 setBlockIndexCandidates; -/** - * 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. +/** 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 mapBlocksUnlinked; +std::multimap &mapBlocksUnlinked = + g_chainstate.mapBlocksUnlinked; CCriticalSection cs_LastBlockFile; std::vector vinfoBlockFile; int nLastBlockFile = 0; -/** - * Global flag to indicate we should check to see if there are block/undo files - * that should be deleted. Set on startup or if we allocate more file space when - * we're in prune mode. +/** Global flag to indicate we should check to see if there are + * block/undo files that should be deleted. Set on startup + * or if we allocate more file space when we're in prune mode */ bool fCheckForPruning = false; /** * 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}; +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 g_failed_blocks; + /** Dirty block index entries. */ -std::set setDirtyBlockIndex; +std::set setDirtyBlockIndex; /** Dirty block file entries. */ std::set setDirtyFileInfo; -} // namespace +} // anon namespace CBlockIndex *FindForkInGlobalIndex(const CChain &chain, const CBlockLocator &locator) { @@ -1054,8 +1173,8 @@ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); } -static void InvalidBlockFound(CBlockIndex *pindex, - const CValidationState &state) { +void CChainState::InvalidBlockFound(CBlockIndex *pindex, + const CValidationState &state) { if (!state.CorruptionPossible()) { pindex->nStatus = pindex->nStatus.withFailed(); setDirtyBlockIndex.insert(pindex); @@ -1301,9 +1420,14 @@ } // namespace -/** Restore the UTXO in a Coin at a given COutPoint. */ -DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, - const COutPoint &out) { +/** + * Restore the UTXO in a Coin at a given COutPoint + * @param undo The Coin to be restored. + * @param view The coins view to which to apply the changes. + * @param out The out point that corresponds to the tx input. + * @return A DisconnectResult as an int + */ DisconnectResult +UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, const COutPoint &out) { bool fClean = true; if (view.HaveCoin(out)) { @@ -1342,9 +1466,9 @@ * Undo the effects of this block (with given index) on the UTXO set represented * by coins. When FAILED is returned, view is left in an indeterminate state. */ -static DisconnectResult DisconnectBlock(const CBlock &block, - const CBlockIndex *pindex, - CCoinsViewCache &view) { +DisconnectResult CChainState::DisconnectBlock(const CBlock &block, + const CBlockIndex *pindex, + CCoinsViewCache &view) { CBlockUndo blockUndo; if (!UndoReadFromDisk(blockUndo, pindex)) { error("DisconnectBlock(): failure reading undo data"); @@ -1577,9 +1701,9 @@ * done; ConnectBlock() can fail if those validity checks fail (among other * reasons). */ -static bool ConnectBlock(const Config &config, const CBlock &block, - CValidationState &state, CBlockIndex *pindex, - CCoinsViewCache &view, bool fJustCheck = false) { +bool CChainState::ConnectBlock(const Config &config, const CBlock &block, + CValidationState &state, CBlockIndex *pindex, + CCoinsViewCache &view, bool fJustCheck) { AssertLockHeld(cs_main); int64_t nTimeStart = GetTimeMicros(); @@ -2150,8 +2274,8 @@ * disconnectpool (note that the caller is responsible for mempool consistency * in any case). */ -static bool DisconnectTip(const Config &config, CValidationState &state, - DisconnectedBlockTransactions *disconnectpool) { +bool CChainState::DisconnectTip(const Config &config, CValidationState &state, + DisconnectedBlockTransactions *disconnectpool) { CBlockIndex *pindexDelete = chainActive.Tip(); assert(pindexDelete); @@ -2306,11 +2430,11 @@ * by copying pblock) - if that is not intended, care must be taken to remove * the last entry in blocksConnected in case of failure. */ -static bool ConnectTip(const Config &config, CValidationState &state, - CBlockIndex *pindexNew, - const std::shared_ptr &pblock, - ConnectTrace &connectTrace, - DisconnectedBlockTransactions &disconnectpool) { +bool CChainState::ConnectTip(const Config &config, CValidationState &state, + CBlockIndex *pindexNew, + const std::shared_ptr &pblock, + ConnectTrace &connectTrace, + DisconnectedBlockTransactions &disconnectpool) { assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. int64_t nTime1 = GetTimeMicros(); @@ -2393,7 +2517,7 @@ * Return the tip of the chain with the most work in it, that isn't known to be * invalid (it's however far from certain to be valid). */ -static CBlockIndex *FindMostWorkChain() { +CBlockIndex *CChainState::FindMostWorkChain() { do { CBlockIndex *pindexNew = nullptr; @@ -2484,7 +2608,7 @@ * Delete all entries in setBlockIndexCandidates that are worse than the current * tip. */ -static void PruneBlockIndexCandidates() { +void CChainState::PruneBlockIndexCandidates() { // Note that we can't delete the current block itself, as we may need to // return to it later in case a reorganization to a better block fails. auto it = setBlockIndexCandidates.begin(); @@ -2503,11 +2627,10 @@ * pblock is either nullptr or a pointer to a CBlock corresponding to * pindexMostWork. */ -static bool ActivateBestChainStep(const Config &config, CValidationState &state, - CBlockIndex *pindexMostWork, - const std::shared_ptr &pblock, - bool &fInvalidFound, - ConnectTrace &connectTrace) { +bool CChainState::ActivateBestChainStep( + const Config &config, CValidationState &state, CBlockIndex *pindexMostWork, + const std::shared_ptr &pblock, bool &fInvalidFound, + ConnectTrace &connectTrace) { AssertLockHeld(cs_main); const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); @@ -2622,8 +2745,14 @@ } } -bool ActivateBestChain(const Config &config, CValidationState &state, - std::shared_ptr pblock) { +/** + * Make the best chain active, in multiple steps. The result is either failure + * or an activated best chain. pblock is either nullptr or a pointer to a block + * that is already loaded (to avoid loading it again from disk). + */ +bool CChainState::ActivateBestChain(const Config &config, + CValidationState &state, + std::shared_ptr pblock) { // Note that while we're often called here from ProcessNewBlock, this is // far from a guarantee. Things in the P2P/RPC will often end up calling // us in the middle of ProcessNewBlock - do not assume pblock is set @@ -2717,8 +2846,13 @@ return true; } -bool PreciousBlock(const Config &config, CValidationState &state, - CBlockIndex *pindex) { +bool ActivateBestChain(const Config &config, CValidationState &state, + std::shared_ptr pblock) { + return g_chainstate.ActivateBestChain(config, state, std::move(pblock)); +} + +bool CChainState::PreciousBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex) { { LOCK(cs_main); if (pindex->nChainWork < chainActive.Tip()->nChainWork) { @@ -2750,8 +2884,14 @@ return ActivateBestChain(config, state); } -static bool UnwindBlock(const Config &config, CValidationState &state, - CBlockIndex *pindex, bool invalidate) { +bool PreciousBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex) { + return g_chainstate.PreciousBlock(config, state, pindex); +} + +bool CChainState::UnwindBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex, bool invalidate) { + AssertLockHeld(cs_main); // Mark the block itself as invalid. @@ -2799,15 +2939,21 @@ bool InvalidateBlock(const Config &config, CValidationState &state, CBlockIndex *pindex) { - return UnwindBlock(config, state, pindex, true); + return g_chainstate.UnwindBlock(config, state, pindex, true); } +/** Park a block. */ bool ParkBlock(const Config &config, CValidationState &state, CBlockIndex *pindex) { + return g_chainstate.ParkBlock(config, state, pindex); +} + +bool CChainState::ParkBlock(const Config &config, CValidationState &state, + CBlockIndex *pindex) { return UnwindBlock(config, state, pindex, false); } -template bool UpdateFlags(CBlockIndex *pindex, F f) { +template bool CChainState::UpdateFlags(CBlockIndex *pindex, F f) { AssertLockHeld(cs_main); int nHeight = pindex->nHeight; @@ -2845,7 +2991,7 @@ return true; } -bool ResetBlockFailureFlags(CBlockIndex *pindex) { +bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) { AssertLockHeld(cs_main); if (pindexBestInvalid && @@ -2861,7 +3007,16 @@ }); } +bool ResetBlockFailureFlags(CBlockIndex *pindex) { + return g_chainstate.ResetBlockFailureFlags(pindex); +} + +/** Remove parked status from a block and its descendants. */ bool UnparkBlock(CBlockIndex *pindex) { + return g_chainstate.UnparkBlock(pindex); +} + +bool CChainState::UnparkBlock(CBlockIndex *pindex) { AssertLockHeld(cs_main); if (pindexBestParked && @@ -2876,7 +3031,7 @@ }); } -static CBlockIndex *AddToBlockIndex(const CBlockHeader &block) { +CBlockIndex *CChainState::AddToBlockIndex(const CBlockHeader &block) { // Check for duplicate uint256 hash = block.GetHash(); BlockMap::iterator it = mapBlockIndex.find(hash); @@ -2922,9 +3077,10 @@ * Mark a block as having its data received and checked (up to * BLOCK_VALID_TRANSACTIONS). */ -bool ReceivedBlockTransactions(const CBlock &block, CValidationState &state, - CBlockIndex *pindexNew, - const CDiskBlockPos &pos) { +bool CChainState::ReceivedBlockTransactions(const CBlock &block, + CValidationState &state, + CBlockIndex *pindexNew, + const CDiskBlockPos &pos) { pindexNew->nTx = block.vtx.size(); pindexNew->nChainTx = 0; pindexNew->nFile = pos.nFile; @@ -3405,8 +3561,10 @@ * * Returns true if the block is succesfully added to the block index. */ -static bool AcceptBlockHeader(const Config &config, const CBlockHeader &block, - CValidationState &state, CBlockIndex **ppindex) { +bool CChainState::AcceptBlockHeader(const Config &config, + const CBlockHeader &block, + CValidationState &state, + CBlockIndex **ppindex) { AssertLockHeld(cs_main); const CChainParams &chainparams = config.GetChainParams(); @@ -3493,7 +3651,8 @@ for (const CBlockHeader &header : headers) { // Use a temp pindex instead of ppindex to avoid a const_cast CBlockIndex *pindex = nullptr; - if (!AcceptBlockHeader(config, header, state, &pindex)) { + if (!g_chainstate.AcceptBlockHeader(config, header, state, + &pindex)) { if (first_invalid) { *first_invalid = header; } @@ -3547,11 +3706,11 @@ * @param[in-out] fNewBlock True if block was first received via this call. * @return True if the block is accepted as a valid block and written to disk. */ -static bool AcceptBlock(const Config &config, - const std::shared_ptr &pblock, - CValidationState &state, CBlockIndex **ppindex, - bool fRequested, const CDiskBlockPos *dbp, - bool *fNewBlock) { +bool CChainState::AcceptBlock(const Config &config, + const std::shared_ptr &pblock, + CValidationState &state, CBlockIndex **ppindex, + bool fRequested, const CDiskBlockPos *dbp, + bool *fNewBlock) { AssertLockHeld(cs_main); const CBlock &block = *pblock; if (fNewBlock) { @@ -3561,7 +3720,7 @@ CBlockIndex *pindexDummy = nullptr; CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; - if (!AcceptBlockHeader(config, block, state, &pindex)) { + if (!g_chainstate.AcceptBlockHeader(config, block, state, &pindex)) { return false; } @@ -3677,6 +3836,8 @@ FlushStateToDisk(config.GetChainParams(), state, FLUSH_STATE_NONE); } + CheckBlockIndex(chainparams.GetConsensus()); + return true; } @@ -3689,8 +3850,6 @@ *fNewBlock = false; } - const CChainParams &chainparams = config.GetChainParams(); - CValidationState state; // Ensure that CheckBlock() passes before calling AcceptBlock, as // belt-and-suspenders. @@ -3700,11 +3859,11 @@ if (ret) { // Store to disk - ret = AcceptBlock(config, pblock, state, &pindex, fForceProcessing, - nullptr, fNewBlock); + ret = + g_chainstate.AcceptBlock(config, pblock, state, &pindex, + fForceProcessing, nullptr, fNewBlock); } - CheckBlockIndex(chainparams.GetConsensus()); if (!ret) { GetMainSignals().BlockChecked(*pblock, state); return error("%s: AcceptBlock FAILED", __func__); @@ -3715,7 +3874,7 @@ // Only used to report errors, not invalidity - ignore it CValidationState state; - if (!ActivateBestChain(config, state, pblock)) { + if (!g_chainstate.ActivateBestChain(config, state, pblock)) { return error("%s: ActivateBestChain failed", __func__); } @@ -3758,7 +3917,8 @@ FormatStateMessage(state)); } - if (!ConnectBlock(config, block, state, &indexDummy, viewNew, true)) { + if (!g_chainstate.ConnectBlock(config, block, state, &indexDummy, viewNew, + true)) { return false; } @@ -3995,7 +4155,7 @@ return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); } -CBlockIndex *InsertBlockIndex(uint256 hash) { +CBlockIndex *CChainState::InsertBlockIndex(const uint256 &hash) { if (hash.IsNull()) { return nullptr; } @@ -4019,8 +4179,11 @@ return pindexNew; } -static bool LoadBlockIndexDB(const Config &config) { - if (!pblocktree->LoadBlockIndexGuts(config, InsertBlockIndex)) { +bool CChainState::LoadBlockIndex(const Config &config, + CBlockTreeDB &blocktree) { + if (!blocktree.LoadBlockIndexGuts(config, [this](const uint256 &hash) { + return this->InsertBlockIndex(hash); + })) { return false; } @@ -4086,6 +4249,12 @@ } } + return true; +} + +bool static LoadBlockIndexDB(const Config &config) { + if (!g_chainstate.LoadBlockIndex(config, *pblocktree)) return false; + // Load block file info pblocktree->ReadLastBlockFile(nLastBlockFile); vinfoBlockFile.resize(nLastBlockFile + 1); @@ -4134,7 +4303,7 @@ // Check whether we need to continue reindexing bool fReindexing = false; pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; + fReindex = (fReindex | fReindexing); // Check whether we have a transaction index pblocktree->ReadFlag("txindex", fTxIndex); @@ -4168,7 +4337,7 @@ chainActive.SetTip(it->second); - PruneBlockIndexCandidates(); + g_chainstate.PruneBlockIndexCandidates(); LogPrintf( "Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n", @@ -4279,7 +4448,8 @@ (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { assert(coins.GetBestBlock() == pindex->GetBlockHash()); - DisconnectResult res = DisconnectBlock(block, pindex, coins); + DisconnectResult res = + g_chainstate.DisconnectBlock(block, pindex, coins); if (res == DISCONNECT_FAILED) { return error("VerifyDB(): *** irrecoverable inconsistency in " "block data at %d, hash=%s", @@ -4327,7 +4497,8 @@ "VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); } - if (!ConnectBlock(config, block, state, pindex, coins)) { + if (!g_chainstate.ConnectBlock(config, block, state, pindex, + coins)) { return error( "VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); @@ -4347,8 +4518,9 @@ * Apply the effects of a block on the utxo cache, ignoring that it may already * have been applied. */ -static bool RollforwardBlock(const CBlockIndex *pindex, CCoinsViewCache &view, - const Config &config) { +bool CChainState::RollforwardBlock(const CBlockIndex *pindex, + CCoinsViewCache &view, + const Config &config) { // TODO: merge with ConnectBlock CBlock block; if (!ReadBlockFromDisk(block, pindex, config)) { @@ -4374,7 +4546,7 @@ return true; } -bool ReplayBlocks(const Config &config, CCoinsView *view) { +bool CChainState::ReplayBlocks(const Config &config, CCoinsView *view) { LOCK(cs_main); CCoinsViewCache cache(view); @@ -4468,7 +4640,11 @@ return true; } -bool RewindBlockIndex(const Config &config) { +bool ReplayBlocks(const Config &config, CCoinsView *view) { + return g_chainstate.ReplayBlocks(config, view); +} + +bool CChainState::RewindBlockIndex(const Config &config) { LOCK(cs_main); const CChainParams ¶ms = config.GetChainParams(); @@ -4517,11 +4693,23 @@ PruneBlockIndexCandidates(); CheckBlockIndex(params.GetConsensus()); + } + return true; +} + +bool RewindBlockIndex(const Config &config) { + if (!g_chainstate.RewindBlockIndex(config)) { + return false; + } + + if (chainActive.Tip() != nullptr) { // FlushStateToDisk can possibly read chainActive. Be conservative // and skip it here, we're about to -reindex-chainstate anyway, so // it'll get called a bunch real soon. - if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) { + CValidationState state; + if (!FlushStateToDisk(config.GetChainParams(), state, + FLUSH_STATE_ALWAYS)) { return false; } } @@ -4531,9 +4719,15 @@ // May NOT be used after any connections are up as much of the peer-processing // logic assumes a consistent block index state +void CChainState::UnloadBlockIndex() { + setBlockIndexCandidates.clear(); +} + +// May NOT be used after any connections are up as much +// of the peer-processing logic assumes a consistent +// block index state void UnloadBlockIndex() { LOCK(cs_main); - setBlockIndexCandidates.clear(); chainActive.SetTip(nullptr); pindexBestInvalid = nullptr; pindexBestParked = nullptr; @@ -4553,6 +4747,8 @@ mapBlockIndex.clear(); fHavePruned = false; + + g_chainstate.UnloadBlockIndex(); } bool LoadBlockIndex(const Config &config) { @@ -4582,7 +4778,7 @@ return true; } -bool LoadGenesisBlock(const CChainParams &chainparams) { +bool CChainState::LoadGenesisBlock(const CChainParams &chainparams) { LOCK(cs_main); // Check whether we're already initialized by checking for genesis in @@ -4615,6 +4811,10 @@ return true; } +bool LoadGenesisBlock(const CChainParams &chainparams) { + return g_chainstate.LoadGenesisBlock(chainparams); +} + bool LoadExternalBlockFile(const Config &config, FILE *fileIn, CDiskBlockPos *dbp) { // Map of disk positions for blocks with unknown parent (only used for @@ -4696,8 +4896,8 @@ !mapBlockIndex[hash]->nStatus.hasData()) { LOCK(cs_main); CValidationState state; - if (AcceptBlock(config, pblock, state, nullptr, true, dbp, - nullptr)) { + if (g_chainstate.AcceptBlock(config, pblock, state, nullptr, + true, dbp, nullptr)) { nLoaded++; } @@ -4717,7 +4917,7 @@ // continue if (hash == chainparams.GetConsensus().hashGenesisBlock) { CValidationState state; - if (!ActivateBestChain(config, state)) { + if (!g_chainstate.ActivateBestChain(config, state)) { break; } } @@ -4748,9 +4948,9 @@ head.ToString()); LOCK(cs_main); CValidationState dummy; - if (AcceptBlock(config, pblockrecursive, dummy, - nullptr, true, &it->second, - nullptr)) { + if (g_chainstate.AcceptBlock( + config, pblockrecursive, dummy, nullptr, + true, &it->second, nullptr)) { nLoaded++; queue.push_back(pblockrecursive->GetHash()); } @@ -4777,7 +4977,7 @@ return nLoaded > 0; } -static void CheckBlockIndex(const Consensus::Params &consensusParams) { +void CChainState::CheckBlockIndex(const Consensus::Params &consensusParams) { if (!fCheckBlockIndex) { return; }