Skip to content

Commit fa5989d

Browse files
author
MarcoFalke
committed
refactor: rpc: Pass CBlockIndex by reference instead of pointer
All functions assume that the pointer is never null, so pass by reference, to avoid accidental segfaults at runtime, or at least make them more obvious. Also, remove unused c-style casts in touched lines. Also, add CHECK_NONFATAL checks, to turn segfault crashes into an recoverable runtime error with debug information.
1 parent fa604eb commit fa5989d

File tree

6 files changed

+51
-53
lines changed

6 files changed

+51
-53
lines changed

src/bench/rpc_blockchain.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench)
4141
{
4242
TestBlockAndIndex data;
4343
bench.run([&] {
44-
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
44+
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
4545
ankerl::nanobench::doNotOptimizeAway(univalue);
4646
});
4747
}
@@ -51,7 +51,7 @@ BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH);
5151
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
5252
{
5353
TestBlockAndIndex data;
54-
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
54+
auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, data.blockindex, data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT);
5555
bench.run([&] {
5656
auto str = univalue.write();
5757
ankerl::nanobench::doNotOptimizeAway(str);

src/rest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ static bool rest_headers(const std::any& context,
264264
case RESTResponseFormat::JSON: {
265265
UniValue jsonHeaders(UniValue::VARR);
266266
for (const CBlockIndex *pindex : headers) {
267-
jsonHeaders.push_back(blockheaderToJSON(tip, pindex));
267+
jsonHeaders.push_back(blockheaderToJSON(*tip, *pindex));
268268
}
269269
std::string strJSON = jsonHeaders.write() + "\n";
270270
req->WriteHeader("Content-Type", "application/json");
@@ -333,7 +333,7 @@ static bool rest_block(const std::any& context,
333333
}
334334

335335
case RESTResponseFormat::JSON: {
336-
UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
336+
UniValue objBlock = blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
337337
std::string strJSON = objBlock.write() + "\n";
338338
req->WriteHeader("Content-Type", "application/json");
339339
req->WriteReply(HTTP_OK, strJSON);

src/rpc/blockchain.cpp

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,11 @@ static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
7373

7474
/* Calculate the difficulty for a given block index.
7575
*/
76-
double GetDifficulty(const CBlockIndex* blockindex)
76+
double GetDifficulty(const CBlockIndex& blockindex)
7777
{
78-
CHECK_NONFATAL(blockindex);
79-
80-
int nShift = (blockindex->nBits >> 24) & 0xff;
78+
int nShift = (blockindex.nBits >> 24) & 0xff;
8179
double dDiff =
82-
(double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
80+
(double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
8381

8482
while (nShift < 29)
8583
{
@@ -95,14 +93,14 @@ double GetDifficulty(const CBlockIndex* blockindex)
9593
return dDiff;
9694
}
9795

98-
static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
96+
static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
9997
{
100-
next = tip->GetAncestor(blockindex->nHeight + 1);
101-
if (next && next->pprev == blockindex) {
102-
return tip->nHeight - blockindex->nHeight + 1;
98+
next = tip.GetAncestor(blockindex.nHeight + 1);
99+
if (next && next->pprev == &blockindex) {
100+
return tip.nHeight - blockindex.nHeight + 1;
103101
}
104102
next = nullptr;
105-
return blockindex == tip ? 1 : -1;
103+
return &blockindex == &tip ? 1 : -1;
106104
}
107105

108106
static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
@@ -133,36 +131,36 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan
133131
}
134132
}
135133

136-
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
134+
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex)
137135
{
138136
// Serialize passed information without accessing chain state of the active chain!
139137
AssertLockNotHeld(cs_main); // For performance reasons
140138

141139
UniValue result(UniValue::VOBJ);
142-
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
140+
result.pushKV("hash", blockindex.GetBlockHash().GetHex());
143141
const CBlockIndex* pnext;
144142
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
145143
result.pushKV("confirmations", confirmations);
146-
result.pushKV("height", blockindex->nHeight);
147-
result.pushKV("version", blockindex->nVersion);
148-
result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
149-
result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
150-
result.pushKV("time", (int64_t)blockindex->nTime);
151-
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
152-
result.pushKV("nonce", (uint64_t)blockindex->nNonce);
153-
result.pushKV("bits", strprintf("%08x", blockindex->nBits));
144+
result.pushKV("height", blockindex.nHeight);
145+
result.pushKV("version", blockindex.nVersion);
146+
result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
147+
result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
148+
result.pushKV("time", blockindex.nTime);
149+
result.pushKV("mediantime", blockindex.GetMedianTimePast());
150+
result.pushKV("nonce", blockindex.nNonce);
151+
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
154152
result.pushKV("difficulty", GetDifficulty(blockindex));
155-
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
156-
result.pushKV("nTx", (uint64_t)blockindex->nTx);
153+
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
154+
result.pushKV("nTx", blockindex.nTx);
157155

158-
if (blockindex->pprev)
159-
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
156+
if (blockindex.pprev)
157+
result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
160158
if (pnext)
161159
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
162160
return result;
163161
}
164162

165-
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
163+
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
166164
{
167165
UniValue result = blockheaderToJSON(tip, blockindex);
168166

@@ -181,8 +179,8 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
181179
case TxVerbosity::SHOW_DETAILS:
182180
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
183181
CBlockUndo blockUndo;
184-
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(*blockindex))};
185-
const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, *blockindex)};
182+
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
183+
const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)};
186184

187185
for (size_t i = 0; i < block.vtx.size(); ++i) {
188186
const CTransactionRef& tx = block.vtx.at(i);
@@ -418,7 +416,7 @@ static RPCHelpMan getdifficulty()
418416
{
419417
ChainstateManager& chainman = EnsureAnyChainman(request.context);
420418
LOCK(cs_main);
421-
return GetDifficulty(chainman.ActiveChain().Tip());
419+
return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
422420
},
423421
};
424422
}
@@ -571,22 +569,22 @@ static RPCHelpMan getblockheader()
571569
return strHex;
572570
}
573571

574-
return blockheaderToJSON(tip, pblockindex);
572+
return blockheaderToJSON(*tip, *pblockindex);
575573
},
576574
};
577575
}
578576

579-
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
577+
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
580578
{
581579
CBlock block;
582580
{
583581
LOCK(cs_main);
584-
if (blockman.IsBlockPruned(*pblockindex)) {
582+
if (blockman.IsBlockPruned(blockindex)) {
585583
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
586584
}
587585
}
588586

589-
if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
587+
if (!blockman.ReadBlockFromDisk(block, blockindex)) {
590588
// Block not found on disk. This could be because we have the block
591589
// header in our index but not yet have the block or did not accept the
592590
// block. Or if the block was pruned right after we released the lock above.
@@ -596,21 +594,21 @@ static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblocki
596594
return block;
597595
}
598596

599-
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
597+
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
600598
{
601599
CBlockUndo blockUndo;
602600

603601
// The Genesis block does not have undo data
604-
if (pblockindex->nHeight == 0) return blockUndo;
602+
if (blockindex.nHeight == 0) return blockUndo;
605603

606604
{
607605
LOCK(cs_main);
608-
if (blockman.IsBlockPruned(*pblockindex)) {
606+
if (blockman.IsBlockPruned(blockindex)) {
609607
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
610608
}
611609
}
612610

613-
if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
611+
if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) {
614612
throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
615613
}
616614

@@ -736,7 +734,7 @@ static RPCHelpMan getblock()
736734
}
737735
}
738736

739-
const CBlock block{GetBlockChecked(chainman.m_blockman, pblockindex)};
737+
const CBlock block{GetBlockChecked(chainman.m_blockman, *pblockindex)};
740738

741739
if (verbosity <= 0)
742740
{
@@ -755,7 +753,7 @@ static RPCHelpMan getblock()
755753
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
756754
}
757755

758-
return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
756+
return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
759757
},
760758
};
761759
}
@@ -1257,7 +1255,7 @@ RPCHelpMan getblockchaininfo()
12571255
obj.pushKV("blocks", height);
12581256
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
12591257
obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1260-
obj.pushKV("difficulty", GetDifficulty(&tip));
1258+
obj.pushKV("difficulty", GetDifficulty(tip));
12611259
obj.pushKV("time", tip.GetBlockTime());
12621260
obj.pushKV("mediantime", tip.GetMedianTimePast());
12631261
obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
@@ -1815,8 +1813,8 @@ static RPCHelpMan getblockstats()
18151813
}
18161814
}
18171815

1818-
const CBlock& block = GetBlockChecked(chainman.m_blockman, &pindex);
1819-
const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, &pindex);
1816+
const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
1817+
const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
18201818

18211819
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
18221820
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
@@ -2275,8 +2273,8 @@ class BlockFiltersScanReserver
22752273

22762274
static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
22772275
{
2278-
const CBlock block{GetBlockChecked(blockman, &blockindex)};
2279-
const CBlockUndo block_undo{GetUndoChecked(blockman, &blockindex)};
2276+
const CBlock block{GetBlockChecked(blockman, blockindex)};
2277+
const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
22802278

22812279
// Check if any of the outputs match the scriptPubKey
22822280
for (const auto& tx : block.vtx) {
@@ -2845,7 +2843,7 @@ return RPCHelpMan{
28452843

28462844
data.pushKV("blocks", (int)chain.Height());
28472845
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
2848-
data.pushKV("difficulty", (double)GetDifficulty(tip));
2846+
data.pushKV("difficulty", GetDifficulty(*tip));
28492847
data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
28502848
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
28512849
data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);

src/rpc/blockchain.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
3232
* @return A floating point number that is a multiple of the main net minimum
3333
* difficulty (4295032833 hashes).
3434
*/
35-
double GetDifficulty(const CBlockIndex* blockindex);
35+
double GetDifficulty(const CBlockIndex& blockindex);
3636

3737
/** Callback for when block tip changed. */
3838
void RPCNotifyBlockChange(const CBlockIndex*);
3939

4040
/** Block description to JSON */
41-
UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
41+
UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);
4242

4343
/** Block header to JSON */
44-
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex) LOCKS_EXCLUDED(cs_main);
44+
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex) LOCKS_EXCLUDED(cs_main);
4545

4646
/** Used by getblockstats to get feerates at different percentiles by weight */
4747
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight);

src/rpc/mining.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ static RPCHelpMan getmininginfo()
441441
obj.pushKV("blocks", active_chain.Height());
442442
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
443443
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
444-
obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip()));
444+
obj.pushKV("difficulty", GetDifficulty(*CHECK_NONFATAL(active_chain.Tip())));
445445
obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
446446
obj.pushKV("pooledtx", (uint64_t)mempool.size());
447447
obj.pushKV("chain", chainman.GetParams().GetChainTypeString());

src/test/blockchain_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static void RejectDifficultyMismatch(double difficulty, double expected_difficul
4141
static void TestDifficulty(uint32_t nbits, double expected_difficulty)
4242
{
4343
CBlockIndex* block_index = CreateBlockIndexWithNbits(nbits);
44-
double difficulty = GetDifficulty(block_index);
44+
double difficulty = GetDifficulty(*block_index);
4545
delete block_index;
4646

4747
RejectDifficultyMismatch(difficulty, expected_difficulty);

0 commit comments

Comments
 (0)