diff options
Diffstat (limited to 'src/rpc/net.cpp')
-rw-r--r-- | src/rpc/net.cpp | 267 |
1 files changed, 191 insertions, 76 deletions
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 9981ea35df..b81e6414a5 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -29,9 +29,18 @@ #include <univalue.h> -static UniValue getconnectioncount(const JSONRPCRequest& request) +const std::vector<std::string> CONNECTION_TYPE_DOC{ + "outbound-full-relay (default automatic connections)", + "block-relay-only (does not relay transactions or addresses)", + "inbound (initiated by the peer)", + "manual (added via addnode RPC or -addnode/-connect configuration options)", + "addr-fetch (short-lived automatic connection for soliciting addresses)", + "feeler (short-lived automatic connection for testing addresses)" +}; + +static RPCHelpMan getconnectioncount() { - RPCHelpMan{"getconnectioncount", + return RPCHelpMan{"getconnectioncount", "\nReturns the number of connections to other nodes.\n", {}, RPCResult{ @@ -41,18 +50,20 @@ static UniValue getconnectioncount(const JSONRPCRequest& request) HelpExampleCli("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); return (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL); +}, + }; } -static UniValue ping(const JSONRPCRequest& request) +static RPCHelpMan ping() { - RPCHelpMan{"ping", + return RPCHelpMan{"ping", "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n", @@ -62,8 +73,8 @@ static UniValue ping(const JSONRPCRequest& request) HelpExampleCli("ping", "") + HelpExampleRpc("ping", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -73,11 +84,13 @@ static UniValue ping(const JSONRPCRequest& request) pnode->fPingQueued = true; }); return NullUniValue; +}, + }; } -static UniValue getpeerinfo(const JSONRPCRequest& request) +static RPCHelpMan getpeerinfo() { - RPCHelpMan{"getpeerinfo", + return RPCHelpMan{"getpeerinfo", "\nReturns data about each connected network node as a json array of objects.\n", {}, RPCResult{ @@ -90,6 +103,7 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"}, {RPCResult::Type::STR, "addrbind", "(ip:port) Bind address of the connection to the peer"}, {RPCResult::Type::STR, "addrlocal", "(ip:port) Local address as reported by the peer"}, + {RPCResult::Type::STR, "network", "Network (ipv4, ipv6, or onion) the peer connected through"}, {RPCResult::Type::NUM, "mapped_as", "The AS in the BGP route to the peer used for diversifying\n" "peer selection (only available if the asmap config flag is set)"}, {RPCResult::Type::STR_HEX, "services", "The services offered"}, @@ -100,6 +114,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) {RPCResult::Type::BOOL, "relaytxes", "Whether peer has asked us to relay transactions to it"}, {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"}, {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"}, + {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"}, + {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"}, {RPCResult::Type::NUM, "bytessent", "The total bytes sent"}, {RPCResult::Type::NUM, "bytesrecv", "The total bytes received"}, {RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"}, @@ -110,7 +126,11 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) {RPCResult::Type::NUM, "version", "The peer version, such as 70001"}, {RPCResult::Type::STR, "subver", "The string version"}, {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"}, - {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection"}, + {RPCResult::Type::BOOL, "addnode", "Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n" + "(DEPRECATED, returned only if the config option -deprecatedrpc=getpeerinfo_addnode is passed)"}, + {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n" + "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n" + "best capture connection behaviors."}, {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"}, {RPCResult::Type::NUM, "banscore", "The ban score (DEPRECATED, returned only if config option -deprecatedrpc=banscore is passed)"}, {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"}, @@ -119,7 +139,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) { {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"}, }}, - {RPCResult::Type::BOOL, "whitelisted", "Whether the peer is whitelisted"}, + {RPCResult::Type::BOOL, "whitelisted", /* optional */ true, "Whether the peer is whitelisted with default permissions\n" + "(DEPRECATED, returned only if config option -deprecatedrpc=whitelisted is passed)"}, {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"}, {RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "", { @@ -131,7 +152,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) { {RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n" "When a message type is not listed in this json object, the bytes received are 0.\n" - "Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."} + "Only known message types can appear as keys in the object and all bytes received\n" + "of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'."} }}, }}, }}, @@ -140,8 +162,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) HelpExampleCli("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -157,10 +179,13 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); obj.pushKV("id", stats.nodeid); obj.pushKV("addr", stats.addrName); - if (!(stats.addrLocal.empty())) - obj.pushKV("addrlocal", stats.addrLocal); - if (stats.addrBind.IsValid()) + if (stats.addrBind.IsValid()) { obj.pushKV("addrbind", stats.addrBind.ToString()); + } + if (!(stats.addrLocal.empty())) { + obj.pushKV("addrlocal", stats.addrLocal); + } + obj.pushKV("network", stats.m_network); if (stats.m_mapped_as != 0) { obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); } @@ -169,6 +194,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) obj.pushKV("relaytxes", stats.fRelayTxes); obj.pushKV("lastsend", stats.nLastSend); obj.pushKV("lastrecv", stats.nLastRecv); + obj.pushKV("last_transaction", stats.nLastTXTime); + obj.pushKV("last_block", stats.nLastBlockTime); obj.pushKV("bytessent", stats.nSendBytes); obj.pushKV("bytesrecv", stats.nRecvBytes); obj.pushKV("conntime", stats.nTimeConnected); @@ -188,12 +215,15 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) // their ver message. obj.pushKV("subver", stats.cleanSubVer); obj.pushKV("inbound", stats.fInbound); - obj.pushKV("addnode", stats.m_manual_connection); + if (IsDeprecatedRPCEnabled("getpeerinfo_addnode")) { + // addnode is deprecated in v0.21 for removal in v0.22 + obj.pushKV("addnode", stats.m_manual_connection); + } obj.pushKV("startingheight", stats.nStartingHeight); if (fStateStats) { if (IsDeprecatedRPCEnabled("banscore")) { // banscore is deprecated in v0.21 for removal in v0.22 - obj.pushKV("banscore", statestats.nMisbehavior); + obj.pushKV("banscore", statestats.m_misbehavior_score); } obj.pushKV("synced_headers", statestats.nSyncHeight); obj.pushKV("synced_blocks", statestats.nCommonHeight); @@ -203,7 +233,10 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) } obj.pushKV("inflight", heights); } - obj.pushKV("whitelisted", stats.m_legacyWhitelisted); + if (IsDeprecatedRPCEnabled("whitelisted")) { + // whitelisted is deprecated in v0.21 for removal in v0.22 + obj.pushKV("whitelisted", stats.m_legacyWhitelisted); + } UniValue permissions(UniValue::VARR); for (const auto& permission : NetPermissions::ToStrings(stats.m_permissionFlags)) { permissions.push_back(permission); @@ -224,22 +257,19 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) recvPerMsgCmd.pushKV(i.first, i.second); } obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd); + obj.pushKV("connection_type", stats.m_conn_type_string); ret.push_back(obj); } return ret; +}, + }; } -static UniValue addnode(const JSONRPCRequest& request) +static RPCHelpMan addnode() { - std::string strCommand; - if (!request.params[1].isNull()) - strCommand = request.params[1].get_str(); - if (request.fHelp || request.params.size() != 2 || - (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) - throw std::runtime_error( - RPCHelpMan{"addnode", + return RPCHelpMan{"addnode", "\nAttempts to add or remove a node from the addnode list.\n" "Or try a connection to a node once.\n" "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n" @@ -253,7 +283,15 @@ static UniValue addnode(const JSONRPCRequest& request) HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"") }, - }.ToString()); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + std::string strCommand; + if (!request.params[1].isNull()) + strCommand = request.params[1].get_str(); + if (request.fHelp || request.params.size() != 2 || + (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) + throw std::runtime_error( + self.ToString()); NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) @@ -264,7 +302,7 @@ static UniValue addnode(const JSONRPCRequest& request) if (strCommand == "onetry") { CAddress addr; - node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true); + node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL); return NullUniValue; } @@ -276,15 +314,17 @@ static UniValue addnode(const JSONRPCRequest& request) else if(strCommand == "remove") { if(!node.connman->RemoveAddedNode(strNode)) - throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); + throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously."); } return NullUniValue; +}, + }; } -static UniValue disconnectnode(const JSONRPCRequest& request) +static RPCHelpMan disconnectnode() { - RPCHelpMan{"disconnectnode", + return RPCHelpMan{"disconnectnode", "\nImmediately disconnects from the specified peer node.\n" "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n" "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n", @@ -299,8 +339,8 @@ static UniValue disconnectnode(const JSONRPCRequest& request) + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + HelpExampleRpc("disconnectnode", "\"\", 1") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -325,11 +365,13 @@ static UniValue disconnectnode(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue getaddednodeinfo(const JSONRPCRequest& request) +static RPCHelpMan getaddednodeinfo() { - RPCHelpMan{"getaddednodeinfo", + return RPCHelpMan{"getaddednodeinfo", "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n", { @@ -357,8 +399,8 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -397,11 +439,13 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) } return ret; +}, + }; } -static UniValue getnettotals(const JSONRPCRequest& request) +static RPCHelpMan getnettotals() { - RPCHelpMan{"getnettotals", + return RPCHelpMan{"getnettotals", "\nReturns information about network traffic, including bytes in, bytes out,\n" "and current time.\n", {}, @@ -410,7 +454,7 @@ static UniValue getnettotals(const JSONRPCRequest& request) { {RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"}, {RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"}, - {RPCResult::Type::NUM_TIME, "timemillis", "Current UNIX time in milliseconds"}, + {RPCResult::Type::NUM_TIME, "timemillis", "Current " + UNIX_EPOCH_TIME + " in milliseconds"}, {RPCResult::Type::OBJ, "uploadtarget", "", { {RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"}, @@ -426,7 +470,8 @@ static UniValue getnettotals(const JSONRPCRequest& request) HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -445,6 +490,8 @@ static UniValue getnettotals(const JSONRPCRequest& request) outboundLimit.pushKV("time_left_in_cycle", node.connman->GetMaxOutboundTimeLeftInCycle()); obj.pushKV("uploadtarget", outboundLimit); return obj; +}, + }; } static UniValue GetNetworksInfo() @@ -468,9 +515,9 @@ static UniValue GetNetworksInfo() return networks; } -static UniValue getnetworkinfo(const JSONRPCRequest& request) +static RPCHelpMan getnetworkinfo() { - RPCHelpMan{"getnetworkinfo", + return RPCHelpMan{"getnetworkinfo", "Returns an object containing various state info regarding P2P networking.\n", {}, RPCResult{ @@ -486,7 +533,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) }}, {RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"}, {RPCResult::Type::NUM, "timeoffset", "the time offset"}, - {RPCResult::Type::NUM, "connections", "the number of connections"}, + {RPCResult::Type::NUM, "connections", "the total number of connections"}, + {RPCResult::Type::NUM, "connections_in", "the number of inbound connections"}, + {RPCResult::Type::NUM, "connections_out", "the number of outbound connections"}, {RPCResult::Type::BOOL, "networkactive", "whether p2p networking is enabled"}, {RPCResult::Type::ARR, "networks", "information per network", { @@ -517,8 +566,8 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ LOCK(cs_main); UniValue obj(UniValue::VOBJ); obj.pushKV("version", CLIENT_VERSION); @@ -534,7 +583,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("timeoffset", GetTimeOffset()); if (node.connman) { obj.pushKV("networkactive", node.connman->GetNetworkActive()); - obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); + obj.pushKV("connections", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); + obj.pushKV("connections_in", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_IN)); + obj.pushKV("connections_out", (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_OUT)); } obj.pushKV("networks", GetNetworksInfo()); obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())); @@ -554,11 +605,13 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("localaddresses", localAddresses); obj.pushKV("warnings", GetWarnings(false).original); return obj; +}, + }; } -static UniValue setban(const JSONRPCRequest& request) +static RPCHelpMan setban() { - const RPCHelpMan help{"setban", + return RPCHelpMan{"setban", "\nAttempts to add or remove an IP/Subnet from the banned list.\n", { {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"}, @@ -572,7 +625,8 @@ static UniValue setban(const JSONRPCRequest& request) + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") }, - }; + [&](const RPCHelpMan& help, const JSONRPCRequest& request) -> UniValue +{ std::string strCommand; if (!request.params[1].isNull()) strCommand = request.params[1].get_str(); @@ -635,11 +689,13 @@ static UniValue setban(const JSONRPCRequest& request) } } return NullUniValue; +}, + }; } -static UniValue listbanned(const JSONRPCRequest& request) +static RPCHelpMan listbanned() { - RPCHelpMan{"listbanned", + return RPCHelpMan{"listbanned", "\nList all manually banned IPs/Subnets.\n", {}, RPCResult{RPCResult::Type::ARR, "", "", @@ -655,8 +711,8 @@ static UniValue listbanned(const JSONRPCRequest& request) HelpExampleCli("listbanned", "") + HelpExampleRpc("listbanned", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if(!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); @@ -678,11 +734,13 @@ static UniValue listbanned(const JSONRPCRequest& request) } return bannedAddresses; +}, + }; } -static UniValue clearbanned(const JSONRPCRequest& request) +static RPCHelpMan clearbanned() { - RPCHelpMan{"clearbanned", + return RPCHelpMan{"clearbanned", "\nClear all banned IPs.\n", {}, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -690,7 +748,8 @@ static UniValue clearbanned(const JSONRPCRequest& request) HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); @@ -699,19 +758,21 @@ static UniValue clearbanned(const JSONRPCRequest& request) node.banman->ClearBanned(); return NullUniValue; +}, + }; } -static UniValue setnetworkactive(const JSONRPCRequest& request) +static RPCHelpMan setnetworkactive() { - RPCHelpMan{"setnetworkactive", + return RPCHelpMan{"setnetworkactive", "\nDisable/enable all p2p network activity.\n", { {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"}, }, RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"}, RPCExamples{""}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if (!node.connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -720,14 +781,16 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) node.connman->SetNetworkActive(request.params[0].get_bool()); return node.connman->GetNetworkActive(); +}, + }; } -static UniValue getnodeaddresses(const JSONRPCRequest& request) +static RPCHelpMan getnodeaddresses() { - RPCHelpMan{"getnodeaddresses", + return RPCHelpMan{"getnodeaddresses", "\nReturn known addresses which can potentially be used to find new nodes in the network\n", { - {"count", RPCArg::Type::NUM, /* default */ "1", "How many addresses to return. Limited to the smaller of " + ToString(ADDRMAN_GETADDR_MAX) + " or " + ToString(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses."}, + {"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."}, }, RPCResult{ RPCResult::Type::ARR, "", "", @@ -745,7 +808,8 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) HelpExampleCli("getnodeaddresses", "8") + HelpExampleRpc("getnodeaddresses", "8") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ NodeContext& node = EnsureNodeContext(request.context); if (!node.connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -754,18 +818,16 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) int count = 1; if (!request.params[0].isNull()) { count = request.params[0].get_int(); - if (count <= 0) { + if (count < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); } } // returns a shuffled list of CAddress - std::vector<CAddress> vAddr = node.connman->GetAddresses(); + std::vector<CAddress> vAddr = node.connman->GetAddresses(count, /* max_pct */ 0); UniValue ret(UniValue::VARR); - int address_return_count = std::min<int>(count, vAddr.size()); - for (int i = 0; i < address_return_count; ++i) { + for (const CAddress& addr : vAddr) { UniValue obj(UniValue::VOBJ); - const CAddress& addr = vAddr[i]; obj.pushKV("time", (int)addr.nTime); obj.pushKV("services", (uint64_t)addr.nServices); obj.pushKV("address", addr.ToStringIP()); @@ -773,6 +835,58 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) ret.push_back(obj); } return ret; +}, + }; +} + +static RPCHelpMan addpeeraddress() +{ + return RPCHelpMan{"addpeeraddress", + "\nAdd the address of a potential peer to the address manager. This RPC is for testing only.\n", + { + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"}, + {"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager"}, + }, + }, + RPCExamples{ + HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333") + + HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + NodeContext& node = EnsureNodeContext(request.context); + if (!node.connman) { + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); + } + + UniValue obj(UniValue::VOBJ); + + std::string addr_string = request.params[0].get_str(); + uint16_t port = request.params[1].get_int(); + + CNetAddr net_addr; + if (!LookupHost(addr_string, net_addr, false)) { + obj.pushKV("success", false); + return obj; + } + CAddress address = CAddress({net_addr, port}, ServiceFlags(NODE_NETWORK|NODE_WITNESS)); + address.nTime = GetAdjustedTime(); + // The source address is set equal to the address. This is equivalent to the peer + // announcing itself. + if (!node.connman->AddNewAddresses({address}, address)) { + obj.pushKV("success", false); + return obj; + } + + obj.pushKV("success", true); + return obj; +}, + }; } void RegisterNetRPCCommands(CRPCTable &t) @@ -794,9 +908,10 @@ static const CRPCCommand commands[] = { "network", "clearbanned", &clearbanned, {} }, { "network", "setnetworkactive", &setnetworkactive, {"state"} }, { "network", "getnodeaddresses", &getnodeaddresses, {"count"} }, + { "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} }, }; // clang-format on - - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) - t.appendCommand(commands[vcidx].name, &commands[vcidx]); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); + } } |