From 15ee06f5eb49170ed1a19ac76b0abb3fc73af06e Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Wed, 8 Jun 2022 14:23:09 +0200 Subject: [PATCH 1/3] Introduce RPCContext instance. This introduces the RPCContext class, and an associated global instance (accessible through RPCContext::Get). This class is empty for now, but will in the future hold contextual information such as references to the global chainstate, masternode module and others, for use by RPC method handlers while the RPC server is running. It will be difficult to explicitly pass references like these to the RPC handlers, as that would require updating the entire RPC server infrastructure and all RPC handler methods at once. With this class, we still lay the foundation for removing direct "global" accesses from the RPC methods, and instead bundling them in the RPCContext class. This makes the use of global state from the RPC server clearer, and can be used later on to fully remove any global access by simply providing the RPCContext instance explicitly to handlers somehow. --- divi/src/Makefile.am | 2 ++ divi/src/RPCContext.cpp | 5 +++++ divi/src/RPCContext.h | 28 +++++++++++++++++++++++++++ divi/src/rpcserver.cpp | 43 +++++++++++++++++++++++++++++------------ 4 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 divi/src/RPCContext.cpp create mode 100644 divi/src/RPCContext.h diff --git a/divi/src/Makefile.am b/divi/src/Makefile.am index fd7bf78be..7e4f38c95 100644 --- a/divi/src/Makefile.am +++ b/divi/src/Makefile.am @@ -216,6 +216,7 @@ BITCOIN_CORE_H = \ IndexDatabaseUpdateCollector.h \ NodeState.h \ NodeStateRegistry.h \ + RPCContext.h \ BlocksInFlightRegistry.h \ NodeSignals.h \ BlockRejects.h\ @@ -436,6 +437,7 @@ libbitcoin_server_a_SOURCES = \ NodeState.cpp \ BlocksInFlightRegistry.cpp \ NodeStateRegistry.cpp \ + RPCContext.cpp \ BlockFileHelpers.cpp \ main.cpp \ TransactionSearchIndexes.cpp \ diff --git a/divi/src/RPCContext.cpp b/divi/src/RPCContext.cpp new file mode 100644 index 000000000..b697f2d26 --- /dev/null +++ b/divi/src/RPCContext.cpp @@ -0,0 +1,5 @@ +#include "RPCContext.h" + +RPCContext::RPCContext () = default; + +RPCContext::~RPCContext () = default; diff --git a/divi/src/RPCContext.h b/divi/src/RPCContext.h new file mode 100644 index 000000000..27fe16f8c --- /dev/null +++ b/divi/src/RPCContext.h @@ -0,0 +1,28 @@ +#ifndef RPC_CONTEXT_H +#define RPC_CONTEXT_H + +/** This class holds all the "context" (such as the chainstate, masternode + * and other references) needed to handle RPC method calls. */ +class RPCContext +{ + +public: + + /** Constructs a new instance based on globals. */ + RPCContext (); + + RPCContext (const RPCContext&) = delete; + void operator= (const RPCContext&) = delete; + + ~RPCContext (); + + /** Returns the global instance that should be used during RPC calls + * (called from the RPC method handler). + * + * This method is implemented in rpcserver.cpp. + */ + static RPCContext& Get (); + +}; + +#endif // RPC_CONTEXT_H diff --git a/divi/src/rpcserver.cpp b/divi/src/rpcserver.cpp index 3f24f68a2..c80fd8fa6 100644 --- a/divi/src/rpcserver.cpp +++ b/divi/src/rpcserver.cpp @@ -17,6 +17,7 @@ #ifdef ENABLE_WALLET #include "wallet.h" #endif +#include "RPCContext.h" #include "Settings.h" #include #include @@ -162,20 +163,30 @@ using namespace boost::asio; using namespace json_spirit; using namespace std; extern Settings& settings; -static std::string strRPCUserColonPass; -static bool fRPCRunning = false; -static bool fRPCInWarmup = true; -static std::string rpcWarmupStatus("RPC server started"); -static CCriticalSection cs_rpcWarmup; +namespace +{ + +std::string strRPCUserColonPass; + +bool fRPCRunning = false; +bool fRPCInWarmup = true; +std::string rpcWarmupStatus("RPC server started"); +CCriticalSection cs_rpcWarmup; //! These are created by StartRPCThreads, destroyed in StopRPCThreads -static asio::io_service* rpc_io_service = NULL; -static map > deadlineTimers; -static boost::thread_group* rpc_worker_group = NULL; -static boost::asio::io_service::work* rpc_dummy_work = NULL; -static std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from -static std::vector > rpc_acceptors; +asio::io_service* rpc_io_service = NULL; +std::map > deadlineTimers; +boost::thread_group* rpc_worker_group = NULL; +boost::asio::io_service::work* rpc_dummy_work = NULL; +std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from +std::vector > rpc_acceptors; + +/** The global RPCContext instance. It is created when the RPC server + * has finished warmup, and destructed when the RPC threads are stopped. */ +std::unique_ptr rpcContext; + +} // anonymous namespace void RPCTypeCheck(const Array& params, const list& typesExpected, @@ -787,6 +798,7 @@ void StopRPCThreads() rpc_worker_group = NULL; delete rpc_io_service; rpc_io_service = NULL; + rpcContext.reset(); } bool IsRPCRunning() @@ -804,6 +816,7 @@ void SetRPCWarmupFinished() { LOCK(cs_rpcWarmup); assert(fRPCInWarmup); + rpcContext.reset(new RPCContext()); fRPCInWarmup = false; } @@ -815,6 +828,12 @@ bool RPCIsInWarmup(std::string* outStatus) return fRPCInWarmup; } +RPCContext& RPCContext::Get() +{ + assert(rpcContext != nullptr); + return *rpcContext; +} + void RPCRunHandler(const boost::system::error_code& err, boost::function func) { if (!err) @@ -1233,4 +1252,4 @@ std::string HelpExampleRpc(string methodname, string args) return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:51473/\n"; -} \ No newline at end of file +} From d3d7f53738f714a2611cb4c588c5d9a9fee0f3f8 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Wed, 8 Jun 2022 15:02:59 +0200 Subject: [PATCH 2/3] Add spork manager to RPCContext. Add the global CSporkManager to RPCContext as the first actual data field. With this, we can replace the use of GetSporkManager() from all RPC methods with the RPCContext. --- divi/src/RPCContext.cpp | 6 +++++- divi/src/RPCContext.h | 12 ++++++++++++ divi/src/rpcblockchain.cpp | 8 +++++--- divi/src/rpclottery.cpp | 7 ++++--- divi/src/rpcmisc.cpp | 4 +++- divi/src/rpcwallet.cpp | 30 ++++++++++++++++++++---------- 6 files changed, 49 insertions(+), 18 deletions(-) diff --git a/divi/src/RPCContext.cpp b/divi/src/RPCContext.cpp index b697f2d26..940c6e01b 100644 --- a/divi/src/RPCContext.cpp +++ b/divi/src/RPCContext.cpp @@ -1,5 +1,9 @@ #include "RPCContext.h" -RPCContext::RPCContext () = default; +#include "spork.h" + +RPCContext::RPCContext () + : sporkManager(GetSporkManager ()) +{} RPCContext::~RPCContext () = default; diff --git a/divi/src/RPCContext.h b/divi/src/RPCContext.h index 27fe16f8c..eb2ec9380 100644 --- a/divi/src/RPCContext.h +++ b/divi/src/RPCContext.h @@ -1,11 +1,17 @@ #ifndef RPC_CONTEXT_H #define RPC_CONTEXT_H +class CSporkManager; + /** This class holds all the "context" (such as the chainstate, masternode * and other references) needed to handle RPC method calls. */ class RPCContext { +private: + + CSporkManager& sporkManager; + public: /** Constructs a new instance based on globals. */ @@ -23,6 +29,12 @@ class RPCContext */ static RPCContext& Get (); + CSporkManager& + SporkManager () + { + return sporkManager; + } + }; #endif // RPC_CONTEXT_H diff --git a/divi/src/rpcblockchain.cpp b/divi/src/rpcblockchain.cpp index 8590c4f9a..b3a498607 100644 --- a/divi/src/rpcblockchain.cpp +++ b/divi/src/rpcblockchain.cpp @@ -6,6 +6,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include "checkpoints.h" #include "main.h" #include "BlockDiskAccessor.h" @@ -27,7 +28,6 @@ #include #include #include -#include using namespace json_spirit; using namespace std; @@ -628,6 +628,7 @@ Value invalidateblock(const Array& params, bool fHelp, CWallet* pwallet) uint256 hash(strHash); CValidationState state; + auto& ctx = RPCContext::Get(); ChainstateManager::Reference chainstate; auto& blockMap = chainstate->GetBlockMap(); const auto mit = blockMap.find(hash); @@ -638,7 +639,7 @@ Value invalidateblock(const Array& params, bool fHelp, CWallet* pwallet) InvalidateBlock(*chainstate, state, pblockindex); if (state.IsValid()) { - ActivateBestChain(*chainstate, GetSporkManager(), state); + ActivateBestChain(*chainstate, ctx.SporkManager(), state); } if (!state.IsValid()) { @@ -665,6 +666,7 @@ Value reconsiderblock(const Array& params, bool fHelp, CWallet* pwallet) uint256 hash(strHash); CValidationState state; + auto& ctx = RPCContext::Get(); ChainstateManager::Reference chainstate; auto& blockMap = chainstate->GetBlockMap(); const auto mit = blockMap.find(hash); @@ -675,7 +677,7 @@ Value reconsiderblock(const Array& params, bool fHelp, CWallet* pwallet) ReconsiderBlock(*chainstate, state, pblockindex); if (state.IsValid()) { - ActivateBestChain(*chainstate, GetSporkManager(), state); + ActivateBestChain(*chainstate, ctx.SporkManager(), state); } if (!state.IsValid()) { diff --git a/divi/src/rpclottery.cpp b/divi/src/rpclottery.cpp index 7d5e414f2..d56e85be5 100644 --- a/divi/src/rpclottery.cpp +++ b/divi/src/rpclottery.cpp @@ -1,7 +1,7 @@ #include #include -#include #include +#include #include #include