Skip to content

Commit db526ab

Browse files
ryanofskyPiRK
authored andcommitted
assumeutxo cleanup: Move IsInitialBlockDownload & NotifyHeaderTip to ChainstateManager
Summary: 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. This is a backport of [[bitcoin/bitcoin#28218 | core#28218]] Depends on D17605 Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D17635
1 parent 1b64fae commit db526ab

File tree

12 files changed

+82
-78
lines changed

12 files changed

+82
-78
lines changed

src/avalanche/processor.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ bool Processor::stopEventLoop() {
777777
void Processor::avaproofsSent(NodeId nodeid) {
778778
AssertLockNotHeld(cs_main);
779779

780-
if (chainman.ActiveChainstate().IsInitialBlockDownload()) {
780+
if (chainman.IsInitialBlockDownload()) {
781781
// Before IBD is complete there is no way to make sure a proof is valid
782782
// or not, e.g. it can be spent in a block we don't know yet. In order
783783
// to increase confidence that our proof set is similar to other nodes
@@ -822,7 +822,7 @@ bool Processor::isQuorumEstablished() {
822822
}
823823

824824
// Don't do Avalanche while node is IBD'ing
825-
if (chainman.ActiveChainstate().IsInitialBlockDownload()) {
825+
if (chainman.IsInitialBlockDownload()) {
826826
return false;
827827
}
828828

src/bitcoin-chainstate.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ int main(int argc, char *argv[]) {
175175
<< "Active Height: " << chainman.ActiveHeight() << std::endl
176176
<< "\t"
177177
<< "Active IBD: " << std::boolalpha
178-
<< chainman.ActiveChainstate().IsInitialBlockDownload()
179-
<< std::noboolalpha << std::endl;
178+
<< chainman.IsInitialBlockDownload() << std::noboolalpha
179+
<< std::endl;
180180
CBlockIndex *tip = chainman.ActiveTip();
181181
if (tip) {
182182
std::cout << "\t" << tip->ToString() << std::endl;

src/net_processing.cpp

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2453,7 +2453,7 @@ void PeerManagerImpl::AvalanchePeriodicNetworking(CScheduler &scheduler) const {
24532453
}
24542454
}
24552455

2456-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
2456+
if (m_chainman.IsInitialBlockDownload()) {
24572457
// Don't request proofs while in IBD. We're likely to orphan them
24582458
// because we don't have the UTXOs.
24592459
goto scheduleLater;
@@ -3081,8 +3081,7 @@ void PeerManagerImpl::BlockChecked(const CBlock &block,
30813081
// 3. This is currently the best block we're aware of. We haven't updated
30823082
// the tip yet so we have no way to check this directly here. Instead we
30833083
// just check that there are currently no other blocks in flight.
3084-
else if (state.IsValid() &&
3085-
!m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
3084+
else if (state.IsValid() && !m_chainman.IsInitialBlockDownload() &&
30863085
mapBlocksInFlight.count(hash) == mapBlocksInFlight.size()) {
30873086
if (it != mapBlockSource.end()) {
30883087
MaybeSetPeerAsAnnouncingHeaderAndIDs(it->second.first);
@@ -4057,8 +4056,7 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(
40574056

40584057
// If we're in IBD, we want outbound peers that will serve us a useful
40594058
// chain. Disconnect peers that are on chains with insufficient work.
4060-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
4061-
!may_have_more_headers) {
4059+
if (m_chainman.IsInitialBlockDownload() && !may_have_more_headers) {
40624060
// When nCount < MAX_HEADERS_RESULTS, we know we have no more
40634061
// headers to fetch from this peer.
40644062
if (nodestate->pindexBestKnownBlock &&
@@ -5380,7 +5378,7 @@ void PeerManagerImpl::ProcessMessage(
53805378
AddKnownProof(*peer, proofid);
53815379

53825380
if (!fAlreadyHave && m_avalanche &&
5383-
!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
5381+
!m_chainman.IsInitialBlockDownload()) {
53845382
const bool preferred = isPreferredDownloadPeer(pfrom);
53855383

53865384
LOCK(cs_proofrequest);
@@ -5405,8 +5403,8 @@ void PeerManagerImpl::ProcessMessage(
54055403
txid.ToString(), pfrom.GetId());
54065404
pfrom.fDisconnect = true;
54075405
return;
5408-
} else if (!fAlreadyHave && !m_chainman.ActiveChainstate()
5409-
.IsInitialBlockDownload()) {
5406+
} else if (!fAlreadyHave &&
5407+
!m_chainman.IsInitialBlockDownload()) {
54105408
AddTxAnnouncement(pfrom, txid, current_time);
54115409
}
54125410

@@ -5747,7 +5745,7 @@ void PeerManagerImpl::ProcessMessage(
57475745
// don't have enough information to validate it yet. Sending unsolicited
57485746
// transactions is not considered a protocol violation, so don't punish
57495747
// the peer.
5750-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
5748+
if (m_chainman.IsInitialBlockDownload()) {
57515749
return;
57525750
}
57535751

@@ -6024,7 +6022,7 @@ void PeerManagerImpl::ProcessMessage(
60246022
if (!prev_block) {
60256023
// Doesn't connect (or is genesis), instead of DoSing in
60266024
// AcceptBlockHeader, request deeper headers
6027-
if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
6025+
if (!m_chainman.IsInitialBlockDownload()) {
60286026
MaybeSendGetHeaders(
60296027
pfrom, GetLocator(m_chainman.m_best_header), *peer);
60306028
}
@@ -6516,9 +6514,8 @@ void PeerManagerImpl::ProcessMessage(
65166514
// unless we're still syncing with the network. Such an unrequested
65176515
// block may still be processed, subject to the conditions in
65186516
// AcceptBlock().
6519-
bool forceProcessing =
6520-
pfrom.HasPermission(NetPermissionFlags::NoBan) &&
6521-
!m_chainman.ActiveChainstate().IsInitialBlockDownload();
6517+
bool forceProcessing = pfrom.HasPermission(NetPermissionFlags::NoBan) &&
6518+
!m_chainman.IsInitialBlockDownload();
65226519
const BlockHash hash = pblock->GetHash();
65236520
bool min_pow_checked = false;
65246521
{
@@ -6618,8 +6615,7 @@ void PeerManagerImpl::ProcessMessage(
66186615
WITH_LOCK(peer->m_addr_token_bucket_mutex,
66196616
peer->m_addr_token_bucket += m_opts.max_addr_to_send);
66206617

6621-
if (peer->m_proof_relay &&
6622-
!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
6618+
if (peer->m_proof_relay && !m_chainman.IsInitialBlockDownload()) {
66236619
m_connman.PushMessage(&pfrom,
66246620
msgMaker.Make(NetMsgType::GETAVAPROOFS));
66256621
peer->m_proof_relay->compactproofs_requested = true;
@@ -8180,7 +8176,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode &node, Peer &peer,
81808176
}
81818177

81828178
LOCK(peer.m_addr_send_times_mutex);
8183-
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload() &&
8179+
if (fListen && !m_chainman.IsInitialBlockDownload() &&
81848180
peer.m_next_local_addr_send < current_time) {
81858181
// If we've sent before, clear the bloom filter for the peer, so
81868182
// that our self-announcement will actually go out. This might
@@ -8300,7 +8296,7 @@ void PeerManagerImpl::MaybeSendFeefilter(
83008296

83018297
Amount currentFilter = m_mempool.GetMinFee().GetFeePerK();
83028298

8303-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
8299+
if (m_chainman.IsInitialBlockDownload()) {
83048300
// Received tx-inv messages are discarded when the active
83058301
// chainstate is in IBD, so tell the peer to not send them.
83068302
currentFilter = MAX_MONEY;
@@ -9003,7 +8999,7 @@ bool PeerManagerImpl::SendMessages(const Config &config, CNode *pto) {
90038999

90049000
if (CanServeBlocks(*peer) &&
90059001
((sync_blocks_and_headers_from_peer && !IsLimitedPeer(*peer)) ||
9006-
!m_chainman.ActiveChainstate().IsInitialBlockDownload()) &&
9002+
!m_chainman.IsInitialBlockDownload()) &&
90079003
state.vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
90089004
std::vector<const CBlockIndex *> vToDownload;
90099005
NodeId staller = -1;
@@ -9129,7 +9125,7 @@ bool PeerManagerImpl::ReceivedAvalancheProof(CNode &node, Peer &peer,
91299125

91309126
AddKnownProof(peer, proofid);
91319127

9132-
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
9128+
if (m_chainman.IsInitialBlockDownload()) {
91339129
// We cannot reliably verify proofs during IBD, so bail out early and
91349130
// keep the inventory as pending so it can be requested when the node
91359131
// has synced.

src/node/interfaces.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ namespace {
267267
tip);
268268
}
269269
bool isInitialBlockDownload() override {
270-
return chainman().ActiveChainstate().IsInitialBlockDownload();
270+
return chainman().IsInitialBlockDownload();
271271
}
272272
bool isLoadingBlocks() override {
273273
return chainman().m_blockman.LoadingBlocks();
@@ -697,7 +697,7 @@ namespace {
697697
!isInitialBlockDownload();
698698
}
699699
bool isInitialBlockDownload() override {
700-
return chainman().ActiveChainstate().IsInitialBlockDownload();
700+
return chainman().IsInitialBlockDownload();
701701
}
702702
bool shutdownRequested() override { return ShutdownRequested(); }
703703
void initMessage(const std::string &message) override {

src/rpc/blockchain.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,7 @@ RPCHelpMan getblockchaininfo() {
13591359
"verificationprogress",
13601360
GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
13611361
obj.pushKV("initialblockdownload",
1362-
active_chainstate.IsInitialBlockDownload());
1362+
chainman.IsInitialBlockDownload());
13631363
obj.pushKV("chainwork", tip.nChainWork.GetHex());
13641364
obj.pushKV("size_on_disk",
13651365
chainman.m_blockman.CalculateCurrentUsage());

src/rpc/mining.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ static RPCHelpMan getblocktemplate() {
929929
"Bitcoin is not connected!");
930930
}
931931

932-
if (active_chainstate.IsInitialBlockDownload()) {
932+
if (chainman.IsInitialBlockDownload()) {
933933
throw JSONRPCError(
934934
RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME
935935
" is in initial sync and waiting for blocks...");

src/test/net_tests.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,11 +1293,10 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) {
12931293
const int64_t time{0};
12941294
const CNetMsgMaker msg_maker{PROTOCOL_VERSION};
12951295

1296-
// Force CChainState::IsInitialBlockDownload() to return false.
1296+
// Force ChainstateManager::IsInitialBlockDownload() to return false.
12971297
// Otherwise PushAddress() isn't called by PeerManager::ProcessMessage().
1298-
TestChainState &chainstate =
1299-
*static_cast<TestChainState *>(&m_node.chainman->ActiveChainstate());
1300-
chainstate.JumpOutOfIbd();
1298+
auto &chainman = static_cast<TestChainstateManager &>(*m_node.chainman);
1299+
chainman.JumpOutOfIbd();
13011300

13021301
const Config &config = m_node.chainman->GetConfig();
13031302

@@ -1354,7 +1353,7 @@ BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) {
13541353
BOOST_CHECK(sent);
13551354

13561355
CaptureMessage = CaptureMessageOrig;
1357-
chainstate.ResetIbd();
1356+
chainman.ResetIbd();
13581357

13591358
m_node.peerman->FinalizeNode(config, peer);
13601359

src/test/util/validation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ void ValidationInterfaceTest::BlockConnected(
1414
obj.BlockConnected(block, pindex);
1515
}
1616

17-
void TestChainState::ResetIbd() {
17+
void TestChainstateManager::ResetIbd() {
1818
m_cached_finished_ibd = false;
1919
assert(IsInitialBlockDownload());
2020
}
2121

22-
void TestChainState::JumpOutOfIbd() {
22+
void TestChainstateManager::JumpOutOfIbd() {
2323
Assert(IsInitialBlockDownload());
2424
m_cached_finished_ibd = true;
2525
Assert(!IsInitialBlockDownload());

src/test/util/validation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class ValidationInterfaceTest {
1616
const CBlockIndex *pindex);
1717
};
1818

19-
struct TestChainState : public Chainstate {
19+
struct TestChainstateManager : public ChainstateManager {
2020
/** Reset the ibd cache to its initial state */
2121
void ResetIbd();
2222
/** Toggle IsInitialBlockDownload from true to false */

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <test/util/chainstate.h>
1616
#include <test/util/random.h>
1717
#include <test/util/setup_common.h>
18+
#include <test/util/validation.h>
1819
#include <timedata.h>
1920
#include <validation.h>
2021
#include <validationinterface.h>
@@ -166,14 +167,21 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_rebalance_caches, TestChain100Setup) {
166167
/* cache_size_bytes */ 1 << 23, /* in_memory */ true,
167168
/* should_wipe */ false);
168169

170+
// Reset IBD state so IsInitialBlockDownload() returns true and causes
171+
// MaybeRebalancesCaches() to prioritize the snapshot chainstate, giving it
172+
// more cache space than the snapshot chainstate. Calling ResetIbd() is
173+
// necessary because m_cached_finished_ibd is already latched to true before
174+
// the test starts due to the test setup. After ResetIbd() is called.
175+
// IsInitialBlockDownload will return true because at this point the active
176+
// chainstate has a null chain tip.
177+
static_cast<TestChainstateManager &>(manager).ResetIbd();
178+
169179
{
170180
LOCK(::cs_main);
171181
c2.InitCoinsCache(1 << 23);
172182
manager.MaybeRebalanceCaches();
173183
}
174184

175-
// Since both chainstates are considered to be in initial block download,
176-
// the snapshot chainstate should take priority.
177185
BOOST_CHECK_CLOSE(c1.m_coinstip_cache_size_bytes, max_cache * 0.05, 1);
178186
BOOST_CHECK_CLOSE(c1.m_coinsdb_cache_size_bytes, max_cache * 0.05, 1);
179187
BOOST_CHECK_CLOSE(c2.m_coinstip_cache_size_bytes, max_cache * 0.95, 1);

0 commit comments

Comments
 (0)