Merge #15976: refactor: move methods under CChainState (pt. 1)
403e677c9
refactoring: IsInitialBlockDownload -> CChainState (James O'Beirne)3ccbc376d
refactoring: FlushStateToDisk -> CChainState (James O'Beirne)4d6688603
refactoring: introduce ChainstateActive() (James O'Beirne)d7c97edee
move-only: make the CChainState interface public (James O'Beirne) Pull request description: This is part of the [assumeutxo project](https://github.com/bitcoin/bitcoin/projects/11): Parent PR: #15606 Issue: #15605 Specification: https://github.com/jamesob/assumeutxo-docs/tree/2019-04-proposal/proposal --- This changeset starts moving functionality intimately related to CChainState into methods. Parameterizing these functions by a particular CChainState is necessary for the use of multiple chainstates simultaneously (e.g. for asynchronous background validation). In this change, we - make the CChainState interface public - since other units will start to invoke its methods directly, - introduce `::ChainstateActive()`, the CChainState equivalent for `::ChainActive()`, - and move `IsInitialBlockDownload()` and `FlushStateToDisk()` into methods on CChainState. Independent of assumeutxo, these changes better encapsulate chainstate behavior and allow easier use from a testing context. There are more methods that we'll move in the future, but they require other substantial changes (i.e. moving ownership of the `CCoinsView*` hierarchy into CChainState) so we'll save them for future PRs. --- The first move-only commit is most easily reviewed with `git diff ... --color-moved=dimmed_zebra`. ACKs for commit 403e67: Empact: utACK403e677c9e
no need to address my nits herein Sjors: utACK403e677
ryanofsky: utACK403e677c9e
. Only change since previous review is removing global state comment as suggested. MarcoFalke: utACK403e677c9e
, though the diff still seems a bit bloated with some unnecessary changes in the second commit. promag: utACK403e677
and rebased with current [master](c7cfd20a7
). Tree-SHA512: 6fcf260bb2dc201361170c0b4547405366f5f331fcc3a2bac29b24442814b7b244ca1b58aac5af716885f9a130c343b544590dff780da0bf835c7c5b3ccb2257
This commit is contained in:
commit
5d37c1bde0
8 changed files with 273 additions and 239 deletions
|
@ -259,7 +259,7 @@ void Shutdown(InitInterfaces& interfaces)
|
||||||
|
|
||||||
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
|
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
|
||||||
if (pcoinsTip != nullptr) {
|
if (pcoinsTip != nullptr) {
|
||||||
FlushStateToDisk();
|
::ChainstateActive().ForceFlushStateToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
// After there are no more peers/RPC left to give us new data which may generate
|
// After there are no more peers/RPC left to give us new data which may generate
|
||||||
|
@ -275,7 +275,7 @@ void Shutdown(InitInterfaces& interfaces)
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
if (pcoinsTip != nullptr) {
|
if (pcoinsTip != nullptr) {
|
||||||
FlushStateToDisk();
|
::ChainstateActive().ForceFlushStateToDisk();
|
||||||
}
|
}
|
||||||
pcoinsTip.reset();
|
pcoinsTip.reset();
|
||||||
pcoinscatcher.reset();
|
pcoinscatcher.reset();
|
||||||
|
@ -1693,7 +1693,7 @@ bool AppInitMain(InitInterfaces& interfaces)
|
||||||
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
|
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
|
||||||
if (!fReindex) {
|
if (!fReindex) {
|
||||||
uiInterface.InitMessage(_("Pruning blockstore..."));
|
uiInterface.InitMessage(_("Pruning blockstore..."));
|
||||||
PruneAndFlush();
|
::ChainstateActive().PruneAndFlush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -334,8 +334,8 @@ public:
|
||||||
return ::fHavePruned;
|
return ::fHavePruned;
|
||||||
}
|
}
|
||||||
bool p2pEnabled() override { return g_connman != nullptr; }
|
bool p2pEnabled() override { return g_connman != nullptr; }
|
||||||
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); }
|
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
|
||||||
bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
|
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
|
||||||
bool shutdownRequested() override { return ShutdownRequested(); }
|
bool shutdownRequested() override { return ShutdownRequested(); }
|
||||||
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
|
int64_t getAdjustedTime() override { return GetAdjustedTime(); }
|
||||||
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
|
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
|
||||||
|
|
|
@ -197,7 +197,7 @@ public:
|
||||||
}
|
}
|
||||||
return GuessVerificationProgress(Params().TxData(), tip);
|
return GuessVerificationProgress(Params().TxData(), tip);
|
||||||
}
|
}
|
||||||
bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
|
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); }
|
||||||
bool getReindex() override { return ::fReindex; }
|
bool getReindex() override { return ::fReindex; }
|
||||||
bool getImporting() override { return ::fImporting; }
|
bool getImporting() override { return ::fImporting; }
|
||||||
void setNetworkActive(bool active) override
|
void setNetworkActive(bool active) override
|
||||||
|
|
|
@ -1240,7 +1240,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
|
||||||
// the tip yet so we have no way to check this directly here. Instead we
|
// the tip yet so we have no way to check this directly here. Instead we
|
||||||
// just check that there are currently no other blocks in flight.
|
// just check that there are currently no other blocks in flight.
|
||||||
else if (state.IsValid() &&
|
else if (state.IsValid() &&
|
||||||
!IsInitialBlockDownload() &&
|
!::ChainstateActive().IsInitialBlockDownload() &&
|
||||||
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
|
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
|
||||||
if (it != mapBlockSource.end()) {
|
if (it != mapBlockSource.end()) {
|
||||||
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman);
|
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first, connman);
|
||||||
|
@ -1728,7 +1728,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
|
||||||
}
|
}
|
||||||
// If we're in IBD, we want outbound peers that will serve us a useful
|
// If we're in IBD, we want outbound peers that will serve us a useful
|
||||||
// chain. Disconnect peers that are on chains with insufficient work.
|
// chain. Disconnect peers that are on chains with insufficient work.
|
||||||
if (IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
|
if (::ChainstateActive().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
|
||||||
// When nCount < MAX_HEADERS_RESULTS, we know we have no more
|
// When nCount < MAX_HEADERS_RESULTS, we know we have no more
|
||||||
// headers to fetch from this peer.
|
// headers to fetch from this peer.
|
||||||
if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
|
if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
|
||||||
|
@ -1994,7 +1994,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
if (!pfrom->fInbound)
|
if (!pfrom->fInbound)
|
||||||
{
|
{
|
||||||
// Advertise our address
|
// Advertise our address
|
||||||
if (fListen && !IsInitialBlockDownload())
|
if (fListen && !::ChainstateActive().IsInitialBlockDownload())
|
||||||
{
|
{
|
||||||
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
|
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
|
||||||
FastRandomContext insecure_rand;
|
FastRandomContext insecure_rand;
|
||||||
|
@ -2229,7 +2229,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
pfrom->AddInventoryKnown(inv);
|
pfrom->AddInventoryKnown(inv);
|
||||||
if (fBlocksOnly) {
|
if (fBlocksOnly) {
|
||||||
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
|
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->GetId());
|
||||||
} else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) {
|
} else if (!fAlreadyHave && !fImporting && !fReindex && !::ChainstateActive().IsInitialBlockDownload()) {
|
||||||
RequestTx(State(pfrom->GetId()), inv.hash, nNow);
|
RequestTx(State(pfrom->GetId()), inv.hash, nNow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2387,7 +2387,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
if (IsInitialBlockDownload() && !pfrom->fWhitelisted) {
|
if (::ChainstateActive().IsInitialBlockDownload() && !pfrom->fWhitelisted) {
|
||||||
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
|
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->GetId());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2609,7 +2609,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||||
|
|
||||||
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
|
if (!LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
|
||||||
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
|
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
|
||||||
if (!IsInitialBlockDownload())
|
if (!::ChainstateActive().IsInitialBlockDownload())
|
||||||
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
|
connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3524,7 +3524,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
||||||
|
|
||||||
// Address refresh broadcast
|
// Address refresh broadcast
|
||||||
int64_t nNow = GetTimeMicros();
|
int64_t nNow = GetTimeMicros();
|
||||||
if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
|
if (!::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
|
||||||
AdvertiseLocal(pto);
|
AdvertiseLocal(pto);
|
||||||
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
|
pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
|
||||||
}
|
}
|
||||||
|
@ -3925,7 +3925,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
|
||||||
// Message: getdata (blocks)
|
// Message: getdata (blocks)
|
||||||
//
|
//
|
||||||
std::vector<CInv> vGetData;
|
std::vector<CInv> vGetData;
|
||||||
if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !::ChainstateActive().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
|
||||||
std::vector<const CBlockIndex*> vToDownload;
|
std::vector<const CBlockIndex*> vToDownload;
|
||||||
NodeId staller = -1;
|
NodeId staller = -1;
|
||||||
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
|
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller, consensusParams);
|
||||||
|
|
|
@ -1095,7 +1095,7 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
|
||||||
UniValue ret(UniValue::VOBJ);
|
UniValue ret(UniValue::VOBJ);
|
||||||
|
|
||||||
CCoinsStats stats;
|
CCoinsStats stats;
|
||||||
FlushStateToDisk();
|
::ChainstateActive().ForceFlushStateToDisk();
|
||||||
if (GetUTXOStats(pcoinsdbview.get(), stats)) {
|
if (GetUTXOStats(pcoinsdbview.get(), stats)) {
|
||||||
ret.pushKV("height", (int64_t)stats.nHeight);
|
ret.pushKV("height", (int64_t)stats.nHeight);
|
||||||
ret.pushKV("bestblock", stats.hashBlock.GetHex());
|
ret.pushKV("bestblock", stats.hashBlock.GetHex());
|
||||||
|
@ -1360,7 +1360,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
|
||||||
obj.pushKV("difficulty", (double)GetDifficulty(tip));
|
obj.pushKV("difficulty", (double)GetDifficulty(tip));
|
||||||
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
|
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
|
||||||
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
|
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
|
||||||
obj.pushKV("initialblockdownload", IsInitialBlockDownload());
|
obj.pushKV("initialblockdownload", ::ChainstateActive().IsInitialBlockDownload());
|
||||||
obj.pushKV("chainwork", tip->nChainWork.GetHex());
|
obj.pushKV("chainwork", tip->nChainWork.GetHex());
|
||||||
obj.pushKV("size_on_disk", CalculateCurrentUsage());
|
obj.pushKV("size_on_disk", CalculateCurrentUsage());
|
||||||
obj.pushKV("pruned", fPruneMode);
|
obj.pushKV("pruned", fPruneMode);
|
||||||
|
@ -2292,7 +2292,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
|
||||||
std::unique_ptr<CCoinsViewCursor> pcursor;
|
std::unique_ptr<CCoinsViewCursor> pcursor;
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
FlushStateToDisk();
|
::ChainstateActive().ForceFlushStateToDisk();
|
||||||
pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
|
pcursor = std::unique_ptr<CCoinsViewCursor>(pcoinsdbview->Cursor());
|
||||||
assert(pcursor);
|
assert(pcursor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -442,7 +442,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
|
||||||
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
|
if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0)
|
||||||
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
|
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
|
||||||
|
|
||||||
if (IsInitialBlockDownload())
|
if (::ChainstateActive().IsInitialBlockDownload())
|
||||||
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
|
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
|
||||||
|
|
||||||
static unsigned int nTransactionsUpdatedLast;
|
static unsigned int nTransactionsUpdatedLast;
|
||||||
|
|
|
@ -60,165 +60,27 @@
|
||||||
#define MICRO 0.000001
|
#define MICRO 0.000001
|
||||||
#define MILLI 0.001
|
#define MILLI 0.001
|
||||||
|
|
||||||
/**
|
bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
|
||||||
* Global state
|
// First sort by most total work, ...
|
||||||
*/
|
if (pa->nChainWork > pb->nChainWork) return false;
|
||||||
namespace {
|
if (pa->nChainWork < pb->nChainWork) return true;
|
||||||
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, ...
|
// ... then by earliest time received, ...
|
||||||
if (pa->nSequenceId < pb->nSequenceId) return false;
|
if (pa->nSequenceId < pb->nSequenceId) return false;
|
||||||
if (pa->nSequenceId > pb->nSequenceId) return true;
|
if (pa->nSequenceId > pb->nSequenceId) return true;
|
||||||
|
|
||||||
// Use pointer address as tie breaker (should only happen with blocks
|
// Use pointer address as tie breaker (should only happen with blocks
|
||||||
// loaded from disk, as those all have id 0).
|
// loaded from disk, as those all have id 0).
|
||||||
if (pa < pb) return false;
|
if (pa < pb) return false;
|
||||||
if (pa > pb) return true;
|
if (pa > pb) return true;
|
||||||
|
|
||||||
// Identical blocks.
|
// Identical blocks.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
} // anon namespace
|
|
||||||
|
|
||||||
enum DisconnectResult
|
CChainState g_chainstate;
|
||||||
{
|
|
||||||
DISCONNECT_OK, // All good.
|
|
||||||
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
|
|
||||||
DISCONNECT_FAILED // Something else went wrong.
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConnectTrace;
|
CChainState& ChainstateActive() { return g_chainstate; }
|
||||||
|
|
||||||
/**
|
|
||||||
* CChainState stores and provides an API to update our local knowledge of the
|
|
||||||
* current best chain and header tree.
|
|
||||||
*
|
|
||||||
* It generally provides access to the current block tree, as well as functions
|
|
||||||
* to provide new data, which it will appropriately validate and incorporate in
|
|
||||||
* its state as necessary.
|
|
||||||
*
|
|
||||||
* Eventually, the API here is targeted at being exposed externally as a
|
|
||||||
* consumable libconsensus library, so any functions added must only call
|
|
||||||
* other class member functions, pure functions in other parts of the consensus
|
|
||||||
* library, callbacks via the validation interface, or read/write-to-disk
|
|
||||||
* functions (eventually this will also be via callbacks).
|
|
||||||
*/
|
|
||||||
class CChainState {
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
|
|
||||||
* as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
|
|
||||||
* missing the data for the block.
|
|
||||||
*/
|
|
||||||
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Every received block is assigned a unique and increasing identifier, so we
|
|
||||||
* know which one to give priority in case of a fork.
|
|
||||||
*/
|
|
||||||
CCriticalSection cs_nBlockSequenceId;
|
|
||||||
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
|
|
||||||
int32_t nBlockSequenceId = 1;
|
|
||||||
/** Decreasing counter (used by subsequent preciousblock calls). */
|
|
||||||
int32_t nBlockReverseSequenceId = -1;
|
|
||||||
/** chainwork for the last block that preciousblock has been applied to. */
|
|
||||||
arith_uint256 nLastPreciousChainwork = 0;
|
|
||||||
|
|
||||||
/** In order to efficiently track invalidity of headers, we keep the set of
|
|
||||||
* blocks which we tried to connect and found to be invalid here (ie which
|
|
||||||
* were set to BLOCK_FAILED_VALID since the last restart). We can then
|
|
||||||
* walk this set and check if a new header is a descendant of something in
|
|
||||||
* this set, preventing us from having to walk mapBlockIndex when we try
|
|
||||||
* to connect a bad block and fail.
|
|
||||||
*
|
|
||||||
* While this is more complicated than marking everything which descends
|
|
||||||
* from an invalid block as invalid at the time we discover it to be
|
|
||||||
* invalid, doing so would require walking all of mapBlockIndex to find all
|
|
||||||
* descendants. Since this case should be very rare, keeping track of all
|
|
||||||
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
|
|
||||||
* well.
|
|
||||||
*
|
|
||||||
* Because we already walk mapBlockIndex in height-order at startup, we go
|
|
||||||
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
|
|
||||||
* instead of putting things in this set.
|
|
||||||
*/
|
|
||||||
std::set<CBlockIndex*> m_failed_blocks;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the ChainState CriticalSection
|
|
||||||
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
|
|
||||||
*/
|
|
||||||
CCriticalSection m_cs_chainstate;
|
|
||||||
|
|
||||||
public:
|
|
||||||
//! The current chain of blockheaders we consult and build on.
|
|
||||||
//! @see CChain, CBlockIndex.
|
|
||||||
CChain m_chain;
|
|
||||||
BlockMap mapBlockIndex GUARDED_BY(cs_main);
|
|
||||||
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
|
|
||||||
CBlockIndex *pindexBestInvalid = nullptr;
|
|
||||||
|
|
||||||
bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
|
|
||||||
* that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
|
|
||||||
*/
|
|
||||||
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
// Block (dis)connection on a given view:
|
|
||||||
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
|
|
||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
|
|
||||||
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
// Block disconnection on our pcoinsTip:
|
|
||||||
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
// Manual block validity manipulation:
|
|
||||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
|
||||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
|
||||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
|
|
||||||
bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
|
|
||||||
bool LoadGenesisBlock(const CChainParams& chainparams);
|
|
||||||
|
|
||||||
void PruneBlockIndexCandidates();
|
|
||||||
|
|
||||||
void UnloadBlockIndex();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
/** Create a new block index entry for a given block hash */
|
|
||||||
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
/**
|
|
||||||
* Make various assertions about the state of the block index.
|
|
||||||
*
|
|
||||||
* By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
|
|
||||||
*/
|
|
||||||
void CheckBlockIndex(const Consensus::Params& consensusParams);
|
|
||||||
|
|
||||||
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
//! Mark a block as not having block data
|
|
||||||
void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
} g_chainstate;
|
|
||||||
|
|
||||||
CChain& ChainActive() { return g_chainstate.m_chain; }
|
CChain& ChainActive() { return g_chainstate.m_chain; }
|
||||||
|
|
||||||
|
@ -234,7 +96,7 @@ CChain& ChainActive() { return g_chainstate.m_chain; }
|
||||||
*/
|
*/
|
||||||
RecursiveMutex cs_main;
|
RecursiveMutex cs_main;
|
||||||
|
|
||||||
BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex;
|
BlockMap& mapBlockIndex = ::ChainstateActive().mapBlockIndex;
|
||||||
CBlockIndex *pindexBestHeader = nullptr;
|
CBlockIndex *pindexBestHeader = nullptr;
|
||||||
Mutex g_best_block_mutex;
|
Mutex g_best_block_mutex;
|
||||||
std::condition_variable g_best_block_cv;
|
std::condition_variable g_best_block_cv;
|
||||||
|
@ -265,12 +127,12 @@ CScript COINBASE_FLAGS;
|
||||||
|
|
||||||
// Internal stuff
|
// Internal stuff
|
||||||
namespace {
|
namespace {
|
||||||
CBlockIndex *&pindexBestInvalid = g_chainstate.pindexBestInvalid;
|
CBlockIndex *&pindexBestInvalid = ::ChainstateActive().pindexBestInvalid;
|
||||||
|
|
||||||
/** 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 = g_chainstate.mapBlocksUnlinked;
|
std::multimap<CBlockIndex*, CBlockIndex*>& mapBlocksUnlinked = ::ChainstateActive().mapBlocksUnlinked;
|
||||||
|
|
||||||
CCriticalSection cs_LastBlockFile;
|
CCriticalSection cs_LastBlockFile;
|
||||||
std::vector<CBlockFileInfo> vinfoBlockFile;
|
std::vector<CBlockFileInfo> vinfoBlockFile;
|
||||||
|
@ -311,15 +173,7 @@ std::unique_ptr<CCoinsViewDB> pcoinsdbview;
|
||||||
std::unique_ptr<CCoinsViewCache> pcoinsTip;
|
std::unique_ptr<CCoinsViewCache> pcoinsTip;
|
||||||
std::unique_ptr<CBlockTreeDB> pblocktree;
|
std::unique_ptr<CBlockTreeDB> pblocktree;
|
||||||
|
|
||||||
enum class FlushStateMode {
|
|
||||||
NONE,
|
|
||||||
IF_NEEDED,
|
|
||||||
PERIODIC,
|
|
||||||
ALWAYS
|
|
||||||
};
|
|
||||||
|
|
||||||
// See definition for documentation
|
// See definition for documentation
|
||||||
static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
|
|
||||||
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
|
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
|
||||||
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
|
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
|
||||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
||||||
|
@ -467,7 +321,7 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
|
||||||
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
if (IsInitialBlockDownload())
|
if (::ChainstateActive().IsInitialBlockDownload())
|
||||||
return false;
|
return false;
|
||||||
if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))
|
if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE))
|
||||||
return false;
|
return false;
|
||||||
|
@ -992,7 +846,7 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
|
||||||
}
|
}
|
||||||
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
|
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
|
||||||
CValidationState stateDummy;
|
CValidationState stateDummy;
|
||||||
FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
|
::ChainstateActive().FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1168,27 +1022,30 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
|
||||||
return nSubsidy;
|
return nSubsidy;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInitialBlockDownload()
|
// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which
|
||||||
|
// is a performance-related implementation detail. This function must be marked
|
||||||
|
// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`)
|
||||||
|
// can call it.
|
||||||
|
//
|
||||||
|
bool CChainState::IsInitialBlockDownload() const
|
||||||
{
|
{
|
||||||
// Once this function has returned false, it must remain false.
|
|
||||||
static std::atomic<bool> latchToFalse{false};
|
|
||||||
// Optimization: pre-test latch before taking the lock.
|
// Optimization: pre-test latch before taking the lock.
|
||||||
if (latchToFalse.load(std::memory_order_relaxed))
|
if (m_cached_finished_ibd.load(std::memory_order_relaxed))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
if (latchToFalse.load(std::memory_order_relaxed))
|
if (m_cached_finished_ibd.load(std::memory_order_relaxed))
|
||||||
return false;
|
return false;
|
||||||
if (fImporting || fReindex)
|
if (fImporting || fReindex)
|
||||||
return true;
|
return true;
|
||||||
if (::ChainActive().Tip() == nullptr)
|
if (m_chain.Tip() == nullptr)
|
||||||
return true;
|
return true;
|
||||||
if (::ChainActive().Tip()->nChainWork < nMinimumChainWork)
|
if (m_chain.Tip()->nChainWork < nMinimumChainWork)
|
||||||
return true;
|
return true;
|
||||||
if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
|
if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
|
||||||
return true;
|
return true;
|
||||||
LogPrintf("Leaving InitialBlockDownload (latching to false)\n");
|
LogPrintf("Leaving InitialBlockDownload (latching to false)\n");
|
||||||
latchToFalse.store(true, std::memory_order_relaxed);
|
m_cached_finished_ibd.store(true, std::memory_order_relaxed);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,7 +1074,7 @@ static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
// Before we get past initial download, we cannot reliably alert about forks
|
// Before we get past initial download, we cannot reliably alert about forks
|
||||||
// (we assume we don't get stuck on a fork before finishing our initial sync)
|
// (we assume we don't get stuck on a fork before finishing our initial sync)
|
||||||
if (IsInitialBlockDownload())
|
if (::ChainstateActive().IsInitialBlockDownload())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
|
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it)
|
||||||
|
@ -2089,16 +1946,12 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool CChainState::FlushStateToDisk(
|
||||||
* Update the on-disk chain state.
|
const CChainParams& chainparams,
|
||||||
* The caches and indexes are flushed depending on the mode we're called with
|
CValidationState &state,
|
||||||
* if they're too large, if it's been a while since the last write,
|
FlushStateMode mode,
|
||||||
* or always and in all cases if we're in prune mode and are deleting files.
|
int nManualPruneHeight)
|
||||||
*
|
{
|
||||||
* If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
|
|
||||||
* besides checking if we need to prune.
|
|
||||||
*/
|
|
||||||
bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
|
|
||||||
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
|
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
static int64_t nLastWrite = 0;
|
static int64_t nLastWrite = 0;
|
||||||
|
@ -2196,7 +2049,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||||
}
|
}
|
||||||
if (full_flush_completed) {
|
if (full_flush_completed) {
|
||||||
// Update best block in wallet (so we can detect restored wallets).
|
// Update best block in wallet (so we can detect restored wallets).
|
||||||
GetMainSignals().ChainStateFlushed(::ChainActive().GetLocator());
|
GetMainSignals().ChainStateFlushed(m_chain.GetLocator());
|
||||||
}
|
}
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
return AbortNode(state, std::string("System error while flushing: ") + e.what());
|
return AbortNode(state, std::string("System error while flushing: ") + e.what());
|
||||||
|
@ -2204,19 +2057,20 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlushStateToDisk() {
|
void CChainState::ForceFlushStateToDisk() {
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
|
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
|
||||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PruneAndFlush() {
|
void CChainState::PruneAndFlush() {
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
fCheckForPruning = true;
|
fCheckForPruning = true;
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
|
|
||||||
|
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) {
|
||||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2250,7 +2104,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string warningMessages;
|
std::string warningMessages;
|
||||||
if (!IsInitialBlockDownload())
|
if (!::ChainstateActive().IsInitialBlockDownload())
|
||||||
{
|
{
|
||||||
int nUpgraded = 0;
|
int nUpgraded = 0;
|
||||||
const CBlockIndex* pindex = pindexNew;
|
const CBlockIndex* pindex = pindexNew;
|
||||||
|
@ -2641,7 +2495,7 @@ static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
|
||||||
|
|
||||||
if (pindexHeader != pindexHeaderOld) {
|
if (pindexHeader != pindexHeaderOld) {
|
||||||
fNotify = true;
|
fNotify = true;
|
||||||
fInitialBlockDownload = IsInitialBlockDownload();
|
fInitialBlockDownload = ::ChainstateActive().IsInitialBlockDownload();
|
||||||
pindexHeaderOld = pindexHeader;
|
pindexHeaderOld = pindexHeader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2767,7 +2621,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
||||||
return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
|
return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
|
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
|
||||||
|
@ -2799,7 +2653,7 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par
|
||||||
return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
|
return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
|
||||||
}
|
}
|
||||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
|
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
|
||||||
return g_chainstate.PreciousBlock(state, params, pindex);
|
return ::ChainstateActive().PreciousBlock(state, params, pindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
|
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
|
||||||
|
@ -2888,7 +2742,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
|
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
|
||||||
return g_chainstate.InvalidateBlock(state, chainparams, pindex);
|
return ::ChainstateActive().InvalidateBlock(state, chainparams, pindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
|
void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
|
||||||
|
@ -2926,7 +2780,7 @@ void CChainState::ResetBlockFailureFlags(CBlockIndex *pindex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetBlockFailureFlags(CBlockIndex *pindex) {
|
void ResetBlockFailureFlags(CBlockIndex *pindex) {
|
||||||
return g_chainstate.ResetBlockFailureFlags(pindex);
|
return ::ChainstateActive().ResetBlockFailureFlags(pindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
|
CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
|
||||||
|
@ -3464,7 +3318,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 (!g_chainstate.AcceptBlockHeader(header, state, chainparams, &pindex)) {
|
if (!::ChainstateActive().AcceptBlockHeader(header, state, chainparams, &pindex)) {
|
||||||
if (first_invalid) *first_invalid = header;
|
if (first_invalid) *first_invalid = header;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3595,7 +3449,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
||||||
bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
|
bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus());
|
||||||
if (ret) {
|
if (ret) {
|
||||||
// Store to disk
|
// Store to disk
|
||||||
ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
|
ret = ::ChainstateActive().AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock);
|
||||||
}
|
}
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
GetMainSignals().BlockChecked(*pblock, state);
|
GetMainSignals().BlockChecked(*pblock, state);
|
||||||
|
@ -3606,7 +3460,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 (!g_chainstate.ActivateBestChain(state, chainparams, pblock))
|
if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock))
|
||||||
return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
|
return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -3630,7 +3484,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 (!g_chainstate.ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
|
if (!::ChainstateActive().ConnectBlock(block, state, &indexDummy, viewNew, chainparams, true))
|
||||||
return false;
|
return false;
|
||||||
assert(state.IsValid());
|
assert(state.IsValid());
|
||||||
|
|
||||||
|
@ -3725,7 +3579,8 @@ void PruneBlockFilesManual(int nManualPruneHeight)
|
||||||
{
|
{
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
if (!FlushStateToDisk(chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
|
if (!::ChainstateActive().FlushStateToDisk(
|
||||||
|
chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
|
||||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3769,7 +3624,7 @@ static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfte
|
||||||
// To avoid excessive prune events negating the benefit of high dbcache
|
// To avoid excessive prune events negating the benefit of high dbcache
|
||||||
// values, we should not prune too rapidly.
|
// values, we should not prune too rapidly.
|
||||||
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
|
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
|
||||||
if (IsInitialBlockDownload()) {
|
if (::ChainstateActive().IsInitialBlockDownload()) {
|
||||||
// Since this is only relevant during IBD, we use a fixed 10%
|
// Since this is only relevant during IBD, we use a fixed 10%
|
||||||
nBuffer += nPruneTarget / 10;
|
nBuffer += nPruneTarget / 10;
|
||||||
}
|
}
|
||||||
|
@ -3898,7 +3753,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
|
||||||
|
|
||||||
bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
|
if (!::ChainstateActive().LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Load block file info
|
// Load block file info
|
||||||
|
@ -3963,7 +3818,7 @@ bool LoadChainTip(const CChainParams& chainparams)
|
||||||
}
|
}
|
||||||
::ChainActive().SetTip(pindex);
|
::ChainActive().SetTip(pindex);
|
||||||
|
|
||||||
g_chainstate.PruneBlockIndexCandidates();
|
::ChainstateActive().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(),
|
||||||
|
@ -4036,7 +3891,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 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
|
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
|
||||||
assert(coins.GetBestBlock() == pindex->GetBlockHash());
|
assert(coins.GetBestBlock() == pindex->GetBlockHash());
|
||||||
DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
|
DisconnectResult res = ::ChainstateActive().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());
|
||||||
}
|
}
|
||||||
|
@ -4071,7 +3926,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 (!g_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
|
if (!::ChainstateActive().ConnectBlock(block, state, pindex, coins, chainparams))
|
||||||
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
|
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4170,7 +4025,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
|
bool ReplayBlocks(const CChainParams& params, CCoinsView* view) {
|
||||||
return g_chainstate.ReplayBlocks(params, view);
|
return ::ChainstateActive().ReplayBlocks(params, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Helper for CChainState::RewindBlockIndex
|
//! Helper for CChainState::RewindBlockIndex
|
||||||
|
@ -4303,7 +4158,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RewindBlockIndex(const CChainParams& params) {
|
bool RewindBlockIndex(const CChainParams& params) {
|
||||||
if (!g_chainstate.RewindBlockIndex(params)) {
|
if (!::ChainstateActive().RewindBlockIndex(params)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4313,7 +4168,7 @@ bool RewindBlockIndex(const CChainParams& params) {
|
||||||
// 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;
|
CValidationState state;
|
||||||
if (!FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
|
if (!::ChainstateActive().FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
|
||||||
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
|
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4354,7 +4209,7 @@ void UnloadBlockIndex()
|
||||||
mapBlockIndex.clear();
|
mapBlockIndex.clear();
|
||||||
fHavePruned = false;
|
fHavePruned = false;
|
||||||
|
|
||||||
g_chainstate.UnloadBlockIndex();
|
::ChainstateActive().UnloadBlockIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadBlockIndex(const CChainParams& chainparams)
|
bool LoadBlockIndex(const CChainParams& chainparams)
|
||||||
|
@ -4406,7 +4261,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
|
||||||
|
|
||||||
bool LoadGenesisBlock(const CChainParams& chainparams)
|
bool LoadGenesisBlock(const CChainParams& chainparams)
|
||||||
{
|
{
|
||||||
return g_chainstate.LoadGenesisBlock(chainparams);
|
return ::ChainstateActive().LoadGenesisBlock(chainparams);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos *dbp)
|
bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos *dbp)
|
||||||
|
@ -4471,7 +4326,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
|
||||||
CBlockIndex* pindex = LookupBlockIndex(hash);
|
CBlockIndex* pindex = LookupBlockIndex(hash);
|
||||||
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
|
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
if (g_chainstate.AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
|
if (::ChainstateActive().AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
}
|
}
|
||||||
if (state.IsError()) {
|
if (state.IsError()) {
|
||||||
|
@ -4508,7 +4363,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
|
||||||
head.ToString());
|
head.ToString());
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState dummy;
|
CValidationState dummy;
|
||||||
if (g_chainstate.AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
|
if (::ChainstateActive().AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
|
||||||
{
|
{
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
queue.push_back(pblockrecursive->GetHash());
|
queue.push_back(pblockrecursive->GetHash());
|
||||||
|
|
191
src/validation.h
191
src/validation.h
|
@ -31,6 +31,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class CChainState;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CBlockTreeDB;
|
class CBlockTreeDB;
|
||||||
class CBlockUndo;
|
class CBlockUndo;
|
||||||
|
@ -44,6 +45,7 @@ class CTxMemPool;
|
||||||
class CValidationState;
|
class CValidationState;
|
||||||
struct ChainTxData;
|
struct ChainTxData;
|
||||||
|
|
||||||
|
struct DisconnectedBlockTransactions;
|
||||||
struct PrecomputedTransactionData;
|
struct PrecomputedTransactionData;
|
||||||
struct LockPoints;
|
struct LockPoints;
|
||||||
|
|
||||||
|
@ -247,8 +249,6 @@ bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_m
|
||||||
void UnloadBlockIndex();
|
void UnloadBlockIndex();
|
||||||
/** Run an instance of the script checking thread */
|
/** Run an instance of the script checking thread */
|
||||||
void ThreadScriptCheck(int worker_num);
|
void ThreadScriptCheck(int worker_num);
|
||||||
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
|
|
||||||
bool IsInitialBlockDownload();
|
|
||||||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||||
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
|
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
|
||||||
/**
|
/**
|
||||||
|
@ -276,10 +276,6 @@ void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
*/
|
*/
|
||||||
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
|
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
|
||||||
|
|
||||||
/** Flush all state, indexes and buffers to disk. */
|
|
||||||
void FlushStateToDisk();
|
|
||||||
/** Prune block files and flush state to disk. */
|
|
||||||
void PruneAndFlush();
|
|
||||||
/** Prune block files up to a given height */
|
/** Prune block files up to a given height */
|
||||||
void PruneBlockFilesManual(int nManualPruneHeight);
|
void PruneBlockFilesManual(int nManualPruneHeight);
|
||||||
|
|
||||||
|
@ -422,6 +418,186 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIR
|
||||||
/** Find the last common block between the parameter chain and a locator. */
|
/** Find the last common block between the parameter chain and a locator. */
|
||||||
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
enum DisconnectResult
|
||||||
|
{
|
||||||
|
DISCONNECT_OK, // All good.
|
||||||
|
DISCONNECT_UNCLEAN, // Rolled back, but UTXO set was inconsistent with block.
|
||||||
|
DISCONNECT_FAILED // Something else went wrong.
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectTrace;
|
||||||
|
|
||||||
|
/** @see CChainState::FlushStateToDisk */
|
||||||
|
enum class FlushStateMode {
|
||||||
|
NONE,
|
||||||
|
IF_NEEDED,
|
||||||
|
PERIODIC,
|
||||||
|
ALWAYS
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CBlockIndexWorkComparator
|
||||||
|
{
|
||||||
|
bool operator()(const CBlockIndex *pa, const CBlockIndex *pb) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CChainState stores and provides an API to update our local knowledge of the
|
||||||
|
* current best chain and header tree.
|
||||||
|
*
|
||||||
|
* It generally provides access to the current block tree, as well as functions
|
||||||
|
* to provide new data, which it will appropriately validate and incorporate in
|
||||||
|
* its state as necessary.
|
||||||
|
*
|
||||||
|
* Eventually, the API here is targeted at being exposed externally as a
|
||||||
|
* consumable libconsensus library, so any functions added must only call
|
||||||
|
* other class member functions, pure functions in other parts of the consensus
|
||||||
|
* library, callbacks via the validation interface, or read/write-to-disk
|
||||||
|
* functions (eventually this will also be via callbacks).
|
||||||
|
*/
|
||||||
|
class CChainState {
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and
|
||||||
|
* as good as our current tip or better. Entries may be failed, though, and pruning nodes may be
|
||||||
|
* missing the data for the block.
|
||||||
|
*/
|
||||||
|
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every received block is assigned a unique and increasing identifier, so we
|
||||||
|
* know which one to give priority in case of a fork.
|
||||||
|
*/
|
||||||
|
CCriticalSection cs_nBlockSequenceId;
|
||||||
|
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
|
||||||
|
int32_t nBlockSequenceId = 1;
|
||||||
|
/** Decreasing counter (used by subsequent preciousblock calls). */
|
||||||
|
int32_t nBlockReverseSequenceId = -1;
|
||||||
|
/** chainwork for the last block that preciousblock has been applied to. */
|
||||||
|
arith_uint256 nLastPreciousChainwork = 0;
|
||||||
|
|
||||||
|
/** In order to efficiently track invalidity of headers, we keep the set of
|
||||||
|
* blocks which we tried to connect and found to be invalid here (ie which
|
||||||
|
* were set to BLOCK_FAILED_VALID since the last restart). We can then
|
||||||
|
* walk this set and check if a new header is a descendant of something in
|
||||||
|
* this set, preventing us from having to walk mapBlockIndex when we try
|
||||||
|
* to connect a bad block and fail.
|
||||||
|
*
|
||||||
|
* While this is more complicated than marking everything which descends
|
||||||
|
* from an invalid block as invalid at the time we discover it to be
|
||||||
|
* invalid, doing so would require walking all of mapBlockIndex to find all
|
||||||
|
* descendants. Since this case should be very rare, keeping track of all
|
||||||
|
* BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
|
||||||
|
* well.
|
||||||
|
*
|
||||||
|
* Because we already walk mapBlockIndex in height-order at startup, we go
|
||||||
|
* ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
|
||||||
|
* instead of putting things in this set.
|
||||||
|
*/
|
||||||
|
std::set<CBlockIndex*> m_failed_blocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the ChainState CriticalSection
|
||||||
|
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
|
||||||
|
*/
|
||||||
|
CCriticalSection m_cs_chainstate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this chainstate is undergoing initial block download.
|
||||||
|
*
|
||||||
|
* Mutable because we need to be able to mark IsInitialBlockDownload()
|
||||||
|
* const, which latches this for caching purposes.
|
||||||
|
*/
|
||||||
|
mutable std::atomic<bool> m_cached_finished_ibd{false};
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! The current chain of blockheaders we consult and build on.
|
||||||
|
//! @see CChain, CBlockIndex.
|
||||||
|
CChain m_chain;
|
||||||
|
BlockMap mapBlockIndex GUARDED_BY(cs_main);
|
||||||
|
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
|
||||||
|
CBlockIndex *pindexBestInvalid = nullptr;
|
||||||
|
|
||||||
|
bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the on-disk chain state.
|
||||||
|
* The caches and indexes are flushed depending on the mode we're called with
|
||||||
|
* if they're too large, if it's been a while since the last write,
|
||||||
|
* or always and in all cases if we're in prune mode and are deleting files.
|
||||||
|
*
|
||||||
|
* If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
|
||||||
|
* besides checking if we need to prune.
|
||||||
|
*/
|
||||||
|
bool FlushStateToDisk(
|
||||||
|
const CChainParams& chainparams,
|
||||||
|
CValidationState &state,
|
||||||
|
FlushStateMode mode,
|
||||||
|
int nManualPruneHeight = 0);
|
||||||
|
|
||||||
|
//! Unconditionally flush all changes to disk.
|
||||||
|
void ForceFlushStateToDisk();
|
||||||
|
|
||||||
|
//! Prune blockfiles from the disk if necessary and then flush chainstate changes
|
||||||
|
//! if we pruned.
|
||||||
|
void PruneAndFlush();
|
||||||
|
|
||||||
|
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
|
||||||
|
* that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
|
||||||
|
*/
|
||||||
|
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
// Block (dis)connection on a given view:
|
||||||
|
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
|
||||||
|
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
|
||||||
|
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
// Block disconnection on our pcoinsTip:
|
||||||
|
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
// Manual block validity manipulation:
|
||||||
|
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
|
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
|
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
|
||||||
|
bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
|
||||||
|
bool LoadGenesisBlock(const CChainParams& chainparams);
|
||||||
|
|
||||||
|
void PruneBlockIndexCandidates();
|
||||||
|
|
||||||
|
void UnloadBlockIndex();
|
||||||
|
|
||||||
|
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
|
||||||
|
bool IsInitialBlockDownload() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
/** Create a new block index entry for a given block hash */
|
||||||
|
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
/**
|
||||||
|
* Make various assertions about the state of the block index.
|
||||||
|
*
|
||||||
|
* By default this only executes fully when using the Regtest chain; see: fCheckBlockIndex.
|
||||||
|
*/
|
||||||
|
void CheckBlockIndex(const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
|
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
//! Mark a block as not having block data
|
||||||
|
void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
};
|
||||||
|
|
||||||
/** Mark a block as precious and reorganize.
|
/** Mark a block as precious and reorganize.
|
||||||
*
|
*
|
||||||
* May not be called in a
|
* May not be called in a
|
||||||
|
@ -435,6 +611,9 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
|
||||||
/** Remove invalidity status from a block and its descendants. */
|
/** Remove invalidity status from a block and its descendants. */
|
||||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
|
/** @returns the most-work valid chainstate. */
|
||||||
|
CChainState& ChainstateActive();
|
||||||
|
|
||||||
/** @returns the most-work chain. */
|
/** @returns the most-work chain. */
|
||||||
CChain& ChainActive();
|
CChain& ChainActive();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue