diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -194,6 +194,7 @@ } case RetFormat::JSON: { UniValue jsonHeaders(UniValue::VARR); + for (const CBlockIndex *pindex : headers) { jsonHeaders.push_back(blockheaderToJSON(tip, pindex)); } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -5,8 +5,15 @@ #ifndef BITCOIN_RPCBLOCKCHAIN_H #define BITCOIN_RPCBLOCKCHAIN_H +#include +#include #include +#include +#include + +extern CCriticalSection cs_main; + class CBlock; class CBlockIndex; class Config; @@ -28,7 +35,8 @@ /** Block description to JSON */ UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, - const CBlockIndex *blockindex, bool txDetails = false); + const CBlockIndex *blockindex, bool txDetails = false) + LOCKS_EXCLUDED(cs_main); /** Mempool information to JSON */ UniValue mempoolInfoToJSON(); @@ -38,6 +46,7 @@ /** Block header to JSON */ UniValue blockheaderToJSON(const CBlockIndex *tip, - const CBlockIndex *blockindex); + const CBlockIndex *blockindex) + LOCKS_EXCLUDED(cs_main); #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 @@ -78,6 +78,9 @@ 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()); const CBlockIndex *pnext; @@ -106,6 +109,9 @@ UniValue blockToJSON(const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails) { + // 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()); const CBlockIndex *pnext; @@ -868,8 +874,6 @@ "214adbda81d7e2a3dd146f6ed09\"")); } - LOCK(cs_main); - std::string strHash = request.params[0].get_str(); uint256 hash(uint256S(strHash)); @@ -882,23 +886,32 @@ } } - const CBlockIndex *pblockindex = LookupBlockIndex(hash); - if (!pblockindex) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - } - CBlock block; - if (fHavePruned && !pblockindex->nStatus.hasData() && - pblockindex->nTx > 0) { - throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)"); - } + const CBlockIndex *pblockindex; + const CBlockIndex *tip; + { + LOCK(cs_main); + pblockindex = LookupBlockIndex(hash); + tip = chainActive.Tip(); - if (!ReadBlockFromDisk(block, pblockindex, config)) { - // Block not found on disk. This could be because we have the block - // header in our index but don't have the block (for example if a - // non-whitelisted node sends us an unrequested long chain of valid - // blocks, we add the headers to our index, but don't accept the block). - throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); + if (!pblockindex) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + } + + if (fHavePruned && !pblockindex->nStatus.hasData() && + pblockindex->nTx > 0) { + throw JSONRPCError(RPC_MISC_ERROR, + "Block not available (pruned data)"); + } + + if (!ReadBlockFromDisk(block, pblockindex, config)) { + // Block not found on disk. This could be because we have the block + // header in our index but don't have the block (for example if a + // non-whitelisted node sends us an unrequested long chain of valid + // blocks, we add the headers to our index, but don't accept the + // block). + throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); + } } if (verbosity <= 0) { @@ -909,7 +922,7 @@ return strHex; } - return blockToJSON(block, chainActive.Tip(), pblockindex, verbosity >= 2); + return blockToJSON(block, tip, pblockindex, verbosity >= 2); } struct CCoinsStats {