aboutsummaryrefslogtreecommitdiff
path: root/src/node
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2022-03-17 07:23:36 +0100
committerMarcoFalke <falke.marco@gmail.com>2022-03-17 07:23:43 +0100
commit601bfc417d1fb3ac78cda9477814df319182599f (patch)
tree4949f66ffc46ae8630ed4b044acfb4a9231df399 /src/node
parentaece56624941bc6284a01a4df7881e73cdf4290f (diff)
parentf865cf8ded2b2fbc82a6fbc41226d991909a6880 (diff)
downloadbitcoin-601bfc417d1fb3ac78cda9477814df319182599f.tar.xz
Merge bitcoin/bitcoin#24515: Only load BlockMan in BlockMan member functions
f865cf8ded2b2fbc82a6fbc41226d991909a6880 Add and use BlockManager::GetAllBlockIndices (Carl Dong) 28ba0313eac37e4a900b7e97af7169ce999c4024 Add and use CBlockIndexHeightOnlyComparator (Carl Dong) 12eb05df63f930969115af6dc66e2e5d02f2a517 move-only: Move CBlockIndexWorkComparator to blockstorage (Carl Dong) c600ee38168a460d3026eae0e289c976194aad14 Only load BlockMan in BlockMan member functions (Carl Dong) 42e56d9b188f97c077ed2269e24acc0be35ece17 style-only: No need for std::pair for vSortedByHeight (Carl Dong) 3bbb6fea051f4e19bd2448e401a6c4e9b4cc7a41 style-only: Various blockstorage.cpp cleanups (Carl Dong) 5be9ee3c54dcb396ff52fc8c8b7e4e6e39ec4a3b refactor: more const annotations for uses of CBlockIndex* (Anthony Towns) Pull request description: The only important commit is "Only load BlockMan in BlockMan member functions", everything else is all just small style changes. Here's the commit message, reproduced: ``` This commit effectively splits the "load block index itself" logic from "derive Chainstate variables from loaded block index" logic. This means that BlockManager::LoadBlockIndex{,DB} will only load what's relevant to the BlockManager. ``` ACKs for top commit: ajtowns: ACK f865cf8ded2b2fbc82a6fbc41226d991909a6880 ; code review only MarcoFalke: review ACK f865cf8ded2b2fbc82a6fbc41226d991909a6880 🗂 Tree-SHA512: 7b204d782834e06fd7329d022e2ae860181b4e8105c33bfb928539a4ec24161dc7438a9c4d4ee279dcad77de310c160b997bb8aa18923243d0fd55ccf4ad7c3a
Diffstat (limited to 'src/node')
-rw-r--r--src/node/blockstorage.cpp125
-rw-r--r--src/node/blockstorage.h16
-rw-r--r--src/node/interfaces.cpp4
-rw-r--r--src/node/miner.cpp2
4 files changed, 61 insertions, 86 deletions
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 7392830261..763fd29744 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -28,10 +28,45 @@ bool fHavePruned = false;
bool fPruneMode = false;
uint64_t nPruneTarget = 0;
+bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
+{
+ // First sort by most total work, ...
+ if (pa->nChainWork > pb->nChainWork) return false;
+ if (pa->nChainWork < pb->nChainWork) return true;
+
+ // ... then by earliest time received, ...
+ if (pa->nSequenceId < pb->nSequenceId) return false;
+ if (pa->nSequenceId > pb->nSequenceId) return true;
+
+ // Use pointer address as tie breaker (should only happen with blocks
+ // loaded from disk, as those all have id 0).
+ if (pa < pb) return false;
+ if (pa > pb) return true;
+
+ // Identical blocks.
+ return false;
+}
+
+bool CBlockIndexHeightOnlyComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
+{
+ return pa->nHeight < pb->nHeight;
+}
+
static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
static FlatFileSeq BlockFileSeq();
static FlatFileSeq UndoFileSeq();
+std::vector<CBlockIndex*> BlockManager::GetAllBlockIndices()
+{
+ AssertLockHeld(cs_main);
+ std::vector<CBlockIndex*> rv;
+ rv.reserve(m_block_index.size());
+ for (auto& [_, block_index] : m_block_index) {
+ rv.push_back(&block_index);
+ }
+ return rv;
+}
+
CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash)
{
AssertLockHeld(cs_main);
@@ -203,8 +238,7 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
return nullptr;
}
- // Return existing or create new
- auto [mi, inserted] = m_block_index.try_emplace(hash);
+ const auto [mi, inserted]{m_block_index.try_emplace(hash)};
CBlockIndex* pindex = &(*mi).second;
if (inserted) {
pindex->phashBlock = &((*mi).first);
@@ -212,46 +246,19 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
return pindex;
}
-bool BlockManager::LoadBlockIndex(
- const Consensus::Params& consensus_params,
- ChainstateManager& chainman)
+bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
{
if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
return false;
}
// Calculate nChainWork
- std::vector<std::pair<int, CBlockIndex*>> vSortedByHeight;
- vSortedByHeight.reserve(m_block_index.size());
- for (auto& [_, block_index] : m_block_index) {
- CBlockIndex* pindex = &block_index;
- vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
- }
- sort(vSortedByHeight.begin(), vSortedByHeight.end());
-
- // Find start of assumed-valid region.
- int first_assumed_valid_height = std::numeric_limits<int>::max();
-
- for (const auto& [height, block] : vSortedByHeight) {
- if (block->IsAssumedValid()) {
- auto chainstates = chainman.GetAll();
-
- // If we encounter an assumed-valid block index entry, ensure that we have
- // one chainstate that tolerates assumed-valid entries and another that does
- // not (i.e. the background validation chainstate), since assumed-valid
- // entries should always be pending validation by a fully-validated chainstate.
- auto any_chain = [&](auto fnc) { return std::any_of(chainstates.cbegin(), chainstates.cend(), fnc); };
- assert(any_chain([](auto chainstate) { return chainstate->reliesOnAssumedValid(); }));
- assert(any_chain([](auto chainstate) { return !chainstate->reliesOnAssumedValid(); }));
-
- first_assumed_valid_height = height;
- break;
- }
- }
+ std::vector<CBlockIndex*> vSortedByHeight{GetAllBlockIndices()};
+ std::sort(vSortedByHeight.begin(), vSortedByHeight.end(),
+ CBlockIndexHeightOnlyComparator());
- for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight) {
+ for (CBlockIndex* pindex : vSortedByHeight) {
if (ShutdownRequested()) return false;
- CBlockIndex* pindex = item.second;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
@@ -275,43 +282,6 @@ bool BlockManager::LoadBlockIndex(
pindex->nStatus |= BLOCK_FAILED_CHILD;
m_dirty_blockindex.insert(pindex);
}
- if (pindex->IsAssumedValid() ||
- (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
- (pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
-
- // Fill each chainstate's block candidate set. Only add assumed-valid
- // blocks to the tip candidate set if the chainstate is allowed to rely on
- // assumed-valid blocks.
- //
- // If all setBlockIndexCandidates contained the assumed-valid blocks, the
- // background chainstate's ActivateBestChain() call would add assumed-valid
- // blocks to the chain (based on how FindMostWorkChain() works). Obviously
- // we don't want this since the purpose of the background validation chain
- // is to validate assued-valid blocks.
- //
- // Note: This is considering all blocks whose height is greater or equal to
- // the first assumed-valid block to be assumed-valid blocks, and excluding
- // them from the background chainstate's setBlockIndexCandidates set. This
- // does mean that some blocks which are not technically assumed-valid
- // (later blocks on a fork beginning before the first assumed-valid block)
- // might not get added to the background chainstate, but this is ok,
- // because they will still be attached to the active chainstate if they
- // actually contain more work.
- //
- // Instead of this height-based approach, an earlier attempt was made at
- // detecting "holistically" whether the block index under consideration
- // relied on an assumed-valid ancestor, but this proved to be too slow to
- // be practical.
- for (CChainState* chainstate : chainman.GetAll()) {
- if (chainstate->reliesOnAssumedValid() ||
- pindex->nHeight < first_assumed_valid_height) {
- chainstate->setBlockIndexCandidates.insert(pindex);
- }
- }
- }
- if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainWork > chainman.m_best_invalid->nChainWork)) {
- chainman.m_best_invalid = pindex;
- }
if (pindex->pprev) {
pindex->BuildSkip();
}
@@ -355,9 +325,9 @@ bool BlockManager::WriteBlockIndexDB()
return true;
}
-bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
+bool BlockManager::LoadBlockIndexDB()
{
- if (!LoadBlockIndex(::Params().GetConsensus(), chainman)) {
+ if (!LoadBlockIndex(::Params().GetConsensus())) {
return false;
}
@@ -382,9 +352,8 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
LogPrintf("Checking all blk files are present...\n");
std::set<int> setBlkDataFiles;
for (const auto& [_, block_index] : m_block_index) {
- const CBlockIndex* pindex = &block_index;
- if (pindex->nStatus & BLOCK_HAVE_DATA) {
- setBlkDataFiles.insert(pindex->nFile);
+ if (block_index.nStatus & BLOCK_HAVE_DATA) {
+ setBlkDataFiles.insert(block_index.nFile);
}
}
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) {
@@ -408,13 +377,13 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
return true;
}
-CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
+const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
{
const MapCheckpoints& checkpoints = data.mapCheckpoints;
for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) {
const uint256& hash = i.second;
- CBlockIndex* pindex = LookupBlockIndex(hash);
+ const CBlockIndex* pindex = LookupBlockIndex(hash);
if (pindex) {
return pindex;
}
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index 12224f7a5d..a051e90808 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -62,6 +62,11 @@ struct CBlockIndexWorkComparator {
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
};
+struct CBlockIndexHeightOnlyComparator {
+ /* Only compares the height of two block indices, doesn't try to tie-break */
+ bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
+};
+
/**
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
* to determine where the most-work tip is.
@@ -118,6 +123,8 @@ private:
public:
BlockMap m_block_index GUARDED_BY(cs_main);
+ std::vector<CBlockIndex*> GetAllBlockIndices() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+
/**
* All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
* Pruned nodes may have entries where B is missing data.
@@ -127,16 +134,15 @@ public:
std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
- bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
+ bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/**
* Load the blocktree off disk and into memory. Populate certain metadata
* per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
* collections like m_dirty_blockindex.
*/
- bool LoadBlockIndex(
- const Consensus::Params& consensus_params,
- ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool LoadBlockIndex(const Consensus::Params& consensus_params)
+ EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Clear all data members. */
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -163,7 +169,7 @@ public:
uint64_t CalculateCurrentUsage();
//! Returns last CBlockIndex* that is a checkpoint
- CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
~BlockManager()
{
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp
index cb063ae9f8..74d53d2062 100644
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -490,7 +490,7 @@ public:
{
LOCK(cs_main);
const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
- if (CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
+ if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
return fork->nHeight;
}
return std::nullopt;
@@ -557,7 +557,7 @@ public:
// 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.
LOCK(::cs_main);
- if (CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
+ if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
// Check pprev to not segfault if min_height is too low
diff --git a/src/node/miner.cpp b/src/node/miner.cpp
index 54afbb8839..917df91933 100644
--- a/src/node/miner.cpp
+++ b/src/node/miner.cpp
@@ -50,7 +50,7 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
tx.vout.erase(tx.vout.begin() + GetWitnessCommitmentIndex(block));
block.vtx.at(0) = MakeTransactionRef(tx);
- CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock));
+ const CBlockIndex* prev_block = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock));
GenerateCoinbaseCommitment(block, prev_block, Params().GetConsensus());
block.hashMerkleRoot = BlockMerkleRoot(block);