diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -156,10 +156,12 @@ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); } + const CBlockIndex *tip = nullptr; std::vector headers; headers.reserve(count); { LOCK(cs_main); + tip = chainActive.Tip(); const CBlockIndex *pindex = LookupBlockIndex(hash); while (pindex != nullptr && chainActive.Contains(pindex)) { headers.push_back(pindex); @@ -192,11 +194,8 @@ } case RetFormat::JSON: { UniValue jsonHeaders(UniValue::VARR); - { - LOCK(cs_main); - for (const CBlockIndex *pindex : headers) { - jsonHeaders.push_back(blockheaderToJSON(pindex)); - } + for (const CBlockIndex *pindex : headers) { + jsonHeaders.push_back(blockheaderToJSON(tip, pindex)); } std::string strJSON = jsonHeaders.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); @@ -230,8 +229,10 @@ CBlock block; CBlockIndex *pblockindex = nullptr; + CBlockIndex *tip = nullptr; { LOCK(cs_main); + tip = chainActive.Tip(); pblockindex = LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); @@ -268,11 +269,8 @@ } case RetFormat::JSON: { - UniValue objBlock; - { - LOCK(cs_main); - objBlock = blockToJSON(block, pblockindex, showTxDetails); - } + UniValue objBlock = + blockToJSON(block, tip, pblockindex, showTxDetails); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -27,8 +27,8 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex *pindex); /** Block description to JSON */ -UniValue blockToJSON(const CBlock &block, const CBlockIndex *blockindex, - bool txDetails = false); +UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, + const CBlockIndex *blockindex, bool txDetails = false); /** Mempool information to JSON */ UniValue mempoolInfoToJSON(); @@ -37,6 +37,7 @@ UniValue mempoolToJSON(bool fVerbose = false); /** Block header to JSON */ -UniValue blockheaderToJSON(const CBlockIndex *blockindex); +UniValue blockheaderToJSON(const CBlockIndex *tip, + const CBlockIndex *blockindex); #endif // BITCOIN_RPCBLOCKCHAIN_H diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -60,24 +60,28 @@ } double GetDifficulty(const CBlockIndex *blockindex) { - // Floating point number that is a multiple of the minimum difficulty, - // minimum difficulty = 1.0. - if (blockindex == nullptr) { - return 1.0; - } + assert(blockindex); return GetDifficultyFromBits(blockindex->nBits); } -UniValue blockheaderToJSON(const CBlockIndex *blockindex) { - AssertLockHeld(cs_main); +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 = nullptr; + return blockindex == tip ? 1 : -1; +} + +UniValue blockheaderToJSON(const CBlockIndex *tip, + const CBlockIndex *blockindex) { UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) { - confirmations = chainActive.Height() - blockindex->nHeight + 1; - } + const CBlockIndex *pnext; + int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); result.pushKV("confirmations", confirmations); result.pushKV("height", blockindex->nHeight); result.pushKV("version", blockindex->nVersion); @@ -94,23 +98,18 @@ result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); } - CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) { result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); } return result; } -UniValue blockToJSON(const CBlock &block, const CBlockIndex *blockindex, - bool txDetails) { - AssertLockHeld(cs_main); +UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, + const CBlockIndex *blockindex, bool txDetails) { UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) { - confirmations = chainActive.Height() - blockindex->nHeight + 1; - } + const CBlockIndex *pnext; + int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext); result.pushKV("confirmations", confirmations); result.pushKV( "size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)); @@ -140,7 +139,6 @@ result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); } - CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) { result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); } @@ -801,7 +799,7 @@ return strHex; } - return blockheaderToJSON(pblockindex); + return blockheaderToJSON(chainActive.Tip(), pblockindex); } static UniValue getblock(const Config &config, const JSONRPCRequest &request) { @@ -911,7 +909,7 @@ return strHex; } - return blockToJSON(block, pblockindex, verbosity >= 2); + return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2); } struct CCoinsStats { @@ -1222,7 +1220,7 @@ } /** Implementation of IsSuperMajority with better feedback */ -static UniValue SoftForkMajorityDesc(int version, CBlockIndex *pindex, +static UniValue SoftForkMajorityDesc(int version, const CBlockIndex *pindex, const Consensus::Params &consensusParams) { UniValue rv(UniValue::VOBJ); bool activated = false; @@ -1245,7 +1243,7 @@ } static UniValue SoftForkDesc(const std::string &name, int version, - CBlockIndex *pindex, + const CBlockIndex *pindex, const Consensus::Params &consensusParams) { UniValue rv(UniValue::VOBJ); rv.pushKV("id", name); @@ -1311,22 +1309,22 @@ LOCK(cs_main); + const CBlockIndex *tip = chainActive.Tip(); UniValue obj(UniValue::VOBJ); obj.pushKV("chain", config.GetChainParams().NetworkIDString()); obj.pushKV("blocks", int(chainActive.Height())); obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1); - obj.pushKV("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()); - obj.pushKV("difficulty", double(GetDifficulty(chainActive.Tip()))); - obj.pushKV("mediantime", int64_t(chainActive.Tip()->GetMedianTimePast())); + obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); + obj.pushKV("difficulty", double(GetDifficulty(tip))); + obj.pushKV("mediantime", int64_t(tip->GetMedianTimePast())); obj.pushKV("verificationprogress", - GuessVerificationProgress(config.GetChainParams().TxData(), - chainActive.Tip())); - obj.pushKV("chainwork", chainActive.Tip()->nChainWork.GetHex()); + GuessVerificationProgress(Params().TxData(), tip)); + obj.pushKV("chainwork", tip->nChainWork.GetHex()); obj.pushKV("size_on_disk", CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); if (fPruneMode) { - CBlockIndex *block = chainActive.Tip(); + const CBlockIndex *block = tip; assert(block); while (block->pprev && (block->pprev->nStatus.hasData())) { block = block->pprev; @@ -1344,7 +1342,6 @@ const Consensus::Params &consensusParams = config.GetChainParams().GetConsensus(); - CBlockIndex *tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));