mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 06:43:45 +01:00
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.
This commit is contained in:
@@ -73,13 +73,11 @@ static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
|
||||
|
||||
/* Calculate the difficulty for a given block index.
|
||||
*/
|
||||
double GetDifficulty(const CBlockIndex* blockindex)
|
||||
double GetDifficulty(const CBlockIndex& blockindex)
|
||||
{
|
||||
CHECK_NONFATAL(blockindex);
|
||||
|
||||
int nShift = (blockindex->nBits >> 24) & 0xff;
|
||||
int nShift = (blockindex.nBits >> 24) & 0xff;
|
||||
double dDiff =
|
||||
(double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
|
||||
(double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
|
||||
|
||||
while (nShift < 29)
|
||||
{
|
||||
@@ -95,14 +93,14 @@ double GetDifficulty(const CBlockIndex* blockindex)
|
||||
return dDiff;
|
||||
}
|
||||
|
||||
static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* blockindex, const CBlockIndex*& next)
|
||||
static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
|
||||
{
|
||||
next = tip->GetAncestor(blockindex->nHeight + 1);
|
||||
if (next && next->pprev == blockindex) {
|
||||
return tip->nHeight - blockindex->nHeight + 1;
|
||||
next = tip.GetAncestor(blockindex.nHeight + 1);
|
||||
if (next && next->pprev == &blockindex) {
|
||||
return tip.nHeight - blockindex.nHeight + 1;
|
||||
}
|
||||
next = nullptr;
|
||||
return blockindex == tip ? 1 : -1;
|
||||
return &blockindex == &tip ? 1 : -1;
|
||||
}
|
||||
|
||||
static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
|
||||
@@ -133,36 +131,36 @@ static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateMan
|
||||
}
|
||||
}
|
||||
|
||||
UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex)
|
||||
UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex)
|
||||
{
|
||||
// Serialize passed information without accessing chain state of the active chain!
|
||||
AssertLockNotHeld(cs_main); // For performance reasons
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("hash", blockindex->GetBlockHash().GetHex());
|
||||
result.pushKV("hash", blockindex.GetBlockHash().GetHex());
|
||||
const CBlockIndex* pnext;
|
||||
int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
|
||||
result.pushKV("confirmations", confirmations);
|
||||
result.pushKV("height", blockindex->nHeight);
|
||||
result.pushKV("version", blockindex->nVersion);
|
||||
result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
|
||||
result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
|
||||
result.pushKV("time", (int64_t)blockindex->nTime);
|
||||
result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
|
||||
result.pushKV("nonce", (uint64_t)blockindex->nNonce);
|
||||
result.pushKV("bits", strprintf("%08x", blockindex->nBits));
|
||||
result.pushKV("height", blockindex.nHeight);
|
||||
result.pushKV("version", blockindex.nVersion);
|
||||
result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
|
||||
result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
|
||||
result.pushKV("time", blockindex.nTime);
|
||||
result.pushKV("mediantime", blockindex.GetMedianTimePast());
|
||||
result.pushKV("nonce", blockindex.nNonce);
|
||||
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
|
||||
result.pushKV("difficulty", GetDifficulty(blockindex));
|
||||
result.pushKV("chainwork", blockindex->nChainWork.GetHex());
|
||||
result.pushKV("nTx", (uint64_t)blockindex->nTx);
|
||||
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
|
||||
result.pushKV("nTx", blockindex.nTx);
|
||||
|
||||
if (blockindex->pprev)
|
||||
result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex());
|
||||
if (blockindex.pprev)
|
||||
result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
|
||||
if (pnext)
|
||||
result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, TxVerbosity verbosity)
|
||||
UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
|
||||
{
|
||||
UniValue result = blockheaderToJSON(tip, blockindex);
|
||||
|
||||
@@ -181,8 +179,8 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
|
||||
case TxVerbosity::SHOW_DETAILS:
|
||||
case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
|
||||
CBlockUndo blockUndo;
|
||||
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(*blockindex))};
|
||||
const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, *blockindex)};
|
||||
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
|
||||
const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)};
|
||||
|
||||
for (size_t i = 0; i < block.vtx.size(); ++i) {
|
||||
const CTransactionRef& tx = block.vtx.at(i);
|
||||
@@ -418,7 +416,7 @@ static RPCHelpMan getdifficulty()
|
||||
{
|
||||
ChainstateManager& chainman = EnsureAnyChainman(request.context);
|
||||
LOCK(cs_main);
|
||||
return GetDifficulty(chainman.ActiveChain().Tip());
|
||||
return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -571,22 +569,22 @@ static RPCHelpMan getblockheader()
|
||||
return strHex;
|
||||
}
|
||||
|
||||
return blockheaderToJSON(tip, pblockindex);
|
||||
return blockheaderToJSON(*tip, *pblockindex);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
|
||||
static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
|
||||
{
|
||||
CBlock block;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (blockman.IsBlockPruned(*pblockindex)) {
|
||||
if (blockman.IsBlockPruned(blockindex)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
|
||||
}
|
||||
}
|
||||
|
||||
if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
|
||||
if (!blockman.ReadBlockFromDisk(block, blockindex)) {
|
||||
// Block not found on disk. This could be because we have the block
|
||||
// header in our index but not yet have the block or did not accept the
|
||||
// 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
|
||||
return block;
|
||||
}
|
||||
|
||||
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex* pblockindex)
|
||||
static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
|
||||
{
|
||||
CBlockUndo blockUndo;
|
||||
|
||||
// The Genesis block does not have undo data
|
||||
if (pblockindex->nHeight == 0) return blockUndo;
|
||||
if (blockindex.nHeight == 0) return blockUndo;
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (blockman.IsBlockPruned(*pblockindex)) {
|
||||
if (blockman.IsBlockPruned(blockindex)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
|
||||
}
|
||||
}
|
||||
|
||||
if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
|
||||
if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
|
||||
}
|
||||
|
||||
@@ -736,7 +734,7 @@ static RPCHelpMan getblock()
|
||||
}
|
||||
}
|
||||
|
||||
const CBlock block{GetBlockChecked(chainman.m_blockman, pblockindex)};
|
||||
const CBlock block{GetBlockChecked(chainman.m_blockman, *pblockindex)};
|
||||
|
||||
if (verbosity <= 0)
|
||||
{
|
||||
@@ -755,7 +753,7 @@ static RPCHelpMan getblock()
|
||||
tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT;
|
||||
}
|
||||
|
||||
return blockToJSON(chainman.m_blockman, block, tip, pblockindex, tx_verbosity);
|
||||
return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1257,7 +1255,7 @@ RPCHelpMan getblockchaininfo()
|
||||
obj.pushKV("blocks", height);
|
||||
obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
|
||||
obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
|
||||
obj.pushKV("difficulty", GetDifficulty(&tip));
|
||||
obj.pushKV("difficulty", GetDifficulty(tip));
|
||||
obj.pushKV("time", tip.GetBlockTime());
|
||||
obj.pushKV("mediantime", tip.GetMedianTimePast());
|
||||
obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
|
||||
@@ -1815,8 +1813,8 @@ static RPCHelpMan getblockstats()
|
||||
}
|
||||
}
|
||||
|
||||
const CBlock& block = GetBlockChecked(chainman.m_blockman, &pindex);
|
||||
const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, &pindex);
|
||||
const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
|
||||
const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
|
||||
|
||||
const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
|
||||
const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
|
||||
@@ -2275,8 +2273,8 @@ public:
|
||||
|
||||
static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
|
||||
{
|
||||
const CBlock block{GetBlockChecked(blockman, &blockindex)};
|
||||
const CBlockUndo block_undo{GetUndoChecked(blockman, &blockindex)};
|
||||
const CBlock block{GetBlockChecked(blockman, blockindex)};
|
||||
const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
|
||||
|
||||
// Check if any of the outputs match the scriptPubKey
|
||||
for (const auto& tx : block.vtx) {
|
||||
@@ -2845,7 +2843,7 @@ return RPCHelpMan{
|
||||
|
||||
data.pushKV("blocks", (int)chain.Height());
|
||||
data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
|
||||
data.pushKV("difficulty", (double)GetDifficulty(tip));
|
||||
data.pushKV("difficulty", GetDifficulty(*tip));
|
||||
data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
|
||||
data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
|
||||
data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
|
||||
|
||||
Reference in New Issue
Block a user