From bf4383277d6761cc5b7a91975752c08df829af72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Fri, 14 Dec 2018 15:43:59 +0000 Subject: [PATCH 1/5] rpc: Remove unused PreCommand signal --- src/rpc/server.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 733f8601ee..5b4d8e2f3d 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -36,7 +36,6 @@ static struct CRPCSignals { boost::signals2::signal Started; boost::signals2::signal Stopped; - boost::signals2::signal PreCommand; } g_rpcSignals; void RPCServer::OnStarted(std::function slot) @@ -484,8 +483,6 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const if (!pcmd) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); - g_rpcSignals.PreCommand(*pcmd); - try { // Execute, convert arguments to array if necessary From 068a8fc05f8dbec198bdc3fe46f955d8a5255303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 2 Jan 2019 12:34:39 +0000 Subject: [PATCH 2/5] rpc: Track active commands --- src/rpc/server.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 5b4d8e2f3d..926fabe6af 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -32,6 +32,35 @@ static RPCTimerInterface* timerInterface = nullptr; /* Map of name to timer. */ static std::map > deadlineTimers; +struct RPCCommandExecutionInfo +{ + std::string method; + int64_t start; +}; + +struct RPCServerInfo +{ + Mutex mutex; + std::list active_commands GUARDED_BY(mutex); +}; + +static RPCServerInfo g_rpc_server_info; + +struct RPCCommandExecution +{ + std::list::iterator it; + explicit RPCCommandExecution(const std::string& method) + { + LOCK(g_rpc_server_info.mutex); + it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.cend(), {method, GetTimeMicros()}); + } + ~RPCCommandExecution() + { + LOCK(g_rpc_server_info.mutex); + g_rpc_server_info.active_commands.erase(it); + } +}; + static struct CRPCSignals { boost::signals2::signal Started; @@ -485,6 +514,7 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const try { + RPCCommandExecution execution(request.strMethod); // Execute, convert arguments to array if necessary if (request.params.isObject()) { return pcmd->actor(transformNamedArguments(request, pcmd->argNames)); From d0730f5ce475e5a84da7c61fe79bcd6ed24d693e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Fri, 14 Dec 2018 15:53:59 +0000 Subject: [PATCH 3/5] rpc: Add getrpcinfo command --- src/rpc/server.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 926fabe6af..9f03c1e134 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -283,11 +283,37 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) return GetTime() - GetStartupTime(); } +static UniValue getrpcinfo(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 0) { + throw std::runtime_error( + RPCHelpMan{"getrpcinfo", + "\nReturns details of the RPC server.\n", {}} + .ToString() + ); + } + + LOCK(g_rpc_server_info.mutex); + UniValue active_commands(UniValue::VARR); + for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) { + UniValue entry(UniValue::VOBJ); + entry.pushKV("method", info.method); + entry.pushKV("duration", GetTimeMicros() - info.start); + active_commands.push_back(entry); + } + + UniValue result(UniValue::VOBJ); + result.pushKV("active_commands", active_commands); + + return result; +} + // clang-format off static const CRPCCommand vRPCCommands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ + { "control", "getrpcinfo", &getrpcinfo, {} }, { "control", "help", &help, {"command"} }, { "control", "stop", &stop, {"wait"} }, { "control", "uptime", &uptime, {} }, From 251a91c1bf245b3674c2612149382a0f1e18dc98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 2 Jan 2019 12:46:39 +0000 Subject: [PATCH 4/5] qa: Add tests for getrpcinfo --- test/functional/interface_rpc.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py index e3d7b0655d..b6955d4492 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -5,13 +5,23 @@ """Tests some generic aspects of the RPC interface.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal +from test_framework.util import assert_equal, assert_greater_than_or_equal class RPCInterfaceTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True + def test_getrpcinfo(self): + self.log.info("Testing getrpcinfo...") + + info = self.nodes[0].getrpcinfo() + assert_equal(len(info['active_commands']), 1) + + command = info['active_commands'][0] + assert_equal(command['method'], 'getrpcinfo') + assert_greater_than_or_equal(command['duration'], 0) + def test_batch_request(self): self.log.info("Testing basic JSON-RPC batch request...") @@ -39,6 +49,7 @@ class RPCInterfaceTest(BitcoinTestFramework): assert result_by_id[3]['result'] is not None def run_test(self): + self.test_getrpcinfo() self.test_batch_request() From a0ac15459a0df598e1ee1fd36a3899a129cecaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 2 Jan 2019 12:40:21 +0000 Subject: [PATCH 5/5] doc: Add getrpcinfo release notes --- doc/release-notes-14982.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 doc/release-notes-14982.md diff --git a/doc/release-notes-14982.md b/doc/release-notes-14982.md new file mode 100644 index 0000000000..3f0bf8aacd --- /dev/null +++ b/doc/release-notes-14982.md @@ -0,0 +1,5 @@ +New RPCs +-------- + +- The RPC `getrpcinfo` returns runtime details of the RPC server. At the moment + it returns the active commands and the corresponding execution time.