diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -109,6 +109,28 @@ return node_context->mempool.get(); } +/** + * Get the node context chainstatemanager. + * + * @param[in] req The HTTP request, whose status code will be set if node + * context chainstatemanager is not found. + * @returns Pointer to the chainstatemanager or nullptr if none found. + */ +static ChainstateManager *GetChainman(const std::any &context, + HTTPRequest *req) { + auto node_context = util::AnyPtr(context); + if (!node_context || !node_context->chainman) { + RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, + strprintf("%s:%d (%s)\n" + "Internal bug detected: Chainman disabled or instance" + " not found!\n" + "You may report this issue here: %s\n", + __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT)); + return nullptr; + } + return node_context->chainman; +} + static RetFormat ParseDataFormat(std::string ¶m, const std::string &strReq) { const std::string::size_type pos = strReq.rfind('.'); @@ -194,15 +216,20 @@ headers.reserve(count); { LOCK(cs_main); - tip = ::ChainActive().Tip(); - const CBlockIndex *pindex = - g_chainman.m_blockman.LookupBlockIndex(hash); - while (pindex != nullptr && ::ChainActive().Contains(pindex)) { + ChainstateManager *maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) { + return false; + } + ChainstateManager &chainman = *maybe_chainman; + CChain &active_chain = chainman.ActiveChain(); + tip = active_chain.Tip(); + const CBlockIndex *pindex = chainman.m_blockman.LookupBlockIndex(hash); + while (pindex != nullptr && active_chain.Contains(pindex)) { headers.push_back(pindex); if (headers.size() == size_t(count)) { break; } - pindex = ::ChainActive().Next(pindex); + pindex = active_chain.Next(pindex); } } @@ -270,8 +297,13 @@ CBlockIndex *tip = nullptr; { LOCK(cs_main); - tip = ::ChainActive().Tip(); - pblockindex = g_chainman.m_blockman.LookupBlockIndex(hash); + ChainstateManager *maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) { + return false; + } + ChainstateManager &chainman = *maybe_chainman; + tip = chainman.ActiveTip(); + pblockindex = chainman.m_blockman.LookupBlockIndex(hash); if (!pblockindex) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } @@ -614,6 +646,11 @@ std::string bitmapStringRepresentation; std::vector hits; bitmap.resize((vOutPoints.size() + 7) / 8); + ChainstateManager *maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) { + return false; + } + ChainstateManager &chainman = *maybe_chainman; { auto process_utxos = [&vOutPoints, &outs, &hits](const CCoinsView &view, @@ -638,13 +675,13 @@ // use db+mempool as cache backend in case user likes to query // mempool LOCK2(cs_main, mempool->cs); - CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); + CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, *mempool); process_utxos(viewMempool, *mempool); } else { // no need to lock mempool! LOCK(cs_main); - process_utxos(::ChainstateActive().CoinsTip(), CTxMemPool()); + process_utxos(chainman.ActiveChainstate().CoinsTip(), CTxMemPool()); } for (size_t i = 0; i < hits.size(); ++i) { @@ -661,8 +698,8 @@ // serialize data // use exact same output as mentioned in Bip64 CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << ::ChainActive().Height() - << ::ChainActive().Tip()->GetBlockHash() << bitmap + ssGetUTXOResponse << chainman.ActiveHeight() + << chainman.ActiveTip()->GetBlockHash() << bitmap << outs; std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); @@ -673,8 +710,8 @@ case RetFormat::HEX: { CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION); - ssGetUTXOResponse << ::ChainActive().Height() - << ::ChainActive().Tip()->GetBlockHash() << bitmap + ssGetUTXOResponse << chainman.ActiveHeight() + << chainman.ActiveTip()->GetBlockHash() << bitmap << outs; std::string strHex = HexStr(ssGetUTXOResponse) + "\n"; @@ -688,9 +725,9 @@ // pack in some essentials // use more or less the same output as mentioned in Bip64 - objGetUTXOResponse.pushKV("chainHeight", ::ChainActive().Height()); + objGetUTXOResponse.pushKV("chainHeight", chainman.ActiveHeight()); objGetUTXOResponse.pushKV( - "chaintipHash", ::ChainActive().Tip()->GetBlockHash().GetHex()); + "chaintipHash", chainman.ActiveTip()->GetBlockHash().GetHex()); objGetUTXOResponse.pushKV("bitmap", bitmapStringRepresentation); UniValue utxos(UniValue::VARR); @@ -738,11 +775,17 @@ CBlockIndex *pblockindex = nullptr; { + ChainstateManager *maybe_chainman = GetChainman(context, req); + if (!maybe_chainman) { + return false; + } + ChainstateManager &chainman = *maybe_chainman; LOCK(cs_main); - if (blockheight > ::ChainActive().Height()) { + const CChain &active_chain = chainman.ActiveChain(); + if (blockheight > active_chain.Height()) { return RESTERR(req, HTTP_NOT_FOUND, "Block height out of range"); } - pblockindex = ::ChainActive()[blockheight]; + pblockindex = active_chain[blockheight]; } switch (rf) { case RetFormat::BINARY: {