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.
501UniValue prop{OpenRPCResultSchema(inner)};502if (!inner.m_description.empty()) prop.pushKV("description", inner.m_description);503properties.pushKV(inner.m_key_name, std::move(prop));504if (!inner.m_optional) required.push_back(inner.m_key_name);505}506UniValue schema{UniValue::VOBJ};507schema.pushKV("type", "object");508schema.pushKV("properties", std::move(properties));509schema.pushKV("additionalProperties", false);510if (!required.empty()) schema.pushKV("required", std::move(required));511return schema;512}513case RPCResult::Type::OBJ_DYN: {514UniValue schema{UniValue::VOBJ};515schema.pushKV("type", "object");516if (!result.m_inner.empty()) {517schema.pushKV("additionalProperties", OpenRPCResultSchema(result.m_inner[0]));518} else {519schema.pushKV("additionalProperties", UniValue{UniValue::VOBJ});520}521return schema;522}523case RPCResult::Type::ANY:524return UniValue{UniValue::VOBJ};525} // no default case, so the compiler can warn about missing cases526NONFATAL_UNREACHABLE();527}528} // namespace530static RPCResult OpenRPCDocResult()531{532return RPCResult{533RPCResult::Type::OBJ, "", "",534{535{RPCResult::Type::STR, "openrpc", "OpenRPC specification version."},536{RPCResult::Type::OBJ, "info", "Metadata about this JSON-RPC interface.",537{538{RPCResult::Type::STR, "title", "API title."},539{RPCResult::Type::STR, "version", "Bitcoin Core version string."},540{RPCResult::Type::STR, "description", "API description."},541}},542{RPCResult::Type::ARR, "methods", "Documented RPC methods.",543{{RPCResult::Type::OBJ, "", "An RPC method description object.",544{545{RPCResult::Type::STR, "name", "Method name."},546{RPCResult::Type::STR, "description", "Method description."},547{RPCResult::Type::ARR, "params", "Method parameters.",548{{RPCResult::Type::OBJ, "", "A parameter.",549{550{RPCResult::Type::STR, "name", "Parameter name."},551{RPCResult::Type::BOOL, "required", "Whether the parameter is required."},552{RPCResult::Type::ANY, "schema", "JSON Schema for the parameter."},553{RPCResult::Type::STR, "description", /*optional=*/true, "Parameter description."},554{RPCResult::Type::ARR, "x-bitcoin-aliases", /*optional=*/true, "Alternative parameter names.",555{{RPCResult::Type::STR, "", "An alias."}}},556{RPCResult::Type::BOOL, "x-bitcoin-placeholder", /*optional=*/true, "Whether the parameter is retained only for compatibility."},557{RPCResult::Type::BOOL, "x-bitcoin-also-positional", /*optional=*/true, "Whether the parameter can also be passed positionally."},558}}}},559{RPCResult::Type::OBJ, "result", "Method result.",560{561{RPCResult::Type::STR, "name", "Result name."},562{RPCResult::Type::ANY, "schema", "JSON Schema for the result. Numeric schemas may include "563"\"x-bitcoin-unit\" property: \"amount\" which denotes a Bitcoin amount in BTC."},564}},565{RPCResult::Type::STR, "x-bitcoin-category", "RPC category."},566}}}},567},568{.skip_type_check = true}};569}571static RPCMethod getopenrpcinfo()572{573return RPCMethod{574"getopenrpcinfo",575"Returns an OpenRPC document for currently available RPC commands.\n",576{577{"show_hidden", RPCArg::Type::BOOL, RPCArg::Default{false}, "Also include hidden RPC commands and arguments."},578},579OpenRPCDocResult(),580RPCExamples{581HelpExampleCli("getopenrpcinfo", "")582+ HelpExampleRpc("getopenrpcinfo", "")583},584[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue585{586const bool include_hidden{self.Arg<bool>("show_hidden")};587return tableRPC.buildOpenRPCDoc(include_hidden);588},589};590}592static RPCMethod rpc_discover()593{594return RPCMethod{595"rpc.discover",596"Returns an OpenRPC schema as a description of this service.\n",597{},598OpenRPCDocResult(),599RPCExamples{600HelpExampleCli("rpc.discover", "")601+ HelpExampleRpc("rpc.discover", "")602},603[](const RPCMethod&, const JSONRPCRequest&) -> UniValue604{605return tableRPC.buildOpenRPCDoc(/*include_hidden=*/false);606},607};608}610static const CRPCCommand vRPCCommands[]{611/* Overall control/query calls */612{"control", &getopenrpcinfo},613{"control", &rpc_discover},614{"control", &getrpcinfo},615{"control", &help},616{"control", &stop},617{"control", &uptime},618};620CRPCTable::CRPCTable()621{622for (const auto& c : vRPCCommands) {623appendCommand(c.name, &c);624}625}627void CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)628{629CHECK_NONFATAL(!IsRPCRunning()); // Only add commands before rpc is running631mapCommands[name].push_back(pcmd);632}634bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)635{636auto it = mapCommands.find(name);637if (it != mapCommands.end()) {638auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);639if (it->second.end() != new_end) {640it->second.erase(new_end, it->second.end());641if (it->second.empty()) {642mapCommands.erase(it);643}644return true;645}646}647return false;648}650void StartRPC()651{652LogDebug(BCLog::RPC, "Starting RPC\n");653g_rpc_running = true;654}656void InterruptRPC()657{658static std::once_flag g_rpc_interrupt_flag;659// This function could be called twice if the GUI has been started with -server=1.660std::call_once(g_rpc_interrupt_flag, []() {661LogDebug(BCLog::RPC, "Interrupting RPC\n");662// Interrupt e.g. running longpolls663g_rpc_running = false;664});665}667void StopRPC()668{669static std::once_flag g_rpc_stop_flag;670// This function could be called twice if the GUI has been started with -server=1.671assert(!g_rpc_running);672std::call_once(g_rpc_stop_flag, [&]() {673LogDebug(BCLog::RPC, "Stopping RPC\n");674DeleteAuthCookie();675LogDebug(BCLog::RPC, "RPC stopped.\n");676});677}679bool IsRPCRunning()680{681return g_rpc_running;682}684void RpcInterruptionPoint()685{686if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");687}689void SetRPCWarmupStatus(const std::string& newStatus)690{691LOCK(g_rpc_warmup_mutex);692rpcWarmupStatus = newStatus;693}695void SetRPCWarmupStarting()696{697LOCK(g_rpc_warmup_mutex);698fRPCInWarmup = true;699}701void SetRPCWarmupFinished()702{703LOCK(g_rpc_warmup_mutex);704assert(fRPCInWarmup);705fRPCInWarmup = false;706}708bool RPCIsInWarmup(std::string *outStatus)709{710LOCK(g_rpc_warmup_mutex);711if (outStatus)712*outStatus = rpcWarmupStatus;713return fRPCInWarmup;714}716bool IsDeprecatedRPCEnabled(const std::string& method)717{718const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");720return find(enabled_methods.begin(), enabled_methods.end(), method) != enabled_methods.end();721}723UniValue JSONRPCExec(const JSONRPCRequest& jreq, bool catch_errors)724{725UniValue result;726if (catch_errors) {727try {728result = tableRPC.execute(jreq);729} catch (UniValue& e) {730return JSONRPCReplyObj(NullUniValue, std::move(e), jreq.id, jreq.m_json_version);731} catch (const std::exception& e) {732return JSONRPCReplyObj(NullUniValue, JSONRPCError(RPC_MISC_ERROR, e.what()), jreq.id, jreq.m_json_version);733}734} else {735result = tableRPC.execute(jreq);736}738return JSONRPCReplyObj(std::move(result), NullUniValue, jreq.id, jreq.m_json_version);739}741/**742* Process named arguments into a vector of positional arguments, based on the743* passed-in specification for the RPC call's arguments.744*/745static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::pair<std::string, bool>>& argNames)746{747JSONRPCRequest out = in;748out.params = UniValue(UniValue::VARR);749// Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if750// there is an unknown one.