|
|
|
@ -59,11 +59,117 @@
@@ -59,11 +59,117 @@
|
|
|
|
|
/**
|
|
|
|
|
* 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; |
|
|
|
|
|
|
|
|
|
// ... 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; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} // 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; |
|
|
|
|
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; |
|
|
|
|
CChain chainActive; |
|
|
|
|
BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex; |
|
|
|
|
CChain& chainActive = g_chainstate.chainActive; |
|
|
|
|
CBlockIndex *pindexBestHeader = nullptr; |
|
|
|
|
CWaitableCriticalSection csBestBlock; |
|
|
|
|
CConditionVariable cvBlockChange; |
|
|
|
@ -91,8 +197,6 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@@ -91,8 +197,6 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
|
|
|
|
|
CBlockPolicyEstimator feeEstimator; |
|
|
|
|
CTxMemPool mempool(&feeEstimator); |
|
|
|
|
|
|
|
|
|
static void CheckBlockIndex(const Consensus::Params& consensusParams); |
|
|
|
|
|
|
|
|
|
/** Constant stuff for coinbase transactions we create: */ |
|
|
|
|
CScript COINBASE_FLAGS; |
|
|
|
|
|
|
|
|
@ -100,40 +204,12 @@ const std::string strMessageMagic = "Bitcoin Signed Message:\n";
@@ -100,40 +204,12 @@ const std::string strMessageMagic = "Bitcoin Signed Message:\n";
|
|
|
|
|
|
|
|
|
|
// Internal stuff
|
|
|
|
|
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.
|
|
|
|
|
* 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; |
|
|
|
|
std::vector<CBlockFileInfo> vinfoBlockFile; |
|
|
|
@ -1197,7 +1273,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
@@ -1197,7 +1273,7 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
|
|
|
|
|
CheckForkWarningConditions(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { |
|
|
|
|
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { |
|
|
|
|
if (!state.CorruptionPossible()) { |
|
|
|
|
pindex->nStatus |= BLOCK_FAILED_VALID; |
|
|
|
|
g_failed_blocks.insert(pindex); |
|
|
|
@ -1431,13 +1507,6 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
@@ -1431,13 +1507,6 @@ bool AbortNode(CValidationState& state, const std::string& strMessage, const std
|
|
|
|
|
|
|
|
|
|
} // 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 |
|
|
|
|
* @param undo The Coin to be restored. |
|
|
|
@ -1474,7 +1543,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
@@ -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.
|
|
|
|
|
* 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; |
|
|
|
|
|
|
|
|
@ -1693,8 +1762,8 @@ static int64_t nBlocksTotal = 0;
@@ -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.
|
|
|
|
|
* Validity checks that depend on the UTXO set are also done; ConnectBlock() |
|
|
|
|
* can fail if those validity checks fail (among other reasons). */ |
|
|
|
|
static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, |
|
|
|
|
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) |
|
|
|
|
bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, |
|
|
|
|
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck) |
|
|
|
|
{ |
|
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
assert(pindex); |
|
|
|
@ -2124,7 +2193,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
@@ -2124,7 +2193,7 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
|
|
|
|
|
* disconnectpool (note that the caller is responsible for mempool consistency |
|
|
|
|
* 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(); |
|
|
|
|
assert(pindexDelete); |
|
|
|
@ -2246,7 +2315,7 @@ public:
@@ -2246,7 +2315,7 @@ public:
|
|
|
|
|
* |
|
|
|
|
* 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()); |
|
|
|
|
// Read block from disk.
|
|
|
|
@ -2304,7 +2373,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
@@ -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 |
|
|
|
|
* known to be invalid (it's however far from certain to be valid). |
|
|
|
|
*/ |
|
|
|
|
static CBlockIndex* FindMostWorkChain() { |
|
|
|
|
CBlockIndex* CChainState::FindMostWorkChain() { |
|
|
|
|
do { |
|
|
|
|
CBlockIndex *pindexNew = nullptr; |
|
|
|
|
|
|
|
|
@ -2359,7 +2428,7 @@ static CBlockIndex* FindMostWorkChain() {
@@ -2359,7 +2428,7 @@ static CBlockIndex* FindMostWorkChain() {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 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.
|
|
|
|
|
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin(); |
|
|
|
@ -2374,7 +2443,7 @@ static void PruneBlockIndexCandidates() {
@@ -2374,7 +2443,7 @@ static void PruneBlockIndexCandidates() {
|
|
|
|
|
* Try to make some progress towards making pindexMostWork the active block. |
|
|
|
|
* 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); |
|
|
|
|
const CBlockIndex *pindexOldTip = chainActive.Tip(); |
|
|
|
@ -2481,7 +2550,7 @@ static void NotifyHeaderTip() {
@@ -2481,7 +2550,7 @@ static void NotifyHeaderTip() {
|
|
|
|
|
* 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 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
|
|
|
|
|
// 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
|
|
|
|
@ -2551,9 +2620,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
@@ -2551,9 +2620,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
|
|
|
|
|
|
|
|
|
|
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 PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) |
|
|
|
|
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) |
|
|
|
|
{ |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_main); |
|
|
|
@ -2579,10 +2650,13 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
@@ -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); |
|
|
|
|
|
|
|
|
@ -2641,8 +2715,11 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
@@ -2641,8 +2715,11 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
|
|
|
|
|
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev); |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
int nHeight = pindex->nHeight; |
|
|
|
@ -2675,8 +2752,11 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
@@ -2675,8 +2752,11 @@ bool ResetBlockFailureFlags(CBlockIndex *pindex) {
|
|
|
|
|
} |
|
|
|
|
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
|
|
|
|
|
uint256 hash = block.GetHash(); |
|
|
|
@ -2711,7 +2791,7 @@ static CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
@@ -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). */ |
|
|
|
|
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->nChainTx = 0; |
|
|
|
@ -3116,7 +3196,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
@@ -3116,7 +3196,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|
|
|
|
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); |
|
|
|
|
// Check for duplicate
|
|
|
|
@ -3183,7 +3263,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
@@ -3183,7 +3263,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio
|
|
|
|
|
LOCK(cs_main); |
|
|
|
|
for (const CBlockHeader& header : headers) { |
|
|
|
|
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; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -3216,7 +3296,7 @@ static CDiskBlockPos SaveBlockToDisk(const CBlock& block, int nHeight, const CCh
@@ -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 */ |
|
|
|
|
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; |
|
|
|
|
|
|
|
|
@ -3292,6 +3372,8 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
@@ -3292,6 +3372,8 @@ static bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidation
|
|
|
|
|
if (fCheckForPruning) |
|
|
|
|
FlushStateToDisk(chainparams, state, FLUSH_STATE_NONE); // we just allocated more disk space for block files
|
|
|
|
|
|
|
|
|
|
CheckBlockIndex(chainparams.GetConsensus()); |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -3309,9 +3391,8 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
@@ -3309,9 +3391,8 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
|
|
|
|
|
|
|
|
|
if (ret) { |
|
|
|
|
// 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) { |
|
|
|
|
GetMainSignals().BlockChecked(*pblock, state); |
|
|
|
|
return error("%s: AcceptBlock FAILED (%s)", __func__, state.GetDebugMessage()); |
|
|
|
@ -3321,7 +3402,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
@@ -3321,7 +3402,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
|
|
|
|
NotifyHeaderTip(); |
|
|
|
|
|
|
|
|
|
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 true; |
|
|
|
@ -3343,7 +3424,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
@@ -3343,7 +3424,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
|
|
|
|
|
return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); |
|
|
|
|
if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev)) |
|
|
|
|
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; |
|
|
|
|
assert(state.IsValid()); |
|
|
|
|
|
|
|
|
@ -3551,7 +3632,7 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
@@ -3551,7 +3632,7 @@ fs::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix)
|
|
|
|
|
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; |
|
|
|
@ -3569,9 +3650,9 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
@@ -3569,9 +3650,9 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
|
|
|
|
|
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; |
|
|
|
|
|
|
|
|
|
boost::this_thread::interruption_point(); |
|
|
|
@ -3618,6 +3699,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
@@ -3618,6 +3699,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
|
|
|
|
|
pindexBestHeader = pindex; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool static LoadBlockIndexDB(const CChainParams& chainparams) |
|
|
|
|
{ |
|
|
|
|
if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
// Load block file info
|
|
|
|
|
pblocktree->ReadLastBlockFile(nLastBlockFile); |
|
|
|
|
vinfoBlockFile.resize(nLastBlockFile + 1); |
|
|
|
@ -3690,7 +3779,7 @@ bool LoadChainTip(const CChainParams& chainparams)
@@ -3690,7 +3779,7 @@ bool LoadChainTip(const CChainParams& chainparams)
|
|
|
|
|
return false; |
|
|
|
|
chainActive.SetTip(it->second); |
|
|
|
|
|
|
|
|
|
PruneBlockIndexCandidates(); |
|
|
|
|
g_chainstate.PruneBlockIndexCandidates(); |
|
|
|
|
|
|
|
|
|
LogPrintf("Loaded best chain: hashBestChain=%s height=%d date=%s progress=%f\n", |
|
|
|
|
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), |
|
|
|
@ -3764,7 +3853,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
@@ -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
|
|
|
|
|
if (nCheckLevel >= 3 && pindex == pindexState && (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", pindex->nHeight, pindex->GetBlockHash().ToString()); |
|
|
|
|
} |
|
|
|
@ -3792,7 +3881,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
@@ -3792,7 +3881,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
|
|
|
|
|
CBlock block; |
|
|
|
|
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) |
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -3804,7 +3893,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
@@ -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. */ |
|
|
|
|
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
|
|
|
|
|
CBlock block; |
|
|
|
@ -3824,7 +3913,7 @@ static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs,
@@ -3824,7 +3913,7 @@ static bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs,
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool ReplayBlocks(const CChainParams& params, CCoinsView* view) |
|
|
|
|
bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_main); |
|
|
|
|
|
|
|
|
@ -3889,7 +3978,11 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
@@ -3889,7 +3978,11 @@ bool ReplayBlocks(const CChainParams& params, CCoinsView* view)
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
@ -3970,10 +4063,21 @@ bool RewindBlockIndex(const CChainParams& params)
@@ -3970,10 +4063,21 @@ bool RewindBlockIndex(const CChainParams& params)
|
|
|
|
|
PruneBlockIndexCandidates(); |
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
// and skip it here, we're about to -reindex-chainstate anyway, so
|
|
|
|
|
// it'll get called a bunch real soon.
|
|
|
|
|
CValidationState state; |
|
|
|
|
if (!FlushStateToDisk(params, state, FLUSH_STATE_ALWAYS)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
@ -3982,13 +4086,16 @@ bool RewindBlockIndex(const CChainParams& params)
@@ -3982,13 +4086,16 @@ bool RewindBlockIndex(const CChainParams& params)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
pindexBestHeader = nullptr; |
|
|
|
@ -4010,6 +4117,8 @@ void UnloadBlockIndex()
@@ -4010,6 +4117,8 @@ void UnloadBlockIndex()
|
|
|
|
|
} |
|
|
|
|
mapBlockIndex.clear(); |
|
|
|
|
fHavePruned = false; |
|
|
|
|
|
|
|
|
|
g_chainstate.UnloadBlockIndex(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool LoadBlockIndex(const CChainParams& chainparams) |
|
|
|
@ -4037,7 +4146,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
@@ -4037,7 +4146,7 @@ bool LoadBlockIndex(const CChainParams& chainparams)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool LoadGenesisBlock(const CChainParams& chainparams) |
|
|
|
|
bool CChainState::LoadGenesisBlock(const CChainParams& chainparams) |
|
|
|
|
{ |
|
|
|
|
LOCK(cs_main); |
|
|
|
|
|
|
|
|
@ -4064,6 +4173,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
@@ -4064,6 +4173,11 @@ bool LoadGenesisBlock(const CChainParams& chainparams)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool LoadGenesisBlock(const CChainParams& chainparams) |
|
|
|
|
{ |
|
|
|
|
return g_chainstate.LoadGenesisBlock(chainparams); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) |
|
|
|
|
{ |
|
|
|
|
// 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
@@ -4124,7 +4238,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
|
|
|
|
|
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { |
|
|
|
|
LOCK(cs_main); |
|
|
|
|
CValidationState state; |
|
|
|
|
if (AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) |
|
|
|
|
if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) |
|
|
|
|
nLoaded++; |
|
|
|
|
if (state.IsError()) |
|
|
|
|
break; |
|
|
|
@ -4158,7 +4272,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
@@ -4158,7 +4272,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
|
|
|
|
|
head.ToString()); |
|
|
|
|
LOCK(cs_main); |
|
|
|
|
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++; |
|
|
|
|
queue.push_back(pblockrecursive->GetHash()); |
|
|
|
@ -4181,7 +4295,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
@@ -4181,7 +4295,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
|
|
|
|
|
return nLoaded > 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void static CheckBlockIndex(const Consensus::Params& consensusParams) |
|
|
|
|
void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) |
|
|
|
|
{ |
|
|
|
|
if (!fCheckBlockIndex) { |
|
|
|
|
return; |
|
|
|
|