Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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.
751return num_required_args <= num_args && num_args <= m_args.size();752}754std::vector<std::pair<std::string, bool>> RPCMethod::GetArgNames() const755{756std::vector<std::pair<std::string, bool>> ret;757ret.reserve(m_args.size());758for (const auto& arg : m_args) {759if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {760for (const auto& inner : arg.m_inner) {761ret.emplace_back(inner.m_names, /*named_only=*/true);762}763}764ret.emplace_back(arg.m_names, /*named_only=*/false);765}766return ret;767}769size_t RPCMethod::GetParamIndex(std::string_view key) const770{771auto it{std::find_if(772m_args.begin(), m_args.end(), [&key](const auto& arg) { return arg.GetName() == key;}773)};775CHECK_NONFATAL(it != m_args.end()); // TODO: ideally this is checked at compile time776return std::distance(m_args.begin(), it);777}779std::string RPCMethod::ToString() const780{781std::string ret;783// Oneline summary784ret += m_name;785bool was_optional{false};786for (const auto& arg : m_args) {787if (arg.m_opts.hidden) break; // Any arg that follows is also hidden788const bool optional = arg.IsOptional();789ret += " ";790if (optional) {791if (!was_optional) ret += "( ";792was_optional = true;793} else {794if (was_optional) ret += ") ";795was_optional = false;796}797ret += arg.ToString(/*oneline=*/true);798}799if (was_optional) ret += " )";801// Description802CHECK_NONFATAL(!m_description.starts_with('\n')); // Historically \n was required, but reject it for new code.803ret += "\n\n" + TrimString(m_description) + "\n";805// Arguments806Sections sections;807Sections named_only_sections;808for (size_t i{0}; i < m_args.size(); ++i) {809const auto& arg = m_args.at(i);810if (arg.m_opts.hidden) break; // Any arg that follows is also hidden812// Push named argument name and description813sections.m_sections.emplace_back(util::ToString(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString(/*is_named_arg=*/true));814sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());816// Recursively push nested args817sections.Push(arg);819// Push named-only argument sections820if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {821for (const auto& arg_inner : arg.m_inner) {822named_only_sections.PushSection({arg_inner.GetFirstName(), arg_inner.ToDescriptionString(/*is_named_arg=*/true)});823named_only_sections.Push(arg_inner);824}825}826}828if (!sections.m_sections.empty()) ret += "\nArguments:\n";829ret += sections.ToString();830if (!named_only_sections.m_sections.empty()) ret += "\nNamed Arguments:\n";831ret += named_only_sections.ToString();833// Result834ret += m_results.ToDescriptionString();836// Examples837ret += m_examples.ToDescriptionString();839return ret;840}842UniValue RPCMethod::GetArgMap() const843{844UniValue arr{UniValue::VARR};846auto push_back_arg_info = [&arr](const std::string& rpc_name, int pos, const std::string& arg_name, const RPCArg::Type& type) {847UniValue map{UniValue::VARR};848map.push_back(rpc_name);849map.push_back(pos);850map.push_back(arg_name);851map.push_back(type == RPCArg::Type::STR ||852type == RPCArg::Type::STR_HEX);853arr.push_back(std::move(map));854};856for (int i{0}; i < int(m_args.size()); ++i) {857const auto& arg = m_args.at(i);858std::vector<std::string> arg_names = SplitString(arg.m_names, '|');859for (const auto& arg_name : arg_names) {860push_back_arg_info(m_name, i, arg_name, arg.m_type);861if (arg.m_type == RPCArg::Type::OBJ_NAMED_PARAMS) {862for (const auto& inner : arg.m_inner) {863std::vector<std::string> inner_names = SplitString(inner.m_names, '|');864for (const std::string& inner_name : inner_names) {865push_back_arg_info(m_name, i, inner_name, inner.m_type);866}867}868}869}870}871return arr;872}874static std::optional<UniValue::VType> ExpectedType(RPCArg::Type type)875{876using Type = RPCArg::Type;877switch (type) {878case Type::STR_HEX:879case Type::STR: {880return UniValue::VSTR;881}882case Type::NUM: {883return UniValue::VNUM;884}885case Type::AMOUNT: {886// VNUM or VSTR, checked inside AmountFromValue()887return std::nullopt;888}889case Type::RANGE: {890// VNUM or VARR, checked inside ParseRange()891return std::nullopt;892}893case Type::BOOL: {894return UniValue::VBOOL;895}896case Type::OBJ:897case Type::OBJ_NAMED_PARAMS:898case Type::OBJ_USER_KEYS: {899return UniValue::VOBJ;900}901case Type::ARR: {902return UniValue::VARR;903}904} // no default case, so the compiler can warn about missing cases905NONFATAL_UNREACHABLE();906}908UniValue RPCArg::MatchesType(const UniValue& request) const909{910if (m_opts.skip_type_check) return true;911if (IsOptional() && request.isNull()) return true;912const auto exp_type{ExpectedType(m_type)};913if (!exp_type) return true; // nothing to check915if (*exp_type != request.getType()) {916return strprintf("JSON value of type %s is not of expected type %s", uvTypeName(request.getType()), uvTypeName(*exp_type));917}918return true;919}921std::string RPCArg::GetFirstName() const922{923return m_names.substr(0, m_names.find('|'));924}926std::string RPCArg::GetName() const927{928CHECK_NONFATAL(std::string::npos == m_names.find('|'));929return m_names;930}932bool RPCArg::IsOptional() const933{934if (m_fallback.index() != 0) {935return true;936} else {937return RPCArg::Optional::NO != std::get<RPCArg::Optional>(m_fallback);938}939}941std::string RPCArg::ToDescriptionString(bool is_named_arg) const942{943std::string ret;944ret += "(";945if (m_opts.type_str.size() != 0) {946ret += m_opts.type_str.at(1);947} else {948switch (m_type) {949case Type::STR_HEX:950case Type::STR: {951ret += "string";952break;953}954case Type::NUM: {955ret += "numeric";956break;957}958case Type::AMOUNT: {959ret += "numeric or string";960break;961}962case Type::RANGE: {963ret += "numeric or array";964break;965}966case Type::BOOL: {967ret += "boolean";968break;969}970case Type::OBJ:971case Type::OBJ_NAMED_PARAMS:972case Type::OBJ_USER_KEYS: {973ret += "json object";974break;975}976case Type::ARR: {977ret += "json array";978break;979}980} // no default case, so the compiler can warn about missing cases981}982if (m_fallback.index() == 1) {983ret += ", optional, default=" + std::get<RPCArg::DefaultHint>(m_fallback);984} else if (m_fallback.index() == 2) {985ret += ", optional, default=" + std::get<RPCArg::Default>(m_fallback).write();986} else {987switch (std::get<RPCArg::Optional>(m_fallback)) {988case RPCArg::Optional::OMITTED: {989if (is_named_arg) ret += ", optional"; // Default value is "null" in dicts. Otherwise,990// nothing to do. Element is treated as if not present and has no default value991break;992}993case RPCArg::Optional::NO: {994ret += ", required";995break;996}997} // no default case, so the compiler can warn about missing cases998}999ret += ")";1000if (m_type == Type::OBJ_NAMED_PARAMS) ret += " Options object that can be used to pass named arguments, listed below.";