Browse Source

Create initial CChainState to hold chain state information

0.16
Matt Corallo 7 years ago
parent
commit
fd4d80a2f8
  1. 272
      src/validation.cpp
  2. 6
      src/validation.h

272
src/validation.cpp

@ -59,11 +59,117 @@
/** /**
* Global state * Global state
*/ */
namespace {
struct CBlockIndexWorkComparator
{
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->nChainWork > pb->nChainWork) return false;
if (pa->nChainWork < pb->nChainWork) return true;
CCriticalSection cs_main; // ... then by earliest time received, ...
if (pa->nSequenceId < pb->nSequenceId) return false;
if (pa->nSequenceId > pb->nSequenceId) return true;
BlockMap mapBlockIndex; // Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if (pa < pb) return false;
if (pa > pb) return true;
// Identical blocks.
return false;
}
};
} // anon namespace
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;
/**
* 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;
public:
CChain chainActive; CChain chainActive;
BlockMap mapBlockIndex;
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CBlockIndex *pindexBestInvalid = nullptr;
bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree);
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex);
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, 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 CBlock& block, CValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false);
// Block disconnection on our pcoinsTip:
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
// Manual block validity manipulation:
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
bool ResetBlockFailureFlags(CBlockIndex *pindex);
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
bool RewindBlockIndex(const CChainParams& params);
bool LoadGenesisBlock(const CChainParams& chainparams);
void PruneBlockIndexCandidates();
void UnloadBlockIndex();
private:
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& 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, const Consensus::Params& consensusParams);
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params);
} g_chainstate;
CCriticalSection cs_main;
BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex;
CChain& chainActive = g_chainstate.chainActive;
CBlockIndex *pindexBestHeader = nullptr; CBlockIndex *pindexBestHeader = nullptr;
CWaitableCriticalSection csBestBlock; CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange; CConditionVariable cvBlockChange;
@ -91,8 +197,6 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
CBlockPolicyEstimator feeEstimator; CBlockPolicyEstimator feeEstimator;
CTxMemPool mempool(&feeEstimator); CTxMemPool mempool(&feeEstimator);
static void CheckBlockIndex(const Consensus::Params& consensusParams);
/** Constant stuff for coinbase transactions we create: */ /** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS; CScript COINBASE_FLAGS;
@ -100,40 +204,12 @@ const std::string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff // Internal stuff
namespace { namespace {
CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid;
struct CBlockIndexWorkComparator
{
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
// First sort by most total work, ...
if (pa->nChainWork > pb->nChainWork) return false;
if (pa->nChainWork < pb->nChainWork) return true;
// ... then by earliest time received, ...
if (pa->nSequenceId < pb->nSequenceId) return false;
if (pa->nSequenceId > pb->nSequenceId) return true;
// Use pointer address as tie breaker (should only happen with blocks
// loaded from disk, as those all have id 0).
if (pa < pb) return false;
if (pa > pb) return true;
// Identical blocks.
return false;
}
};
CBlockIndex *pindexBestInvalid;
/**
* 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;
/** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. /** 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. * Pruned nodes may have entries where B is missing data.
*/ */
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked; std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = g_chainstate.mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile; CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile; std::vector<CBlockFileInfo> vinfoBlockFile;
@ -1197,7 +1273,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
CheckForkWarningConditions(); CheckForkWarningConditions();
} }
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
if (!state.CorruptionPossible()) { if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
g_failed_blocks.insert(pindex); g_failed_blocks.insert(pindex);
@ -1431,13 +1507,6 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
} // namespace } // namespace
enum DisconnectResult
{
DISCONNECT_OK, // All good.
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
DISCONNECT_FAILED // Something else went wrong.
};
/** /**
* Restore the UTXO in a Coin at a given COutPoint * Restore the UTXO in a Coin at a given COutPoint
* @param undo The Coin to be restored. * @param undo The Coin to be restored.
@ -1474,7 +1543,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
/** Undo the effects of this block (with given index) on the UTXO set represented by coins. /** 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. */ * 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)
{ {
bool fClean = true; bool fClean = true;
@ -1693,8 +1762,8 @@ static int64_t nBlocksTotal = 0;
/** Apply the effects of this block (with given index) on the UTXO set represented by coins. /** Apply the effects of this block (with given index) on the UTXO set represented by coins.
* Validity checks that depend on the UTXO set are also done; ConnectBlock() * Validity checks that depend on the UTXO set are also done; ConnectBlock()
* can fail if those validity checks fail (among other reasons). */ * can fail if those validity checks fail (among other reasons). */
static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
assert(pindex); assert(pindex);
@ -2124,7 +2193,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
* disconnectpool (note that the caller is responsible for mempool consistency * disconnectpool (note that the caller is responsible for mempool consistency
* in any case). * in any case).
*/ */
bool static DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool) bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
{ {
CBlockIndex *pindexDelete = chainActive.Tip(); CBlockIndex *pindexDelete = chainActive.Tip();
assert(pindexDelete); assert(pindexDelete);
@ -2246,7 +2315,7 @@ public:
* *
* The block is added to connectTrace if connection succeeds. * The block is added to connectTrace if connection succeeds.
*/ */
bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
{ {
assert(pindexNew->pprev == chainActive.Tip()); assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk. // Read block from disk.
@ -2304,7 +2373,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
* Return the tip of the chain with the most work in it, that isn't * 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). * known to be invalid (it's however far from certain to be valid).
*/ */
static CBlockIndex* FindMostWorkChain() { CBlockIndex* CChainState::FindMostWorkChain() {
do { do {
CBlockIndex *pindexNew = nullptr; CBlockIndex *pindexNew = nullptr;
@ -2359,7 +2428,7 @@ static CBlockIndex* FindMostWorkChain() {
} }
/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ /** 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 // 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. // reorganization to a better block fails.
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin(); std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin();
@ -2374,7 +2443,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block. * Try to make some progress towards making pindexMostWork the active block.
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork. * pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork.
*/ */
static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip(); const CBlockIndex *pindexOldTip = chainActive.Tip();
@ -2481,7 +2550,7 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either nullptr or a pointer to a block * 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). * that is already loaded (to avoid loading it again from disk).
*/ */
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) { bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
// Note that while we're often called here from ProcessNewBlock, this is // 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 // 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 // us in the middle of ProcessNewBlock - do not assume pblock is set
@ -2551,9 +2620,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return true; return true;
} }
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
}
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
{ {
{ {
LOCK(cs_main); LOCK(cs_main);
@ -2579,10 +2650,13 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
} }
} }
return ActivateBestChain(state, params); return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
}
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
return g_chainstate.PreciousBlock(state, params, pindex);
} }
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -2641,8 +2715,11 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true; return true;
} }
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
return g_chainstate.InvalidateBlock(state, chainparams, pindex);
}
bool ResetBlockFailureFlags(CBlockIndex *pindex) { bool CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
int nHeight = pindex->nHeight; int nHeight = pindex->nHeight;
@ -2675,8 +2752,11 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
} }
return true; return true;
} }
bool ResetBlockFailureFlags(CBlockIndex *pindex) {
return g_chainstate.ResetBlockFailureFlags(pindex);
}
static CBlockIndex* AddToBlockIndex(const CBlockHeader& block) CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
{ {
// Check for duplicate // Check for duplicate
uint256 hash = block.GetHash(); uint256 hash = block.GetHash();
@ -2711,7 +2791,7 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
} }
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
static bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{ {
pindexNew->nTx = block.vtx.size(); pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0; pindexNew->nChainTx = 0;
@ -3116,7 +3196,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
return true; return true;
} }
static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Check for duplicate // Check for duplicate
@ -3183,7 +3263,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
LOCK(cs_main); LOCK(cs_main);
for (const CBlockHeader& header : headers) { for (const CBlockHeader& header : headers) {
CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
if (!AcceptBlockHeader(header, state, chainparams, &pindex)) { if (!g_chainstate.AcceptBlockHeader(header, state, chainparams, &pindex)) {
if (first_invalid) *first_invalid = header; if (first_invalid) *first_invalid = header;
return false; return false;
} }
@ -3216,7 +3296,7 @@ static CDiskBlockPos SaveBlockToDisk(const CBlock& block, int nHeight, const CCh
} }
/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock) bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock)
{ {
const CBlock& block = *pblock; const CBlock& block = *pblock;
@ -3292,6 +3372,8 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
if (fCheckForPruning) if (fCheckForPruning)
FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
CheckBlockIndex(chainparams.GetConsensus());
return true; return true;
} }
@ -3309,9 +3391,8 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
if (ret) { if (ret) {
// Store to disk // Store to disk
ret = AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock); ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
} }
CheckBlockIndex(chainparams.GetConsensus());
if (!ret) { if (!ret) {
GetMainSignals().BlockChecked(*pblock, state); GetMainSignals().BlockChecked(*pblock, state);
return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage()); return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage());
@ -3321,7 +3402,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
NotifyHeaderTip(); NotifyHeaderTip();
CValidationState state; // Only used to report errors, not invalidity - ignore it CValidationState state; // Only used to report errors, not invalidity - ignore it
if (!ActivateBestChain(state, chainparams, pblock)) if (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__); return error("%s: ActivateBestChain failed", __func__);
return true; return true;
@ -3343,7 +3424,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state));
if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev)) if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state)); return error("%s: Consensus::ContextualCheckBlock: %s", __func__, FormatStateMessage(state));
if (!ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true)) if (!g_chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
return false; return false;
assert(state.IsValid()); assert(state.IsValid());
@ -3551,7 +3632,7 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile);
} }
CBlockIndex * InsertBlockIndex(uint256 hash) CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
{ {
if (hash.IsNull()) if (hash.IsNull())
return nullptr; return nullptr;
@ -3569,9 +3650,9 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
return pindexNew; return pindexNew;
} }
bool static LoadBlockIndexDB(const CChainParams& chainparams) bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree)
{ {
if (!pblocktree->LoadBlockIndexGuts(chainparams.GetConsensus(), InsertBlockIndex)) if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash){ return this->InsertBlockIndex(hash); }))
return false; return false;
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
@ -3618,6 +3699,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
pindexBestHeader = pindex; pindexBestHeader = pindex;
} }
return true;
}
bool static LoadBlockIndexDB(const CChainParams& chainparams)
{
if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
return false;
// Load block file info // Load block file info
pblocktree->ReadLastBlockFile(nLastBlockFile); pblocktree->ReadLastBlockFile(nLastBlockFile);
vinfoBlockFile.resize(nLastBlockFile + 1); vinfoBlockFile.resize(nLastBlockFile + 1);
@ -3690,7 +3779,7 @@ bool LoadChainTip(const CChainParams& chainparams)
return false; return false;
chainActive.SetTip(it->second); chainActive.SetTip(it->second);
PruneBlockIndexCandidates(); g_chainstate.PruneBlockIndexCandidates();
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n", LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n",
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(),
@ -3764,7 +3853,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks // check level 3: check for inconsistencies during memory-only disconnect of tip blocks
if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash()); assert(coins.GetBestBlock() == pindex->GetBlockHash());
DisconnectResult res = DisconnectBlock(block, pindex, coins); DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) { if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
} }
@ -3792,7 +3881,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
CBlock block; CBlock block;
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
if (!ConnectBlock(block, state, pindex, coins, chainparams)) if (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
} }
} }
@ -3804,7 +3893,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
} }
/** Apply the effects of a block on the utxo cache, ignoring that it may already have been applied. */ /** 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& inputs, const CChainParams& params) bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params)
{ {
// TODO: merge with ConnectBlock // TODO: merge with ConnectBlock
CBlock block; CBlock block;
@ -3824,7 +3913,7 @@ static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs,
return true; return true;
} }
bool ReplayBlocks(const CChainParams& params, CCoinsView* view) bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
{ {
LOCK(cs_main); LOCK(cs_main);
@ -3889,7 +3978,11 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
return true; return true;
} }
bool RewindBlockIndex(const CChainParams& params) bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
return g_chainstate.ReplayBlocks(params, view);
}
bool CChainState::RewindBlockIndex(const CChainParams& params)
{ {
LOCK(cs_main); LOCK(cs_main);
@ -3970,10 +4063,21 @@ bool RewindBlockIndex(const CChainParams& params)
PruneBlockIndexCandidates(); PruneBlockIndexCandidates();
CheckBlockIndex(params.GetConsensus()); CheckBlockIndex(params.GetConsensus());
}
return true;
}
bool RewindBlockIndex(const CChainParams& params) {
if (!g_chainstate.RewindBlockIndex(params)) {
return false;
}
if (chainActive.Tip() != nullptr) {
// FlushStateToDisk can possibly read chainActive. Be conservative // FlushStateToDisk can possibly read chainActive. Be conservative
// and skip it here, we're about to -reindex-chainstate anyway, so // and skip it here, we're about to -reindex-chainstate anyway, so
// it'll get called a bunch real soon. // it'll get called a bunch real soon.
CValidationState state;
if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) { if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) {
return false; return false;
} }
@ -3982,13 +4086,16 @@ bool RewindBlockIndex(const CChainParams& params)
return true; return true;
} }
void CChainState::UnloadBlockIndex() {
setBlockIndexCandidates.clear();
}
// May NOT be used after any connections are up as much // May NOT be used after any connections are up as much
// of the peer-processing logic assumes a consistent // of the peer-processing logic assumes a consistent
// block index state // block index state
void UnloadBlockIndex() void UnloadBlockIndex()
{ {
LOCK(cs_main); LOCK(cs_main);
setBlockIndexCandidates.clear();
chainActive.SetTip(nullptr); chainActive.SetTip(nullptr);
pindexBestInvalid = nullptr; pindexBestInvalid = nullptr;
pindexBestHeader = nullptr; pindexBestHeader = nullptr;
@ -4010,6 +4117,8 @@ void UnloadBlockIndex()
} }
mapBlockIndex.clear(); mapBlockIndex.clear();
fHavePruned = false; fHavePruned = false;
g_chainstate.UnloadBlockIndex();
} }
bool LoadBlockIndex(const CChainParams& chainparams) bool LoadBlockIndex(const CChainParams& chainparams)
@ -4037,7 +4146,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
return true; return true;
} }
bool LoadGenesisBlock(const CChainParams& chainparams) bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
{ {
LOCK(cs_main); LOCK(cs_main);
@ -4064,6 +4173,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
return true; return true;
} }
bool LoadGenesisBlock(const CChainParams& chainparams)
{
return g_chainstate.LoadGenesisBlock(chainparams);
}
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp)
{ {
// Map of disk positions for blocks with unknown parent (only used for reindex) // Map of disk positions for blocks with unknown parent (only used for reindex)
@ -4124,7 +4238,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
LOCK(cs_main); LOCK(cs_main);
CValidationState state; CValidationState state;
if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr))
nLoaded++; nLoaded++;
if (state.IsError()) if (state.IsError())
break; break;
@ -4158,7 +4272,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
head.ToString()); head.ToString());
LOCK(cs_main); LOCK(cs_main);
CValidationState dummy; CValidationState dummy;
if (AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr)) if (g_chainstate.AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
{ {
nLoaded++; nLoaded++;
queue.push_back(pblockrecursive->GetHash()); queue.push_back(pblockrecursive->GetHash());
@ -4181,7 +4295,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
return nLoaded > 0; return nLoaded > 0;
} }
void static CheckBlockIndex(const Consensus::Params& consensusParams) void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams)
{ {
if (!fCheckBlockIndex) { if (!fCheckBlockIndex) {
return; return;

6
src/validation.h

@ -159,7 +159,7 @@ extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator; extern CBlockPolicyEstimator feeEstimator;
extern CTxMemPool mempool; extern CTxMemPool mempool;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
extern BlockMap mapBlockIndex; extern BlockMap& mapBlockIndex;
extern uint64_t nLastBlockTx; extern uint64_t nLastBlockTx;
extern uint64_t nLastBlockWeight; extern uint64_t nLastBlockWeight;
extern const std::string strMessageMagic; extern const std::string strMessageMagic;
@ -294,8 +294,6 @@ void PruneOneBlockFile(const int fileNumber);
*/ */
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune); void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
/** Flush all state, indexes and buffers to disk. */ /** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk(); void FlushStateToDisk();
/** Prune block files and flush state to disk. */ /** Prune block files and flush state to disk. */
@ -441,7 +439,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
bool ResetBlockFailureFlags(CBlockIndex *pindex); bool ResetBlockFailureFlags(CBlockIndex *pindex);
/** The currently-connected chain of blocks (protected by cs_main). */ /** 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) */ /** Global variable that points to the coins database (protected by cs_main) */
extern std::unique_ptr<CCoinsViewDB> pcoinsdbview; extern std::unique_ptr<CCoinsViewDB> pcoinsdbview;

Loading…
Cancel
Save