diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -64,10 +65,14 @@ // not possible as the whole application has too many global state. However, // this is a first step. auto &config = const_cast(GetConfig()); + RPCServer rpcServer; - HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer); NodeContext node; + util::Ref context{node}; + + HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer, context); + bool fRet = false; util::ThreadSetInternalName("init"); diff --git a/src/httprpc.h b/src/httprpc.h --- a/src/httprpc.h +++ b/src/httprpc.h @@ -10,6 +10,10 @@ class Config; +namespace util { +class Ref; +} // namespace util + class HTTPRPCRequestProcessor { private: Config &config; @@ -18,8 +22,11 @@ bool ProcessHTTPRequest(HTTPRequest *request); public: - HTTPRPCRequestProcessor(Config &configIn, RPCServer &rpcServerIn) - : config(configIn), rpcServer(rpcServerIn) {} + const util::Ref &context; + + HTTPRPCRequestProcessor(Config &configIn, RPCServer &rpcServerIn, + const util::Ref &contextIn) + : config(configIn), rpcServer(rpcServerIn), context(contextIn) {} static bool DelegateHTTPRequest(HTTPRPCRequestProcessor *requestProcessor, HTTPRequest *request) { @@ -46,7 +53,7 @@ * Start HTTP REST subsystem. * Precondition; HTTP and RPC has been started. */ -void StartREST(); +void StartREST(const util::Ref &context); /** Interrupt RPC REST subsystem */ void InterruptREST(); diff --git a/src/httprpc.cpp b/src/httprpc.cpp --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -305,7 +306,7 @@ return false; } - JSONRPCRequest jreq; + JSONRPCRequest jreq(context); jreq.peerAddr = req->GetPeer().ToString(); if (!RPCAuthorized(authHeader.second, jreq.authUser)) { LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", diff --git a/src/init.h b/src/init.h --- a/src/init.h +++ b/src/init.h @@ -22,6 +22,9 @@ namespace boost { class thread_group; } // namespace boost +namespace util { +class Ref; +} // namespace util /** Interrupt threads */ void Interrupt(NodeContext &node); diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -1413,7 +1413,7 @@ return false; } if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) { - StartREST(); + StartREST(httpRPCRequestProcessor.context); } StartHTTPServer(); diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -257,7 +258,7 @@ UniValue executeRpc(Config &config, const std::string &command, const UniValue ¶ms, const std::string &uri) override { - JSONRPCRequest req; + JSONRPCRequest req(m_context_ref); req.params = params; req.strMethod = command; req.URI = uri; @@ -364,6 +365,7 @@ } NodeContext *context() override { return &m_context; } NodeContext m_context; + util::Ref m_context_ref{m_context}; }; } // namespace diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -728,7 +729,8 @@ } RPCServer rpcServer; - HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer); + util::Ref context{node}; + HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer, context); try { app.createWindow(&config, networkStyle.data()); diff --git a/src/qt/test/apptests.cpp b/src/qt/test/apptests.cpp --- a/src/qt/test/apptests.cpp +++ b/src/qt/test/apptests.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #if defined(HAVE_CONFIG_H) @@ -93,7 +94,8 @@ m_app.baseInitialize(config); RPCServer rpcServer; - HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer); + util::Ref context{test.m_node}; + HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer, context); m_app.requestInitialize(config, rpcServer, httpRPCRequestProcessor); m_app.exec(); m_app.requestShutdown(config); diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -82,12 +83,14 @@ * @param[in] req the HTTP request * return pointer to the mempool or nullptr if no mempool found */ -static CTxMemPool *GetMemPool(HTTPRequest *req) { - if (!g_rpc_node || !g_rpc_node->mempool) { +static CTxMemPool *GetMemPool(const util::Ref &context, HTTPRequest *req) { + NodeContext *node = + context.Has() ? &context.Get() : nullptr; + if (!node || !node->mempool) { RESTERR(req, HTTP_NOT_FOUND, "Mempool disabled or instance not found"); return nullptr; } - return g_rpc_node->mempool; + return node->mempool; } static RetFormat ParseDataFormat(std::string ¶m, @@ -139,8 +142,8 @@ return true; } -static bool rest_headers(Config &config, HTTPRequest *req, - const std::string &strURIPart) { +static bool rest_headers(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { if (!CheckWarmup(req)) { return false; } @@ -304,18 +307,20 @@ } } -static bool rest_block_extended(Config &config, HTTPRequest *req, +static bool rest_block_extended(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { return rest_block(config, req, strURIPart, true); } -static bool rest_block_notxdetails(Config &config, HTTPRequest *req, +static bool rest_block_notxdetails(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { return rest_block(config, req, strURIPart, false); } -static bool rest_chaininfo(Config &config, HTTPRequest *req, - const std::string &strURIPart) { +static bool rest_chaininfo(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { if (!CheckWarmup(req)) { return false; } @@ -325,7 +330,7 @@ switch (rf) { case RetFormat::JSON: { - JSONRPCRequest jsonRequest; + JSONRPCRequest jsonRequest(context); jsonRequest.params = UniValue(UniValue::VARR); UniValue chainInfoObject = getblockchaininfo(config, jsonRequest); std::string strJSON = chainInfoObject.write() + "\n"; @@ -340,13 +345,13 @@ } } -static bool rest_mempool_info(Config &config, HTTPRequest *req, - const std::string &strURIPart) { +static bool rest_mempool_info(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { if (!CheckWarmup(req)) { return false; } - const CTxMemPool *mempool = GetMemPool(req); + const CTxMemPool *mempool = GetMemPool(context, req); if (!mempool) { return false; } @@ -370,13 +375,14 @@ } } -static bool rest_mempool_contents(Config &config, HTTPRequest *req, +static bool rest_mempool_contents(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { if (!CheckWarmup(req)) { return false; } - const CTxMemPool *mempool = GetMemPool(req); + const CTxMemPool *mempool = GetMemPool(context, req); if (!mempool) { return false; } @@ -400,7 +406,7 @@ } } -static bool rest_tx(Config &config, HTTPRequest *req, +static bool rest_tx(Config &config, const util::Ref &context, HTTPRequest *req, const std::string &strURIPart) { if (!CheckWarmup(req)) { return false; @@ -467,8 +473,8 @@ } } -static bool rest_getutxos(Config &config, HTTPRequest *req, - const std::string &strURIPart) { +static bool rest_getutxos(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &strURIPart) { if (!CheckWarmup(req)) { return false; } @@ -599,7 +605,7 @@ }; if (fCheckMemPool) { - const CTxMemPool *mempool = GetMemPool(req); + const CTxMemPool *mempool = GetMemPool(context, req); if (!mempool) { return false; } @@ -692,7 +698,8 @@ } } -static bool rest_blockhash_by_height(Config &config, HTTPRequest *req, +static bool rest_blockhash_by_height(Config &config, const util::Ref &context, + HTTPRequest *req, const std::string &str_uri_part) { if (!CheckWarmup(req)) { return false; @@ -745,7 +752,7 @@ static const struct { const char *prefix; - bool (*handler)(Config &config, HTTPRequest *req, + bool (*handler)(Config &config, const util::Ref &context, HTTPRequest *req, const std::string &strReq); } uri_prefixes[] = { {"/rest/tx/", rest_tx}, @@ -759,10 +766,13 @@ {"/rest/blockhashbyheight/", rest_blockhash_by_height}, }; -void StartREST() { - for (size_t i = 0; i < ARRAYLEN(uri_prefixes); i++) { - RegisterHTTPHandler(uri_prefixes[i].prefix, false, - uri_prefixes[i].handler); +void StartREST(const util::Ref &context) { + for (const auto &up : uri_prefixes) { + auto handler = [&context, up](Config &config, HTTPRequest *req, + const std::string &prefix) { + return up.handler(config, context, req, prefix); + }; + RegisterHTTPHandler(up.prefix, false, handler); } } diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -15,6 +15,9 @@ class CTxMemPool; class JSONRPCRequest; struct NodeContext; +namespace util { +class Ref; +} // namespace util extern RecursiveMutex cs_main; @@ -52,6 +55,7 @@ //! direct way to pass in state to RPC methods without globals. extern NodeContext *g_rpc_node; -CTxMemPool &EnsureMemPool(); +NodeContext &EnsureNodeContext(const util::Ref &context); +CTxMemPool &EnsureMemPool(const util::Ref &context); #endif // BITCOIN_RPC_BLOCKCHAIN_H diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -53,13 +54,20 @@ static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange); -CTxMemPool &EnsureMemPool() { - CHECK_NONFATAL(g_rpc_node); - if (!g_rpc_node->mempool) { +NodeContext &EnsureNodeContext(const util::Ref &context) { + if (!context.Has()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found"); + } + return context.Get(); +} + +CTxMemPool &EnsureMemPool(const util::Ref &context) { + NodeContext &node = EnsureNodeContext(context); + if (!node.mempool) { throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found"); } - return *g_rpc_node->mempool; + return *node.mempool; } /** @@ -595,7 +603,7 @@ fVerbose = request.params[0].get_bool(); } - return MempoolToJSON(EnsureMemPool(), fVerbose); + return MempoolToJSON(EnsureMemPool(request.context), fVerbose); } static UniValue getmempoolancestors(const Config &config, @@ -635,7 +643,7 @@ TxId txid(ParseHashV(request.params[0], "parameter 1")); - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(txid); @@ -707,7 +715,7 @@ TxId txid(ParseHashV(request.params[0], "parameter 1")); - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(txid); @@ -759,7 +767,7 @@ TxId txid(ParseHashV(request.params[0], "parameter 1")); - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); LOCK(mempool.cs); CTxMemPool::txiter it = mempool.mapTx.find(txid); @@ -1219,7 +1227,7 @@ CCoinsViewCache *coins_view = &::ChainstateActive().CoinsTip(); if (fMempool) { - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); LOCK(mempool.cs); CCoinsViewMemPool view(coins_view, mempool); if (!view.GetCoin(out, coin) || mempool.isSpent(out)) { @@ -1657,7 +1665,7 @@ } .Check(request); - return MempoolInfoToJSON(EnsureMemPool()); + return MempoolInfoToJSON(EnsureMemPool(request.context)); } static UniValue preciousblock(const Config &config, @@ -2323,7 +2331,7 @@ } .Check(request); - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); if (!mempool.IsLoaded()) { throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet"); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -225,7 +225,7 @@ strprintf("Cannot derive script without private keys")); } - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); CHECK_NONFATAL(coinbase_script.size() == 1); @@ -270,7 +270,7 @@ "Error: Invalid address"); } - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); CScript coinbase_script = GetScriptForDestination(destination); @@ -309,7 +309,7 @@ .Check(request); LOCK(cs_main); - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); UniValue obj(UniValue::VOBJ); obj.pushKV("blocks", int(::ChainActive().Height())); @@ -368,7 +368,7 @@ "prioritisetransaction must be 0."); } - EnsureMemPool().PrioritiseTransaction(txid, nAmount); + EnsureMemPool(request.context).PrioritiseTransaction(txid, nAmount); return true; } @@ -589,13 +589,14 @@ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); } - if (!g_rpc_node->connman) { + NodeContext &node = EnsureNodeContext(request.context); + if (!node.connman) { throw JSONRPCError( RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); } - if (g_rpc_node->connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) { + if (node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) { throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Bitcoin is not connected!"); } @@ -606,7 +607,7 @@ } static unsigned int nTransactionsUpdatedLast; - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has @@ -929,7 +930,7 @@ } .Check(request); - const CTxMemPool &mempool = EnsureMemPool(); + const CTxMemPool &mempool = EnsureMemPool(request.context); return ValueFromAmount(mempool.estimateFee().GetFeePerK()); } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -17,6 +17,7 @@ #include #include