Skip to content

Commit 586190f

Browse files
committed
rpc/rest: Take and reuse local Chain/ChainState obj
In all rest/rpc-related modules, if there are multiple calls to ActiveChain{,State}(), and the calls fall under the same ::cs_main lock, we can simply take a local reference and use/reuse it instead of calling ActiveChain{,State}() again and again.
1 parent bc3bd36 commit 586190f

File tree

4 files changed

+39
-29
lines changed

4 files changed

+39
-29
lines changed

src/rest.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,14 @@ static bool rest_headers(const std::any& context,
182182
{
183183
ChainstateManager& chainman = EnsureAnyChainman(context);
184184
LOCK(cs_main);
185-
tip = chainman.ActiveChain().Tip();
185+
CChain& active_chain = chainman.ActiveChain();
186+
tip = active_chain.Tip();
186187
const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
187-
while (pindex != nullptr && chainman.ActiveChain().Contains(pindex)) {
188+
while (pindex != nullptr && active_chain.Contains(pindex)) {
188189
headers.push_back(pindex);
189190
if (headers.size() == (unsigned long)count)
190191
break;
191-
pindex = chainman.ActiveChain().Next(pindex);
192+
pindex = active_chain.Next(pindex);
192193
}
193194
}
194195

src/rpc/blockchain.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,8 @@ static RPCHelpMan pruneblockchain()
10091009

10101010
ChainstateManager& chainman = EnsureAnyChainman(request.context);
10111011
LOCK(cs_main);
1012+
CChainState& active_chainstate = chainman.ActiveChainstate();
1013+
CChain& active_chain = active_chainstate.m_chain;
10121014

10131015
int heightParam = request.params[0].get_int();
10141016
if (heightParam < 0)
@@ -1018,15 +1020,15 @@ static RPCHelpMan pruneblockchain()
10181020
// too low to be a block time (corresponds to timestamp from Sep 2001).
10191021
if (heightParam > 1000000000) {
10201022
// Add a 2 hour buffer to include blocks which might have had old timestamps
1021-
CBlockIndex* pindex = chainman.ActiveChain().FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
1023+
CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
10221024
if (!pindex) {
10231025
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
10241026
}
10251027
heightParam = pindex->nHeight;
10261028
}
10271029

10281030
unsigned int height = (unsigned int) heightParam;
1029-
unsigned int chainHeight = (unsigned int) chainman.ActiveChain().Height();
1031+
unsigned int chainHeight = (unsigned int) active_chain.Height();
10301032
if (chainHeight < Params().PruneAfterHeight())
10311033
throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
10321034
else if (height > chainHeight)
@@ -1036,8 +1038,8 @@ static RPCHelpMan pruneblockchain()
10361038
height = chainHeight - MIN_BLOCKS_TO_KEEP;
10371039
}
10381040

1039-
PruneBlockFilesManual(chainman.ActiveChainstate(), height);
1040-
const CBlockIndex* block = chainman.ActiveChain().Tip();
1041+
PruneBlockFilesManual(active_chainstate, height);
1042+
const CBlockIndex* block = active_chain.Tip();
10411043
CHECK_NONFATAL(block);
10421044
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
10431045
block = block->pprev;
@@ -1363,8 +1365,9 @@ RPCHelpMan getblockchaininfo()
13631365
{
13641366
ChainstateManager& chainman = EnsureAnyChainman(request.context);
13651367
LOCK(cs_main);
1368+
CChainState& active_chainstate = chainman.ActiveChainstate();
13661369

1367-
const CBlockIndex* tip = chainman.ActiveChain().Tip();
1370+
const CBlockIndex* tip = active_chainstate.m_chain.Tip();
13681371
CHECK_NONFATAL(tip);
13691372
const int height = tip->nHeight;
13701373
UniValue obj(UniValue::VOBJ);
@@ -1375,7 +1378,7 @@ RPCHelpMan getblockchaininfo()
13751378
obj.pushKV("difficulty", (double)GetDifficulty(tip));
13761379
obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
13771380
obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
1378-
obj.pushKV("initialblockdownload", chainman.ActiveChainstate().IsInitialBlockDownload());
1381+
obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
13791382
obj.pushKV("chainwork", tip->nChainWork.GetHex());
13801383
obj.pushKV("size_on_disk", CalculateCurrentUsage());
13811384
obj.pushKV("pruned", fPruneMode);
@@ -1457,6 +1460,7 @@ static RPCHelpMan getchaintips()
14571460
{
14581461
ChainstateManager& chainman = EnsureAnyChainman(request.context);
14591462
LOCK(cs_main);
1463+
CChain& active_chain = chainman.ActiveChain();
14601464

14611465
/*
14621466
* Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
@@ -1470,7 +1474,7 @@ static RPCHelpMan getchaintips()
14701474
std::set<const CBlockIndex*> setPrevs;
14711475

14721476
for (const std::pair<const uint256, CBlockIndex*>& item : chainman.BlockIndex()) {
1473-
if (!chainman.ActiveChain().Contains(item.second)) {
1477+
if (!active_chain.Contains(item.second)) {
14741478
setOrphans.insert(item.second);
14751479
setPrevs.insert(item.second->pprev);
14761480
}
@@ -1483,7 +1487,7 @@ static RPCHelpMan getchaintips()
14831487
}
14841488

14851489
// Always report the currently active tip.
1486-
setTips.insert(chainman.ActiveChain().Tip());
1490+
setTips.insert(active_chain.Tip());
14871491

14881492
/* Construct the output array. */
14891493
UniValue res(UniValue::VARR);
@@ -1492,11 +1496,11 @@ static RPCHelpMan getchaintips()
14921496
obj.pushKV("height", block->nHeight);
14931497
obj.pushKV("hash", block->phashBlock->GetHex());
14941498

1495-
const int branchLen = block->nHeight - chainman.ActiveChain().FindFork(block)->nHeight;
1499+
const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
14961500
obj.pushKV("branchlen", branchLen);
14971501

14981502
std::string status;
1499-
if (chainman.ActiveChain().Contains(block)) {
1503+
if (active_chain.Contains(block)) {
15001504
// This block is part of the currently active chain.
15011505
status = "active";
15021506
} else if (block->nStatus & BLOCK_FAILED_MASK) {
@@ -1903,26 +1907,27 @@ static RPCHelpMan getblockstats()
19031907
{
19041908
ChainstateManager& chainman = EnsureAnyChainman(request.context);
19051909
LOCK(cs_main);
1910+
CChain& active_chain = chainman.ActiveChain();
19061911

19071912
CBlockIndex* pindex;
19081913
if (request.params[0].isNum()) {
19091914
const int height = request.params[0].get_int();
1910-
const int current_tip = chainman.ActiveChain().Height();
1915+
const int current_tip = active_chain.Height();
19111916
if (height < 0) {
19121917
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
19131918
}
19141919
if (height > current_tip) {
19151920
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
19161921
}
19171922

1918-
pindex = chainman.ActiveChain()[height];
1923+
pindex = active_chain[height];
19191924
} else {
19201925
const uint256 hash(ParseHashV(request.params[0], "hash_or_height"));
19211926
pindex = chainman.m_blockman.LookupBlockIndex(hash);
19221927
if (!pindex) {
19231928
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
19241929
}
1925-
if (!chainman.ActiveChain().Contains(pindex)) {
1930+
if (!active_chain.Contains(pindex)) {
19261931
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Block is not in chain %s", Params().NetworkIDString()));
19271932
}
19281933
}
@@ -2307,10 +2312,11 @@ static RPCHelpMan scantxoutset()
23072312
{
23082313
ChainstateManager& chainman = EnsureChainman(node);
23092314
LOCK(cs_main);
2310-
chainman.ActiveChainstate().ForceFlushStateToDisk();
2311-
pcursor = std::unique_ptr<CCoinsViewCursor>(chainman.ActiveChainstate().CoinsDB().Cursor());
2315+
CChainState& active_chainstate = chainman.ActiveChainstate();
2316+
active_chainstate.ForceFlushStateToDisk();
2317+
pcursor = std::unique_ptr<CCoinsViewCursor>(active_chainstate.CoinsDB().Cursor());
23122318
CHECK_NONFATAL(pcursor);
2313-
tip = chainman.ActiveChain().Tip();
2319+
tip = active_chainstate.m_chain.Tip();
23142320
CHECK_NONFATAL(tip);
23152321
}
23162322
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);

src/rpc/mining.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,8 @@ static RPCHelpMan getblocktemplate()
608608
UniValue lpval = NullUniValue;
609609
std::set<std::string> setClientRules;
610610
int64_t nMaxVersionPreVB = -1;
611+
CChainState& active_chainstate = chainman.ActiveChainstate();
612+
CChain& active_chain = active_chainstate.m_chain;
611613
if (!request.params[0].isNull())
612614
{
613615
const UniValue& oparam = request.params[0].get_obj();
@@ -642,12 +644,12 @@ static RPCHelpMan getblocktemplate()
642644
return "duplicate-inconclusive";
643645
}
644646

645-
CBlockIndex* const pindexPrev = chainman.ActiveChain().Tip();
647+
CBlockIndex* const pindexPrev = active_chain.Tip();
646648
// TestBlockValidity only supports blocks built on the current Tip
647649
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
648650
return "inconclusive-not-best-prevblk";
649651
BlockValidationState state;
650-
TestBlockValidity(state, Params(), chainman.ActiveChainstate(), block, pindexPrev, false, true);
652+
TestBlockValidity(state, Params(), active_chainstate, block, pindexPrev, false, true);
651653
return BIP22ValidationResult(state);
652654
}
653655

@@ -677,7 +679,7 @@ static RPCHelpMan getblocktemplate()
677679
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, PACKAGE_NAME " is not connected!");
678680
}
679681

680-
if (chainman.ActiveChainstate().IsInitialBlockDownload()) {
682+
if (active_chainstate.IsInitialBlockDownload()) {
681683
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks...");
682684
}
683685
}
@@ -703,7 +705,7 @@ static RPCHelpMan getblocktemplate()
703705
else
704706
{
705707
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
706-
hashWatchedChain = chainman.ActiveChain().Tip()->GetBlockHash();
708+
hashWatchedChain = active_chain.Tip()->GetBlockHash();
707709
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
708710
}
709711

@@ -748,20 +750,20 @@ static RPCHelpMan getblocktemplate()
748750
static CBlockIndex* pindexPrev;
749751
static int64_t nStart;
750752
static std::unique_ptr<CBlockTemplate> pblocktemplate;
751-
if (pindexPrev != chainman.ActiveChain().Tip() ||
753+
if (pindexPrev != active_chain.Tip() ||
752754
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
753755
{
754756
// Clear pindexPrev so future calls make a new block, despite any failures from here on
755757
pindexPrev = nullptr;
756758

757759
// Store the pindexBest used before CreateNewBlock, to avoid races
758760
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
759-
CBlockIndex* pindexPrevNew = chainman.ActiveChain().Tip();
761+
CBlockIndex* pindexPrevNew = active_chain.Tip();
760762
nStart = GetTime();
761763

762764
// Create new block
763765
CScript scriptDummy = CScript() << OP_TRUE;
764-
pblocktemplate = BlockAssembler(chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(scriptDummy);
766+
pblocktemplate = BlockAssembler(active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy);
765767
if (!pblocktemplate)
766768
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
767769

@@ -897,7 +899,7 @@ static RPCHelpMan getblocktemplate()
897899
result.pushKV("transactions", transactions);
898900
result.pushKV("coinbaseaux", aux);
899901
result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue);
900-
result.pushKV("longpollid", chainman.ActiveChain().Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast));
902+
result.pushKV("longpollid", active_chain.Tip()->GetBlockHash().GetHex() + ToString(nTransactionsUpdatedLast));
901903
result.pushKV("target", hashTarget.GetHex());
902904
result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1);
903905
result.pushKV("mutable", aMutable);

src/rpc/rawtransaction.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,13 @@ static RPCHelpMan gettxoutproof()
268268
}
269269
} else {
270270
LOCK(cs_main);
271+
CChainState& active_chainstate = chainman.ActiveChainstate();
271272

272273
// Loop through txids and try to find which block they're in. Exit loop once a block is found.
273274
for (const auto& tx : setTxids) {
274-
const Coin& coin = AccessByTxid(chainman.ActiveChainstate().CoinsTip(), tx);
275+
const Coin& coin = AccessByTxid(active_chainstate.CoinsTip(), tx);
275276
if (!coin.IsSpent()) {
276-
pblockindex = chainman.ActiveChain()[coin.nHeight];
277+
pblockindex = active_chainstate.m_chain[coin.nHeight];
277278
break;
278279
}
279280
}

0 commit comments

Comments
 (0)