Created
May 27, 2021 20:50
-
-
Save jamesob/264f4bbb402b3c03c8dda241f83e5ae5 to your computer and use it in GitHub Desktop.
utxo-dumpload.61 -> .62
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ git range-diff master utxo-dumpload.61 utxo-dumpload.62 | |
1: a5d6f365c < -: --------- validation: fix up LoadBlockIndex and RewindBlockIndex for multiple chainstates | |
2: 356ad5d86 < -: --------- validation: parameterize VerifyDB by chainstate | |
-: --------- > 1: 24df1d6af validation: change UpdateTip for multiple chainstates | |
-: --------- > 2: f1c2115cf validation: fix CheckBlockIndex for multiple chainstates | |
-: --------- > 3: a1b9a476f move-only: unittest: add test/util/chainstate.h | |
-: --------- > 4: c42dc9aa9 test: refactor: separate CreateBlock in TestChain100Setup | |
-: --------- > 5: e70c94715 refactor: remove assertions preventing multiple chainstates | |
-: --------- > 6: 0e06cd361 test: validation: add unittest for UpdateTip behavior | |
3: f7ee44878 ! 7: 83863ae0a validation: have LoadGenesisBlock work on all chainstates | |
@@ -2,18 +2,19 @@ | |
validation: have LoadGenesisBlock work on all chainstates | |
- diff --git a/src/init.cpp b/src/init.cpp | |
- --- a/src/init.cpp | |
- +++ b/src/init.cpp | |
+ diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp | |
+ --- a/src/node/blockstorage.cpp | |
+ +++ b/src/node/blockstorage.cpp | |
@@ | |
- fReindex = false; | |
- LogPrintf("Reindexing finished\n"); | |
- // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): | |
-- LoadGenesisBlock(chainparams); | |
-+ WITH_LOCK(::cs_main, LoadGenesisBlock(chainparams)); | |
- } | |
+ fReindex = false; | |
+ LogPrintf("Reindexing finished\n"); | |
+ // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): | |
+- chainman.ActiveChainstate().LoadGenesisBlock(chainparams); | |
++ WITH_LOCK(::cs_main, | |
++ chainman.ActiveChainstate().LoadGenesisBlock(chainparams)); | |
+ } | |
- // -loadblock= | |
+ // -loadblock= | |
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp | |
--- a/src/test/util/setup_common.cpp | |
@@ -22,11 +23,11 @@ | |
assert(!::ChainstateActive().CanFlushToDisk()); | |
::ChainstateActive().InitCoinsCache(1 << 23); | |
assert(::ChainstateActive().CanFlushToDisk()); | |
-- if (!LoadGenesisBlock(chainparams)) { | |
+- if (!::ChainstateActive().LoadGenesisBlock(chainparams)) { | |
- throw std::runtime_error("LoadGenesisBlock failed."); | |
+ { | |
+ LOCK(::cs_main); | |
-+ if (!LoadGenesisBlock(chainparams)) { | |
++ if (!::ChainstateActive().LoadGenesisBlock(chainparams)) { | |
+ throw std::runtime_error("LoadGenesisBlock failed."); | |
+ } | |
} | |
@@ -70,9 +71,9 @@ | |
+ if (g_chainman.BlockIndex().count(chainparams.GenesisBlock().GetHash())) | |
return true; | |
- try { | |
+ assert(std::addressof(::ChainActive()) == std::addressof(m_chain)); | |
@@ | |
- FlatFilePos blockPos = SaveBlockToDisk(block, 0, chainparams, nullptr); | |
+ FlatFilePos blockPos = SaveBlockToDisk(block, 0, m_chain, chainparams, nullptr); | |
if (blockPos.IsNull()) | |
return error("%s: writing genesis block to disk failed", __func__); | |
- CBlockIndex *pindex = m_blockman.AddToBlockIndex(block); | |
@@ -84,46 +85,24 @@ | |
} catch (const std::runtime_error& e) { | |
return error("%s: failed to write genesis block: %s", __func__, e.what()); | |
} | |
-@@ | |
- | |
- bool LoadGenesisBlock(const CChainParams& chainparams) | |
- { | |
-- return ::ChainstateActive().LoadGenesisBlock(chainparams); | |
-+ bool okay = true; | |
-+ for (CChainState* chainstate : g_chainman.GetAll()) { | |
-+ okay &= chainstate->LoadGenesisBlock(chainparams); | |
-+ } | |
-+ return okay; | |
- } | |
- | |
- void CChainState::LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFilePos* dbp) | |
diff --git a/src/validation.h b/src/validation.h | |
--- a/src/validation.h | |
+++ b/src/validation.h | |
@@ | |
- /** Translation to a filesystem path */ | |
- 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); | |
-+bool LoadGenesisBlock(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
- /** Unload database information */ | |
- void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman); | |
- /** Run instances of script checking worker threads */ | |
-@@ | |
- /** Replay blocks that aren't fully applied to the database. */ | |
- bool ReplayBlocks(const CChainParams& params); | |
- bool RewindBlockIndex(const CChainParams& params) LOCKS_EXCLUDED(cs_main); | |
+ /** Whether the chain state needs to be redownloaded due to lack of witness data */ | |
+ [[nodiscard]] bool NeedsRedownload(const CChainParams& params) const EXCLUSIVE_LOCKS_REQUIRED(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) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
void PruneBlockIndexCandidates(); | |
@@ | |
- void EraseBlockData(CBlockIndex* index) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
+ bool LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
friend ChainstateManager; | |
+ friend bool LoadGenesisBlock(const CChainParams&); | |
}; | |
- /** Mark a block as precious and reorganize. | |
+ /** | |
4: bcf73dec4 < -: --------- validation: have UpdateTip only act on ActiveChainstate | |
5: 169ca6b99 ! 8: 060d862e1 wallet: avoid rescans if under the snapshot | |
@@ -6,6 +6,8 @@ | |
validation chainstates. Also refuse to load a wallet if it requires a rescan | |
lower than the height of an unvalidated snapshot we're running. | |
+ TODO: more method definitions like GetSnapshotNChainTx() to a more appropriate commit | |
+ | |
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h | |
--- a/src/interfaces/chain.h | |
+++ b/src/interfaces/chain.h | |
@@ -24,18 +26,15 @@ | |
--- a/src/node/interfaces.cpp | |
+++ b/src/node/interfaces.cpp | |
@@ | |
- LOCK(cs_main); | |
- return CheckFinalTx(tx); | |
+ assert(std::addressof(::ChainActive()) == std::addressof(chainman().ActiveChain())); | |
+ return CheckFinalTx(chainman().ActiveChain().Tip(), tx); | |
} | |
+ int getLowestBlockDataHeight() override | |
+ { | |
+ LOCK(cs_main); | |
-+ if (g_chainman.IsSnapshotActive() && !g_chainman.IsSnapshotValidated()) { | |
-+ return g_chainman.SnapshotHeight(); | |
-+ } | |
-+ return 0; | |
++ return g_chainman.GetSnapshotNChainTx().value_or(0); | |
+ } | |
- Optional<int> findLocatorFork(const CBlockLocator& locator) override | |
+ std::optional<int> findLocatorFork(const CBlockLocator& locator) override | |
{ | |
LOCK(cs_main); | |
@@ -43,22 +42,52 @@ | |
--- a/src/validation.cpp | |
+++ b/src/validation.cpp | |
@@ | |
- vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex)); | |
+ } | |
} | |
- sort(vSortedByHeight.begin(), vSortedByHeight.end()); | |
-+ const uint256 snapshot_blockhash = | |
-+ g_chainman.SnapshotBlockhash().value_or(uint256()); | |
- const bool using_unvalidated_snapshot = | |
- g_chainman.IsSnapshotActive() && !g_chainman.IsSnapshotValidated(); | |
- bool pindex_assumed_valid = false; | |
+ } | |
++ | |
++std::optional<unsigned int> ChainstateManager::GetSnapshotNChainTx() | |
++{ | |
++ auto height = this->GetSnapshotHeight(); | |
++ if (!height) { | |
++ return std::nullopt; | |
++ } | |
++ | |
++ auto au_data = ExpectedAssumeutxo(*height, ::Params()); | |
++ if (!au_data) { | |
++ return std::nullopt; | |
++ } | |
++ | |
++ return au_data->nChainTx; | |
++} | |
++ | |
++std::optional<CBlockIndex*> ChainstateManager::GetSnapshotBaseBlock() | |
++ { | |
++ auto blockhash_op = SnapshotBlockhash(); | |
++ if (!blockhash_op) { | |
++ return std::nullopt; | |
++ } | |
++ return m_blockman.LookupBlockIndex(*blockhash_op); | |
++ } | |
++ | |
++//! @returns height at which the active UTXO snapshot was taken. | |
++std::optional<int> ChainstateManager::GetSnapshotHeight() | |
++{ | |
++ std::optional<CBlockIndex*> base = this->GetSnapshotBaseBlock(); | |
++ if (!base) { | |
++ return std::nullopt; | |
++ } | |
++ return (*base)->nHeight; | |
++} | |
diff --git a/src/validation.h b/src/validation.h | |
--- a/src/validation.h | |
+++ b/src/validation.h | |
@@ | |
+ //! Check to see if caches are out of balance and if so, call | |
//! ResizeCoinsCaches() as needed. | |
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
- | |
++ | |
+ //! Returns true if any chainstate in use is in initial block download. | |
+ bool IsAnyChainInIBD() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
+ | |
@@ -71,15 +100,24 @@ | |
+ //! the background validation chainstate is marked accordingly. | |
+ void CheckForUncleanShutdown() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
+ | |
- //! Return the cached nChainTx value for the snapshot (per the chainparams assumeutxo data), | |
- //! if one exists | |
- std::optional<unsigned int> GetSnapshotNChainTx() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
++ //! Return the cached nChainTx value for the snapshot (per the chainparams assumeutxo data), | |
++ //! if one exists | |
++ std::optional<unsigned int> GetSnapshotNChainTx() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
++ | |
++ //! @returns height at which the active UTXO snapshot was taken, if applicable. | |
++ std::optional<CBlockIndex*> GetSnapshotBaseBlock() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
++ | |
++ //! @returns height at which the active UTXO snapshot was taken, if a snapshot is being used. | |
++ std::optional<int> GetSnapshotHeight() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
+ }; | |
+ | |
+ /** DEPRECATED! Please use node.chainman instead. May only be used in validation.cpp internally */ | |
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp | |
--- a/src/wallet/wallet.cpp | |
+++ b/src/wallet/wallet.cpp | |
@@ | |
- return nullptr; | |
+ return false; | |
} | |
} | |
+ // Otherwise refuse to rescan if we're operating on a snapshot and the | |
@@ -92,5 +130,5 @@ | |
+ return nullptr; | |
+ } | |
- chain.initMessage(_("Rescanning...").translated); | |
+ chain.initMessage(_("Rescanning…").translated); | |
walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height); | |
6: 1cf452104 ! 9: 4e456ab0f rpc: add loadtxoutset | |
@@ -11,7 +11,10 @@ | |
#include <core_io.h> | |
+#include <fs.h> | |
#include <hash.h> | |
- #include <index/blockfilterindex.h> | |
+-#include <index/blockfilterindex.h> | |
+ #include <index/coinstatsindex.h> | |
++#include <index/blockfilterindex.h> | |
+ #include <node/blockstorage.h> | |
+#include <logging/timer.h> | |
#include <node/coinstats.h> | |
#include <node/context.h> | |
@@ -19,7 +22,7 @@ | |
@@ | |
FILE* file{fsbridge::fopen(temppath, "wb")}; | |
CAutoFile afile{file, SER_DISK, CLIENT_VERSION}; | |
- NodeContext& node = EnsureNodeContext(request.context); | |
+ NodeContext& node = EnsureAnyNodeContext(request.context); | |
- UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), afile); | |
+ UniValue result = CreateUTXOSnapshot( | |
+ node, node.chainman->ActiveChainstate(), afile, path, temppath); | |
@@ -39,7 +42,7 @@ | |
+ const fs::path temppath) | |
{ | |
std::unique_ptr<CCoinsViewCursor> pcursor; | |
- CCoinsStats stats; | |
+ CCoinsStats stats{CoinStatsHashType::NONE}; | |
@@ | |
CHECK_NONFATAL(tip); | |
} | |
@@ -82,7 +85,7 @@ | |
+{ | |
+ fs::path path = request.params[0].get_str(); | |
+ if (path.is_relative()) { | |
-+ path = fs::absolute(path, GetDataDir()); | |
++ path = fs::absolute(path, gArgs.GetDataDirNet()); | |
+ } | |
+ FILE* file{fsbridge::fopen(path, "rb")}; | |
+ CAutoFile afile{file, SER_DISK, CLIENT_VERSION}; | |
@@ -154,9 +157,9 @@ | |
--- a/src/rpc/blockchain.h | |
+++ b/src/rpc/blockchain.h | |
@@ | |
- #define BITCOIN_RPC_BLOCKCHAIN_H | |
#include <amount.h> | |
+ #include <core_io.h> | |
+#include <fs.h> | |
#include <streams.h> | |
#include <sync.h> | |
@@ -179,12 +182,40 @@ | |
--- a/src/test/validation_chainstatemanager_tests.cpp | |
+++ b/src/test/validation_chainstatemanager_tests.cpp | |
@@ | |
- FILE* outfile{fsbridge::fopen(snapshot_path, "wb")}; | |
- CAutoFile auto_outfile{outfile, SER_DISK, CLIENT_VERSION}; | |
+ BOOST_CHECK_CLOSE(c2.m_coinsdb_cache_size_bytes, max_cache * 0.95, 1); | |
+ } | |
-- UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), auto_outfile); | |
++auto NoMalleation = [](CAutoFile& file, SnapshotMetadata& meta){}; | |
++ | |
++template<typename F = decltype(NoMalleation)> | |
++static bool | |
++CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleation = NoMalleation) | |
++{ | |
++ // Write out a snapshot to the test's tempdir. | |
++ // | |
++ int height; | |
++ WITH_LOCK(::cs_main, height = node.chainman->ActiveHeight()); | |
++ fs::path snapshot_path = root / tfm::format("test_snapshot.%d.dat", height); | |
++ FILE* outfile{fsbridge::fopen(snapshot_path, "wb")}; | |
++ CAutoFile auto_outfile{outfile, SER_DISK, CLIENT_VERSION}; | |
++ | |
+ UniValue result = CreateUTXOSnapshot( | |
+ node, node.chainman->ActiveChainstate(), auto_outfile, snapshot_path, snapshot_path); | |
- BOOST_TEST_MESSAGE( | |
- "Wrote UTXO snapshot to " << snapshot_path.make_preferred().string() << ": " << result.write()); | |
- | |
++ BOOST_TEST_MESSAGE( | |
++ "Wrote UTXO snapshot to " << snapshot_path.make_preferred().string() << ": " << result.write()); | |
++ | |
++ // Read the written snapshot in and then activate it. | |
++ // | |
++ FILE* infile{fsbridge::fopen(snapshot_path, "rb")}; | |
++ CAutoFile auto_infile{infile, SER_DISK, CLIENT_VERSION}; | |
++ SnapshotMetadata metadata; | |
++ auto_infile >> metadata; | |
++ | |
++ malleation(auto_infile, metadata); | |
++ | |
++ return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory*/ true); | |
++} | |
++ | |
+ //! Test basic snapshot activation. | |
+ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) | |
+ { | |
7: 128d4fe42 ! 10: 57912ecdf validation: only send ValidationInterface callbacks for active chain | |
@@ -15,7 +15,7 @@ | |
GetMainSignals().ChainStateFlushed(m_chain.GetLocator()); | |
} | |
@@ | |
- UpdateTip(m_mempool, pindexDelete->pprev, chainparams, CoinsTip()); | |
+ UpdateTip(m_mempool, pindexDelete->pprev, chainparams, *this); | |
// Let wallets know transactions went from 1-confirmed to | |
// 0-confirmed or conflicted: | |
- GetMainSignals().BlockDisconnected(pblock, pindexDelete); | |
8: f35c8abf9 ! 11: 53fea4a38 validation: add BackgroundBlockConnected and use it for indexing | |
@@ -51,7 +51,7 @@ | |
+ | |
void ChainStateFlushed(const CBlockLocator& locator) override; | |
- /// Initialize internal state from the database and block index. | |
+ const CBlockIndex* CurrentIndex() { return m_best_block_index.load(); }; | |
diff --git a/src/validation.cpp b/src/validation.cpp | |
--- a/src/validation.cpp | |
9: c9500b54d ! 12: 845e20786 validation: introduce ChainstateManager::GetChainstateForNewBlock | |
@@ -52,7 +52,7 @@ | |
@@ | |
} | |
- auto snapshot_chainstate = WITH_LOCK(::cs_main, return MakeUnique<CChainState>( | |
+ auto snapshot_chainstate = WITH_LOCK(::cs_main, return std::make_unique<CChainState>( | |
- this->ActiveChainstate().m_mempool, m_blockman, base_blockhash)); | |
+ this->ActiveChainstate().m_mempool, m_blockman, base_blockhash)); | |
10: 0456819dc ! 13: 2a001faa0 net_processing: work with multiple chainstates | |
@@ -25,11 +25,23 @@ | |
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight GUARDED_BY(cs_main); | |
@@ | |
- const CBlockIndex *pindexBestKnownBlock; | |
+ void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
+ /** Update tracking information about which blocks a peer is assumed to have. */ | |
+ void UpdateBlockAvailability(NodeId nodeid, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
++ | |
++ /** | |
++ * Allow the direct fetch of block data if our tip is recent within the past | |
++ * 200 minutes. | |
++ */ | |
+ bool CanDirectFetch() EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
+ | |
+ /** | |
+@@ | |
+ const CBlockIndex* pindexBestKnownBlock{nullptr}; | |
//! The hash of the last unknown block this peer has announced. | |
- uint256 hashLastUnknownBlock; | |
+ uint256 hashLastUnknownBlock{}; | |
- //! The last full block we both have. | |
-- const CBlockIndex *pindexLastCommonBlock; | |
+- const CBlockIndex* pindexLastCommonBlock{nullptr}; | |
+ | |
+ //! The last full block we both have (per chainstate). | |
+ //! | |
@@ -40,42 +52,22 @@ | |
+ //! any CChainState objects which were in use at any point (e.g. a background | |
+ //! validation chainstate which has completed) until the end of | |
+ //! init.cpp:Shutdown(), else we'll have bad pointers here. | |
-+ // | |
+ std::map<const CChainState* const, const CBlockIndex*> chainstate_to_last_common_block = {}; | |
+ | |
//! The best header we have sent our peer. | |
- const CBlockIndex *pindexBestHeaderSent; | |
+ const CBlockIndex* pindexBestHeaderSent{nullptr}; | |
//! Length of current-streak of unconnecting headers announcements | |
@@ | |
- { | |
- pindexBestKnownBlock = nullptr; | |
- hashLastUnknownBlock.SetNull(); | |
-- pindexLastCommonBlock = nullptr; | |
- pindexBestHeaderSent = nullptr; | |
- nUnconnectingHeaders = 0; | |
- fSyncStarted = false; | |
-@@ | |
- return m_last_tip_update < GetTime() - consensusParams.nPowTargetSpacing * 3 && mapBlocksInFlight.empty(); | |
- } | |
- | |
-+/** | |
-+ * Allow the direct fetch of block data if our tip is recent within the past | |
-+ * 200 minutes. | |
-+ */ | |
- static bool CanDirectFetch(const Consensus::Params &consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
- { | |
- return ::ChainActive().Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; | |
-@@ | |
- return false; | |
+ } | |
} | |
--void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
+-void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller) | |
+void PeerManagerImpl::FindNextBlocksToDownload( | |
+ const CChainState* const chainstate, | |
+ NodeId nodeid, | |
+ unsigned int count, | |
+ std::vector<const CBlockIndex*>& vBlocks, | |
-+ NodeId& nodeStaller) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
++ NodeId& nodeStaller) | |
{ | |
if (count == 0) | |
return; | |
@@ -83,7 +75,7 @@ | |
// Make sure pindexBestKnownBlock is up to date, we'll need it. | |
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) { | |
+ const CChain& our_chain = chainstate->m_chain; | |
+ const CBlockIndex* our_tip = our_chain.Tip(); | |
+ | |
@@ -98,11 +90,10 @@ | |
+ if (!state->chainstate_to_last_common_block.count(chainstate)) { | |
// Bootstrap quickly by guessing a parent of our best tip is the forking point. | |
// 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())]; | |
+ // | |
+ // Namespace this by chainstate so that we can simultaneously sync two | |
+ // separate chainstates at different heights. | |
-+ // | |
+ state->chainstate_to_last_common_block[chainstate] = our_chain[ | |
+ std::min(state->pindexBestKnownBlock->nHeight, our_chain.Height())]; | |
} | |
@@ -147,7 +138,7 @@ | |
// We wouldn't download this block or its descendants from this peer. | |
return; | |
} | |
-- if (pindex->nStatus & BLOCK_HAVE_DATA || ::ChainActive().Contains(pindex)) { | |
+- if (pindex->nStatus & BLOCK_HAVE_DATA || m_chainman.ActiveChain().Contains(pindex)) { | |
+ if (pindex->nStatus & BLOCK_HAVE_DATA || our_chain.Contains(pindex)) { | |
if (pindex->HaveTxsDownloaded()) | |
- state->pindexLastCommonBlock = pindex; | |
@@ -175,19 +166,19 @@ | |
if (queue.pindex) | |
stats.vHeightInFlight.push_back(queue.pindex->nHeight); | |
@@ | |
- LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased); | |
- } | |
+ void PeerManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex) | |
+ { | |
+ m_orphanage.EraseForBlock(*pblock); | |
++ // TODO jamesob: do we need to namespace this per chainstate? Will we accidentally | |
++ // evict outbound peers we're IBDing from for the background validation chain? | |
+ m_last_tip_update = GetTime(); | |
-+ // TODO jamesob: do we need to namespace this per chainstate? Will we accidentally | |
-+ // evict outbound peers we're IBDing from for the background validation chain? | |
- m_last_tip_update = GetTime(); | |
- } | |
{ | |
@@ | |
/** | |
* 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. | |
+ * in the active chain to our peers. | |
*/ | |
void PeerManagerImpl::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) | |
@@ -200,22 +191,11 @@ | |
uint256 hashLastBlock; | |
for (const CBlockHeader& header : headers) { | |
if (!hashLastBlock.IsNull() && header.hashPrevBlock != hashLastBlock) { | |
-@@ | |
- // disk-space attacks), but this should be safe due to the | |
- // protections in the compact block handler -- see related comment | |
- // in compact block optimistic reconstruction handling. | |
-+ // | |
-+ // It's okay to restrict this to the active chainstate because we'll | |
-+ // never receive compact blocks when building the snapshot | |
-+ // verification chain. | |
- m_chainman.ProcessNewBlock(m_chainparams, pblock, /*fForceProcessing=*/true, &fNewBlock); | |
- if (fNewBlock) { | |
- pfrom.nLastBlockTime = GetTime(); | |
@@ | |
// Message: getdata (blocks) | |
// | |
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; | |
- NodeId staller = -1; | |
- FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); | |
@@ -227,8 +207,8 @@ | |
- pindex->nHeight, pto->GetId()); | |
- } | |
- if (state.nBlocksInFlight == 0 && staller != -1) { | |
-- if (State(staller)->nStallingSince == 0) { | |
-- State(staller)->nStallingSince = count_microseconds(current_time); | |
+- if (State(staller)->m_stalling_since == 0us) { | |
+- State(staller)->m_stalling_since = current_time; | |
- LogPrint(BCLog::NET, "Stall started peer=%d\n", staller); | |
+ | |
+ // The first chainstate in line for processing will likely exhaust this | |
@@ -257,8 +237,8 @@ | |
+ | |
+ requests_available -= vToDownload.size(); | |
+ if (state.nBlocksInFlight == 0 && staller != -1) { | |
-+ if (State(staller)->nStallingSince == 0) { | |
-+ State(staller)->nStallingSince = count_microseconds(current_time); | |
++ if (State(staller)->m_stalling_since == 0us) { | |
++ State(staller)->m_stalling_since = current_time; | |
+ LogPrint(BCLog::NET, "Stall started peer=%d\n", staller); | |
+ } | |
} | |
@@ -289,9 +269,9 @@ | |
+ return out; | |
+} | |
+ | |
- CChainState& ChainstateManager::InitializeChainstate(CTxMemPool& mempool, const uint256& snapshot_blockhash) | |
+ CChainState& ChainstateManager::InitializeChainstate(CTxMemPool& mempool, const std::optional<uint256>& snapshot_blockhash) | |
{ | |
- bool is_snapshot = !snapshot_blockhash.IsNull(); | |
+ bool is_snapshot = snapshot_blockhash.has_value(); | |
diff --git a/src/validation.h b/src/validation.h | |
--- a/src/validation.h | |
11: 4dce8a304 ! 14: cb5f5b7d9 p2p: don't advertise until we finish all IBDs | |
@@ -24,7 +24,7 @@ | |
// | |
// We skip this for block-relay-only peers to avoid potentially leaking | |
// information about our block-relay-only connections via address relay. | |
-- if (fListen && !::ChainstateActive().IsInitialBlockDownload()) | |
+- if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) | |
+ if (fListen && !is_ibd) | |
{ | |
CAddress addr = GetLocalAddress(&pfrom.addr, pfrom.GetLocalServices()); | |
@@ -33,27 +33,31 @@ | |
} | |
LOCK(cs_main); | |
-- if (::ChainstateActive().IsInitialBlockDownload() && !pfrom.HasPermission(PF_DOWNLOAD)) { | |
-+ if (g_chainman.IsAnyChainInIBD() && !pfrom.HasPermission(PF_DOWNLOAD)) { | |
+- if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !pfrom.HasPermission(NetPermissionFlags::Download)) { | |
++ if (g_chainman.IsAnyChainInIBD() && !pfrom.HasPermission(NetPermissionFlags::Download)) { | |
LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom.GetId()); | |
return; | |
} | |
@@ | |
- // Address refresh broadcast | |
- auto current_time = GetTime<std::chrono::microseconds>(); | |
+ if (!RelayAddrsWithPeer(peer)) return; | |
-- if (pto->RelayAddrsWithConn() && !::ChainstateActive().IsInitialBlockDownload() && pto->m_next_local_addr_send < current_time) { | |
-+ if (pto->RelayAddrsWithConn() && !g_chainman.IsAnyChainInIBD() && pto->m_next_local_addr_send < current_time) { | |
- // If we've sent before, clear the bloom filter for the peer, so that our | |
- // self-announcement will actually go out. | |
- // This might be unnecessary if the bloom filter has already rolled | |
+ LOCK(peer.m_addr_send_times_mutex); | |
++ bool is_ibd = WITH_LOCK(::cs_main, return m_chainman.IsAnyChainInIBD()); | |
++ | |
+ // Periodically advertise our local address to the peer. | |
+- if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() && | |
+- peer.m_next_local_addr_send < current_time) { | |
++ if (fListen && !is_ibd && peer.m_next_local_addr_send < current_time) { | |
+ // If we've sent before, clear the bloom filter for the peer, so that our | |
+ // self-announcement will actually go out. | |
+ // This might be unnecessary if the bloom filter has already rolled | |
diff --git a/src/validation.cpp b/src/validation.cpp | |
--- a/src/validation.cpp | |
+++ b/src/validation.cpp | |
@@ | |
- | |
- return au_data->nChainTx; | |
+ } | |
+ return (*base)->nHeight; | |
} | |
+ | |
+bool ChainstateManager::IsAnyChainInIBD() | |
12: 0e299eb49 ! 15: 7e59aaad1 init: fix up for multiple chainstates | |
@@ -1,9 +1,6 @@ | |
Author: James O'Beirne <james.obeirne@gmail.com> | |
- init: fix up for multiple chainstates | |
- | |
- TODO: maybe separate out snapshot chainstate init detection into a separate | |
- commit? | |
+ add utxo snapshot detection and add to init | |
diff --git a/src/init.cpp b/src/init.cpp | |
--- a/src/init.cpp | |
@@ -25,20 +22,11 @@ | |
@@ | |
UnregisterAllValidationInterfaces(); | |
GetMainSignals().UnregisterBackgroundSignalScheduler(); | |
- globalVerifyHandle.reset(); | |
+ init::UnsetGlobals(); | |
+ WITH_LOCK(::cs_main, g_chainman.Reset()); | |
- ECC_Stop(); | |
node.mempool.reset(); | |
node.fee_estimator.reset(); | |
-@@ | |
- // the relevant pointers before the ABC call. | |
- for (CChainState* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { | |
- BlockValidationState state; | |
-- if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) { | |
-+ if (!chainstate->ActivateBestChain(state, chainparams)) { | |
- LogPrintf("Failed to connect best block (%s)\n", state.ToString()); | |
- StartShutdown(); | |
- return; | |
+ node.chainman = nullptr; | |
@@ | |
const int64_t load_block_index_start_time = GetTimeMillis(); | |
try { | |
@@ -117,8 +105,8 @@ | |
#include <flatfile.h> | |
+#include <fs.h> | |
#include <hash.h> | |
+ #include <index/blockfilterindex.h> | |
#include <index/txindex.h> | |
- #include <logging.h> | |
@@ | |
} | |
return false; | |
@@ -128,7 +116,7 @@ | |
+{ | |
+ constexpr int SNAPSHOT_NAME_LEN = 75; // "chainstate_" + 64 hex characters for blockhash. | |
+ | |
-+ for (fs::directory_iterator it(GetDataDir()); it != fs::directory_iterator(); it++) { | |
++ for (fs::directory_iterator it(gArgs.GetDataDirNet()); it != fs::directory_iterator(); it++) { | |
+ if (fs::is_directory(*it) && | |
+ !fs::is_empty(*it) && | |
+ it->path().filename().string().length() == SNAPSHOT_NAME_LEN && | |
13: 3b9385fcf ! 16: 9286ce21d validation: add ChainstateManager logic for completing UTXO snapshot validation | |
@@ -55,14 +55,6 @@ | |
} | |
} | |
::pblocktree.reset(); | |
-@@ | |
- GetMainSignals().UnregisterBackgroundSignalScheduler(); | |
- globalVerifyHandle.reset(); | |
- WITH_LOCK(::cs_main, g_chainman.Reset()); | |
-+ | |
- ECC_Stop(); | |
- node.mempool.reset(); | |
- node.fee_estimator.reset(); | |
@@ | |
break; // out of the chainstate activation do-while | |
} | |
@@ -105,11 +97,11 @@ | |
+ // time we compare the UTXO set hash to the base of our active snapshot. | |
+ // | |
+ if (g_chainman.IsBackgroundIBD(this)) { | |
-+ if (pindexNew->nHeight > g_chainman.SnapshotHeight()) { | |
++ if (pindexNew->nHeight > g_chainman.GetSnapshotHeight()) { | |
+ // TODO jamesob: better handling? | |
+ LogPrintf("[snapshot] something is wrong! validation chain " /* Continued */ | |
+ "should not have continued past the snapshot origin\n"); | |
-+ } else if (pindexNew->nHeight == g_chainman.SnapshotHeight()) { | |
++ } else if (pindexNew->nHeight == g_chainman.GetSnapshotHeight()) { | |
+ // This may set `m_stop_use`. | |
+ g_chainman.CompleteSnapshotValidation(this); | |
+ } | |
@@ -151,15 +143,6 @@ | |
// Write changes periodically to disk, after relay. | |
if (!FlushStateToDisk(chainparams, state, FlushStateMode::PERIODIC)) { | |
return false; | |
-@@ | |
- return std::min<double>(pindex->nChainTx / fTxTotal, 1.0); | |
- } | |
- | |
--Optional<uint256> ChainstateManager::SnapshotBlockhash() const { | |
-+std::optional<uint256> ChainstateManager::SnapshotBlockhash() const { | |
- LOCK(::cs_main); | |
- if (m_active_chainstate != nullptr && | |
- !m_active_chainstate->m_from_snapshot_blockhash.IsNull()) { | |
@@ | |
return true; | |
} | |
@@ -174,10 +157,10 @@ | |
+ CCoinsViewDB& ibd_coins_db = validation_chainstate->CoinsDB(); | |
+ validation_chainstate->ForceFlushStateToDisk(); | |
+ | |
-+ CCoinsStats ibd_stats; | |
++ CCoinsStats ibd_stats{CoinStatsHashType::HASH_SERIALIZED}; | |
+ auto breakpoint_fnc = [] { /* TODO insert breakpoint here? */ }; | |
+ | |
-+ if (!GetUTXOStats(&ibd_coins_db, ibd_stats, CoinStatsHashType::HASH_SERIALIZED, breakpoint_fnc)) { | |
++ if (!GetUTXOStats(&ibd_coins_db, WITH_LOCK(::cs_main, return std::ref(m_blockman)), ibd_stats, breakpoint_fnc)) { | |
+ LogPrintf("[snapshot] failed to generate stats for validation coins db\n"); | |
+ return false; | |
+ } | |
@@ -208,15 +191,15 @@ | |
+ // TODO: For belt-and-suspenders, we should cache an obfuscated version of the UTXO set | |
+ // hash for the snapshot when it's loaded in its chainstate's leveldb. We should then | |
+ // reference that here for an additional check. | |
-+ if (ibd_stats.hashSerialized != au_data.hash_serialized) { | |
++ if (AssumeutxoHash{ibd_stats.hashSerialized} != au_data.hash_serialized) { | |
+ LogPrintf("[snapshot] hash mismatch: actual=%s, expected=%s\n", | |
+ ibd_stats.hashSerialized.ToString(), | |
+ expected_contents_hash.ToString()); | |
+ snapshot_invalid = true; | |
+ } | |
-+ if (validation_chainstate->m_chain.Height() != SnapshotHeight()) { | |
++ if (validation_chainstate->m_chain.Height() != GetSnapshotHeight()) { | |
+ LogPrintf("[snapshot] height mismatch: actual=%d expected=%d\n", | |
-+ validation_chainstate->m_chain.Height(), SnapshotHeight()); | |
++ validation_chainstate->m_chain.Height(), GetSnapshotHeight().value_or(-1)); | |
+ snapshot_invalid = true; | |
+ } | |
+ | |
@@ -313,28 +296,13 @@ | |
+ if (!(m_snapshot_chainstate && m_ibd_chainstate)) { | |
+ return; | |
+ } | |
-+ if (m_ibd_chainstate->m_chain.Height() != this->SnapshotHeight()) { | |
++ if (m_ibd_chainstate->m_chain.Height() != this->GetSnapshotHeight()) { | |
+ return; | |
+ } | |
+ LogPrintf( | |
+ "[snapshot] unclean shutdown detected - background validation chain needs to " /* Continued */ | |
+ "be checked against the loaded snapshot and cleaned up.\n"); | |
+ this->CompleteSnapshotValidation(m_ibd_chainstate.get()); | |
-+} | |
-+ | |
-+std::optional<unsigned int> ChainstateManager::GetSnapshotNChainTx() | |
-+{ | |
-+ auto height = this->SnapshotHeight(); | |
-+ if (height == -1) { | |
-+ return std::nullopt; | |
-+ } | |
-+ | |
-+ auto au_data = ExpectedAssumeutxo(height, ::Params()); | |
-+ if (!au_data) { | |
-+ return std::nullopt; | |
-+ } | |
-+ | |
-+ return au_data->nChainTx; | |
+} | |
diff --git a/src/validation.h b/src/validation.h | |
@@ -375,8 +343,8 @@ | |
+ void ValidatedSnapshotShutdownCleanup(fs::path new_chainstate, fs::path old_chainstate); | |
+ | |
public: | |
+ std::thread m_load_block; | |
//! A single BlockManager instance is shared across each constructed | |
- //! chainstate to avoid duplicating block metadata. | |
@@ | |
[[nodiscard]] bool ActivateSnapshot( | |
CAutoFile& coins_file, const SnapshotMetadata& metadata, bool in_memory); | |
@@ -395,31 +363,6 @@ | |
//! | |
//! Because the use of UTXO snapshots requires the simultaneous maintenance | |
@@ | |
- | |
- bool IsSnapshotActive() const; | |
- | |
-- Optional<uint256> SnapshotBlockhash() const; | |
-+ std::optional<uint256> SnapshotBlockhash() const; | |
-+ | |
-+ CBlockIndex* SnapshotBaseBlock() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) | |
-+ { | |
-+ auto blockhash_op = SnapshotBlockhash(); | |
-+ if (!blockhash_op) { | |
-+ return nullptr; | |
-+ } | |
-+ return m_blockman.LookupBlockIndex(*blockhash_op); | |
-+ } | |
-+ | |
-+ //! @returns height at which the active UTXO snapshot was taken. | |
-+ int SnapshotHeight() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) | |
-+ { | |
-+ CBlockIndex* base = SnapshotBaseBlock(); | |
-+ return base ? base->nHeight : -1; | |
-+ } | |
- | |
- CBlockIndex* SnapshotBaseBlock() EXCLUSIVE_LOCKS_REQUIRED(::cs_main) | |
- { | |
-@@ | |
void Unload() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
//! Clear (deconstruct) chainstate data. | |
14: 330d6fb61 = 17: adb04416f doc: add note about snapshots and index building | |
15: a3695d8e2 ! 18: ff1fdff42 validation: pruning for multiple chainstates | |
@@ -9,8 +9,8 @@ | |
} else { | |
LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH); | |
-- m_blockman.FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight(), m_chain.Height(), IsInitialBlockDownload()); | |
-+ m_blockman.FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight()); | |
+- m_blockman.FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight(), m_chain.Height(), last_prune, IsInitialBlockDownload()); | |
++ m_blockman.FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight(), last_prune); | |
fCheckForPruning = false; | |
} | |
if (!setFilesToPrune.empty()) { | |
@@ -42,10 +42,7 @@ | |
+ nManualPruneHeight, | |
+ // TODO jamesob: is this an off-by-one? | |
+ chainstate->m_chain.Height() - 1); | |
- } | |
-- PruneOneBlockFile(fileNumber); | |
-- setFilesToPrune.insert(fileNumber); | |
-- count++; | |
++ } | |
+ | |
+ // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip) | |
+ | |
@@ -59,7 +56,10 @@ | |
+ PruneOneBlockFile(fileNumber); | |
+ setFilesToPrune.insert(fileNumber); | |
+ count++; | |
-+ } | |
+ } | |
+- PruneOneBlockFile(fileNumber); | |
+- setFilesToPrune.insert(fileNumber); | |
+- count++; | |
+ LogPrintf("Prune (Manual) (%s): prune_height=%d removed %d blk/rev pairs\n", | |
+ chainstate->ToString(), nLastBlockWeCanPrune, count); | |
} | |
@@ -71,8 +71,8 @@ | |
} | |
} | |
--void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, bool is_ibd) | |
-+void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight) | |
+-void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd) | |
++void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int prune_height) | |
{ | |
LOCK2(cs_main, cs_LastBlockFile); | |
- if (chain_tip_height < 0 || nPruneTarget == 0) { | |
@@ -83,7 +83,7 @@ | |
- return; | |
- } | |
- | |
-- unsigned int nLastBlockWeCanPrune = chain_tip_height - MIN_BLOCKS_TO_KEEP; | |
+- unsigned int nLastBlockWeCanPrune = std::min(prune_height, chain_tip_height - static_cast<int>(MIN_BLOCKS_TO_KEEP)); | |
- uint64_t nCurrentUsage = CalculateCurrentUsage(); | |
- // We don't check to prune until after we've allocated new space for files | |
- // So we should leave a buffer under our target to account for another allocation | |
@@ -108,7 +108,8 @@ | |
- for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { | |
- nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; | |
-+ unsigned int nLastBlockWeCanPrune = height - MIN_BLOCKS_TO_KEEP; | |
++ unsigned int nLastBlockWeCanPrune = | |
++ std::min(prune_height, static_cast<int>(height) - static_cast<int>(MIN_BLOCKS_TO_KEEP)); | |
+ // Depending on which chainstate we're pruning, we may have a differet | |
+ // start height. | |
+ unsigned int start_height = g_chainman.PruneStartHeight(chainstate); | |
@@ -192,10 +193,10 @@ | |
+ } | |
} | |
- static FlatFileSeq BlockFileSeq() | |
+ CBlockIndex * BlockManager::InsertBlockIndex(const uint256& hash) | |
@@ | |
- | |
- return au_data->nChainTx; | |
+ "be checked against the loaded snapshot and cleaned up.\n"); | |
+ this->CompleteSnapshotValidation(m_ibd_chainstate.get()); | |
} | |
+ | |
+unsigned int ChainstateManager::PruneStartHeight(CChainState* chainstate) | |
@@ -213,8 +214,8 @@ | |
* | |
* @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned | |
*/ | |
-- void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, bool is_ibd); | |
-+ void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight); | |
+- void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd); | |
++ void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int prune_height); | |
public: | |
BlockMap m_block_index GUARDED_BY(cs_main); | |
@@ -229,9 +230,9 @@ | |
bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
@@ | |
- //! Return the cached nChainTx value for the snapshot (per the chainparams assumeutxo data), | |
- //! if one exists | |
- std::optional<unsigned int> GetSnapshotNChainTx() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
+ | |
+ //! @returns height at which the active UTXO snapshot was taken, if a snapshot is being used. | |
+ std::optional<int> GetSnapshotHeight() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |
+ | |
+ //! If we're pruning the snapshot chainstate, be sure not to | |
+ //! step on the toes of the background validation by pruning blocks it | |
16: b2caf2a04 ! 19: ac2ae19c7 doc: misc. validation doc updates | |
@@ -12,15 +12,16 @@ | |
- // Check whether ::ChainActive() is an extension of the block at which the LockPoints | |
+ // Check whether the active chain is an extension of the block at which the LockPoints | |
// calculation was valid. If not LockPoints are no longer valid | |
- if (!::ChainActive().Contains(lp->maxInputBlock)) { | |
- return false; | |
+ assert(std::addressof(::ChainActive()) == std::addressof(active_chain)); | |
+ if (!active_chain.Contains(lp->maxInputBlock)) { | |
@@ | |
lockPair.second = lp->time; | |
} | |
else { | |
-- // CoinsTip() contains the UTXO set for ::ChainActive().Tip() | |
+- // CoinsTip() contains the UTXO set for active_chainstate.m_chain.Tip() | |
++ // CoinsTip() contains the UTXO set for active_chainstate.m_chain.Tip(). | |
+ // Since this function is only used for mempool maintenance, we don't | |
+ // need to be concerned with parameterizing the UTXO set. | |
- CCoinsViewMemPool viewMemPool(&::ChainstateActive().CoinsTip(), pool); | |
+ CCoinsViewMemPool viewMemPool(&active_chainstate.CoinsTip(), pool); | |
std::vector<int> prevheights; | |
prevheights.resize(tx.vin.size()); | |
17: 518d19eb7 ! 20: 51f4f8a41 validation: only clean up mempool for active chainstate | |
@@ -21,4 +21,4 @@ | |
+ | |
// Update m_chain & related variables. | |
m_chain.SetTip(pindexNew); | |
- UpdateTip(m_mempool, pindexNew, chainparams, CoinsTip()); | |
+ UpdateTip(m_mempool, pindexNew, chainparams, *this); | |
18: 1d50b301a = 21: 192c3e302 validation: run CheckBlockIndex on all chainstates during ProcessNewHeaders | |
19: c0028e509 = 22: 59472e816 validation: annotation for LoadBlockIndex holding cs_main | |
20: 3e040cc70 = 23: 7c4a91d61 validation: LoadExternalBlockFile comment and chainstate prefix | |
21: 5586e2dee < -: --------- doc: add some minor CChainState doc | |
-: --------- > 24: ce02daa33 doc: add some minor CChainState doc | |
22: 8154db090 = 25: b1b007f8d rpc: add monitorsnapshot | |
23: ee29a7f31 = 26: 89ed062d9 dumptxoutset: add assumeutxo key to output | |
24: 29387bab2 < -: --------- validation: add logging for background validation in UpdateTip | |
25: 285d5dd3e < -: --------- fixup: don't flush if nothing to flush | |
-: --------- > 27: 1b6eea1fd validation: add logging for background validation in UpdateTip | |
-: --------- > 28: eb1c1eefc fixup: don't flush if nothing to flush |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment