Merge #21270: [Bundle 4/n] Prune g_chainman usage in validation-adjacent modules

a67983cd6d net_processing: Add review-only assertion to PeerManager (Carl Dong)
272d993e75 scripted-diff: net_processing: Use existing chainman (Carl Dong)
021a04a469 net_processing: Move some static functions to PeerManager (Carl Dong)
91c5b68acd node/ifaces: ChainImpl: Use existing NodeContext member (Carl Dong)
8a1d580b21 node/ifaces: NodeImpl: Use existing NodeContext member (Carl Dong)
4cde4a701b node: Use existing NodeContext (Carl Dong)
106bcd4f39 node/coinstats: Pass in BlockManager to GetUTXOStats (Carl Dong)
2c3ba00693 miner: Pass in blockman to ::RegenerateCommitments (Carl Dong)
2afcf24408 miner: Remove old CreateNewBlock w/o chainstate param (Carl Dong)
46b7f29340 scripted-diff: Invoke CreateNewBlock with chainstate (Carl Dong)
d0de61b764 miner: Pass in chainstate to BlockAssembler::CreateNewBlock (Carl Dong)
a04aac493f validation: Remove extraneous LoadGenesisBlock function prototype (Carl Dong)

Pull request description:

  Overall PR: #20158 (tree-wide: De-globalize ChainstateManager)

  Based on:
  - [x] #21055 | [Bundle 3/n] Prune g_chainman usage in mempool-related validation functions

  Note to reviewers:
  1. This bundle may _apparently_ introduce usage of `g_chainman` or `::Chain(state|)Active()` globals, but these are resolved later on in the overall PR. [Commits of overall PR](https://github.com/bitcoin/bitcoin/pull/20158/commits)
  2. There may be seemingly obvious local references to `ChainstateManager` or other validation objects which are not being used in callers of the current function in question, this is done intentionally to **_keep each commit centered around one function/method_** to ease review and to make the overall change systematic. We don't assume anything about our callers. Rest assured that once we are considering that particular caller in later commits, we will use the obvious local references. [Commits of overall PR](https://github.com/bitcoin/bitcoin/pull/20158/commits)
  3. When changing a function/method that has many callers (e.g. `LookupBlockIndex` with 55 callers), it is sometimes easier (and less error-prone) to use a scripted-diff. When doing so, there will be 3 commits in sequence so that every commit compiles like so:
  1. Add `new_function`, make `old_function` a wrapper of `new_function`, divert all calls to `old_function` to `new_function` **in the local module only**
  2. Scripted-diff to divert all calls to `old_function` to `new_function` **in the rest of the codebase**
  3. Remove `old_function`

ACKs for top commit:
  laanwj:
    Code review ACK a67983cd6d
  ryanofsky:
    Code review ACK a67983cd6d. Only change since last review new first commit fixing header declaration, and rebase
  glozow:
    code review ACK a67983cd6d

Tree-SHA512: dce182a18b88be80cbf50978d4ba8fa6ab0f01e861d09bae0ae9364051bb78f9334859d164b185b07f1d70a583e739557fab6d820cac8c37b3855b85c2a6771b
This commit is contained in:
Wladimir J. van der Laan 2021-03-11 11:46:28 +01:00
commit 767bb7d5c5
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
18 changed files with 228 additions and 184 deletions

View File

@ -39,13 +39,13 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
return nNewTime - nOldTime; return nNewTime - nOldTime;
} }
void RegenerateCommitments(CBlock& block) void RegenerateCommitments(CBlock& block, BlockManager& blockman)
{ {
CMutableTransaction tx{*block.vtx.at(0)}; CMutableTransaction tx{*block.vtx.at(0)};
tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block)); tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block));
block.vtx.at(0) = MakeTransactionRef(tx); block.vtx.at(0) = MakeTransactionRef(tx);
GenerateCoinbaseCommitment(block, WITH_LOCK(cs_main, return g_chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock)), Params().GetConsensus()); GenerateCoinbaseCommitment(block, WITH_LOCK(::cs_main, assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman)); return blockman.LookupBlockIndex(block.hashPrevBlock)), Params().GetConsensus());
block.hashMerkleRoot = BlockMerkleRoot(block); block.hashMerkleRoot = BlockMerkleRoot(block);
} }
@ -99,7 +99,7 @@ void BlockAssembler::resetBlock()
Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt}; Optional<int64_t> BlockAssembler::m_last_block_num_txs{nullopt};
Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt}; Optional<int64_t> BlockAssembler::m_last_block_weight{nullopt};
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn)
{ {
int64_t nTimeStart = GetTimeMicros(); int64_t nTimeStart = GetTimeMicros();
@ -117,7 +117,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
LOCK2(cs_main, m_mempool.cs); LOCK2(cs_main, m_mempool.cs);
CBlockIndex* pindexPrev = ::ChainActive().Tip(); assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*chainstate.m_chain.Tip()));
CBlockIndex* pindexPrev = chainstate.m_chain.Tip();
assert(pindexPrev != nullptr); assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1; nHeight = pindexPrev->nHeight + 1;
@ -176,7 +177,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
BlockValidationState state; BlockValidationState state;
if (!TestBlockValidity(state, chainparams, ::ChainstateActive(), *pblock, pindexPrev, false, false)) { assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
if (!TestBlockValidity(state, chainparams, chainstate, *pblock, pindexPrev, false, false)) {
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString())); throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
} }
int64_t nTime2 = GetTimeMicros(); int64_t nTime2 = GetTimeMicros();

View File

@ -158,7 +158,7 @@ public:
explicit BlockAssembler(const CTxMemPool& mempool, const CChainParams& params, const Options& options); explicit BlockAssembler(const CTxMemPool& mempool, const CChainParams& params, const Options& options);
/** Construct a new block template with coinbase to scriptPubKeyIn */ /** Construct a new block template with coinbase to scriptPubKeyIn */
std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn); std::unique_ptr<CBlockTemplate> CreateNewBlock(CChainState& chainstate, const CScript& scriptPubKeyIn);
static Optional<int64_t> m_last_block_num_txs; static Optional<int64_t> m_last_block_num_txs;
static Optional<int64_t> m_last_block_weight; static Optional<int64_t> m_last_block_weight;
@ -202,6 +202,6 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev); int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
/** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */ /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
void RegenerateCommitments(CBlock& block); void RegenerateCommitments(CBlock& block, BlockManager& blockman);
#endif // BITCOIN_MINER_H #endif // BITCOIN_MINER_H

View File

@ -472,6 +472,24 @@ private:
std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans); std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans);
/** Offset into vExtraTxnForCompact to insert the next tx */ /** Offset into vExtraTxnForCompact to insert the next tx */
size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0;
void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman);
bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index,
BlockFilterIndex*& filter_index);
void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman);
void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman);
void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman);
}; };
} // namespace } // namespace
@ -665,41 +683,6 @@ bool PeerManagerImpl::MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, co
return true; return true;
} }
/** Check whether the last unknown block a peer advertised is not yet known. */
static void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
CNodeState *state = State(nodeid);
assert(state != nullptr);
if (!state->hashLastUnknownBlock.IsNull()) {
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);
if (pindex && pindex->nChainWork > 0) {
if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
state->pindexBestKnownBlock = pindex;
}
state->hashLastUnknownBlock.SetNull();
}
}
}
/** Update tracking information about which blocks a peer is assumed to have. */
static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
CNodeState *state = State(nodeid);
assert(state != nullptr);
ProcessBlockAvailability(nodeid);
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash);
if (pindex && pindex->nChainWork > 0) {
// An actually better block was announced.
if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
state->pindexBestKnownBlock = pindex;
}
} else {
// An unknown block was announced; just assume that the latest one is the best one.
state->hashLastUnknownBlock = hash;
}
}
void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid) void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
@ -749,9 +732,9 @@ bool PeerManagerImpl::TipMayBeStale()
return m_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty(); return m_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty();
} }
static bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) bool PeerManagerImpl::CanDirectFetch(const Consensus::Params &consensusParams)
{ {
return ::ChainActive().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; return m_chainman.ActiveChain().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20;
} }
static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main) static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@ -763,6 +746,41 @@ static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIV
return false; return false;
} }
/** Check whether the last unknown block a peer advertised is not yet known. */
void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) {
CNodeState *state = State(nodeid);
assert(state != nullptr);
if (!state->hashLastUnknownBlock.IsNull()) {
const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);
if (pindex && pindex->nChainWork > 0) {
if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
state->pindexBestKnownBlock = pindex;
}
state->hashLastUnknownBlock.SetNull();
}
}
}
/** Update tracking information about which blocks a peer is assumed to have. */
void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
CNodeState *state = State(nodeid);
assert(state != nullptr);
ProcessBlockAvailability(nodeid);
const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);
if (pindex && pindex->nChainWork > 0) {
// An actually better block was announced.
if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
state->pindexBestKnownBlock = pindex;
}
} else {
// An unknown block was announced; just assume that the latest one is the best one.
state->hashLastUnknownBlock = hash;
}
}
void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)
{ {
if (count == 0) if (count == 0)
@ -775,7 +793,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
// Make sure pindexBestKnownBlock is up to date, we'll need it. // Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid); ProcessBlockAvailability(nodeid);
if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < ::ChainActive().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
// This peer has nothing interesting. // This peer has nothing interesting.
return; return;
} }
@ -783,7 +801,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
if (state->pindexLastCommonBlock == nullptr) { if (state->pindexLastCommonBlock == nullptr) {
// Bootstrap quickly by guessing a parent of our best tip is the forking point. // Bootstrap quickly by guessing a parent of our best tip is the forking point.
// Guessing wrong in either direction is not a problem. // Guessing wrong in either direction is not a problem.
state->pindexLastCommonBlock = ::ChainActive()[std::min(state->pindexBestKnownBlock->nHeight, ::ChainActive().Height())]; state->pindexLastCommonBlock = m_chainman.ActiveChain()[std::min(state->pindexBestKnownBlock->nHeight, m_chainman.ActiveChain().Height())];
} }
// If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor
@ -826,7 +844,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
// We wouldn't download this block or its descendants from this peer. // We wouldn't download this block or its descendants from this peer.
return; return;
} }
if (pindex->nStatus & BLOCK_HAVE_DATA || ::ChainActive().Contains(pindex)) { if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain().Contains(pindex)) {
if (pindex->HaveTxsDownloaded()) if (pindex->HaveTxsDownloaded())
state->pindexLastCommonBlock = pindex; state->pindexLastCommonBlock = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
@ -1179,10 +1197,10 @@ bool PeerManagerImpl::MaybePunishNodeForTx(NodeId nodeid, const TxValidationStat
// active chain if they are no more than a month older (both in time, and in // active chain if they are no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about and // best equivalent proof of work) than the best header chain we know about and
// we fully-validated them at some point. // we fully-validated them at some point.
static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams)
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
if (::ChainActive().Contains(pindex)) return true; if (m_chainman.ActiveChain().Contains(pindex)) return true;
return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) && return pindex->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != nullptr) &&
(pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) && (pindexBestHeader->GetBlockTime() - pindex->GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT); (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
@ -1206,6 +1224,7 @@ PeerManagerImpl::PeerManagerImpl(const CChainParams& chainparams, CConnman& conn
m_stale_tip_check_time(0), m_stale_tip_check_time(0),
m_ignore_incoming_txs(ignore_incoming_txs) m_ignore_incoming_txs(ignore_incoming_txs)
{ {
assert(std::addressof(g_chainman) == std::addressof(m_chainman));
// Initialize global variables that cannot be constructed at startup. // Initialize global variables that cannot be constructed at startup.
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
@ -1331,7 +1350,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
/** /**
* Update our best height and announce any block hashes which weren't previously * Update our best height and announce any block hashes which weren't previously
* in ::ChainActive() to our peers. * in m_chainman.ActiveChain() to our peers.
*/ */
void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
{ {
@ -1393,7 +1412,7 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
// 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() &&
!::ChainstateActive().IsInitialBlockDownload() && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) { mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
if (it != mapBlockSource.end()) { if (it != mapBlockSource.end()) {
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first); MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
@ -1412,12 +1431,12 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid) bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
{ {
assert(recentRejects); assert(recentRejects);
if (::ChainActive().Tip()->GetBlockHash() != hashRecentRejectsChainTip) { if (m_chainman.ActiveChain().Tip()->GetBlockHash() != hashRecentRejectsChainTip) {
// If the chain tip has changed previously rejected transactions // If the chain tip has changed previously rejected transactions
// might be now valid, e.g. due to a nLockTime'd tx becoming valid, // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
// or a double-spend. Reset the rejects filter and give those // or a double-spend. Reset the rejects filter and give those
// txs a second chance. // txs a second chance.
hashRecentRejectsChainTip = ::ChainActive().Tip()->GetBlockHash(); hashRecentRejectsChainTip = m_chainman.ActiveChain().Tip()->GetBlockHash();
recentRejects->reset(); recentRejects->reset();
} }
@ -1433,9 +1452,9 @@ bool PeerManagerImpl::AlreadyHaveTx(const GenTxid& gtxid)
return recentRejects->contains(hash) || m_mempool.exists(gtxid); return recentRejects->contains(hash) || m_mempool.exists(gtxid);
} }
bool static AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) bool PeerManagerImpl::AlreadyHaveBlock(const uint256& block_hash)
{ {
return g_chainman.m_blockman.LookupBlockIndex(block_hash) != nullptr; return m_chainman.m_blockman.LookupBlockIndex(block_hash) != nullptr;
} }
void PeerManagerImpl::SendPings() void PeerManagerImpl::SendPings()
@ -1514,7 +1533,7 @@ static void RelayAddress(const CNode& originator,
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
} }
void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman) void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& chainparams, const CInv& inv, CConnman& connman)
{ {
bool send = false; bool send = false;
std::shared_ptr<const CBlock> a_recent_block; std::shared_ptr<const CBlock> a_recent_block;
@ -1531,7 +1550,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
bool need_activate_chain = false; bool need_activate_chain = false;
{ {
LOCK(cs_main); LOCK(cs_main);
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(inv.hash); const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(inv.hash);
if (pindex) { if (pindex) {
if (pindex->HaveTxsDownloaded() && !pindex->IsValid(BLOCK_VALID_SCRIPTS) && if (pindex->HaveTxsDownloaded() && !pindex->IsValid(BLOCK_VALID_SCRIPTS) &&
pindex->IsValid(BLOCK_VALID_TREE)) { pindex->IsValid(BLOCK_VALID_TREE)) {
@ -1546,13 +1565,13 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
} // release cs_main before calling ActivateBestChain } // release cs_main before calling ActivateBestChain
if (need_activate_chain) { if (need_activate_chain) {
BlockValidationState state; BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, chainparams, a_recent_block)) { if (!m_chainman.ActiveChainstate().ActivateBestChain(state, chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString()); LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
} }
} }
LOCK(cs_main); LOCK(cs_main);
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(inv.hash); const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(inv.hash);
if (pindex) { if (pindex) {
send = BlockRequestAllowed(pindex, consensusParams); send = BlockRequestAllowed(pindex, consensusParams);
if (!send) { if (!send) {
@ -1574,7 +1593,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
} }
// Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold // Avoid leaking prune-height by never sending blocks below the NODE_NETWORK_LIMITED threshold
if (send && !pfrom.HasPermission(PF_NOBAN) && ( if (send && !pfrom.HasPermission(PF_NOBAN) && (
(((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (::ChainActive().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) ) (((pfrom.GetLocalServices() & NODE_NETWORK_LIMITED) == NODE_NETWORK_LIMITED) && ((pfrom.GetLocalServices() & NODE_NETWORK) != NODE_NETWORK) && (m_chainman.ActiveChain().Tip()->nHeight - pindex->nHeight > (int)NODE_NETWORK_LIMITED_MIN_BLOCKS + 2 /* add two blocks buffer extension for possible races */) )
)) { )) {
LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom.GetId()); LogPrint(BCLog::NET, "Ignore block request below NODE_NETWORK_LIMITED threshold from peer=%d\n", pfrom.GetId());
@ -1641,7 +1660,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
// instead we respond with the full, non-compact block. // instead we respond with the full, non-compact block.
bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness; bool fPeerWantsWitness = State(pfrom.GetId())->fWantsCmpctWitness;
int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS; int nSendFlags = fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS;
if (CanDirectFetch(consensusParams) && pindex->nHeight >= ::ChainActive().Height() - MAX_CMPCTBLOCK_DEPTH) { if (CanDirectFetch(consensusParams) && pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_CMPCTBLOCK_DEPTH) {
if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) { if ((fPeerWantsWitness || !fWitnessesPresentInARecentCompactBlock) && a_recent_compact_block && a_recent_compact_block->header.GetHash() == pindex->GetBlockHash()) {
connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block)); connman.PushMessage(&pfrom, msgMaker.Make(nSendFlags, NetMsgType::CMPCTBLOCK, *a_recent_compact_block));
} else { } else {
@ -1662,7 +1681,7 @@ void static ProcessGetBlockData(CNode& pfrom, Peer& peer, const CChainParams& ch
// and we want it right after the last block so they don't // and we want it right after the last block so they don't
// wait for other stuff first. // wait for other stuff first.
std::vector<CInv> vInv; std::vector<CInv> vInv;
vInv.push_back(CInv(MSG_BLOCK, ::ChainActive().Tip()->GetBlockHash())); vInv.push_back(CInv(MSG_BLOCK, m_chainman.ActiveChain().Tip()->GetBlockHash()));
connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv)); connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
peer.m_continuation_block.SetNull(); peer.m_continuation_block.SetNull();
} }
@ -1841,9 +1860,9 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// don't connect before giving DoS points // don't connect before giving DoS points
// - Once a headers message is received that is valid and does connect, // - Once a headers message is received that is valid and does connect,
// nUnconnectingHeaders gets reset back to 0. // nUnconnectingHeaders gets reset back to 0.
if (!g_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) { if (!m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock) && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
nodestate->nUnconnectingHeaders++; nodestate->nUnconnectingHeaders++;
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256()));
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n", LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
headers[0].GetHash().ToString(), headers[0].GetHash().ToString(),
headers[0].hashPrevBlock.ToString(), headers[0].hashPrevBlock.ToString(),
@ -1871,7 +1890,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// If we don't have the last header, then they'll have given us // If we don't have the last header, then they'll have given us
// something new (if these headers are valid). // something new (if these headers are valid).
if (!g_chainman.m_blockman.LookupBlockIndex(hashLastBlock)) { if (!m_chainman.m_blockman.LookupBlockIndex(hashLastBlock)) {
received_new_header = true; received_new_header = true;
} }
} }
@ -1899,27 +1918,27 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// because it is set in UpdateBlockAvailability. Some nullptr checks // because it is set in UpdateBlockAvailability. Some nullptr checks
// are still present, however, as belt-and-suspenders. // are still present, however, as belt-and-suspenders.
if (received_new_header && pindexLast->nChainWork > ::ChainActive().Tip()->nChainWork) { if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime(); nodestate->m_last_block_announcement = GetTime();
} }
if (nCount == MAX_HEADERS_RESULTS) { if (nCount == MAX_HEADERS_RESULTS) {
// Headers message had its maximum size; the peer may have more headers. // Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue // TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue
// from there instead. // from there instead.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height); pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexLast), uint256()));
} }
bool fCanDirectFetch = CanDirectFetch(m_chainparams.GetConsensus()); bool fCanDirectFetch = CanDirectFetch(m_chainparams.GetConsensus());
// If this set of headers is valid and ends in a block with at least as // If this set of headers is valid and ends in a block with at least as
// much work as our tip, download as much as possible. // much work as our tip, download as much as possible.
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && ::ChainActive().Tip()->nChainWork <= pindexLast->nChainWork) { if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
std::vector<const CBlockIndex*> vToFetch; std::vector<const CBlockIndex*> vToFetch;
const CBlockIndex *pindexWalk = pindexLast; const CBlockIndex *pindexWalk = pindexLast;
// Calculate all the blocks we'd need to switch to pindexLast, up to a limit. // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
while (pindexWalk && !::ChainActive().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
!mapBlocksInFlight.count(pindexWalk->GetBlockHash()) && !mapBlocksInFlight.count(pindexWalk->GetBlockHash()) &&
(!IsWitnessEnabled(pindexWalk->pprev, m_chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) { (!IsWitnessEnabled(pindexWalk->pprev, m_chainparams.GetConsensus()) || State(pfrom.GetId())->fHaveWitness)) {
@ -1932,7 +1951,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// very large reorg at a time we think we're close to caught up to // very large reorg at a time we think we're close to caught up to
// the main chain -- this shouldn't really happen. Bail out on the // the main chain -- this shouldn't really happen. Bail out on the
// direct fetch and rely on parallel download instead. // direct fetch and rely on parallel download instead.
if (!::ChainActive().Contains(pindexWalk)) { if (!m_chainman.ActiveChain().Contains(pindexWalk)) {
LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n", LogPrint(BCLog::NET, "Large reorg, won't direct fetch to %s (%d)\n",
pindexLast->GetBlockHash().ToString(), pindexLast->GetBlockHash().ToString(),
pindexLast->nHeight); pindexLast->nHeight);
@ -1965,7 +1984,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
} }
// 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 (::ChainstateActive().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) { if (m_chainman.ActiveChainstate().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) {
@ -1973,7 +1992,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// us sync -- disconnect if it is an outbound disconnection // us sync -- disconnect if it is an outbound disconnection
// candidate. // candidate.
// Note: We compare their tip to nMinimumChainWork (rather than // Note: We compare their tip to nMinimumChainWork (rather than
// ::ChainActive().Tip()) because we won't start block download // m_chainman.ActiveChain().Tip()) because we won't start block download
// until we have a headers chain that has at least // until we have a headers chain that has at least
// nMinimumChainWork, even if a peer has a chain past our tip, // nMinimumChainWork, even if a peer has a chain past our tip,
// as an anti-DoS measure. // as an anti-DoS measure.
@ -1990,7 +2009,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
// thus always subject to eviction under the bad/lagging chain logic. // thus always subject to eviction under the bad/lagging chain logic.
// See ChainSyncTimeoutState. // See ChainSyncTimeoutState.
if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) { if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) {
if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) { if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId()); LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId());
nodestate->m_chain_sync.m_protect = true; nodestate->m_chain_sync.m_protect = true;
++m_outbound_peers_with_protect_from_disconnect; ++m_outbound_peers_with_protect_from_disconnect;
@ -2021,7 +2040,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash); const auto [porphanTx, from_peer] = m_orphanage.GetTx(orphanHash);
if (porphanTx == nullptr) continue; if (porphanTx == nullptr) continue;
const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), m_mempool, porphanTx, false /* bypass_limits */); const MempoolAcceptResult result = AcceptToMemoryPool(m_chainman.ActiveChainstate(), m_mempool, porphanTx, false /* bypass_limits */);
const TxValidationState& state = result.m_state; const TxValidationState& state = result.m_state;
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
@ -2097,7 +2116,7 @@ void PeerManagerImpl::ProcessOrphanTx(std::set<uint256>& orphan_work_set)
* @param[out] filter_index The filter index, if the request can be serviced. * @param[out] filter_index The filter index, if the request can be serviced.
* @return True if the request can be serviced. * @return True if the request can be serviced.
*/ */
static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params, bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_params,
BlockFilterType filter_type, uint32_t start_height, BlockFilterType filter_type, uint32_t start_height,
const uint256& stop_hash, uint32_t max_height_diff, const uint256& stop_hash, uint32_t max_height_diff,
const CBlockIndex*& stop_index, const CBlockIndex*& stop_index,
@ -2115,7 +2134,7 @@ static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_par
{ {
LOCK(cs_main); LOCK(cs_main);
stop_index = g_chainman.m_blockman.LookupBlockIndex(stop_hash); stop_index = m_chainman.m_blockman.LookupBlockIndex(stop_hash);
// Check that the stop block exists and the peer would be allowed to fetch it. // Check that the stop block exists and the peer would be allowed to fetch it.
if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) { if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) {
@ -2160,7 +2179,7 @@ static bool PrepareBlockFilterRequest(CNode& peer, const CChainParams& chain_par
* @param[in] chain_params Chain parameters * @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager * @param[in] connman Pointer to the connection manager
*/ */
static void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params, void PeerManagerImpl::ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman) CConnman& connman)
{ {
uint8_t filter_type_ser; uint8_t filter_type_ser;
@ -2202,7 +2221,7 @@ static void ProcessGetCFilters(CNode& peer, CDataStream& vRecv, const CChainPara
* @param[in] chain_params Chain parameters * @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager * @param[in] connman Pointer to the connection manager
*/ */
static void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params, void PeerManagerImpl::ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman) CConnman& connman)
{ {
uint8_t filter_type_ser; uint8_t filter_type_ser;
@ -2257,7 +2276,7 @@ static void ProcessGetCFHeaders(CNode& peer, CDataStream& vRecv, const CChainPar
* @param[in] chain_params Chain parameters * @param[in] chain_params Chain parameters
* @param[in] connman Pointer to the connection manager * @param[in] connman Pointer to the connection manager
*/ */
static void ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params, void PeerManagerImpl::ProcessGetCFCheckPt(CNode& peer, CDataStream& vRecv, const CChainParams& chain_params,
CConnman& connman) CConnman& connman)
{ {
uint8_t filter_type_ser; uint8_t filter_type_ser;
@ -2440,7 +2459,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// //
// We skip this for block-relay-only peers to avoid potentially leaking // We skip this for block-relay-only peers to avoid potentially leaking
// information about our block-relay-only connections via address relay. // information about our block-relay-only connections via address relay.
if (fListen && !::ChainstateActive().IsInitialBlockDownload()) if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
{ {
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices()); CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices());
FastRandomContext insecure_rand; FastRandomContext insecure_rand;
@ -2757,7 +2776,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} }
if (best_block != nullptr) { if (best_block != nullptr) {
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block)); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), *best_block));
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId()); LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom.GetId());
} }
@ -2813,7 +2832,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
a_recent_block = most_recent_block; a_recent_block = most_recent_block;
} }
BlockValidationState state; BlockValidationState state;
if (!::ChainstateActive().ActivateBestChain(state, m_chainparams, a_recent_block)) { if (!m_chainman.ActiveChainstate().ActivateBestChain(state, m_chainparams, a_recent_block)) {
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString()); LogPrint(BCLog::NET, "failed to activate chain (%s)\n", state.ToString());
} }
} }
@ -2821,14 +2840,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
LOCK(cs_main); LOCK(cs_main);
// Find the last block the caller has in the main chain // Find the last block the caller has in the main chain
const CBlockIndex* pindex = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); const CBlockIndex* pindex = m_chainman.m_blockman.FindForkInGlobalIndex(m_chainman.ActiveChain(), locator);
// Send the rest of the chain // Send the rest of the chain
if (pindex) if (pindex)
pindex = ::ChainActive().Next(pindex); pindex = m_chainman.ActiveChain().Next(pindex);
int nLimit = 500; int nLimit = 500;
LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom.GetId()); LogPrint(BCLog::NET, "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom.GetId());
for (; pindex; pindex = ::ChainActive().Next(pindex)) for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex))
{ {
if (pindex->GetBlockHash() == hashStop) if (pindex->GetBlockHash() == hashStop)
{ {
@ -2838,7 +2857,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If pruning, don't inv blocks unless we have on disk and are likely to still have // If pruning, don't inv blocks unless we have on disk and are likely to still have
// for some reasonable time window (1 hour) that block relay might require. // for some reasonable time window (1 hour) that block relay might require.
const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing; const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing;
if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= ::ChainActive().Tip()->nHeight - nPrunedBlocksLikelyToHave)) if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave))
{ {
LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
break; break;
@ -2874,13 +2893,13 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{ {
LOCK(cs_main); LOCK(cs_main);
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(req.blockhash); const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(req.blockhash);
if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) { if (!pindex || !(pindex->nStatus & BLOCK_HAVE_DATA)) {
LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId()); LogPrint(BCLog::NET, "Peer %d sent us a getblocktxn for a block we don't have\n", pfrom.GetId());
return; return;
} }
if (pindex->nHeight >= ::ChainActive().Height() - MAX_BLOCKTXN_DEPTH) { if (pindex->nHeight >= m_chainman.ActiveChain().Height() - MAX_BLOCKTXN_DEPTH) {
CBlock block; CBlock block;
bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus()); bool ret = ReadBlockFromDisk(block, pindex, m_chainparams.GetConsensus());
assert(ret); assert(ret);
@ -2918,7 +2937,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
} }
LOCK(cs_main); LOCK(cs_main);
if (::ChainstateActive().IsInitialBlockDownload() && !pfrom.HasPermission(PF_DOWNLOAD)) { if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !pfrom.HasPermission(PF_DOWNLOAD)) {
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; return;
} }
@ -2928,7 +2947,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (locator.IsNull()) if (locator.IsNull())
{ {
// If locator is null, return the hashStop block // If locator is null, return the hashStop block
pindex = g_chainman.m_blockman.LookupBlockIndex(hashStop); pindex = m_chainman.m_blockman.LookupBlockIndex(hashStop);
if (!pindex) { if (!pindex) {
return; return;
} }
@ -2941,23 +2960,23 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
else else
{ {
// Find the last block the caller has in the main chain // Find the last block the caller has in the main chain
pindex = g_chainman.m_blockman.FindForkInGlobalIndex(::ChainActive(), locator); pindex = m_chainman.m_blockman.FindForkInGlobalIndex(m_chainman.ActiveChain(), locator);
if (pindex) if (pindex)
pindex = ::ChainActive().Next(pindex); pindex = m_chainman.ActiveChain().Next(pindex);
} }
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
std::vector<CBlock> vHeaders; std::vector<CBlock> vHeaders;
int nLimit = MAX_HEADERS_RESULTS; int nLimit = MAX_HEADERS_RESULTS;
LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom.GetId()); LogPrint(BCLog::NET, "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), pfrom.GetId());
for (; pindex; pindex = ::ChainActive().Next(pindex)) for (; pindex; pindex = m_chainman.ActiveChain().Next(pindex))
{ {
vHeaders.push_back(pindex->GetBlockHeader()); vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
break; break;
} }
// pindex can be nullptr either if we sent ::ChainActive().Tip() OR // pindex can be nullptr either if we sent m_chainman.ActiveChain().Tip() OR
// if our peer has ::ChainActive().Tip() (and thus we are sending an empty // if our peer has m_chainman.ActiveChain().Tip() (and thus we are sending an empty
// headers message). In both cases it's safe to update // headers message). In both cases it's safe to update
// pindexBestHeaderSent to be our tip. // pindexBestHeaderSent to be our tip.
// //
@ -2968,7 +2987,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// without the new block. By resetting the BestHeaderSent, we ensure we // without the new block. By resetting the BestHeaderSent, we ensure we
// will re-announce the new block via headers (or compact blocks again) // will re-announce the new block via headers (or compact blocks again)
// in the SendMessages logic. // in the SendMessages logic.
nodestate->pindexBestHeaderSent = pindex ? pindex : ::ChainActive().Tip(); nodestate->pindexBestHeaderSent = pindex ? pindex : m_chainman.ActiveChain().Tip();
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders));
return; return;
} }
@ -3036,7 +3055,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
return; return;
} }
const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), m_mempool, ptx, false /* bypass_limits */); const MempoolAcceptResult result = AcceptToMemoryPool(m_chainman.ActiveChainstate(), m_mempool, ptx, false /* bypass_limits */);
const TxValidationState& state = result.m_state; const TxValidationState& state = result.m_state;
if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) { if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
@ -3201,14 +3220,14 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
{ {
LOCK(cs_main); LOCK(cs_main);
if (!g_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) { if (!m_chainman.m_blockman.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 (!::ChainstateActive().IsInitialBlockDownload()) if (!m_chainman.ActiveChainstate().IsInitialBlockDownload())
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), uint256())); m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexBestHeader), uint256()));
return; return;
} }
if (!g_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) { if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.GetHash())) {
received_new_header = true; received_new_header = true;
} }
} }
@ -3248,7 +3267,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// If this was a new header with more work than our tip, update the // If this was a new header with more work than our tip, update the
// peer's last block announcement time // peer's last block announcement time
if (received_new_header && pindex->nChainWork > ::ChainActive().Tip()->nChainWork) { if (received_new_header && pindex->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
nodestate->m_last_block_announcement = GetTime(); nodestate->m_last_block_announcement = GetTime();
} }
@ -3258,7 +3277,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
return; return;
if (pindex->nChainWork <= ::ChainActive().Tip()->nChainWork || // We know something better if (pindex->nChainWork <= m_chainman.ActiveChain().Tip()->nChainWork || // We know something better
pindex->nTx != 0) { // We had this block at some point, but pruned it pindex->nTx != 0) { // We had this block at some point, but pruned it
if (fAlreadyInFlight) { if (fAlreadyInFlight) {
// We requested this block for some reason, but our mempool will probably be useless // We requested this block for some reason, but our mempool will probably be useless
@ -3282,7 +3301,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
// We want to be a bit conservative just to be extra careful about DoS // We want to be a bit conservative just to be extra careful about DoS
// possibilities in compact block processing... // possibilities in compact block processing...
if (pindex->nHeight <= ::ChainActive().Height() + 2) { if (pindex->nHeight <= m_chainman.ActiveChain().Height() + 2) {
if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) || if ((!fAlreadyInFlight && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||
(fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) { (fAlreadyInFlight && blockInFlightIt->second.first == pfrom.GetId())) {
std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr; std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;
@ -3930,7 +3949,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
// their chain has more work than ours, we should sync to it, // their chain has more work than ours, we should sync to it,
// unless it's invalid, in which case we should find that out and // unless it's invalid, in which case we should find that out and
// disconnect from them elsewhere). // disconnect from them elsewhere).
if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= ::ChainActive().Tip()->nChainWork) { if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork) {
if (state.m_chain_sync.m_timeout != 0) { if (state.m_chain_sync.m_timeout != 0) {
state.m_chain_sync.m_timeout = 0; state.m_chain_sync.m_timeout = 0;
state.m_chain_sync.m_work_header = nullptr; state.m_chain_sync.m_work_header = nullptr;
@ -3942,7 +3961,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
// where we checked against our tip. // where we checked against our tip.
// Either way, set a new timeout based on current tip. // Either way, set a new timeout based on current tip.
state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT; state.m_chain_sync.m_timeout = time_in_seconds + CHAIN_SYNC_TIMEOUT;
state.m_chain_sync.m_work_header = ::ChainActive().Tip(); state.m_chain_sync.m_work_header = m_chainman.ActiveChain().Tip();
state.m_chain_sync.m_sent_getheaders = false; state.m_chain_sync.m_sent_getheaders = false;
} else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) { } else if (state.m_chain_sync.m_timeout > 0 && time_in_seconds > state.m_chain_sync.m_timeout) {
// No evidence yet that our peer has synced to a chain with work equal to that // No evidence yet that our peer has synced to a chain with work equal to that
@ -3955,7 +3974,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
} else { } else {
assert(state.m_chain_sync.m_work_header); assert(state.m_chain_sync.m_work_header);
LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString()); LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
m_connman.PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256())); m_connman.PushMessage(&pto, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(state.m_chain_sync.m_work_header->pprev), uint256()));
state.m_chain_sync.m_sent_getheaders = true; state.m_chain_sync.m_sent_getheaders = true;
constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes constexpr int64_t HEADERS_RESPONSE_TIME = 120; // 2 minutes
// Bump the timeout to allow a response, which could clear the timeout // Bump the timeout to allow a response, which could clear the timeout
@ -4192,7 +4211,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
auto current_time = GetTime<std::chrono::microseconds>(); auto current_time = GetTime<std::chrono::microseconds>();
if (fListen && pto->RelayAddrsWithConn() && if (fListen && pto->RelayAddrsWithConn() &&
!::ChainstateActive().IsInitialBlockDownload() && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
pto->m_next_local_addr_send < current_time) { pto->m_next_local_addr_send < current_time) {
// If we've sent before, clear the bloom filter for the peer, so that our // If we've sent before, clear the bloom filter for the peer, so that our
// self-announcement will actually go out. // self-announcement will actually go out.
@ -4253,7 +4272,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// Start block sync // Start block sync
if (pindexBestHeader == nullptr) if (pindexBestHeader == nullptr)
pindexBestHeader = ::ChainActive().Tip(); pindexBestHeader = m_chainman.ActiveChain().Tip();
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do. bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today. // Only actively request headers from a single peer, unless we're close to today.
@ -4278,7 +4297,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (pindexStart->pprev) if (pindexStart->pprev)
pindexStart = pindexStart->pprev; pindexStart = pindexStart->pprev;
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height); LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height);
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexStart), uint256())); m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexStart), uint256()));
} }
} }
@ -4305,11 +4324,11 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
bool fFoundStartingHeader = false; bool fFoundStartingHeader = false;
// Try to find first header that our peer doesn't have, and // Try to find first header that our peer doesn't have, and
// then send all headers past that one. If we come across any // then send all headers past that one. If we come across any
// headers that aren't on ::ChainActive(), give up. // headers that aren't on m_chainman.ActiveChain(), give up.
for (const uint256& hash : peer->m_blocks_for_headers_relay) { for (const uint256& hash : peer->m_blocks_for_headers_relay) {
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hash); const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);
assert(pindex); assert(pindex);
if (::ChainActive()[pindex->nHeight] != pindex) { if (m_chainman.ActiveChain()[pindex->nHeight] != pindex) {
// Bail out if we reorged away from this block // Bail out if we reorged away from this block
fRevertToInv = true; fRevertToInv = true;
break; break;
@ -4399,15 +4418,15 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
// in the past. // in the past.
if (!peer->m_blocks_for_headers_relay.empty()) { if (!peer->m_blocks_for_headers_relay.empty()) {
const uint256& hashToAnnounce = peer->m_blocks_for_headers_relay.back(); const uint256& hashToAnnounce = peer->m_blocks_for_headers_relay.back();
const CBlockIndex* pindex = g_chainman.m_blockman.LookupBlockIndex(hashToAnnounce); const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hashToAnnounce);
assert(pindex); assert(pindex);
// Warn if we're announcing a block that is not on the main chain. // Warn if we're announcing a block that is not on the main chain.
// This should be very rare and could be optimized out. // This should be very rare and could be optimized out.
// Just log for now. // Just log for now.
if (::ChainActive()[pindex->nHeight] != pindex) { if (m_chainman.ActiveChain()[pindex->nHeight] != pindex) {
LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n", LogPrint(BCLog::NET, "Announcing block %s not on main chain (tip=%s)\n",
hashToAnnounce.ToString(), ::ChainActive().Tip()->GetBlockHash().ToString()); hashToAnnounce.ToString(), m_chainman.ActiveChain().Tip()->GetBlockHash().ToString());
} }
// If the peer's chain has this block, don't inv it back. // If the peer's chain has this block, don't inv it back.
@ -4637,7 +4656,7 @@ bool PeerManagerImpl::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) || !::ChainstateActive().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !m_chainman.ActiveChainstate().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); FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
@ -4726,4 +4745,3 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
} // release cs_main } // release cs_main
return true; return true;
} }

View File

@ -12,7 +12,8 @@ void FindCoins(const NodeContext& node, std::map<COutPoint, Coin>& coins)
{ {
assert(node.mempool); assert(node.mempool);
LOCK2(cs_main, node.mempool->cs); LOCK2(cs_main, node.mempool->cs);
CCoinsViewCache& chain_view = ::ChainstateActive().CoinsTip(); assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate()));
CCoinsViewCache& chain_view = node.chainman->ActiveChainstate().CoinsTip();
CCoinsViewMemPool mempool_view(&chain_view, *node.mempool); CCoinsViewMemPool mempool_view(&chain_view, *node.mempool);
for (auto& coin : coins) { for (auto& coin : coins) {
if (!mempool_view.GetCoin(coin.first, coin.second)) { if (!mempool_view.GetCoin(coin.first, coin.second)) {

View File

@ -83,7 +83,7 @@ static void ApplyStats(CCoinsStats& stats, T& hash_obj, const uint256& hash, con
//! Calculate statistics about the unspent transaction output set //! Calculate statistics about the unspent transaction output set
template <typename T> template <typename T>
static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point) static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point)
{ {
stats = CCoinsStats(); stats = CCoinsStats();
std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor()); std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
@ -92,7 +92,8 @@ static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const
stats.hashBlock = pcursor->GetBestBlock(); stats.hashBlock = pcursor->GetBestBlock();
{ {
LOCK(cs_main); LOCK(cs_main);
stats.nHeight = g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock)->nHeight; assert(std::addressof(g_chainman.m_blockman) == std::addressof(blockman));
stats.nHeight = blockman.LookupBlockIndex(stats.hashBlock)->nHeight;
} }
PrepareHash(hash_obj, stats); PrepareHash(hash_obj, stats);
@ -126,19 +127,19 @@ static bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const
return true; return true;
} }
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, CoinStatsHashType hash_type, const std::function<void()>& interruption_point) bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, CoinStatsHashType hash_type, const std::function<void()>& interruption_point)
{ {
switch (hash_type) { switch (hash_type) {
case(CoinStatsHashType::HASH_SERIALIZED): { case(CoinStatsHashType::HASH_SERIALIZED): {
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
return GetUTXOStats(view, stats, ss, interruption_point); return GetUTXOStats(view, blockman, stats, ss, interruption_point);
} }
case(CoinStatsHashType::MUHASH): { case(CoinStatsHashType::MUHASH): {
MuHash3072 muhash; MuHash3072 muhash;
return GetUTXOStats(view, stats, muhash, interruption_point); return GetUTXOStats(view, blockman, stats, muhash, interruption_point);
} }
case(CoinStatsHashType::NONE): { case(CoinStatsHashType::NONE): {
return GetUTXOStats(view, stats, nullptr, interruption_point); return GetUTXOStats(view, blockman, stats, nullptr, interruption_point);
} }
} // no default case, so the compiler can warn about missing cases } // no default case, so the compiler can warn about missing cases
assert(false); assert(false);

View File

@ -8,6 +8,7 @@
#include <amount.h> #include <amount.h>
#include <uint256.h> #include <uint256.h>
#include <validation.h>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
@ -36,6 +37,6 @@ struct CCoinsStats
}; };
//! Calculate statistics about the unspent transaction output set //! Calculate statistics about the unspent transaction output set
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const CoinStatsHashType hash_type, const std::function<void()>& interruption_point = {}); bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, const CoinStatsHashType hash_type, const std::function<void()>& interruption_point = {});
#endif // BITCOIN_NODE_COINSTATS_H #endif // BITCOIN_NODE_COINSTATS_H

View File

@ -182,18 +182,21 @@ public:
int getNumBlocks() override int getNumBlocks() override
{ {
LOCK(::cs_main); LOCK(::cs_main);
return ::ChainActive().Height(); assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
return m_context->chainman->ActiveChain().Height();
} }
uint256 getBestBlockHash() override uint256 getBestBlockHash() override
{ {
const CBlockIndex* tip = WITH_LOCK(::cs_main, return ::ChainActive().Tip()); assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
const CBlockIndex* tip = WITH_LOCK(::cs_main, return m_context->chainman->ActiveChain().Tip());
return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash(); return tip ? tip->GetBlockHash() : Params().GenesisBlock().GetHash();
} }
int64_t getLastBlockTime() override int64_t getLastBlockTime() override
{ {
LOCK(::cs_main); LOCK(::cs_main);
if (::ChainActive().Tip()) { assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
return ::ChainActive().Tip()->GetBlockTime(); if (m_context->chainman->ActiveChain().Tip()) {
return m_context->chainman->ActiveChain().Tip()->GetBlockTime();
} }
return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network return Params().GenesisBlock().GetBlockTime(); // Genesis block's time of current network
} }
@ -202,11 +205,15 @@ public:
const CBlockIndex* tip; const CBlockIndex* tip;
{ {
LOCK(::cs_main); LOCK(::cs_main);
tip = ::ChainActive().Tip(); assert(std::addressof(::ChainActive()) == std::addressof(m_context->chainman->ActiveChain()));
tip = m_context->chainman->ActiveChain().Tip();
} }
return GuessVerificationProgress(Params().TxData(), tip); return GuessVerificationProgress(Params().TxData(), tip);
} }
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); } bool isInitialBlockDownload() override {
assert(std::addressof(::ChainstateActive()) == std::addressof(m_context->chainman->ActiveChainstate()));
return m_context->chainman->ActiveChainstate().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
@ -231,7 +238,8 @@ public:
bool getUnspentOutput(const COutPoint& output, Coin& coin) override bool getUnspentOutput(const COutPoint& output, Coin& coin) override
{ {
LOCK(::cs_main); LOCK(::cs_main);
return ::ChainstateActive().CoinsTip().GetCoin(output, coin); assert(std::addressof(::ChainstateActive()) == std::addressof(m_context->chainman->ActiveChainstate()));
return m_context->chainman->ActiveChainstate().CoinsTip().GetCoin(output, coin);
} }
WalletClient& walletClient() override WalletClient& walletClient() override
{ {
@ -441,13 +449,15 @@ public:
bool checkFinalTx(const CTransaction& tx) override bool checkFinalTx(const CTransaction& tx) override
{ {
LOCK(cs_main); LOCK(cs_main);
return CheckFinalTx(::ChainActive().Tip(), tx); assert(std::addressof(::ChainActive()) == std::addressof(m_node.chainman->ActiveChain()));
return CheckFinalTx(m_node.chainman->ActiveChain().Tip(), tx);
} }
Optional<int> findLocatorFork(const CBlockLocator& locator) override Optional<int> findLocatorFork(const CBlockLocator& locator) override
{ {
LOCK(cs_main); LOCK(cs_main);
const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CChain& active = Assert(m_node.chainman)->ActiveChain();
if (CBlockIndex* fork = g_chainman.m_blockman.FindForkInGlobalIndex(active, locator)) { assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
if (CBlockIndex* fork = m_node.chainman->m_blockman.FindForkInGlobalIndex(active, locator)) {
return fork->nHeight; return fork->nHeight;
} }
return nullopt; return nullopt;
@ -456,7 +466,8 @@ public:
{ {
WAIT_LOCK(cs_main, lock); WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CChain& active = Assert(m_node.chainman)->ActiveChain();
return FillBlock(g_chainman.m_blockman.LookupBlockIndex(hash), block, lock, active); assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
return FillBlock(m_node.chainman->m_blockman.LookupBlockIndex(hash), block, lock, active);
} }
bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override
{ {
@ -468,7 +479,8 @@ public:
{ {
WAIT_LOCK(cs_main, lock); WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CChain& active = Assert(m_node.chainman)->ActiveChain();
if (const CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(block_hash)) { assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
if (const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) { if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) {
return FillBlock(ancestor, ancestor_out, lock, active); return FillBlock(ancestor, ancestor_out, lock, active);
} }
@ -479,8 +491,10 @@ public:
{ {
WAIT_LOCK(cs_main, lock); WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CChain& active = Assert(m_node.chainman)->ActiveChain();
const CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(block_hash); assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
const CBlockIndex* ancestor = g_chainman.m_blockman.LookupBlockIndex(ancestor_hash); const CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash);
assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
const CBlockIndex* ancestor = m_node.chainman->m_blockman.LookupBlockIndex(ancestor_hash);
if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr; if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr;
return FillBlock(ancestor, ancestor_out, lock, active); return FillBlock(ancestor, ancestor_out, lock, active);
} }
@ -488,8 +502,10 @@ public:
{ {
WAIT_LOCK(cs_main, lock); WAIT_LOCK(cs_main, lock);
const CChain& active = Assert(m_node.chainman)->ActiveChain(); const CChain& active = Assert(m_node.chainman)->ActiveChain();
const CBlockIndex* block1 = g_chainman.m_blockman.LookupBlockIndex(block_hash1); assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
const CBlockIndex* block2 = g_chainman.m_blockman.LookupBlockIndex(block_hash2); const CBlockIndex* block1 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash1);
assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
const CBlockIndex* block2 = m_node.chainman->m_blockman.LookupBlockIndex(block_hash2);
const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr; const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr;
// Using & instead of && below to avoid short circuiting and leaving // Using & instead of && below to avoid short circuiting and leaving
// output uninitialized. // output uninitialized.
@ -499,7 +515,8 @@ public:
double guessVerificationProgress(const uint256& block_hash) override double guessVerificationProgress(const uint256& block_hash) override
{ {
LOCK(cs_main); LOCK(cs_main);
return GuessVerificationProgress(Params().TxData(), g_chainman.m_blockman.LookupBlockIndex(block_hash)); assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
return GuessVerificationProgress(Params().TxData(), m_node.chainman->m_blockman.LookupBlockIndex(block_hash));
} }
bool hasBlocks(const uint256& block_hash, int min_height, Optional<int> max_height) override bool hasBlocks(const uint256& block_hash, int min_height, Optional<int> max_height) override
{ {
@ -511,7 +528,8 @@ public:
// used to limit the range, and passing min_height that's too low or // used to limit the range, and passing min_height that's too low or
// max_height that's too high will not crash or change the result. // max_height that's too high will not crash or change the result.
LOCK(::cs_main); LOCK(::cs_main);
if (CBlockIndex* block = g_chainman.m_blockman.LookupBlockIndex(block_hash)) { assert(std::addressof(g_chainman) == std::addressof(*m_node.chainman));
if (CBlockIndex* block = m_node.chainman->m_blockman.LookupBlockIndex(block_hash)) {
if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height); if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) { for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
// Check pprev to not segfault if min_height is too low // Check pprev to not segfault if min_height is too low
@ -601,7 +619,10 @@ public:
return ::fHavePruned; return ::fHavePruned;
} }
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); }
bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); } bool isInitialBlockDownload() override {
assert(std::addressof(::ChainstateActive()) == std::addressof(m_node.chainman->ActiveChainstate()));
return m_node.chainman->ActiveChainstate().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); }

View File

@ -39,9 +39,10 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
{ // cs_main scope { // cs_main scope
LOCK(cs_main); LOCK(cs_main);
assert(std::addressof(::ChainstateActive()) == std::addressof(node.chainman->ActiveChainstate()));
// If the transaction is already confirmed in the chain, don't do anything // If the transaction is already confirmed in the chain, don't do anything
// and return early. // and return early.
CCoinsViewCache &view = ::ChainstateActive().CoinsTip(); CCoinsViewCache &view = node.chainman->ActiveChainstate().CoinsTip();
for (size_t o = 0; o < tx->vout.size(); o++) { for (size_t o = 0; o < tx->vout.size(); o++) {
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o)); const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
// IsSpent doesn't mean the coin is spent, it means the output doesn't exist. // IsSpent doesn't mean the coin is spent, it means the output doesn't exist.
@ -53,7 +54,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
if (max_tx_fee > 0) { if (max_tx_fee > 0) {
// First, call ATMP with test_accept and check the fee. If ATMP // First, call ATMP with test_accept and check the fee. If ATMP
// fails here, return error immediately. // fails here, return error immediately.
const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), *node.mempool, tx, false /* bypass_limits */, const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
true /* test_accept */); true /* test_accept */);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
return HandleATMPError(result.m_state, err_string); return HandleATMPError(result.m_state, err_string);
@ -62,7 +63,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
} }
} }
// Try to submit the transaction to the mempool. // Try to submit the transaction to the mempool.
const MempoolAcceptResult result = AcceptToMemoryPool(::ChainstateActive(), *node.mempool, tx, false /* bypass_limits */, const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, false /* bypass_limits */,
false /* test_accept */); false /* test_accept */);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
return HandleATMPError(result.m_state, err_string); return HandleATMPError(result.m_state, err_string);

View File

@ -1073,9 +1073,9 @@ static RPCHelpMan gettxoutsetinfo()
const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())}; const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
CCoinsView* coins_view = WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB()); CCoinsView* coins_view = WITH_LOCK(::cs_main, return &::ChainstateActive().CoinsDB());
NodeContext& node = EnsureNodeContext(request.context); NodeContext& node = EnsureNodeContext(request.context);
if (GetUTXOStats(coins_view, stats, hash_type, node.rpc_interruption_point)) { if (GetUTXOStats(coins_view, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, hash_type, node.rpc_interruption_point)) {
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());
ret.pushKV("transactions", (int64_t)stats.nTransactions); ret.pushKV("transactions", (int64_t)stats.nTransactions);
@ -2444,7 +2444,7 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil
chainstate.ForceFlushStateToDisk(); chainstate.ForceFlushStateToDisk();
if (!GetUTXOStats(&chainstate.CoinsDB(), stats, CoinStatsHashType::NONE, node.rpc_interruption_point)) { if (!GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, stats, CoinStatsHashType::NONE, node.rpc_interruption_point)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
} }

View File

@ -150,7 +150,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me
UniValue blockHashes(UniValue::VARR); UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd && !ShutdownRequested()) while (nHeight < nHeightEnd && !ShutdownRequested())
{ {
std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(mempool, Params()).CreateNewBlock(coinbase_script)); std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(mempool, Params()).CreateNewBlock(::ChainstateActive(), coinbase_script));
if (!pblocktemplate.get()) if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block; CBlock *pblock = &pblocktemplate->block;
@ -358,7 +358,7 @@ static RPCHelpMan generateblock()
LOCK(cs_main); LOCK(cs_main);
CTxMemPool empty_mempool; CTxMemPool empty_mempool;
std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(empty_mempool, chainparams).CreateNewBlock(coinbase_script)); std::unique_ptr<CBlockTemplate> blocktemplate(BlockAssembler(empty_mempool, chainparams).CreateNewBlock(::ChainstateActive(), coinbase_script));
if (!blocktemplate) { if (!blocktemplate) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
} }
@ -369,7 +369,7 @@ static RPCHelpMan generateblock()
// Add transactions // Add transactions
block.vtx.insert(block.vtx.end(), txs.begin(), txs.end()); block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
RegenerateCommitments(block); RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)));
{ {
LOCK(cs_main); LOCK(cs_main);
@ -747,7 +747,7 @@ static RPCHelpMan getblocktemplate()
// Create new block // Create new block
CScript scriptDummy = CScript() << OP_TRUE; CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate = BlockAssembler(mempool, Params()).CreateNewBlock(scriptDummy); pblocktemplate = BlockAssembler(mempool, Params()).CreateNewBlock(::ChainstateActive(), scriptDummy);
if (!pblocktemplate) if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");

View File

@ -62,7 +62,7 @@ CBlock BuildChainTestingSetup::CreateBlock(const CBlockIndex* prev,
const CScript& scriptPubKey) const CScript& scriptPubKey)
{ {
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(scriptPubKey); std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
CBlock& block = pblocktemplate->block; CBlock& block = pblocktemplate->block;
block.hashPrevBlock = prev->GetBlockHash(); block.hashPrevBlock = prev->GetBlockHash();
block.nTime = prev->nTime + 1; block.nTime = prev->nTime + 1;

View File

@ -264,7 +264,7 @@ FUZZ_TARGET_INIT(coins_view, initialize_coins_view)
CCoinsStats stats; CCoinsStats stats;
bool expected_code_path = false; bool expected_code_path = false;
try { try {
(void)GetUTXOStats(&coins_view_cache, stats, CoinStatsHashType::HASH_SERIALIZED); (void)GetUTXOStats(&coins_view_cache, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED);
} catch (const std::logic_error&) { } catch (const std::logic_error&) {
expected_code_path = true; expected_code_path = true;
} }

View File

@ -122,7 +122,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
uint256 hashHighFeeTx = tx.GetHash(); uint256 hashHighFeeTx = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); std::unique_ptr<CBlockTemplate> pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 4U);
BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx);
BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx);
@ -143,7 +143,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse; tx.vout[0].nValue = 5000000000LL - 1000 - 50000 - feeToUse;
uint256 hashLowFeeTx = tx.GetHash(); uint256 hashLowFeeTx = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(feeToUse).FromTx(tx));
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
// Verify that the free tx and the low fee tx didn't get selected // Verify that the free tx and the low fee tx didn't get selected
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx);
@ -157,7 +157,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee tx.vout[0].nValue -= 2; // Now we should be just over the min relay fee
hashLowFeeTx = tx.GetHash(); hashLowFeeTx = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(feeToUse+2).FromTx(tx));
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx);
BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx);
@ -179,7 +179,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse; tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
uint256 hashLowFeeTx2 = tx.GetHash(); uint256 hashLowFeeTx2 = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
// Verify that this tx isn't selected. // Verify that this tx isn't selected.
for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) {
@ -192,7 +192,7 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
tx.vin[0].prevout.n = 1; tx.vin[0].prevout.n = 1;
tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee
m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(10000).FromTx(tx));
pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey); pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey);
BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U); BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 9U);
BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2);
} }
@ -215,7 +215,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
fCheckpointsEnabled = false; fCheckpointsEnabled = false;
// Simple block creation, nothing special yet: // Simple block creation, nothing special yet:
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// We can't make transactions until we have inputs // We can't make transactions until we have inputs
// Therefore, load 110 blocks :) // Therefore, load 110 blocks :)
@ -252,7 +252,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
LOCK(m_node.mempool->cs); LOCK(m_node.mempool->cs);
// Just to make sure we can still make simple blocks // Just to make sure we can still make simple blocks
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
const CAmount BLOCKSUBSIDY = 50*COIN; const CAmount BLOCKSUBSIDY = 50*COIN;
const CAmount LOWFEE = CENT; const CAmount LOWFEE = CENT;
@ -277,7 +277,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = hash; tx.vin[0].prevout.hash = hash;
} }
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops")); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-blk-sigops"));
m_node.mempool->clear(); m_node.mempool->clear();
tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).SigOpsCost(80).FromTx(tx));
tx.vin[0].prevout.hash = hash; tx.vin[0].prevout.hash = hash;
} }
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
m_node.mempool->clear(); m_node.mempool->clear();
// block size > limit // block size > limit
@ -311,13 +311,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(spendsCoinbase).FromTx(tx));
tx.vin[0].prevout.hash = hash; tx.vin[0].prevout.hash = hash;
} }
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
m_node.mempool->clear(); m_node.mempool->clear();
// orphan in *m_node.mempool, template creation fails // orphan in *m_node.mempool, template creation fails
hash = tx.GetHash(); hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx));
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
m_node.mempool->clear(); m_node.mempool->clear();
// child with higher feerate than parent // child with higher feerate than parent
@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee tx.vout[0].nValue = tx.vout[0].nValue+BLOCKSUBSIDY-HIGHERFEE; //First txn output + fresh coinbase - new txn fee
hash = tx.GetHash(); hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
m_node.mempool->clear(); m_node.mempool->clear();
// coinbase in *m_node.mempool, template creation fails // coinbase in *m_node.mempool, template creation fails
@ -346,7 +346,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// give it a fee so it'll get mined // give it a fee so it'll get mined
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
// Should throw bad-cb-multiple // Should throw bad-cb-multiple
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple")); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-cb-multiple"));
m_node.mempool->clear(); m_node.mempool->clear();
// double spend txn pair in *m_node.mempool, template creation fails // double spend txn pair in *m_node.mempool, template creation fails
@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vout[0].scriptPubKey = CScript() << OP_2; tx.vout[0].scriptPubKey = CScript() << OP_2;
hash = tx.GetHash(); hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent")); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("bad-txns-inputs-missingorspent"));
m_node.mempool->clear(); m_node.mempool->clear();
// subsidy changing // subsidy changing
@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
next->BuildSkip(); next->BuildSkip();
::ChainActive().SetTip(next); ::ChainActive().SetTip(next);
} }
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// Extend to a 210000-long block chain. // Extend to a 210000-long block chain.
while (::ChainActive().Tip()->nHeight < 210000) { while (::ChainActive().Tip()->nHeight < 210000) {
CBlockIndex* prev = ::ChainActive().Tip(); CBlockIndex* prev = ::ChainActive().Tip();
@ -387,7 +387,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
next->BuildSkip(); next->BuildSkip();
::ChainActive().SetTip(next); ::ChainActive().SetTip(next);
} }
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// invalid p2sh txn in *m_node.mempool, template creation fails // invalid p2sh txn in *m_node.mempool, template creation fails
tx.vin[0].prevout.hash = txFirst[0]->GetHash(); tx.vin[0].prevout.hash = txFirst[0]->GetHash();
@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
hash = tx.GetHash(); hash = tx.GetHash();
m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); m_node.mempool->addUnchecked(entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
// Should throw block-validation-failed // Should throw block-validation-failed
BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error, HasReason("block-validation-failed")); BOOST_CHECK_EXCEPTION(AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey), std::runtime_error, HasReason("block-validation-failed"));
m_node.mempool->clear(); m_node.mempool->clear();
// Delete the dummy blocks again. // Delete the dummy blocks again.
@ -492,7 +492,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1;
BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
// None of the of the absolute height/time locked tx should have made // None of the of the absolute height/time locked tx should have made
// it into the template because we still check IsFinalTx in CreateNewBlock, // it into the template because we still check IsFinalTx in CreateNewBlock,
@ -505,7 +505,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
::ChainActive().Tip()->nHeight++; ::ChainActive().Tip()->nHeight++;
SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1); SetMockTime(::ChainActive().Tip()->GetMedianTimePast() + 1);
BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5U);
::ChainActive().Tip()->nHeight--; ::ChainActive().Tip()->nHeight--;

View File

@ -42,7 +42,7 @@ std::shared_ptr<CBlock> PrepareBlock(const NodeContext& node, const CScript& coi
{ {
auto block = std::make_shared<CBlock>( auto block = std::make_shared<CBlock>(
BlockAssembler{*Assert(node.mempool), Params()} BlockAssembler{*Assert(node.mempool), Params()}
.CreateNewBlock(coinbase_scriptPubKey) .CreateNewBlock(::ChainstateActive(), coinbase_scriptPubKey)
->block); ->block);
LOCK(cs_main); LOCK(cs_main);

View File

@ -245,13 +245,13 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa
{ {
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
CTxMemPool empty_pool; CTxMemPool empty_pool;
CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block; CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(::ChainstateActive(), scriptPubKey)->block;
Assert(block.vtx.size() == 1); Assert(block.vtx.size() == 1);
for (const CMutableTransaction& tx : txns) { for (const CMutableTransaction& tx : txns) {
block.vtx.push_back(MakeTransactionRef(tx)); block.vtx.push_back(MakeTransactionRef(tx));
} }
RegenerateCommitments(block); RegenerateCommitments(block, WITH_LOCK(::cs_main, return std::ref(g_chainman.m_blockman)));
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;

View File

@ -63,7 +63,7 @@ std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash)
static int i = 0; static int i = 0;
static uint64_t time = Params().GenesisBlock().nTime; static uint64_t time = Params().GenesisBlock().nTime;
auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(CScript{} << i++ << OP_TRUE); auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), CScript{} << i++ << OP_TRUE);
auto pblock = std::make_shared<CBlock>(ptemplate->block); auto pblock = std::make_shared<CBlock>(ptemplate->block);
pblock->hashPrevBlock = prev_hash; pblock->hashPrevBlock = prev_hash;
pblock->nTime = ++time; pblock->nTime = ++time;
@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE(witness_commitment_index)
{ {
CScript pubKey; CScript pubKey;
pubKey << 1 << OP_TRUE; pubKey << 1 << OP_TRUE;
auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(pubKey); auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(::ChainstateActive(), pubKey);
CBlock pblock = ptemplate->block; CBlock pblock = ptemplate->block;
CTxOut witness; CTxOut witness;

View File

@ -5425,7 +5425,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
// about the snapshot_chainstate. // about the snapshot_chainstate.
CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB()); CCoinsViewDB* snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB());
if (!GetUTXOStats(snapshot_coinsdb, stats, CoinStatsHashType::HASH_SERIALIZED, breakpoint_fnc)) { if (!GetUTXOStats(snapshot_coinsdb, WITH_LOCK(::cs_main, return std::ref(m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED, breakpoint_fnc)) {
LogPrintf("[snapshot] failed to generate coins stats\n"); LogPrintf("[snapshot] failed to generate coins stats\n");
return false; return false;
} }

View File

@ -148,8 +148,6 @@ extern const std::vector<std::string> CHECKLEVEL_DOC;
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false); FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
/** Translation to a filesystem path */ /** Translation to a filesystem path */
fs::path GetBlockPosFilename(const FlatFilePos &pos); fs::path GetBlockPosFilename(const FlatFilePos &pos);
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
bool LoadGenesisBlock(const CChainParams& chainparams);
/** Unload database information */ /** Unload database information */
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman); void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman);
/** Run instances of script checking worker threads */ /** Run instances of script checking worker threads */
@ -725,6 +723,7 @@ public:
/** Replay blocks that aren't fully applied to the database. */ /** Replay blocks that aren't fully applied to the database. */
bool ReplayBlocks(const CChainParams& params); bool ReplayBlocks(const CChainParams& params);
bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main); bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main);
/** Ensures we have a genesis block in the block tree, possibly writing one to disk. */
bool LoadGenesisBlock(const CChainParams& chainparams); bool LoadGenesisBlock(const CChainParams& chainparams);
void PruneBlockIndexCandidates(); void PruneBlockIndexCandidates();