aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/net.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc/net.cpp')
-rw-r--r--src/rpc/net.cpp301
1 files changed, 181 insertions, 120 deletions
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 846d90cd0a..e8cdce623c 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -1,23 +1,26 @@
-// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <rpc/server.h>
+#include <banman.h>
#include <chainparams.h>
#include <clientversion.h>
#include <core_io.h>
-#include <validation.h>
#include <net.h>
#include <net_processing.h>
#include <netbase.h>
#include <policy/policy.h>
+#include <policy/settings.h>
#include <rpc/protocol.h>
+#include <rpc/util.h>
#include <sync.h>
#include <timedata.h>
#include <ui_interface.h>
-#include <util.h>
-#include <utilstrencodings.h>
+#include <util/strencodings.h>
+#include <util/system.h>
+#include <validation.h>
#include <version.h>
#include <warnings.h>
@@ -27,14 +30,17 @@ static UniValue getconnectioncount(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getconnectioncount\n"
- "\nReturns the number of connections to other nodes.\n"
- "\nResult:\n"
+ RPCHelpMan{"getconnectioncount",
+ "\nReturns the number of connections to other nodes.\n",
+ {},
+ RPCResult{
"n (numeric) The connection count\n"
- "\nExamples:\n"
- + HelpExampleCli("getconnectioncount", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getconnectioncount", "")
+ HelpExampleRpc("getconnectioncount", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -46,14 +52,17 @@ static UniValue ping(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "ping\n"
- "\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"
- "\nExamples:\n"
- + HelpExampleCli("ping", "")
+ 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",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("ping", "")
+ HelpExampleRpc("ping", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -69,9 +78,10 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getpeerinfo\n"
- "\nReturns data about each connected network node as a json array of objects.\n"
- "\nResult:\n"
+ RPCHelpMan{"getpeerinfo",
+ "\nReturns data about each connected network node as a json array of objects.\n",
+ {},
+ RPCResult{
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
@@ -104,20 +114,26 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
" \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
" \"minfeefilter\": n, (numeric) The minimum fee rate for transactions this peer accepts\n"
" \"bytessent_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " \"msg\": n, (numeric) The total bytes sent aggregated by message type\n"
+ " When a message type is not listed in this json object, the bytes sent are 0.\n"
+ " Only known message types can appear as keys in the object.\n"
" ...\n"
" },\n"
" \"bytesrecv_per_msg\": {\n"
- " \"addr\": n, (numeric) The total bytes received aggregated by message type\n"
+ " \"msg\": n, (numeric) 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+"'.\n"
" ...\n"
" }\n"
" }\n"
" ,...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getpeerinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getpeerinfo", "")
+ HelpExampleRpc("getpeerinfo", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -173,14 +189,14 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
obj.pushKV("minfeefilter", ValueFromAmount(stats.minFeeFilter));
UniValue sendPerMsgCmd(UniValue::VOBJ);
- for (const mapMsgCmdSize::value_type &i : stats.mapSendBytesPerMsgCmd) {
+ for (const auto& i : stats.mapSendBytesPerMsgCmd) {
if (i.second > 0)
sendPerMsgCmd.pushKV(i.first, i.second);
}
obj.pushKV("bytessent_per_msg", sendPerMsgCmd);
UniValue recvPerMsgCmd(UniValue::VOBJ);
- for (const mapMsgCmdSize::value_type &i : stats.mapRecvBytesPerMsgCmd) {
+ for (const auto& i : stats.mapRecvBytesPerMsgCmd) {
if (i.second > 0)
recvPerMsgCmd.pushKV(i.first, i.second);
}
@@ -200,18 +216,21 @@ static UniValue addnode(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
throw std::runtime_error(
- "addnode \"node\" \"add|remove|onetry\"\n"
- "\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"
- "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n"
- "\nArguments:\n"
- "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
- "2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n"
- "\nExamples:\n"
- + HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"")
+ 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"
+ "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n",
+ {
+ {"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The node (see getpeerinfo for nodes)"},
+ {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"},
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"")
+ HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -243,19 +262,22 @@ static UniValue disconnectnode(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3)
throw std::runtime_error(
- "disconnectnode \"[address]\" [nodeid]\n"
- "\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"
- "\nArguments:\n"
- "1. \"address\" (string, optional) The IP address/port of the node\n"
- "2. \"nodeid\" (number, optional) The node ID (see getpeerinfo for node IDs)\n"
- "\nExamples:\n"
- + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ 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",
+ {
+ {"address", RPCArg::Type::STR, /* default */ "fallback to nodeid", "The IP address/port of the node"},
+ {"nodeid", RPCArg::Type::NUM, /* default */ "fallback to address", "The node ID (see getpeerinfo for node IDs)"},
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleCli("disconnectnode", "\"\" 1")
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleRpc("disconnectnode", "\"\", 1")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -286,12 +308,13 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
throw std::runtime_error(
- "getaddednodeinfo ( \"node\" )\n"
- "\nReturns information about the given added node, or all added nodes\n"
- "(note that onetry addnodes are not listed here)\n"
- "\nArguments:\n"
- "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
- "\nResult:\n"
+ RPCHelpMan{"getaddednodeinfo",
+ "\nReturns information about the given added node, or all added nodes\n"
+ "(note that onetry addnodes are not listed here)\n",
+ {
+ {"node", RPCArg::Type::STR, /* default */ "all nodes", "If provided, return information about this specific node, otherwise all nodes are returned."},
+ },
+ RPCResult{
"[\n"
" {\n"
" \"addednode\" : \"192.168.0.201\", (string) The node IP address or name (as provided to addnode)\n"
@@ -305,10 +328,12 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request)
" }\n"
" ,...\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ },
+ RPCExamples{
+ HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
+ HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -353,10 +378,11 @@ static UniValue getnettotals(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
- "getnettotals\n"
- "\nReturns information about network traffic, including bytes in, bytes out,\n"
- "and current time.\n"
- "\nResult:\n"
+ RPCHelpMan{"getnettotals",
+ "\nReturns information about network traffic, including bytes in, bytes out,\n"
+ "and current time.\n",
+ {},
+ RPCResult{
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
@@ -371,10 +397,12 @@ static UniValue getnettotals(const JSONRPCRequest& request)
" \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n"
" }\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getnettotals", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getnettotals", "")
+ HelpExampleRpc("getnettotals", "")
- );
+ },
+ }.ToString());
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
@@ -406,7 +434,7 @@ static UniValue GetNetworksInfo()
UniValue obj(UniValue::VOBJ);
GetProxy(network, proxy);
obj.pushKV("name", GetNetworkName(network));
- obj.pushKV("limited", IsLimited(network));
+ obj.pushKV("limited", !IsReachable(network));
obj.pushKV("reachable", IsReachable(network));
obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : std::string());
obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials);
@@ -419,9 +447,10 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "getnetworkinfo\n"
- "Returns an object containing various state info regarding P2P networking.\n"
- "\nResult:\n"
+ RPCHelpMan{"getnetworkinfo",
+ "Returns an object containing various state info regarding P2P networking.\n",
+ {},
+ RPCResult{
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n"
@@ -453,10 +482,12 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
" ]\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
- "\nExamples:\n"
- + HelpExampleCli("getnetworkinfo", "")
+ },
+ RPCExamples{
+ HelpExampleCli("getnetworkinfo", "")
+ HelpExampleRpc("getnetworkinfo", "")
- );
+ },
+ }.ToString());
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
@@ -493,26 +524,30 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
static UniValue setban(const JSONRPCRequest& request)
{
+ const RPCHelpMan help{"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)"},
+ {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list"},
+ {"bantime", RPCArg::Type::NUM, /* default */ "0", "time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)"},
+ {"absolute", RPCArg::Type::BOOL, /* default */ "false", "If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)"},
+ },
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
+ },
+ };
std::string strCommand;
if (!request.params[1].isNull())
strCommand = request.params[1].get_str();
- if (request.fHelp || request.params.size() < 2 ||
- (strCommand != "add" && strCommand != "remove"))
- throw std::runtime_error(
- "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n"
- "\nAttempts to add or remove an IP/Subnet from the banned list.\n"
- "\nArguments:\n"
- "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)\n"
- "2. \"command\" (string, required) 'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list\n"
- "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the IP is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
- "4. \"absolute\" (boolean, optional) If set, the bantime must be an absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
- "\nExamples:\n"
- + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
- + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
- + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
- );
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || (strCommand != "add" && strCommand != "remove")) {
+ throw std::runtime_error(help.ToString());
+ }
+ if (!g_banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
CSubNet subNet;
CNetAddr netAddr;
@@ -534,8 +569,9 @@ static UniValue setban(const JSONRPCRequest& request)
if (strCommand == "add")
{
- if (isSubnet ? g_connman->IsBanned(subNet) : g_connman->IsBanned(netAddr))
+ if (isSubnet ? g_banman->IsBanned(subNet) : g_banman->IsBanned(netAddr)) {
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
+ }
int64_t banTime = 0; //use standard bantime if not specified
if (!request.params[2].isNull())
@@ -545,12 +581,23 @@ static UniValue setban(const JSONRPCRequest& request)
if (request.params[3].isTrue())
absolute = true;
- isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+ if (isSubnet) {
+ g_banman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute);
+ if (g_connman) {
+ g_connman->DisconnectNode(subNet);
+ }
+ } else {
+ g_banman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+ if (g_connman) {
+ g_connman->DisconnectNode(netAddr);
+ }
+ }
}
else if(strCommand == "remove")
{
- if (!( isSubnet ? g_connman->Unban(subNet) : g_connman->Unban(netAddr) ))
+ if (!( isSubnet ? g_banman->Unban(subNet) : g_banman->Unban(netAddr) )) {
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously banned.");
+ }
}
return NullUniValue;
}
@@ -559,18 +606,22 @@ static UniValue listbanned(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "listbanned\n"
- "\nList all banned IPs/Subnets.\n"
- "\nExamples:\n"
- + HelpExampleCli("listbanned", "")
+ RPCHelpMan{"listbanned",
+ "\nList all banned IPs/Subnets.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("listbanned", "")
+ HelpExampleRpc("listbanned", "")
- );
+ },
+ }.ToString());
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ if(!g_banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
banmap_t banMap;
- g_connman->GetBanned(banMap);
+ g_banman->GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
for (const auto& entry : banMap)
@@ -592,16 +643,20 @@ static UniValue clearbanned(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
- "clearbanned\n"
- "\nClear all banned IPs.\n"
- "\nExamples:\n"
- + HelpExampleCli("clearbanned", "")
+ RPCHelpMan{"clearbanned",
+ "\nClear all banned IPs.\n",
+ {},
+ RPCResults{},
+ RPCExamples{
+ HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", "")
- );
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
+ },
+ }.ToString());
+ if (!g_banman) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded");
+ }
- g_connman->ClearBanned();
+ g_banman->ClearBanned();
return NullUniValue;
}
@@ -610,10 +665,14 @@ static UniValue setnetworkactive(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
- "setnetworkactive true|false\n"
- "\nDisable/enable all p2p network activity.\n"
- "\nArguments:\n"
- "1. \"state\" (boolean, required) true to enable networking, false to disable\n"
+ RPCHelpMan{"setnetworkactive",
+ "\nDisable/enable all p2p network activity.\n",
+ {
+ {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"},
+ },
+ RPCResults{},
+ RPCExamples{""},
+ }.ToString()
);
}
@@ -630,12 +689,12 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1) {
throw std::runtime_error(
- "getnodeaddresses ( count )\n"
- "\nReturn known addresses which can potentially be used to find new nodes in the network\n"
- "\nArguments:\n"
- "1. \"count\" (numeric, optional) How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) +
- " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses. (default = 1)\n"
- "\nResult:\n"
+ 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 " + std::to_string(ADDRMAN_GETADDR_MAX) + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses."},
+ },
+ RPCResult{
"[\n"
" {\n"
" \"time\": ttt, (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n"
@@ -645,10 +704,12 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
" }\n"
" ,....\n"
"]\n"
- "\nExamples:\n"
- + HelpExampleCli("getnodeaddresses", "8")
+ },
+ RPCExamples{
+ HelpExampleCli("getnodeaddresses", "8")
+ HelpExampleRpc("getnodeaddresses", "8")
- );
+ },
+ }.ToString());
}
if (!g_connman) {
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");