diff options
author | MarcoFalke <falke.marco@gmail.com> | 2020-05-21 06:53:30 -0400 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2020-05-21 06:53:39 -0400 |
commit | 25ad2c623af30056ffb36dcd203a52edda2b170f (patch) | |
tree | 94fabc7fa4df3d58fb1f2f1fc204ffc8db93bd0e | |
parent | 97b21b302a117dc8ef8334a5f3c94f6a6b9eeff0 (diff) | |
parent | b3f7f375efb9a9ca9a7a4f2caf41fe3df2262520 (diff) |
Merge #18740: Remove g_rpc_node global
b3f7f375efb9a9ca9a7a4f2caf41fe3df2262520 refactor: Remove g_rpc_node global (Russell Yanofsky)
ccb5059ee89f6e8dc31ba5b82830b384890bb65e scripted-diff: Remove g_rpc_node references (Russell Yanofsky)
6fca33b2edc09ed62dab2323c780b31585de1750 refactor: Pass NodeContext to RPC and REST methods through util::Ref (Russell Yanofsky)
691c817b340d10e806dc3b1834d2a8fcc5e681fd Add util::Ref class as temporary alternative for c++17 std::any (Russell Yanofsky)
Pull request description:
This PR removes the `g_rpc_node` global, to get same benefits we see removing other globals and make RPC code more testable, modular, and reusable.
This uses a hybrid of the approaches suggested in #17548. Instead of using `std::any`, which isn't available in c++11, or `void*`, which isn't type safe, it uses a small new `util::Ref` helper class, which acts like a simplified `std::any` that only holds references, not values.
Motivation for writing this was to provide an simpler alternative to #18647 by Harris Brakmić (brakmic) which avoids some shortcomings of that PR (https://github.com/bitcoin/bitcoin/pull/18647#issuecomment-617878826)
ACKs for top commit:
MarcoFalke:
re-ACK b3f7f375ef, only change is adding back const and more tests 🚾
ajtowns:
ACK b3f7f375efb9a9ca9a7a4f2caf41fe3df2262520
Tree-SHA512: 56292268a001bdbe34d641db1180c215351503966ff451e55cc96c9137f1d262225d7d7733de9c9da7ce7d7a4b34213a98c2476266b58c89dbbb0f3cb5aa5d70
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/Makefile.test.include | 1 | ||||
-rw-r--r-- | src/bitcoind.cpp | 4 | ||||
-rw-r--r-- | src/httprpc.cpp | 11 | ||||
-rw-r--r-- | src/httprpc.h | 7 | ||||
-rw-r--r-- | src/init.cpp | 11 | ||||
-rw-r--r-- | src/init.h | 5 | ||||
-rw-r--r-- | src/interfaces/node.cpp | 6 | ||||
-rw-r--r-- | src/rest.cpp | 45 | ||||
-rw-r--r-- | src/rpc/blockchain.cpp | 33 | ||||
-rw-r--r-- | src/rpc/blockchain.h | 11 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 17 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 12 | ||||
-rw-r--r-- | src/rpc/net.cpp | 107 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 12 | ||||
-rw-r--r-- | src/rpc/request.h | 7 | ||||
-rw-r--r-- | src/test/ref_tests.cpp | 33 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 14 | ||||
-rw-r--r-- | src/test/util/setup_common.cpp | 4 | ||||
-rw-r--r-- | src/util/check.h | 4 | ||||
-rw-r--r-- | src/util/ref.h | 38 | ||||
-rw-r--r-- | src/wallet/test/wallet_tests.cpp | 10 |
22 files changed, 262 insertions, 131 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index c5cd1c1ea7..882d83e0b8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -227,6 +227,7 @@ BITCOIN_CORE_H = \ util/message.h \ util/moneystr.h \ util/rbf.h \ + util/ref.h \ util/settings.h \ util/string.h \ util/threadnames.h \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 3a0d4fdc15..6ba0e9f270 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -229,6 +229,7 @@ BITCOIN_TESTS =\ test/prevector_tests.cpp \ test/raii_event_tests.cpp \ test/random_tests.cpp \ + test/ref_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ test/sanity_tests.cpp \ diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 43d3f3c5ac..b8e8717896 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -16,6 +16,7 @@ #include <noui.h> #include <shutdown.h> #include <ui_interface.h> +#include <util/ref.h> #include <util/strencodings.h> #include <util/system.h> #include <util/threadnames.h> @@ -77,6 +78,7 @@ static bool AppInit(int argc, char* argv[]) return true; } + util::Ref context{node}; try { if (!CheckDataDirOption()) { @@ -145,7 +147,7 @@ static bool AppInit(int argc, char* argv[]) // If locking the data directory failed, exit immediately return false; } - fRet = AppInitMain(node); + fRet = AppInitMain(context, node); } catch (const std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); diff --git a/src/httprpc.cpp b/src/httprpc.cpp index 95e13998aa..f1b9997371 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -150,7 +150,7 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna return multiUserAuthorized(strUserPass); } -static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) +static bool HTTPReq_JSONRPC(const util::Ref& context, HTTPRequest* req) { // JSONRPC handles only POST if (req->GetRequestMethod() != HTTPRequest::POST) { @@ -165,7 +165,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &) 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", jreq.peerAddr); @@ -284,15 +284,16 @@ static bool InitRPCAuthentication() return true; } -bool StartHTTPRPC() +bool StartHTTPRPC(const util::Ref& context) { LogPrint(BCLog::RPC, "Starting HTTP RPC server\n"); if (!InitRPCAuthentication()) return false; - RegisterHTTPHandler("/", true, HTTPReq_JSONRPC); + auto handle_rpc = [&context](HTTPRequest* req, const std::string&) { return HTTPReq_JSONRPC(context, req); }; + RegisterHTTPHandler("/", true, handle_rpc); if (g_wallet_init_interface.HasWalletSupport()) { - RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC); + RegisterHTTPHandler("/wallet/", false, handle_rpc); } struct event_base* eventBase = EventBase(); assert(eventBase); diff --git a/src/httprpc.h b/src/httprpc.h index 99e4d59b8a..a6a38fc95a 100644 --- a/src/httprpc.h +++ b/src/httprpc.h @@ -5,11 +5,14 @@ #ifndef BITCOIN_HTTPRPC_H #define BITCOIN_HTTPRPC_H +namespace util { +class Ref; +} // namespace util /** Start HTTP RPC subsystem. * Precondition; HTTP and RPC has been started. */ -bool StartHTTPRPC(); +bool StartHTTPRPC(const util::Ref& context); /** Interrupt HTTP RPC subsystem. */ void InterruptHTTPRPC(); @@ -21,7 +24,7 @@ void StopHTTPRPC(); /** 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/init.cpp b/src/init.cpp index 341c37cc5a..025ae06520 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -784,16 +784,16 @@ static bool InitSanityCheck() return true; } -static bool AppInitServers() +static bool AppInitServers(const util::Ref& context) { RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); if (!InitHTTPServer()) return false; StartRPC(); - if (!StartHTTPRPC()) + if (!StartHTTPRPC(context)) return false; - if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(); + if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(context); StartHTTPServer(); return true; } @@ -1238,7 +1238,7 @@ bool AppInitLockDataDirectory() return true; } -bool AppInitMain(NodeContext& node) +bool AppInitMain(const util::Ref& context, NodeContext& node) { const CChainParams& chainparams = Params(); // ********************************************************* Step 4a: application initialization @@ -1340,7 +1340,6 @@ bool AppInitMain(NodeContext& node) for (const auto& client : node.chain_clients) { client->registerRpcs(); } - g_rpc_node = &node; #if ENABLE_ZMQ RegisterZMQRPCCommands(tableRPC); #endif @@ -1353,7 +1352,7 @@ bool AppInitMain(NodeContext& node) if (gArgs.GetBoolArg("-server", false)) { uiInterface.InitMessage_connect(SetRPCWarmupStatus); - if (!AppInitServers()) + if (!AppInitServers(context)) return InitError(_("Unable to start HTTP server. See debug log for details.")); } diff --git a/src/init.h b/src/init.h index ef568b6f38..33fe96e8ea 100644 --- a/src/init.h +++ b/src/init.h @@ -14,6 +14,9 @@ struct NodeContext; namespace boost { class thread_group; } // namespace boost +namespace util { +class Ref; +} // namespace util /** Interrupt threads */ void Interrupt(NodeContext& node); @@ -51,7 +54,7 @@ bool AppInitLockDataDirectory(); * @note This should only be done after daemonization. Call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read, AppInitLockDataDirectory should have been called. */ -bool AppInitMain(NodeContext& node); +bool AppInitMain(const util::Ref& context, NodeContext& node); /** * Register all arguments with the ArgsManager diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index d619d2d67d..3c94e44b53 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -27,6 +27,7 @@ #include <sync.h> #include <txmempool.h> #include <ui_interface.h> +#include <util/ref.h> #include <util/system.h> #include <util/translation.h> #include <validation.h> @@ -80,7 +81,7 @@ public: bool appInitMain() override { m_context.chain = MakeChain(m_context); - return AppInitMain(m_context); + return AppInitMain(m_context_ref, m_context); } void appShutdown() override { @@ -225,7 +226,7 @@ public: CFeeRate getDustRelayFee() override { return ::dustRelayFee; } UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override { - JSONRPCRequest req; + JSONRPCRequest req(m_context_ref); req.params = params; req.strMethod = command; req.URI = uri; @@ -323,6 +324,7 @@ public: } NodeContext* context() override { return &m_context; } NodeContext m_context; + util::Ref m_context_ref{m_context}; }; } // namespace diff --git a/src/rest.cpp b/src/rest.cpp index 1d381696d1..cde8b472d3 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -18,6 +18,7 @@ #include <sync.h> #include <txmempool.h> #include <util/check.h> +#include <util/ref.h> #include <util/strencodings.h> #include <validation.h> #include <version.h> @@ -75,13 +76,14 @@ static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string me * @param[in] req the HTTP request * return pointer to the mempool or nullptr if no mempool found */ -static CTxMemPool* GetMemPool(HTTPRequest* req) +static CTxMemPool* GetMemPool(const util::Ref& context, HTTPRequest* req) { - if (!g_rpc_node || !g_rpc_node->mempool) { + NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : 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& param, const std::string& strReq) @@ -129,7 +131,8 @@ static bool CheckWarmup(HTTPRequest* req) return true; } -static bool rest_headers(HTTPRequest* req, +static bool rest_headers(const util::Ref& context, + HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) @@ -270,12 +273,12 @@ static bool rest_block(HTTPRequest* req, } } -static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart) +static bool rest_block_extended(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) { return rest_block(req, strURIPart, true); } -static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPart) +static bool rest_block_notxdetails(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) { return rest_block(req, strURIPart, false); } @@ -283,7 +286,7 @@ static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPa // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp UniValue getblockchaininfo(const JSONRPCRequest& request); -static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) +static bool rest_chaininfo(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -292,7 +295,7 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) switch (rf) { case RetFormat::JSON: { - JSONRPCRequest jsonRequest; + JSONRPCRequest jsonRequest(context); jsonRequest.params = UniValue(UniValue::VARR); UniValue chainInfoObject = getblockchaininfo(jsonRequest); std::string strJSON = chainInfoObject.write() + "\n"; @@ -306,11 +309,11 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart) } } -static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) +static bool rest_mempool_info(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; std::string param; const RetFormat rf = ParseDataFormat(param, strURIPart); @@ -330,10 +333,10 @@ static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart) } } -static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart) +static bool rest_mempool_contents(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; std::string param; const RetFormat rf = ParseDataFormat(param, strURIPart); @@ -353,7 +356,7 @@ static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPar } } -static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) +static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -409,7 +412,7 @@ static bool rest_tx(HTTPRequest* req, const std::string& strURIPart) } } -static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) +static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std::string& strURIPart) { if (!CheckWarmup(req)) return false; @@ -518,7 +521,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) }; if (fCheckMemPool) { - const CTxMemPool* mempool = GetMemPool(req); + const CTxMemPool* mempool = GetMemPool(context, req); if (!mempool) return false; // use db+mempool as cache backend in case user likes to query mempool LOCK2(cs_main, mempool->cs); @@ -595,7 +598,7 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) } } -static bool rest_blockhash_by_height(HTTPRequest* req, +static bool rest_blockhash_by_height(const util::Ref& context, HTTPRequest* req, const std::string& str_uri_part) { if (!CheckWarmup(req)) return false; @@ -643,7 +646,7 @@ static bool rest_blockhash_by_height(HTTPRequest* req, static const struct { const char* prefix; - bool (*handler)(HTTPRequest* req, const std::string& strReq); + bool (*handler)(const util::Ref& context, HTTPRequest* req, const std::string& strReq); } uri_prefixes[] = { {"/rest/tx/", rest_tx}, {"/rest/block/notxdetails/", rest_block_notxdetails}, @@ -656,10 +659,12 @@ static const struct { {"/rest/blockhashbyheight/", rest_blockhash_by_height}, }; -void StartREST() +void StartREST(const util::Ref& context) { - for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++) - RegisterHTTPHandler(uri_prefixes[i].prefix, false, uri_prefixes[i].handler); + for (const auto& up : uri_prefixes) { + auto handler = [&context, up](HTTPRequest* req, const std::string& prefix) { return up.handler(context, req, prefix); }; + RegisterHTTPHandler(up.prefix, false, handler); + } } void InterruptREST() diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 2c984603ff..3c5fd565e3 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -29,6 +29,7 @@ #include <txdb.h> #include <txmempool.h> #include <undo.h> +#include <util/ref.h> #include <util/strencodings.h> #include <util/system.h> #include <validation.h> @@ -53,13 +54,21 @@ static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock; -CTxMemPool& EnsureMemPool() +NodeContext& EnsureNodeContext(const util::Ref& context) { - CHECK_NONFATAL(g_rpc_node); - if (!g_rpc_node->mempool) { + if (!context.Has<NodeContext>()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found"); + } + return context.Get<NodeContext>(); +} + +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; } /* Calculate the difficulty for a given block index. @@ -519,7 +528,7 @@ static UniValue getrawmempool(const JSONRPCRequest& request) if (!request.params[0].isNull()) fVerbose = request.params[0].get_bool(); - return MempoolToJSON(EnsureMemPool(), fVerbose); + return MempoolToJSON(EnsureMemPool(request.context), fVerbose); } static UniValue getmempoolancestors(const JSONRPCRequest& request) @@ -549,7 +558,7 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) uint256 hash = 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(hash); @@ -612,7 +621,7 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) uint256 hash = 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(hash); @@ -662,7 +671,7 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) uint256 hash = 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(hash); @@ -1045,7 +1054,7 @@ UniValue gettxout(const JSONRPCRequest& request) 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)) { @@ -1415,7 +1424,7 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) }, }.Check(request); - return MempoolInfoToJSON(EnsureMemPool()); + return MempoolInfoToJSON(EnsureMemPool(request.context)); } static UniValue preciousblock(const JSONRPCRequest& request) @@ -1934,7 +1943,7 @@ static UniValue savemempool(const JSONRPCRequest& request) }, }.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"); @@ -2385,5 +2394,3 @@ static const CRPCCommand commands[] = for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) t.appendCommand(commands[vcidx].name, &commands[vcidx]); } - -NodeContext* g_rpc_node = nullptr; diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 54165af707..453d0bc650 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -18,6 +18,9 @@ class CBlockIndex; class CTxMemPool; class UniValue; struct NodeContext; +namespace util { +class Ref; +} // namespace util static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5; @@ -47,11 +50,7 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex /** Used by getblockstats to get feerates at different percentiles by weight */ void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight); -//! Pointer to node state that needs to be declared as a global to be accessible -//! RPC methods. Due to limitations of the RPC framework, there's currently no -//! 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 diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 59ab80bcd5..bcaed1ef88 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -227,7 +227,7 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } - const CTxMemPool& mempool = EnsureMemPool(); + const CTxMemPool& mempool = EnsureMemPool(request.context); return generateBlocks(mempool, coinbase_script, num_blocks, max_tries); } @@ -265,7 +265,7 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address"); } - const CTxMemPool& mempool = EnsureMemPool(); + const CTxMemPool& mempool = EnsureMemPool(request.context); CScript coinbase_script = GetScriptForDestination(destination); @@ -311,7 +311,7 @@ static UniValue generateblock(const JSONRPCRequest& request) coinbase_script = GetScriptForDestination(destination); } - const CTxMemPool& mempool = EnsureMemPool(); + const CTxMemPool& mempool = EnsureMemPool(request.context); std::vector<CTransactionRef> txs; const auto raw_txs_or_txids = request.params[1].get_array(); @@ -403,7 +403,7 @@ static UniValue getmininginfo(const JSONRPCRequest& request) }.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()); @@ -449,7 +449,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0."); } - EnsureMemPool().PrioritiseTransaction(hash, nAmount); + EnsureMemPool(request.context).PrioritiseTransaction(hash, nAmount); return true; } @@ -635,17 +635,18 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) if (strMode != "template") 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, PACKAGE_NAME " is not connected!"); if (::ChainstateActive().IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); static unsigned int nTransactionsUpdatedLast; - const CTxMemPool& mempool = EnsureMemPool(); + const CTxMemPool& mempool = EnsureMemPool(request.context); if (!lpval.isNull()) { diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index f3c5fed858..ce98a7c937 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -15,6 +15,7 @@ #include <script/descriptor.h> #include <util/check.h> #include <util/message.h> // For MessageSign(), MessageVerify() +#include <util/ref.h> #include <util/strencodings.h> #include <util/system.h> @@ -366,8 +367,8 @@ static UniValue setmocktime(const JSONRPCRequest& request) RPCTypeCheck(request.params, {UniValue::VNUM}); int64_t time = request.params[0].get_int64(); SetMockTime(time); - if (g_rpc_node) { - for (const auto& chain_client : g_rpc_node->chain_clients) { + if (request.context.Has<NodeContext>()) { + for (const auto& chain_client : request.context.Get<NodeContext>().chain_clients) { chain_client->setMockTime(time); } } @@ -398,9 +399,10 @@ static UniValue mockscheduler(const JSONRPCRequest& request) } // protect against null pointer dereference - CHECK_NONFATAL(g_rpc_node); - CHECK_NONFATAL(g_rpc_node->scheduler); - g_rpc_node->scheduler->MockForward(std::chrono::seconds(delta_seconds)); + CHECK_NONFATAL(request.context.Has<NodeContext>()); + NodeContext& node = request.context.Get<NodeContext>(); + CHECK_NONFATAL(node.scheduler); + node.scheduler->MockForward(std::chrono::seconds(delta_seconds)); return NullUniValue; } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index d6d15f8b56..e29aa03695 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -42,10 +42,11 @@ static UniValue getconnectioncount(const JSONRPCRequest& request) }, }.Check(request); - 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"); - return (int)g_rpc_node->connman->GetNodeCount(CConnman::CONNECTIONS_ALL); + return (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL); } static UniValue ping(const JSONRPCRequest& request) @@ -62,11 +63,12 @@ static UniValue ping(const JSONRPCRequest& request) }, }.Check(request); - 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"); // Request that each node send a ping during next message processing pass - g_rpc_node->connman->ForEachNode([](CNode* pnode) { + node.connman->ForEachNode([](CNode* pnode) { pnode->fPingQueued = true; }); return NullUniValue; @@ -139,11 +141,12 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) }, }.Check(request); - 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"); std::vector<CNodeStats> vstats; - g_rpc_node->connman->GetNodeStats(vstats); + node.connman->GetNodeStats(vstats); UniValue ret(UniValue::VARR); @@ -248,7 +251,8 @@ static UniValue addnode(const JSONRPCRequest& request) }, }.ToString()); - 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"); std::string strNode = request.params[0].get_str(); @@ -256,18 +260,18 @@ static UniValue addnode(const JSONRPCRequest& request) if (strCommand == "onetry") { CAddress addr; - g_rpc_node->connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true); + node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true); return NullUniValue; } if (strCommand == "add") { - if(!g_rpc_node->connman->AddNode(strNode)) + if(!node.connman->AddNode(strNode)) throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); } else if(strCommand == "remove") { - if(!g_rpc_node->connman->RemoveAddedNode(strNode)) + if(!node.connman->RemoveAddedNode(strNode)) throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); } @@ -293,7 +297,8 @@ static UniValue disconnectnode(const JSONRPCRequest& request) }, }.Check(request); - 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"); bool success; @@ -302,11 +307,11 @@ static UniValue disconnectnode(const JSONRPCRequest& request) if (!address_arg.isNull() && id_arg.isNull()) { /* handle disconnect-by-address */ - success = g_rpc_node->connman->DisconnectNode(address_arg.get_str()); + success = node.connman->DisconnectNode(address_arg.get_str()); } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { /* handle disconnect-by-id */ NodeId nodeid = (NodeId) id_arg.get_int64(); - success = g_rpc_node->connman->DisconnectNode(nodeid); + success = node.connman->DisconnectNode(nodeid); } else { throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided."); } @@ -350,10 +355,11 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) }, }.Check(request); - 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"); - std::vector<AddedNodeInfo> vInfo = g_rpc_node->connman->GetAddedNodeInfo(); + std::vector<AddedNodeInfo> vInfo = node.connman->GetAddedNodeInfo(); if (!request.params[0].isNull()) { bool found = false; @@ -417,21 +423,22 @@ static UniValue getnettotals(const JSONRPCRequest& request) + HelpExampleRpc("getnettotals", "") }, }.Check(request); - 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"); UniValue obj(UniValue::VOBJ); - obj.pushKV("totalbytesrecv", g_rpc_node->connman->GetTotalBytesRecv()); - obj.pushKV("totalbytessent", g_rpc_node->connman->GetTotalBytesSent()); + obj.pushKV("totalbytesrecv", node.connman->GetTotalBytesRecv()); + obj.pushKV("totalbytessent", node.connman->GetTotalBytesSent()); obj.pushKV("timemillis", GetTimeMillis()); UniValue outboundLimit(UniValue::VOBJ); - outboundLimit.pushKV("timeframe", g_rpc_node->connman->GetMaxOutboundTimeframe()); - outboundLimit.pushKV("target", g_rpc_node->connman->GetMaxOutboundTarget()); - outboundLimit.pushKV("target_reached", g_rpc_node->connman->OutboundTargetReached(false)); - outboundLimit.pushKV("serve_historical_blocks", !g_rpc_node->connman->OutboundTargetReached(true)); - outboundLimit.pushKV("bytes_left_in_cycle", g_rpc_node->connman->GetOutboundTargetBytesLeft()); - outboundLimit.pushKV("time_left_in_cycle", g_rpc_node->connman->GetMaxOutboundTimeLeftInCycle()); + outboundLimit.pushKV("timeframe", node.connman->GetMaxOutboundTimeframe()); + outboundLimit.pushKV("target", node.connman->GetMaxOutboundTarget()); + outboundLimit.pushKV("target_reached", node.connman->OutboundTargetReached(false)); + outboundLimit.pushKV("serve_historical_blocks", !node.connman->OutboundTargetReached(true)); + outboundLimit.pushKV("bytes_left_in_cycle", node.connman->GetOutboundTargetBytesLeft()); + outboundLimit.pushKV("time_left_in_cycle", node.connman->GetMaxOutboundTimeLeftInCycle()); obj.pushKV("uploadtarget", outboundLimit); return obj; } @@ -513,16 +520,17 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("version", CLIENT_VERSION); obj.pushKV("subversion", strSubVersion); obj.pushKV("protocolversion",PROTOCOL_VERSION); - if (g_rpc_node->connman) { - ServiceFlags services = g_rpc_node->connman->GetLocalServices(); + NodeContext& node = EnsureNodeContext(request.context); + if (node.connman) { + ServiceFlags services = node.connman->GetLocalServices(); obj.pushKV("localservices", strprintf("%016x", services)); obj.pushKV("localservicesnames", GetServicesNames(services)); } obj.pushKV("localrelay", g_relay_txes); obj.pushKV("timeoffset", GetTimeOffset()); - if (g_rpc_node->connman) { - obj.pushKV("networkactive", g_rpc_node->connman->GetNetworkActive()); - obj.pushKV("connections", (int)g_rpc_node->connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); + if (node.connman) { + obj.pushKV("networkactive", node.connman->GetNetworkActive()); + obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); } obj.pushKV("networks", GetNetworksInfo()); obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); @@ -567,7 +575,8 @@ static UniValue setban(const JSONRPCRequest& request) if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || (strCommand != "add" && strCommand != "remove")) { throw std::runtime_error(help.ToString()); } - if (!g_rpc_node->banman) { + NodeContext& node = EnsureNodeContext(request.context); + if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } @@ -591,7 +600,7 @@ static UniValue setban(const JSONRPCRequest& request) if (strCommand == "add") { - if (isSubnet ? g_rpc_node->banman->IsBanned(subNet) : g_rpc_node->banman->IsBanned(netAddr)) { + if (isSubnet ? node.banman->IsBanned(subNet) : node.banman->IsBanned(netAddr)) { throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); } @@ -604,20 +613,20 @@ static UniValue setban(const JSONRPCRequest& request) absolute = true; if (isSubnet) { - g_rpc_node->banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute); - if (g_rpc_node->connman) { - g_rpc_node->connman->DisconnectNode(subNet); + node.banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute); + if (node.connman) { + node.connman->DisconnectNode(subNet); } } else { - g_rpc_node->banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); - if (g_rpc_node->connman) { - g_rpc_node->connman->DisconnectNode(netAddr); + node.banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute); + if (node.connman) { + node.connman->DisconnectNode(netAddr); } } } else if(strCommand == "remove") { - if (!( isSubnet ? g_rpc_node->banman->Unban(subNet) : g_rpc_node->banman->Unban(netAddr) )) { + if (!( isSubnet ? node.banman->Unban(subNet) : node.banman->Unban(netAddr) )) { throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned."); } } @@ -645,12 +654,13 @@ static UniValue listbanned(const JSONRPCRequest& request) }, }.Check(request); - if(!g_rpc_node->banman) { + NodeContext& node = EnsureNodeContext(request.context); + if(!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } banmap_t banMap; - g_rpc_node->banman->GetBanned(banMap); + node.banman->GetBanned(banMap); UniValue bannedAddresses(UniValue::VARR); for (const auto& entry : banMap) @@ -679,11 +689,12 @@ static UniValue clearbanned(const JSONRPCRequest& request) + HelpExampleRpc("clearbanned", "") }, }.Check(request); - if (!g_rpc_node->banman) { + NodeContext& node = EnsureNodeContext(request.context); + if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); } - g_rpc_node->banman->ClearBanned(); + node.banman->ClearBanned(); return NullUniValue; } @@ -699,13 +710,14 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) RPCExamples{""}, }.Check(request); - 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"); } - g_rpc_node->connman->SetNetworkActive(request.params[0].get_bool()); + node.connman->SetNetworkActive(request.params[0].get_bool()); - return g_rpc_node->connman->GetNetworkActive(); + return node.connman->GetNetworkActive(); } static UniValue getnodeaddresses(const JSONRPCRequest& request) @@ -732,7 +744,8 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) + HelpExampleRpc("getnodeaddresses", "8") }, }.Check(request); - 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"); } @@ -744,7 +757,7 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) } } // returns a shuffled list of CAddress - std::vector<CAddress> vAddr = g_rpc_node->connman->GetAddresses(); + std::vector<CAddress> vAddr = node.connman->GetAddresses(); UniValue ret(UniValue::VARR); int address_return_count = std::min<int>(count, vAddr.size()); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 063ee1697c..e14217c307 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -653,7 +653,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { - const CTxMemPool& mempool = EnsureMemPool(); + const CTxMemPool& mempool = EnsureMemPool(request.context); LOCK(cs_main); LOCK(mempool.cs); CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); @@ -778,7 +778,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) for (const CTxIn& txin : mtx.vin) { coins[txin.prevout]; // Create empty map entry keyed by prevout. } - FindCoins(*g_rpc_node, coins); + NodeContext& node = EnsureNodeContext(request.context); + FindCoins(node, coins); // Parse the prevtxs array ParsePrevouts(request.params[2], &keystore, coins); @@ -837,7 +838,8 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) std::string err_string; AssertLockNotHeld(cs_main); - const TransactionError err = BroadcastTransaction(*g_rpc_node, tx, err_string, max_raw_tx_fee, /*relay*/ true, /*wait_callback*/ true); + NodeContext& node = EnsureNodeContext(request.context); + const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay*/ true, /*wait_callback*/ true); if (TransactionError::OK != err) { throw JSONRPCTransactionError(err, err_string); } @@ -904,7 +906,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) DEFAULT_MAX_RAW_TX_FEE_RATE : CFeeRate(AmountFromValue(request.params[1])); - CTxMemPool& mempool = EnsureMemPool(); + CTxMemPool& mempool = EnsureMemPool(request.context); int64_t virtual_size = GetVirtualTransactionSize(*tx); CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size); @@ -1555,7 +1557,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { - const CTxMemPool& mempool = EnsureMemPool(); + const CTxMemPool& mempool = EnsureMemPool(request.context); LOCK2(cs_main, mempool.cs); CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, mempool); diff --git a/src/rpc/request.h b/src/rpc/request.h index 99eb4f9354..0a15b48de4 100644 --- a/src/rpc/request.h +++ b/src/rpc/request.h @@ -10,6 +10,10 @@ #include <univalue.h> +namespace util { +class Ref; +} // namespace util + UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id); UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id); std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id); @@ -34,8 +38,9 @@ public: std::string URI; std::string authUser; std::string peerAddr; + const util::Ref& context; - JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {} + JSONRPCRequest(const util::Ref& context) : id(NullUniValue), params(NullUniValue), fHelp(false), context(context) {} void parse(const UniValue& valRequest); }; diff --git a/src/test/ref_tests.cpp b/src/test/ref_tests.cpp new file mode 100644 index 0000000000..0ec0799fbc --- /dev/null +++ b/src/test/ref_tests.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <util/ref.h> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_SUITE(ref_tests) + +BOOST_AUTO_TEST_CASE(ref_test) +{ + util::Ref ref; + BOOST_CHECK(!ref.Has<int>()); + BOOST_CHECK_THROW(ref.Get<int>(), NonFatalCheckError); + int value = 5; + ref.Set(value); + BOOST_CHECK(ref.Has<int>()); + BOOST_CHECK_EQUAL(ref.Get<int>(), 5); + ++ref.Get<int>(); + BOOST_CHECK_EQUAL(ref.Get<int>(), 6); + BOOST_CHECK_EQUAL(value, 6); + ++value; + BOOST_CHECK_EQUAL(value, 7); + BOOST_CHECK_EQUAL(ref.Get<int>(), 7); + BOOST_CHECK(!ref.Has<bool>()); + BOOST_CHECK_THROW(ref.Get<bool>(), NonFatalCheckError); + ref.Clear(); + BOOST_CHECK(!ref.Has<int>()); + BOOST_CHECK_THROW(ref.Get<int>(), NonFatalCheckError); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index d9c66f1c19..b54cbb3f00 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -10,6 +10,7 @@ #include <interfaces/chain.h> #include <node/context.h> #include <test/util/setup_common.h> +#include <util/ref.h> #include <util/time.h> #include <boost/algorithm/string.hpp> @@ -19,13 +20,20 @@ #include <rpc/blockchain.h> -UniValue CallRPC(std::string args) +class RPCTestingSetup : public TestingSetup +{ +public: + UniValue CallRPC(std::string args); +}; + +UniValue RPCTestingSetup::CallRPC(std::string args) { std::vector<std::string> vArgs; boost::split(vArgs, args, boost::is_any_of(" \t")); std::string strMethod = vArgs[0]; vArgs.erase(vArgs.begin()); - JSONRPCRequest request; + util::Ref context{m_node}; + JSONRPCRequest request(context); request.strMethod = strMethod; request.params = RPCConvertValues(strMethod, vArgs); request.fHelp = false; @@ -40,7 +48,7 @@ UniValue CallRPC(std::string args) } -BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup) +BOOST_FIXTURE_TEST_SUITE(rpc_tests, RPCTestingSetup) BOOST_AUTO_TEST_CASE(rpc_rawparams) { diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index bf0afc4171..86dac55b2b 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -123,7 +123,6 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const const CChainParams& chainparams = Params(); // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. - g_rpc_node = &m_node; RegisterAllCoreRPCCommands(tableRPC); m_node.scheduler = MakeUnique<CScheduler>(); @@ -131,7 +130,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const // We have to run a scheduler thread to prevent ActivateBestChain // from blocking due to queue overrun. threadGroup.create_thread([&]{ m_node.scheduler->serviceQueue(); }); - GetMainSignals().RegisterBackgroundSignalScheduler(*g_rpc_node->scheduler); + GetMainSignals().RegisterBackgroundSignalScheduler(*m_node.scheduler); pblocktree.reset(new CBlockTreeDB(1 << 20, true)); @@ -176,7 +175,6 @@ TestingSetup::~TestingSetup() threadGroup.join_all(); GetMainSignals().FlushBackgroundCallbacks(); GetMainSignals().UnregisterBackgroundSignalScheduler(); - g_rpc_node = nullptr; m_node.connman.reset(); m_node.banman.reset(); m_node.args = nullptr; diff --git a/src/util/check.h b/src/util/check.h index d18887ae95..5c0f32cf51 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -5,6 +5,10 @@ #ifndef BITCOIN_UTIL_CHECK_H #define BITCOIN_UTIL_CHECK_H +#if defined(HAVE_CONFIG_H) +#include <config/bitcoin-config.h> +#endif + #include <tinyformat.h> #include <stdexcept> diff --git a/src/util/ref.h b/src/util/ref.h new file mode 100644 index 0000000000..9685ea9fec --- /dev/null +++ b/src/util/ref.h @@ -0,0 +1,38 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_UTIL_REF_H +#define BITCOIN_UTIL_REF_H + +#include <util/check.h> + +#include <typeindex> + +namespace util { + +/** + * Type-safe dynamic reference. + * + * This implements a small subset of the functionality in C++17's std::any + * class, and can be dropped when the project updates to C++17 + * (https://github.com/bitcoin/bitcoin/issues/16684) + */ +class Ref +{ +public: + Ref() = default; + template<typename T> Ref(T& value) { Set(value); } + template<typename T> T& Get() const { CHECK_NONFATAL(Has<T>()); return *static_cast<T*>(m_value); } + template<typename T> void Set(T& value) { m_value = &value; m_type = std::type_index(typeid(T)); } + template<typename T> bool Has() const { return m_value && m_type == std::type_index(typeid(T)); } + void Clear() { m_value = nullptr; m_type = std::type_index(typeid(void)); } + +private: + void* m_value = nullptr; + std::type_index m_type = std::type_index(typeid(void)); +}; + +} // namespace util + +#endif // BITCOIN_UTIL_REF_H diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index d888b8f842..eff24025f4 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -15,6 +15,7 @@ #include <rpc/server.h> #include <test/util/logging.h> #include <test/util/setup_common.h> +#include <util/ref.h> #include <util/translation.h> #include <validation.h> #include <wallet/coincontrol.h> @@ -208,7 +209,8 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) key.pushKV("timestamp", newTip->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1); key.pushKV("internal", UniValue(true)); keys.push_back(key); - JSONRPCRequest request; + util::Ref context; + JSONRPCRequest request(context); request.params.setArray(); request.params.push_back(keys); @@ -262,7 +264,8 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) AddWallet(wallet); wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); } - JSONRPCRequest request; + util::Ref context; + JSONRPCRequest request(context); request.params.setArray(); request.params.push_back(backup_file); @@ -277,7 +280,8 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) LOCK(wallet->cs_wallet); wallet->SetupLegacyScriptPubKeyMan(); - JSONRPCRequest request; + util::Ref context; + JSONRPCRequest request(context); request.params.setArray(); request.params.push_back(backup_file); AddWallet(wallet); |