Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <bitcoin-build-config.h> // IWYU pragma: keep8#include <rpc/server.h>10#include <common/args.h>11#include <common/system.h>12#include <logging.h>13#include <node/context.h>14#include <rpc/protocol.h>15#include <rpc/server_util.h>16#include <rpc/util.h>17#include <sync.h>18#include <tinyformat.h>19#include <util/check.h>20#include <util/fs.h>21#include <util/overloaded.h>22#include <util/strencodings.h>23#include <util/string.h>24#include <util/time.h>26#include <algorithm>27#include <atomic>28#include <cstddef>29#include <exception>30#include <list>31#include <mutex>32#include <optional>33#include <set>34#include <span>35#include <string_view>36#include <unordered_map>37#include <unordered_set>38#include <variant>40using util::SplitString;42static GlobalMutex g_rpc_warmup_mutex;43static std::atomic<bool> g_rpc_running{false};44static bool fRPCInWarmup GUARDED_BY(g_rpc_warmup_mutex) = true;45static std::string rpcWarmupStatus GUARDED_BY(g_rpc_warmup_mutex) = "RPC server started";46static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);48struct RPCCommandExecutionInfo49{50std::string method;51SteadyClock::time_point start;52};54struct RPCServerInfo55{56Mutex mutex;57std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex);58};60static RPCServerInfo g_rpc_server_info;62struct RPCCommandExecution63{64std::list<RPCCommandExecutionInfo>::iterator it;65explicit RPCCommandExecution(const std::string& method)66{67LOCK(g_rpc_server_info.mutex);68it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, SteadyClock::now()});69}70~RPCCommandExecution()71{72LOCK(g_rpc_server_info.mutex);73g_rpc_server_info.active_commands.erase(it);74}75};77std::string CRPCTable::help(std::string_view strCommand, const JSONRPCRequest& helpreq) const78{79std::string strRet;80std::string category;81std::set<intptr_t> setDone;82std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;83vCommands.reserve(mapCommands.size());85for (const auto& entry : mapCommands)86vCommands.emplace_back(entry.second.front()->category + entry.first, entry.second.front());87std::ranges::sort(vCommands);89JSONRPCRequest jreq = helpreq;90jreq.mode = JSONRPCRequest::GET_HELP;91jreq.params = UniValue();93for (const auto& [_, pcmd] : vCommands) {94std::string strMethod = pcmd->name;95if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)96continue;97jreq.strMethod = strMethod;98try99{100UniValue unused_result;101if (setDone.insert(pcmd->unique_id).second)102pcmd->actor(jreq, unused_result, /*last_handler=*/true);103} catch (const HelpResult& e) {104std::string strHelp{e.what()};105if (strCommand == "")106{107if (strHelp.find('\n') != std::string::npos)108strHelp = strHelp.substr(0, strHelp.find('\n'));110if (category != pcmd->category)111{112if (!category.empty())113strRet += "\n";114category = pcmd->category;115strRet += "== " + Capitalize(category) + " ==\n";116}117}118strRet += strHelp + "\n";119}120}121if (strRet == "")122strRet = strprintf("help: unknown command: %s\n", strCommand);123strRet = strRet.substr(0,strRet.size()-1);124return strRet;125}127static RPCMethod help()128{129return RPCMethod{130"help",131"List all commands, or get help for a specified command.\n",132{133{"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"},134},135{136RPCResult{RPCResult::Type::STR, "", "The help text"},137RPCResult{RPCResult::Type::ANY, "", "The command conversions. (Hidden in dump_all_command_conversions)", /*inner=*/{},138RPCResultOptions{139.print_elision = HelpElisionSkip{},140}},141},142RPCExamples{""},143[](const RPCMethod& self, const JSONRPCRequest& jsonRequest) -> UniValue144{145auto command{self.MaybeArg<std::string_view>("command")};146if (command == "dump_all_command_conversions") {147// Used for testing only, undocumented148return tableRPC.dumpArgMap(jsonRequest);149}151return tableRPC.help(command.value_or(""), jsonRequest);152},153};154}156static RPCMethod stop()157{158static const std::string RESULT{CLIENT_NAME " stopping"};159return RPCMethod{160"stop",161// Also accept the hidden 'wait' integer argument (milliseconds)162// For instance, 'stop 1000' makes the call wait 1 second before returning163// to the client (intended for testing)164"Request a graceful shutdown of " CLIENT_NAME ".",165{166{"wait", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "how long to wait in ms", RPCArgOptions{.hidden=true}},167},168RPCResult{RPCResult::Type::STR, "", "A string with the content '" + RESULT + "'"},169RPCExamples{""},170[](const RPCMethod& self, const JSONRPCRequest& jsonRequest) -> UniValue171{172// Event loop will exit after current HTTP requests have been handled, so173// this reply will get back to the client.174CHECK_NONFATAL((CHECK_NONFATAL(EnsureAnyNodeContext(jsonRequest.context).shutdown_request))());175if (jsonRequest.params[0].isNum()) {176UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt<int>()});177}178return RESULT;179},180};181}183static RPCMethod uptime()184{185return RPCMethod{186"uptime",187"Returns the total uptime of the server.\n",188{},189RPCResult{190RPCResult::Type::NUM, "", "The number of seconds that the server has been running"191},192RPCExamples{193HelpExampleCli("uptime", "")194+ HelpExampleRpc("uptime", "")195},196[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue197{198return TicksSeconds(GetUptime());199}200};201}203static RPCMethod getrpcinfo()204{205return RPCMethod{206"getrpcinfo",207"Returns details of the RPC server.\n",208{},209RPCResult{210RPCResult::Type::OBJ, "", "",211{212{RPCResult::Type::ARR, "active_commands", "All active commands",213{214{RPCResult::Type::OBJ, "", "Information about an active command",215{216{RPCResult::Type::STR, "method", "The name of the RPC command"},217{RPCResult::Type::NUM, "duration", "The running time in microseconds"},218}},219}},220{RPCResult::Type::STR, "logpath", "The complete file path to the debug log"},221}222},223RPCExamples{224HelpExampleCli("getrpcinfo", "")225+ HelpExampleRpc("getrpcinfo", "")},226[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue227{228LOCK(g_rpc_server_info.mutex);229UniValue active_commands(UniValue::VARR);230for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {231UniValue entry(UniValue::VOBJ);232entry.pushKV("method", info.method);233entry.pushKV("duration", Ticks<std::chrono::microseconds>(SteadyClock::now() - info.start));234active_commands.push_back(std::move(entry));235}237UniValue result(UniValue::VOBJ);238result.pushKV("active_commands", std::move(active_commands));240const std::string path = LogInstance().m_file_path.utf8string();241UniValue log_path(UniValue::VSTR, path);242result.pushKV("logpath", std::move(log_path));244return result;245}246};247}249namespace {250UniValue OpenRPCArgSchema(const RPCArg& arg, bool include_hidden, bool in_skip_type_check);