Skip to content

Commit 94a98fb

Browse files
committed
assumeutxo cleanup: Move IsInitialBlockDownload & NotifyHeaderTip to ChainstateManager
This change makes IsInitialBlockDownload and NotifyHeaderTip functions no longer tied to individual Chainstate objects. It makes them work with the ChainstateManager object instead so code is simpler and it is no longer possible to call them incorrectly with an inactive Chainstate. This change also makes m_cached_finished_ibd caching easier to reason about, because now there is only one cached value instead of two (for background and snapshot chainstates) so the cached IBD state now no longer gets reset when a snapshot is loaded. There should be no change in behavior because these functions were always called on the active ChainState objects. These changes were discussed previously bitcoin/bitcoin#27746 (comment) and bitcoin/bitcoin#27746 (comment) as possible followups for that PR.
1 parent 9b066da commit 94a98fb

14 files changed

+79
-66
lines changed

src/bitcoin-chainstate.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ int main(int argc, char* argv[])
163163
<< "\t" << "Reindexing: " << std::boolalpha << node::fReindex.load() << std::noboolalpha << std::endl
164164
<< "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
165165
<< "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
166-
<< "\t" << "Active IBD: " << std::boolalpha << chainman.ActiveChainstate().IsInitialBlockDownload() << std::noboolalpha << std::endl;
166+
<< "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;
167167
CBlockIndex* tip = chainman.ActiveTip();
168168
if (tip) {
169169
std::cout << "\t" << tip->ToString() << std::endl;

src/net_processing.cpp

+8-8
Original file line numberDiff line numberDiff line change
@@ -2010,7 +2010,7 @@ void PeerManagerImpl::BlockChecked(const CBlock& block, const BlockValidationSta
20102010
// the tip yet so we have no way to check this directly here. Instead we
20112011
// just check that there are currently no other blocks in flight.
20122012
else if (state.IsValid() &&
2013-
!m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
2013+
!m_chainman.IsInitialBlockDownload() &&
20142014
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
20152015
if (it != mapBlockSource.end()) {
20162016
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
@@ -2729,7 +2729,7 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, Peer& peer
27292729

27302730
// If we're in IBD, we want outbound peers that will serve us a useful
27312731
// chain. Disconnect peers that are on chains with insufficient work.
2732-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !may_have_more_headers) {
2732+
if (m_chainman.IsInitialBlockDownload() && !may_have_more_headers) {
27332733
// If the peer has no more headers to give us, then we know we have
27342734
// their tip.
27352735
if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < m_chainman.MinimumChainWork()) {
@@ -3808,7 +3808,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
38083808
LogPrint(BCLog::NET, "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());
38093809

38103810
AddKnownTx(*peer, inv.hash);
3811-
if (!fAlreadyHave && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
3811+
if (!fAlreadyHave && !m_chainman.IsInitialBlockDownload()) {
38123812
AddTxAnnouncement(pfrom, gtxid, current_time);
38133813
}
38143814
} else {
@@ -4080,7 +4080,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
40804080
// Stop processing the transaction early if we are still in IBD since we don't
40814081
// have enough information to validate it yet. Sending unsolicited transactions
40824082
// is not considered a protocol violation, so don't punish the peer.
4083-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) return;
4083+
if (m_chainman.IsInitialBlockDownload()) return;
40844084

40854085
CTransactionRef ptx;
40864086
vRecv >> ptx;
@@ -4284,7 +4284,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
42844284
const CBlockIndex* prev_block = m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock);
42854285
if (!prev_block) {
42864286
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
4287-
if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
4287+
if (!m_chainman.IsInitialBlockDownload()) {
42884288
MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer);
42894289
}
42904290
return;
@@ -5228,7 +5228,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
52285228

52295229
LOCK(peer.m_addr_send_times_mutex);
52305230
// Periodically advertise our local address to the peer.
5231-
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
5231+
if (fListen && !m_chainman.IsInitialBlockDownload() &&
52325232
peer.m_next_local_addr_send < current_time) {
52335233
// If we've sent before, clear the bloom filter for the peer, so that our
52345234
// self-announcement will actually go out.
@@ -5323,7 +5323,7 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::mi
53235323
CAmount currentFilter = m_mempool.GetMinFee().GetFeePerK();
53245324
static FeeFilterRounder g_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}};
53255325

5326-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
5326+
if (m_chainman.IsInitialBlockDownload()) {
53275327
// Received tx-inv messages are discarded when the active
53285328
// chainstate is in IBD, so tell the peer to not send them.
53295329
currentFilter = MAX_MONEY;
@@ -5827,7 +5827,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
58275827
// Message: getdata (blocks)
58285828
//
58295829
std::vector<CInv> vGetData;
5830-
if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
5830+
if (CanServeBlocks(*peer) && ((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) || !m_chainman.IsInitialBlockDownload()) && state.vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
58315831
std::vector<const CBlockIndex*> vToDownload;
58325832
NodeId staller = -1;
58335833
FindNextBlocksToDownload(*peer, MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.vBlocksInFlight.size(), vToDownload, staller);

src/node/interfaces.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,9 @@ class NodeImpl : public Node
298298
{
299299
return GuessVerificationProgress(chainman().GetParams().TxData(), WITH_LOCK(::cs_main, return chainman().ActiveChain().Tip()));
300300
}
301-
bool isInitialBlockDownload() override {
302-
return chainman().ActiveChainstate().IsInitialBlockDownload();
301+
bool isInitialBlockDownload() override
302+
{
303+
return chainman().IsInitialBlockDownload();
303304
}
304305
bool isLoadingBlocks() override { return chainman().m_blockman.LoadingBlocks(); }
305306
void setNetworkActive(bool active) override
@@ -720,7 +721,7 @@ class ChainImpl : public Chain
720721
bool isReadyToBroadcast() override { return !chainman().m_blockman.LoadingBlocks() && !isInitialBlockDownload(); }
721722
bool isInitialBlockDownload() override
722723
{
723-
return chainman().ActiveChainstate().IsInitialBlockDownload();
724+
return chainman().IsInitialBlockDownload();
724725
}
725726
bool shutdownRequested() override { return ShutdownRequested(); }
726727
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }

src/rpc/blockchain.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ RPCHelpMan getblockchaininfo()
12601260
obj.pushKV("time", tip.GetBlockTime());
12611261
obj.pushKV("mediantime", tip.GetMedianTimePast());
12621262
obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1263-
obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
1263+
obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
12641264
obj.pushKV("chainwork", tip.nChainWork.GetHex());
12651265
obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
12661266
obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());

src/rpc/mempool.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -752,9 +752,10 @@ static RPCHelpMan importmempool()
752752
const NodeContext& node{EnsureAnyNodeContext(request.context)};
753753

754754
CTxMemPool& mempool{EnsureMemPool(node)};
755-
Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
755+
ChainstateManager& chainman = EnsureChainman(node);
756+
Chainstate& chainstate = chainman.ActiveChainstate();
756757

757-
if (chainstate.IsInitialBlockDownload()) {
758+
if (chainman.IsInitialBlockDownload()) {
758759
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
759760
}
760761

src/rpc/mining.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ static RPCHelpMan getblocktemplate()
706706
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
707707
}
708708

709-
if (active_chainstate.IsInitialBlockDownload()) {
709+
if (chainman.IsInitialBlockDownload()) {
710710
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
711711
}
712712
}

src/test/fuzz/process_message.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ FUZZ_TARGET(process_message, .init = initialize_process_message)
6363
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
6464

6565
ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
66-
TestChainState& chainstate = *static_cast<TestChainState*>(&g_setup->m_node.chainman->ActiveChainstate());
66+
auto& chainman = static_cast<TestChainstateManager&>(*g_setup->m_node.chainman);
6767
SetMockTime(1610000000); // any time to successfully reset ibd
68-
chainstate.ResetIbd();
68+
chainman.ResetIbd();
6969

7070
LOCK(NetEventsInterface::g_msgproc_mutex);
7171

src/test/fuzz/process_messages.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ FUZZ_TARGET(process_messages, .init = initialize_process_messages)
3838
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
3939

4040
ConnmanTestMsg& connman = *static_cast<ConnmanTestMsg*>(g_setup->m_node.connman.get());
41-
TestChainState& chainstate = *static_cast<TestChainState*>(&g_setup->m_node.chainman->ActiveChainstate());
41+
auto& chainman = static_cast<TestChainstateManager&>(*g_setup->m_node.chainman);
4242
SetMockTime(1610000000); // any time to successfully reset ibd
43-
chainstate.ResetIbd();
43+
chainman.ResetIbd();
4444

4545
LOCK(NetEventsInterface::g_msgproc_mutex);
4646

src/test/net_tests.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -841,11 +841,10 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
841841
const int64_t time{0};
842842
const CNetMsgMaker msg_maker{PROTOCOL_VERSION};
843843

844-
// Force Chainstate::IsInitialBlockDownload() to return false.
844+
// Force ChainstateManager::IsInitialBlockDownload() to return false.
845845
// Otherwise PushAddress() isn't called by PeerManager::ProcessMessage().
846-
TestChainState& chainstate =
847-
*static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate());
848-
chainstate.JumpOutOfIbd();
846+
auto& chainman = static_cast<TestChainstateManager&>(*m_node.chainman);
847+
chainman.JumpOutOfIbd();
849848

850849
m_node.peerman->InitializeNode(peer, NODE_NETWORK);
851850

@@ -895,7 +894,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message)
895894
BOOST_CHECK(sent);
896895

897896
CaptureMessage = CaptureMessageOrig;
898-
chainstate.ResetIbd();
897+
chainman.ResetIbd();
899898
m_node.args->ForceSetArg("-capturemessages", "0");
900899
m_node.args->ForceSetArg("-bind", "");
901900
// PeerManager::ProcessMessage() calls AddTimeData() which changes the internal state

src/test/util/validation.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
#include <validation.h>
1010
#include <validationinterface.h>
1111

12-
void TestChainState::ResetIbd()
12+
void TestChainstateManager::ResetIbd()
1313
{
1414
m_cached_finished_ibd = false;
1515
assert(IsInitialBlockDownload());
1616
}
1717

18-
void TestChainState::JumpOutOfIbd()
18+
void TestChainstateManager::JumpOutOfIbd()
1919
{
2020
Assert(IsInitialBlockDownload());
2121
m_cached_finished_ibd = true;

src/test/util/validation.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
class CValidationInterface;
1111

12-
struct TestChainState : public Chainstate {
12+
struct TestChainstateManager : public ChainstateManager {
1313
/** Reset the ibd cache to its initial state */
1414
void ResetIbd();
1515
/** Toggle IsInitialBlockDownload from true to false */

src/test/validation_chainstatemanager_tests.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <test/util/logging.h>
1414
#include <test/util/random.h>
1515
#include <test/util/setup_common.h>
16+
#include <test/util/validation.h>
1617
#include <timedata.h>
1718
#include <uint256.h>
1819
#include <validation.h>
@@ -143,14 +144,21 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup)
143144
c2.InitCoinsDB(
144145
/*cache_size_bytes=*/1 << 23, /*in_memory=*/true, /*should_wipe=*/false);
145146

147+
// Reset IBD state so IsInitialBlockDownload() returns true and causes
148+
// MaybeRebalancesCaches() to prioritize the snapshot chainstate, giving it
149+
// more cache space than the snapshot chainstate. Calling ResetIbd() is
150+
// necessary because m_cached_finished_ibd is already latched to true before
151+
// the test starts due to the test setup. After ResetIbd() is called.
152+
// IsInitialBlockDownload will return true because at this point the active
153+
// chainstate has a null chain tip.
154+
static_cast<TestChainstateManager&>(manager).ResetIbd();
155+
146156
{
147157
LOCK(::cs_main);
148158
c2.InitCoinsCache(1 << 23);
149159
manager.MaybeRebalanceCaches();
150160
}
151161

152-
// Since both chainstates are considered to be in initial block download,
153-
// the snapshot chainstate should take priority.
154162
BOOST_CHECK_CLOSE(c1.m_coinstip_cache_size_bytes, max_cache * 0.05, 1);
155163
BOOST_CHECK_CLOSE(c1.m_coinsdb_cache_size_bytes, max_cache * 0.05, 1);
156164
BOOST_CHECK_CLOSE(c2.m_coinstip_cache_size_bytes, max_cache * 0.95, 1);

0 commit comments

Comments
 (0)