Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/net.cpp
Show All 26 Lines | |||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <util/translation.h> | #include <util/translation.h> | ||||
#include <validation.h> | #include <validation.h> | ||||
#include <version.h> | #include <version.h> | ||||
#include <warnings.h> | #include <warnings.h> | ||||
#include <univalue.h> | #include <univalue.h> | ||||
static UniValue getconnectioncount(const Config &config, | static RPCHelpMan getconnectioncount() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"getconnectioncount", | "getconnectioncount", | ||||
"Returns the number of connections to other nodes.\n", | "Returns the number of connections to other nodes.\n", | ||||
{}, | {}, | ||||
RPCResult{RPCResult::Type::NUM, "", "The connection count"}, | RPCResult{RPCResult::Type::NUM, "", "The connection count"}, | ||||
RPCExamples{HelpExampleCli("getconnectioncount", "") + | RPCExamples{HelpExampleCli("getconnectioncount", "") + | ||||
HelpExampleRpc("getconnectioncount", "")}, | HelpExampleRpc("getconnectioncount", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
return int(node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); | return int(node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL)); | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue ping(const Config &config, const JSONRPCRequest &request) { | static RPCHelpMan ping() { | ||||
RPCHelpMan{ | return RPCHelpMan{ | ||||
"ping", | "ping", | ||||
"Requests that a ping be sent to all other nodes, to measure ping " | "Requests that a ping be sent to all other nodes, to measure ping " | ||||
"time.\n" | "time.\n" | ||||
"Results provided in getpeerinfo, pingtime and pingwait fields are " | "Results provided in getpeerinfo, pingtime and pingwait fields are " | ||||
"decimal seconds.\n" | "decimal seconds.\n" | ||||
"Ping command is handled in queue with all other commands, so it " | "Ping command is handled in queue with all other commands, so it " | ||||
"measures processing backlog, not just network ping.\n", | "measures processing backlog, not just network ping.\n", | ||||
{}, | {}, | ||||
RPCResult{RPCResult::Type::NONE, "", ""}, | RPCResult{RPCResult::Type::NONE, "", ""}, | ||||
RPCExamples{HelpExampleCli("ping", "") + HelpExampleRpc("ping", "")}, | RPCExamples{HelpExampleCli("ping", "") + HelpExampleRpc("ping", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
// Request that each node send a ping during next message processing pass | // Request that each node send a ping during next message processing | ||||
node.connman->ForEachNode([](CNode *pnode) { pnode->fPingQueued = true; }); | // pass | ||||
node.connman->ForEachNode( | |||||
[](CNode *pnode) { pnode->fPingQueued = true; }); | |||||
return NullUniValue; | return NullUniValue; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue getpeerinfo(const Config &config, | static RPCHelpMan getpeerinfo() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"getpeerinfo", | "getpeerinfo", | ||||
"Returns data about each connected network node as a json array of " | "Returns data about each connected network node as a json array of " | ||||
"objects.\n", | "objects.\n", | ||||
{}, | {}, | ||||
RPCResult{ | RPCResult{ | ||||
RPCResult::Type::ARR, | RPCResult::Type::ARR, | ||||
"", | "", | ||||
"", | "", | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
"object and all bytes received of unknown message types " | "object and all bytes received of unknown message types " | ||||
"are listed under '" + | "are listed under '" + | ||||
NET_MESSAGE_COMMAND_OTHER + "'."}}}, | NET_MESSAGE_COMMAND_OTHER + "'."}}}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
}, | }, | ||||
RPCExamples{HelpExampleCli("getpeerinfo", "") + | RPCExamples{HelpExampleCli("getpeerinfo", "") + | ||||
HelpExampleRpc("getpeerinfo", "")}, | HelpExampleRpc("getpeerinfo", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
std::vector<CNodeStats> vstats; | std::vector<CNodeStats> vstats; | ||||
node.connman->GetNodeStats(vstats); | node.connman->GetNodeStats(vstats); | ||||
UniValue ret(UniValue::VARR); | UniValue ret(UniValue::VARR); | ||||
for (const CNodeStats &stats : vstats) { | for (const CNodeStats &stats : vstats) { | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
CNodeStateStats statestats; | CNodeStateStats statestats; | ||||
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); | bool fStateStats = GetNodeStateStats(stats.nodeid, statestats); | ||||
obj.pushKV("id", stats.nodeid); | obj.pushKV("id", stats.nodeid); | ||||
obj.pushKV("addr", stats.addrName); | obj.pushKV("addr", stats.addrName); | ||||
if (!(stats.addrLocal.empty())) { | if (!(stats.addrLocal.empty())) { | ||||
obj.pushKV("addrlocal", stats.addrLocal); | obj.pushKV("addrlocal", stats.addrLocal); | ||||
} | } | ||||
if (stats.addrBind.IsValid()) { | if (stats.addrBind.IsValid()) { | ||||
obj.pushKV("addrbind", stats.addrBind.ToString()); | obj.pushKV("addrbind", stats.addrBind.ToString()); | ||||
} | } | ||||
if (stats.m_mapped_as != 0) { | if (stats.m_mapped_as != 0) { | ||||
obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); | obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); | ||||
} | } | ||||
obj.pushKV("services", strprintf("%016x", stats.nServices)); | obj.pushKV("services", strprintf("%016x", stats.nServices)); | ||||
obj.pushKV("servicesnames", GetServicesNames(stats.nServices)); | obj.pushKV("servicesnames", GetServicesNames(stats.nServices)); | ||||
obj.pushKV("relaytxes", stats.fRelayTxes); | obj.pushKV("relaytxes", stats.fRelayTxes); | ||||
obj.pushKV("lastsend", stats.nLastSend); | obj.pushKV("lastsend", stats.nLastSend); | ||||
obj.pushKV("lastrecv", stats.nLastRecv); | obj.pushKV("lastrecv", stats.nLastRecv); | ||||
obj.pushKV("last_transaction", stats.nLastTXTime); | obj.pushKV("last_transaction", stats.nLastTXTime); | ||||
if (g_avalanche) { | if (g_avalanche) { | ||||
obj.pushKV("last_proof", stats.nLastProofTime); | obj.pushKV("last_proof", stats.nLastProofTime); | ||||
} | } | ||||
obj.pushKV("last_block", stats.nLastBlockTime); | obj.pushKV("last_block", stats.nLastBlockTime); | ||||
obj.pushKV("bytessent", stats.nSendBytes); | obj.pushKV("bytessent", stats.nSendBytes); | ||||
obj.pushKV("bytesrecv", stats.nRecvBytes); | obj.pushKV("bytesrecv", stats.nRecvBytes); | ||||
obj.pushKV("conntime", stats.nTimeConnected); | obj.pushKV("conntime", stats.nTimeConnected); | ||||
obj.pushKV("timeoffset", stats.nTimeOffset); | obj.pushKV("timeoffset", stats.nTimeOffset); | ||||
if (stats.m_ping_usec > 0) { | if (stats.m_ping_usec > 0) { | ||||
obj.pushKV("pingtime", double(stats.m_ping_usec) / 1e6); | obj.pushKV("pingtime", double(stats.m_ping_usec) / 1e6); | ||||
} | } | ||||
if (stats.m_min_ping_usec < std::numeric_limits<int64_t>::max()) { | if (stats.m_min_ping_usec < | ||||
std::numeric_limits<int64_t>::max()) { | |||||
obj.pushKV("minping", double(stats.m_min_ping_usec) / 1e6); | obj.pushKV("minping", double(stats.m_min_ping_usec) / 1e6); | ||||
} | } | ||||
if (stats.m_ping_wait_usec > 0) { | if (stats.m_ping_wait_usec > 0) { | ||||
obj.pushKV("pingwait", double(stats.m_ping_wait_usec) / 1e6); | obj.pushKV("pingwait", | ||||
double(stats.m_ping_wait_usec) / 1e6); | |||||
} | } | ||||
obj.pushKV("version", stats.nVersion); | obj.pushKV("version", stats.nVersion); | ||||
// Use the sanitized form of subver here, to avoid tricksy remote peers | // Use the sanitized form of subver here, to avoid tricksy | ||||
// from corrupting or modifying the JSON output by putting special | // remote peers from corrupting or modifying the JSON output by | ||||
// characters in their ver message. | // putting special characters in their ver message. | ||||
obj.pushKV("subver", stats.cleanSubVer); | obj.pushKV("subver", stats.cleanSubVer); | ||||
obj.pushKV("inbound", stats.fInbound); | obj.pushKV("inbound", stats.fInbound); | ||||
obj.pushKV("addnode", stats.m_manual_connection); | obj.pushKV("addnode", stats.m_manual_connection); | ||||
obj.pushKV("startingheight", stats.nStartingHeight); | obj.pushKV("startingheight", stats.nStartingHeight); | ||||
if (fStateStats) { | if (fStateStats) { | ||||
if (IsDeprecatedRPCEnabled(gArgs, "banscore")) { | if (IsDeprecatedRPCEnabled(gArgs, "banscore")) { | ||||
// banscore is deprecated in v0.22.11 for removal in v0.23 | // banscore is deprecated in v0.22.11 for removal in | ||||
// v0.23 | |||||
Fabien: That's a good reminder | |||||
PiRKAuthorUnsubmitted Done Inline ActionsYes, I checked that there is an upcoming PR dealing with it, when I saw it: https://github.com/bitcoin/bitcoin/pull/20755 PiRK: Yes, I checked that there is an upcoming PR dealing with it, when I saw it: https://github. | |||||
obj.pushKV("banscore", statestats.m_misbehavior_score); | obj.pushKV("banscore", statestats.m_misbehavior_score); | ||||
} | } | ||||
obj.pushKV("synced_headers", statestats.nSyncHeight); | obj.pushKV("synced_headers", statestats.nSyncHeight); | ||||
obj.pushKV("synced_blocks", statestats.nCommonHeight); | obj.pushKV("synced_blocks", statestats.nCommonHeight); | ||||
UniValue heights(UniValue::VARR); | UniValue heights(UniValue::VARR); | ||||
for (const int height : statestats.vHeightInFlight) { | for (const int height : statestats.vHeightInFlight) { | ||||
heights.push_back(height); | heights.push_back(height); | ||||
} | } | ||||
obj.pushKV("inflight", heights); | obj.pushKV("inflight", heights); | ||||
} | } | ||||
obj.pushKV("whitelisted", stats.m_legacyWhitelisted); | obj.pushKV("whitelisted", stats.m_legacyWhitelisted); | ||||
UniValue permissions(UniValue::VARR); | UniValue permissions(UniValue::VARR); | ||||
for (const auto &permission : | for (const auto &permission : | ||||
NetPermissions::ToStrings(stats.m_permissionFlags)) { | NetPermissions::ToStrings(stats.m_permissionFlags)) { | ||||
permissions.push_back(permission); | permissions.push_back(permission); | ||||
} | } | ||||
obj.pushKV("permissions", permissions); | obj.pushKV("permissions", permissions); | ||||
obj.pushKV("minfeefilter", stats.minFeeFilter); | obj.pushKV("minfeefilter", stats.minFeeFilter); | ||||
UniValue sendPerMsgCmd(UniValue::VOBJ); | UniValue sendPerMsgCmd(UniValue::VOBJ); | ||||
for (const auto &i : stats.mapSendBytesPerMsgCmd) { | for (const auto &i : stats.mapSendBytesPerMsgCmd) { | ||||
if (i.second > 0) { | if (i.second > 0) { | ||||
sendPerMsgCmd.pushKV(i.first, i.second); | sendPerMsgCmd.pushKV(i.first, i.second); | ||||
} | } | ||||
} | } | ||||
obj.pushKV("bytessent_per_msg", sendPerMsgCmd); | obj.pushKV("bytessent_per_msg", sendPerMsgCmd); | ||||
UniValue recvPerMsgCmd(UniValue::VOBJ); | UniValue recvPerMsgCmd(UniValue::VOBJ); | ||||
for (const auto &i : stats.mapRecvBytesPerMsgCmd) { | for (const auto &i : stats.mapRecvBytesPerMsgCmd) { | ||||
if (i.second > 0) { | if (i.second > 0) { | ||||
recvPerMsgCmd.pushKV(i.first, i.second); | recvPerMsgCmd.pushKV(i.first, i.second); | ||||
} | } | ||||
} | } | ||||
obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd); | obj.pushKV("bytesrecv_per_msg", recvPerMsgCmd); | ||||
ret.push_back(obj); | ret.push_back(obj); | ||||
} | } | ||||
return ret; | return ret; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue addnode(const Config &config, const JSONRPCRequest &request) { | static RPCHelpMan addnode() { | ||||
std::string strCommand; | return RPCHelpMan{ | ||||
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", | "addnode", | ||||
"Attempts to add or remove a node from the addnode list.\n" | "Attempts to add or remove a node from the addnode list.\n" | ||||
"Or try a connection to a node once.\n" | "Or try a connection to a node once.\n" | ||||
"Nodes added using addnode (or -connect) are protected from " | "Nodes added using addnode (or -connect) are protected from " | ||||
"DoS disconnection and are not required to be\n" | "DoS disconnection and are not required to be\n" | ||||
"full nodes as other outbound peers are (though such peers " | "full nodes as other outbound peers are (though such peers " | ||||
"will not be synced from).\n", | "will not be synced from).\n", | ||||
{ | { | ||||
{"node", RPCArg::Type::STR, RPCArg::Optional::NO, | {"node", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"The node (see getpeerinfo for nodes)"}, | "The node (see getpeerinfo for nodes)"}, | ||||
{"command", RPCArg::Type::STR, RPCArg::Optional::NO, | {"command", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"'add' to add a node to the list, 'remove' to remove a " | "'add' to add a node to the list, 'remove' to remove a " | ||||
"node from the list, 'onetry' to try a connection to the " | "node from the list, 'onetry' to try a connection to the " | ||||
"node once"}, | "node once"}, | ||||
}, | }, | ||||
RPCResult{RPCResult::Type::NONE, "", ""}, | RPCResult{RPCResult::Type::NONE, "", ""}, | ||||
RPCExamples{ | RPCExamples{ | ||||
HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") + | HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\"") + | ||||
HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")}, | HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\"")}, | ||||
[&](const RPCHelpMan &self, const Config &config, | |||||
const JSONRPCRequest &request) -> UniValue { | |||||
std::string strCommand; | |||||
if (!request.params[1].isNull()) { | |||||
strCommand = request.params[1].get_str(); | |||||
} | } | ||||
.ToString()); | |||||
if (request.fHelp || request.params.size() != 2 || | |||||
(strCommand != "onetry" && strCommand != "add" && | |||||
strCommand != "remove")) { | |||||
throw std::runtime_error(self.ToString()); | |||||
} | } | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
std::string strNode = request.params[0].get_str(); | std::string strNode = request.params[0].get_str(); | ||||
if (strCommand == "onetry") { | if (strCommand == "onetry") { | ||||
CAddress addr; | CAddress addr; | ||||
node.connman->OpenNetworkConnection( | node.connman->OpenNetworkConnection(addr, false, nullptr, | ||||
addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL); | strNode.c_str(), | ||||
ConnectionType::MANUAL); | |||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if ((strCommand == "add") && (!node.connman->AddNode(strNode))) { | if ((strCommand == "add") && (!node.connman->AddNode(strNode))) { | ||||
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, | throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, | ||||
"Error: Node already added"); | "Error: Node already added"); | ||||
} else if ((strCommand == "remove") && | } else if ((strCommand == "remove") && | ||||
(!node.connman->RemoveAddedNode(strNode))) { | (!node.connman->RemoveAddedNode(strNode))) { | ||||
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, | throw JSONRPCError( | ||||
RPC_CLIENT_NODE_NOT_ADDED, | |||||
"Error: Node could not be removed. It has not been " | "Error: Node could not be removed. It has not been " | ||||
"added previously."); | "added previously."); | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue disconnectnode(const Config &config, | static RPCHelpMan disconnectnode() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"disconnectnode", | "disconnectnode", | ||||
"Immediately disconnects from the specified peer node.\n" | "Immediately disconnects from the specified peer node.\n" | ||||
"\nStrictly one out of 'address' and 'nodeid' can be provided to " | "\nStrictly one out of 'address' and 'nodeid' can be provided to " | ||||
"identify the node.\n" | "identify the node.\n" | ||||
"\nTo disconnect by nodeid, either set 'address' to the empty string, " | "\nTo disconnect by nodeid, either set 'address' to the empty string, " | ||||
"or call using the named 'nodeid' argument only.\n", | "or call using the named 'nodeid' argument only.\n", | ||||
{ | { | ||||
{"address", RPCArg::Type::STR, | {"address", RPCArg::Type::STR, | ||||
/* default */ "fallback to nodeid", | /* default */ "fallback to nodeid", | ||||
"The IP address/port of the node"}, | "The IP address/port of the node"}, | ||||
{"nodeid", RPCArg::Type::NUM, | {"nodeid", RPCArg::Type::NUM, | ||||
/* default */ "fallback to address", | /* default */ "fallback to address", | ||||
"The node ID (see getpeerinfo for node IDs)"}, | "The node ID (see getpeerinfo for node IDs)"}, | ||||
}, | }, | ||||
RPCResult{RPCResult::Type::NONE, "", ""}, | RPCResult{RPCResult::Type::NONE, "", ""}, | ||||
RPCExamples{HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") + | RPCExamples{HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") + | ||||
HelpExampleCli("disconnectnode", "\"\" 1") + | HelpExampleCli("disconnectnode", "\"\" 1") + | ||||
HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + | HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") + | ||||
HelpExampleRpc("disconnectnode", "\"\", 1")}, | HelpExampleRpc("disconnectnode", "\"\", 1")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
bool success; | bool success; | ||||
const UniValue &address_arg = request.params[0]; | const UniValue &address_arg = request.params[0]; | ||||
const UniValue &id_arg = request.params[1]; | const UniValue &id_arg = request.params[1]; | ||||
if (!address_arg.isNull() && id_arg.isNull()) { | if (!address_arg.isNull() && id_arg.isNull()) { | ||||
/* handle disconnect-by-address */ | /* handle disconnect-by-address */ | ||||
success = node.connman->DisconnectNode(address_arg.get_str()); | success = node.connman->DisconnectNode(address_arg.get_str()); | ||||
} else if (!id_arg.isNull() && | } else if (!id_arg.isNull() && (address_arg.isNull() || | ||||
(address_arg.isNull() || | (address_arg.isStr() && | ||||
(address_arg.isStr() && address_arg.get_str().empty()))) { | address_arg.get_str().empty()))) { | ||||
/* handle disconnect-by-id */ | /* handle disconnect-by-id */ | ||||
NodeId nodeid = (NodeId)id_arg.get_int64(); | NodeId nodeid = (NodeId)id_arg.get_int64(); | ||||
success = node.connman->DisconnectNode(nodeid); | success = node.connman->DisconnectNode(nodeid); | ||||
} else { | } else { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_INVALID_PARAMS, | RPC_INVALID_PARAMS, | ||||
"Only one of address and nodeid should be provided."); | "Only one of address and nodeid should be provided."); | ||||
} | } | ||||
if (!success) { | if (!success) { | ||||
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, | throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, | ||||
"Node not found in connected nodes"); | "Node not found in connected nodes"); | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue getaddednodeinfo(const Config &config, | static RPCHelpMan getaddednodeinfo() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"getaddednodeinfo", | "getaddednodeinfo", | ||||
"Returns information about the given added node, or all added nodes\n" | "Returns information about the given added node, or all added nodes\n" | ||||
"(note that onetry addnodes are not listed here)\n", | "(note that onetry addnodes are not listed here)\n", | ||||
{ | { | ||||
{"node", RPCArg::Type::STR, /* default */ "all nodes", | {"node", RPCArg::Type::STR, /* default */ "all nodes", | ||||
"If provided, return information about this specific node, " | "If provided, return information about this specific node, " | ||||
"otherwise all nodes are returned."}, | "otherwise all nodes are returned."}, | ||||
}, | }, | ||||
Show All 23 Lines | return RPCHelpMan{ | ||||
{RPCResult::Type::STR, "connected", | {RPCResult::Type::STR, "connected", | ||||
"connection, inbound or outbound"}, | "connection, inbound or outbound"}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
RPCExamples{HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + | RPCExamples{HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + | ||||
HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")}, | HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
std::vector<AddedNodeInfo> vInfo = node.connman->GetAddedNodeInfo(); | std::vector<AddedNodeInfo> vInfo = node.connman->GetAddedNodeInfo(); | ||||
if (!request.params[0].isNull()) { | if (!request.params[0].isNull()) { | ||||
bool found = false; | bool found = false; | ||||
for (const AddedNodeInfo &info : vInfo) { | for (const AddedNodeInfo &info : vInfo) { | ||||
if (info.strAddedNode == request.params[0].get_str()) { | if (info.strAddedNode == request.params[0].get_str()) { | ||||
vInfo.assign(1, info); | vInfo.assign(1, info); | ||||
found = true; | found = true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (!found) { | if (!found) { | ||||
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, | throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, | ||||
"Error: Node has not been added."); | "Error: Node has not been added."); | ||||
} | } | ||||
} | } | ||||
UniValue ret(UniValue::VARR); | UniValue ret(UniValue::VARR); | ||||
for (const AddedNodeInfo &info : vInfo) { | for (const AddedNodeInfo &info : vInfo) { | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
obj.pushKV("addednode", info.strAddedNode); | obj.pushKV("addednode", info.strAddedNode); | ||||
obj.pushKV("connected", info.fConnected); | obj.pushKV("connected", info.fConnected); | ||||
UniValue addresses(UniValue::VARR); | UniValue addresses(UniValue::VARR); | ||||
if (info.fConnected) { | if (info.fConnected) { | ||||
UniValue address(UniValue::VOBJ); | UniValue address(UniValue::VOBJ); | ||||
address.pushKV("address", info.resolvedAddress.ToString()); | address.pushKV("address", info.resolvedAddress.ToString()); | ||||
address.pushKV("connected", info.fInbound ? "inbound" : "outbound"); | address.pushKV("connected", | ||||
info.fInbound ? "inbound" : "outbound"); | |||||
addresses.push_back(address); | addresses.push_back(address); | ||||
} | } | ||||
obj.pushKV("addresses", addresses); | obj.pushKV("addresses", addresses); | ||||
ret.push_back(obj); | ret.push_back(obj); | ||||
} | } | ||||
return ret; | return ret; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue getnettotals(const Config &config, | static RPCHelpMan getnettotals() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"getnettotals", | "getnettotals", | ||||
"Returns information about network traffic, including bytes in, " | "Returns information about network traffic, including bytes in, " | ||||
"bytes out,\n" | "bytes out,\n" | ||||
"and current time.\n", | "and current time.\n", | ||||
{}, | {}, | ||||
RPCResult{ | RPCResult{ | ||||
RPCResult::Type::OBJ, | RPCResult::Type::OBJ, | ||||
"", | "", | ||||
Show All 18 Lines | return RPCHelpMan{ | ||||
{RPCResult::Type::NUM, "bytes_left_in_cycle", | {RPCResult::Type::NUM, "bytes_left_in_cycle", | ||||
"Bytes left in current time cycle"}, | "Bytes left in current time cycle"}, | ||||
{RPCResult::Type::NUM, "time_left_in_cycle", | {RPCResult::Type::NUM, "time_left_in_cycle", | ||||
"Seconds left in current time cycle"}, | "Seconds left in current time cycle"}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
RPCExamples{HelpExampleCli("getnettotals", "") + | RPCExamples{HelpExampleCli("getnettotals", "") + | ||||
HelpExampleRpc("getnettotals", "")}, | HelpExampleRpc("getnettotals", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
obj.pushKV("totalbytesrecv", node.connman->GetTotalBytesRecv()); | obj.pushKV("totalbytesrecv", node.connman->GetTotalBytesRecv()); | ||||
obj.pushKV("totalbytessent", node.connman->GetTotalBytesSent()); | obj.pushKV("totalbytessent", node.connman->GetTotalBytesSent()); | ||||
obj.pushKV("timemillis", GetTimeMillis()); | obj.pushKV("timemillis", GetTimeMillis()); | ||||
UniValue outboundLimit(UniValue::VOBJ); | UniValue outboundLimit(UniValue::VOBJ); | ||||
outboundLimit.pushKV("timeframe", node.connman->GetMaxOutboundTimeframe()); | outboundLimit.pushKV("timeframe", | ||||
outboundLimit.pushKV("target", node.connman->GetMaxOutboundTarget()); | node.connman->GetMaxOutboundTimeframe()); | ||||
outboundLimit.pushKV("target", | |||||
node.connman->GetMaxOutboundTarget()); | |||||
outboundLimit.pushKV("target_reached", | outboundLimit.pushKV("target_reached", | ||||
node.connman->OutboundTargetReached(false)); | node.connman->OutboundTargetReached(false)); | ||||
outboundLimit.pushKV("serve_historical_blocks", | outboundLimit.pushKV("serve_historical_blocks", | ||||
!node.connman->OutboundTargetReached(true)); | !node.connman->OutboundTargetReached(true)); | ||||
outboundLimit.pushKV("bytes_left_in_cycle", | outboundLimit.pushKV("bytes_left_in_cycle", | ||||
node.connman->GetOutboundTargetBytesLeft()); | node.connman->GetOutboundTargetBytesLeft()); | ||||
outboundLimit.pushKV("time_left_in_cycle", | outboundLimit.pushKV("time_left_in_cycle", | ||||
node.connman->GetMaxOutboundTimeLeftInCycle()); | node.connman->GetMaxOutboundTimeLeftInCycle()); | ||||
obj.pushKV("uploadtarget", outboundLimit); | obj.pushKV("uploadtarget", outboundLimit); | ||||
return obj; | return obj; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue GetNetworksInfo() { | static UniValue GetNetworksInfo() { | ||||
UniValue networks(UniValue::VARR); | UniValue networks(UniValue::VARR); | ||||
for (int n = 0; n < NET_MAX; ++n) { | for (int n = 0; n < NET_MAX; ++n) { | ||||
enum Network network = static_cast<enum Network>(n); | enum Network network = static_cast<enum Network>(n); | ||||
if (network == NET_UNROUTABLE || network == NET_INTERNAL) { | if (network == NET_UNROUTABLE || network == NET_INTERNAL) { | ||||
continue; | continue; | ||||
} | } | ||||
proxyType proxy; | proxyType proxy; | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
GetProxy(network, proxy); | GetProxy(network, proxy); | ||||
obj.pushKV("name", GetNetworkName(network)); | obj.pushKV("name", GetNetworkName(network)); | ||||
obj.pushKV("limited", !IsReachable(network)); | obj.pushKV("limited", !IsReachable(network)); | ||||
obj.pushKV("reachable", IsReachable(network)); | obj.pushKV("reachable", IsReachable(network)); | ||||
obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() | obj.pushKV("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() | ||||
: std::string()); | : std::string()); | ||||
obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials); | obj.pushKV("proxy_randomize_credentials", proxy.randomize_credentials); | ||||
networks.push_back(obj); | networks.push_back(obj); | ||||
} | } | ||||
return networks; | return networks; | ||||
} | } | ||||
static UniValue getnetworkinfo(const Config &config, | static RPCHelpMan getnetworkinfo() { | ||||
const JSONRPCRequest &request) { | |||||
const auto &ticker = Currency::get().ticker; | const auto &ticker = Currency::get().ticker; | ||||
RPCHelpMan{ | return RPCHelpMan{ | ||||
"getnetworkinfo", | "getnetworkinfo", | ||||
"Returns an object containing various state info regarding P2P " | "Returns an object containing various state info regarding P2P " | ||||
"networking.\n", | "networking.\n", | ||||
{}, | {}, | ||||
RPCResult{ | RPCResult{ | ||||
RPCResult::Type::OBJ, | RPCResult::Type::OBJ, | ||||
"", | "", | ||||
"", | "", | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | return RPCHelpMan{ | ||||
{RPCResult::Type::NUM, "score", "relative score"}, | {RPCResult::Type::NUM, "score", "relative score"}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
{RPCResult::Type::STR, "warnings", | {RPCResult::Type::STR, "warnings", | ||||
"any network and blockchain warnings"}, | "any network and blockchain warnings"}, | ||||
}}, | }}, | ||||
RPCExamples{HelpExampleCli("getnetworkinfo", "") + | RPCExamples{HelpExampleCli("getnetworkinfo", "") + | ||||
HelpExampleRpc("getnetworkinfo", "")}, | HelpExampleRpc("getnetworkinfo", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
obj.pushKV("version", CLIENT_VERSION); | obj.pushKV("version", CLIENT_VERSION); | ||||
obj.pushKV("subversion", userAgent(config)); | obj.pushKV("subversion", userAgent(config)); | ||||
obj.pushKV("protocolversion", PROTOCOL_VERSION); | obj.pushKV("protocolversion", PROTOCOL_VERSION); | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (node.connman) { | if (node.connman) { | ||||
ServiceFlags services = node.connman->GetLocalServices(); | ServiceFlags services = node.connman->GetLocalServices(); | ||||
obj.pushKV("localservices", strprintf("%016x", services)); | obj.pushKV("localservices", strprintf("%016x", services)); | ||||
obj.pushKV("localservicesnames", GetServicesNames(services)); | obj.pushKV("localservicesnames", GetServicesNames(services)); | ||||
} | } | ||||
obj.pushKV("localrelay", g_relay_txes); | obj.pushKV("localrelay", g_relay_txes); | ||||
obj.pushKV("timeoffset", GetTimeOffset()); | obj.pushKV("timeoffset", GetTimeOffset()); | ||||
if (node.connman) { | if (node.connman) { | ||||
obj.pushKV("networkactive", node.connman->GetNetworkActive()); | obj.pushKV("networkactive", node.connman->GetNetworkActive()); | ||||
obj.pushKV("connections", | obj.pushKV("connections", int(node.connman->GetNodeCount( | ||||
int(node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL))); | CConnman::CONNECTIONS_ALL))); | ||||
obj.pushKV("connections_in", | obj.pushKV("connections_in", int(node.connman->GetNodeCount( | ||||
int(node.connman->GetNodeCount(CConnman::CONNECTIONS_IN))); | CConnman::CONNECTIONS_IN))); | ||||
obj.pushKV("connections_out", | obj.pushKV("connections_out", int(node.connman->GetNodeCount( | ||||
int(node.connman->GetNodeCount(CConnman::CONNECTIONS_OUT))); | CConnman::CONNECTIONS_OUT))); | ||||
} | } | ||||
obj.pushKV("networks", GetNetworksInfo()); | obj.pushKV("networks", GetNetworksInfo()); | ||||
obj.pushKV("relayfee", ::minRelayTxFee.GetFeePerK()); | obj.pushKV("relayfee", ::minRelayTxFee.GetFeePerK()); | ||||
obj.pushKV("excessutxocharge", config.GetExcessUTXOCharge()); | obj.pushKV("excessutxocharge", config.GetExcessUTXOCharge()); | ||||
UniValue localAddresses(UniValue::VARR); | UniValue localAddresses(UniValue::VARR); | ||||
{ | { | ||||
LOCK(cs_mapLocalHost); | LOCK(cs_mapLocalHost); | ||||
for (const std::pair<const CNetAddr, LocalServiceInfo> &item : | for (const std::pair<const CNetAddr, LocalServiceInfo> &item : | ||||
mapLocalHost) { | mapLocalHost) { | ||||
UniValue rec(UniValue::VOBJ); | UniValue rec(UniValue::VOBJ); | ||||
rec.pushKV("address", item.first.ToString()); | rec.pushKV("address", item.first.ToString()); | ||||
rec.pushKV("port", item.second.nPort); | rec.pushKV("port", item.second.nPort); | ||||
rec.pushKV("score", item.second.nScore); | rec.pushKV("score", item.second.nScore); | ||||
localAddresses.push_back(rec); | localAddresses.push_back(rec); | ||||
} | } | ||||
} | } | ||||
obj.pushKV("localaddresses", localAddresses); | obj.pushKV("localaddresses", localAddresses); | ||||
obj.pushKV("warnings", GetWarnings(false).original); | obj.pushKV("warnings", GetWarnings(false).original); | ||||
return obj; | return obj; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue setban(const Config &config, const JSONRPCRequest &request) { | static RPCHelpMan setban() { | ||||
const RPCHelpMan help{ | return RPCHelpMan{ | ||||
"setban", | "setban", | ||||
"Attempts to add or remove an IP/Subnet from the banned list.\n", | "Attempts to add or remove an IP/Subnet from the banned list.\n", | ||||
{ | { | ||||
{"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, | {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"The IP/Subnet (see getpeerinfo for nodes IP) with an optional " | "The IP/Subnet (see getpeerinfo for nodes IP) with an optional " | ||||
"netmask (default is /32 = single IP)"}, | "netmask (default is /32 = single IP)"}, | ||||
{"command", RPCArg::Type::STR, RPCArg::Optional::NO, | {"command", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"'add' to add an IP/Subnet to the list, 'remove' to remove an " | "'add' to add an IP/Subnet to the list, 'remove' to remove an " | ||||
"IP/Subnet from the list"}, | "IP/Subnet from the list"}, | ||||
{"bantime", RPCArg::Type::NUM, /* default */ "0", | {"bantime", RPCArg::Type::NUM, /* default */ "0", | ||||
"time in seconds how long (or until when if [absolute] is set) " | "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 " | "the IP is banned (0 or empty means using the default time of 24h " | ||||
"which can also be overwritten by the -bantime startup argument)"}, | "which can also be overwritten by the -bantime startup argument)"}, | ||||
{"absolute", RPCArg::Type::BOOL, /* default */ "false", | {"absolute", RPCArg::Type::BOOL, /* default */ "false", | ||||
"If set, the bantime must be an absolute timestamp expressed in " + | "If set, the bantime must be an absolute timestamp expressed in " + | ||||
UNIX_EPOCH_TIME}, | UNIX_EPOCH_TIME}, | ||||
}, | }, | ||||
RPCResult{RPCResult::Type::NONE, "", ""}, | RPCResult{RPCResult::Type::NONE, "", ""}, | ||||
RPCExamples{ | RPCExamples{ | ||||
HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + | HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") + | ||||
HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + | HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + | ||||
HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")}, | HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")}, | ||||
}; | [&](const RPCHelpMan &help, const Config &config, | ||||
const JSONRPCRequest &request) -> UniValue { | |||||
std::string strCommand; | std::string strCommand; | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
strCommand = request.params[1].get_str(); | strCommand = request.params[1].get_str(); | ||||
} | } | ||||
if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || | if (request.fHelp || !help.IsValidNumArgs(request.params.size()) || | ||||
(strCommand != "add" && strCommand != "remove")) { | (strCommand != "add" && strCommand != "remove")) { | ||||
throw std::runtime_error(help.ToString()); | throw std::runtime_error(help.ToString()); | ||||
} | } | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.banman) { | if (!node.banman) { | ||||
throw JSONRPCError(RPC_DATABASE_ERROR, | throw JSONRPCError(RPC_DATABASE_ERROR, | ||||
"Error: Ban database not loaded"); | "Error: Ban database not loaded"); | ||||
} | } | ||||
CSubNet subNet; | CSubNet subNet; | ||||
CNetAddr netAddr; | CNetAddr netAddr; | ||||
bool isSubnet = false; | bool isSubnet = false; | ||||
if (request.params[0].get_str().find('/') != std::string::npos) { | if (request.params[0].get_str().find('/') != std::string::npos) { | ||||
isSubnet = true; | isSubnet = true; | ||||
} | } | ||||
if (!isSubnet) { | if (!isSubnet) { | ||||
CNetAddr resolved; | CNetAddr resolved; | ||||
LookupHost(request.params[0].get_str(), resolved, false); | LookupHost(request.params[0].get_str(), resolved, false); | ||||
netAddr = resolved; | netAddr = resolved; | ||||
} else { | } else { | ||||
LookupSubNet(request.params[0].get_str(), subNet); | LookupSubNet(request.params[0].get_str(), subNet); | ||||
} | } | ||||
if (!(isSubnet ? subNet.IsValid() : netAddr.IsValid())) { | if (!(isSubnet ? subNet.IsValid() : netAddr.IsValid())) { | ||||
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, | throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, | ||||
"Error: Invalid IP/Subnet"); | "Error: Invalid IP/Subnet"); | ||||
} | } | ||||
if (strCommand == "add") { | if (strCommand == "add") { | ||||
if (isSubnet ? node.banman->IsBanned(subNet) | if (isSubnet ? node.banman->IsBanned(subNet) | ||||
: node.banman->IsBanned(netAddr)) { | : node.banman->IsBanned(netAddr)) { | ||||
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, | throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, | ||||
"Error: IP/Subnet already banned"); | "Error: IP/Subnet already banned"); | ||||
} | } | ||||
// Use standard bantime if not specified. | // Use standard bantime if not specified. | ||||
int64_t banTime = 0; | int64_t banTime = 0; | ||||
if (!request.params[2].isNull()) { | if (!request.params[2].isNull()) { | ||||
banTime = request.params[2].get_int64(); | banTime = request.params[2].get_int64(); | ||||
} | } | ||||
bool absolute = false; | bool absolute = false; | ||||
if (request.params[3].isTrue()) { | if (request.params[3].isTrue()) { | ||||
absolute = true; | absolute = true; | ||||
} | } | ||||
if (isSubnet) { | if (isSubnet) { | ||||
node.banman->Ban(subNet, banTime, absolute); | node.banman->Ban(subNet, banTime, absolute); | ||||
if (node.connman) { | if (node.connman) { | ||||
node.connman->DisconnectNode(subNet); | node.connman->DisconnectNode(subNet); | ||||
} | } | ||||
} else { | } else { | ||||
node.banman->Ban(netAddr, banTime, absolute); | node.banman->Ban(netAddr, banTime, absolute); | ||||
if (node.connman) { | if (node.connman) { | ||||
node.connman->DisconnectNode(netAddr); | node.connman->DisconnectNode(netAddr); | ||||
} | } | ||||
} | } | ||||
} else if (strCommand == "remove") { | } else if (strCommand == "remove") { | ||||
if (!(isSubnet ? node.banman->Unban(subNet) | if (!(isSubnet ? node.banman->Unban(subNet) | ||||
: node.banman->Unban(netAddr))) { | : node.banman->Unban(netAddr))) { | ||||
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, | throw JSONRPCError( | ||||
RPC_CLIENT_INVALID_IP_OR_SUBNET, | |||||
"Error: Unban failed. Requested address/subnet " | "Error: Unban failed. Requested address/subnet " | ||||
"was not previously manually banned."); | "was not previously manually banned."); | ||||
} | } | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue listbanned(const Config &config, | static RPCHelpMan listbanned() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"listbanned", | "listbanned", | ||||
"List all manually banned IPs/Subnets.\n", | "List all manually banned IPs/Subnets.\n", | ||||
{}, | {}, | ||||
RPCResult{RPCResult::Type::ARR, | RPCResult{RPCResult::Type::ARR, | ||||
"", | "", | ||||
"", | "", | ||||
{ | { | ||||
{RPCResult::Type::OBJ, | {RPCResult::Type::OBJ, | ||||
"", | "", | ||||
"", | "", | ||||
{ | { | ||||
{RPCResult::Type::STR, "address", ""}, | {RPCResult::Type::STR, "address", ""}, | ||||
{RPCResult::Type::NUM_TIME, "banned_until", ""}, | {RPCResult::Type::NUM_TIME, "banned_until", ""}, | ||||
{RPCResult::Type::NUM_TIME, "ban_created", ""}, | {RPCResult::Type::NUM_TIME, "ban_created", ""}, | ||||
{RPCResult::Type::STR, "ban_reason", ""}, | {RPCResult::Type::STR, "ban_reason", ""}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
RPCExamples{HelpExampleCli("listbanned", "") + | RPCExamples{HelpExampleCli("listbanned", "") + | ||||
HelpExampleRpc("listbanned", "")}, | HelpExampleRpc("listbanned", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.banman) { | if (!node.banman) { | ||||
throw JSONRPCError(RPC_DATABASE_ERROR, | throw JSONRPCError(RPC_DATABASE_ERROR, | ||||
"Error: Ban database not loaded"); | "Error: Ban database not loaded"); | ||||
} | } | ||||
banmap_t banMap; | banmap_t banMap; | ||||
node.banman->GetBanned(banMap); | node.banman->GetBanned(banMap); | ||||
UniValue bannedAddresses(UniValue::VARR); | UniValue bannedAddresses(UniValue::VARR); | ||||
for (const auto &entry : banMap) { | for (const auto &entry : banMap) { | ||||
const CBanEntry &banEntry = entry.second; | const CBanEntry &banEntry = entry.second; | ||||
UniValue rec(UniValue::VOBJ); | UniValue rec(UniValue::VOBJ); | ||||
rec.pushKV("address", entry.first.ToString()); | rec.pushKV("address", entry.first.ToString()); | ||||
rec.pushKV("banned_until", banEntry.nBanUntil); | rec.pushKV("banned_until", banEntry.nBanUntil); | ||||
rec.pushKV("ban_created", banEntry.nCreateTime); | rec.pushKV("ban_created", banEntry.nCreateTime); | ||||
bannedAddresses.push_back(rec); | bannedAddresses.push_back(rec); | ||||
} | } | ||||
return bannedAddresses; | return bannedAddresses; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue clearbanned(const Config &config, | static RPCHelpMan clearbanned() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"clearbanned", | "clearbanned", | ||||
"Clear all banned IPs.\n", | "Clear all banned IPs.\n", | ||||
{}, | {}, | ||||
RPCResult{RPCResult::Type::NONE, "", ""}, | RPCResult{RPCResult::Type::NONE, "", ""}, | ||||
RPCExamples{HelpExampleCli("clearbanned", "") + | RPCExamples{HelpExampleCli("clearbanned", "") + | ||||
HelpExampleRpc("clearbanned", "")}, | HelpExampleRpc("clearbanned", "")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.banman) { | if (!node.banman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
node.banman->ClearBanned(); | node.banman->ClearBanned(); | ||||
return NullUniValue; | return NullUniValue; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue setnetworkactive(const Config &config, | static RPCHelpMan setnetworkactive() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"setnetworkactive", | "setnetworkactive", | ||||
"Disable/enable all p2p network activity.\n", | "Disable/enable all p2p network activity.\n", | ||||
{ | { | ||||
{"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, | {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, | ||||
"true to enable networking, false to disable"}, | "true to enable networking, false to disable"}, | ||||
}, | }, | ||||
RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"}, | RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"}, | ||||
RPCExamples{""}, | RPCExamples{""}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.banman) { | if (!node.banman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
node.connman->SetNetworkActive(request.params[0].get_bool()); | node.connman->SetNetworkActive(request.params[0].get_bool()); | ||||
return node.connman->GetNetworkActive(); | return node.connman->GetNetworkActive(); | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue getnodeaddresses(const Config &config, | static RPCHelpMan getnodeaddresses() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"getnodeaddresses", | "getnodeaddresses", | ||||
"Return known addresses which can potentially be used to find new " | "Return known addresses which can potentially be used to find new " | ||||
"nodes in the network\n", | "nodes in the network\n", | ||||
{ | { | ||||
{"count", RPCArg::Type::NUM, /* default */ "1", | {"count", RPCArg::Type::NUM, /* default */ "1", | ||||
"The maximum number of addresses to return. Specify 0 to return " | "The maximum number of addresses to return. Specify 0 to return " | ||||
"all known addresses."}, | "all known addresses."}, | ||||
}, | }, | ||||
Show All 12 Lines | return RPCHelpMan{ | ||||
{RPCResult::Type::NUM, "services", "The services offered"}, | {RPCResult::Type::NUM, "services", "The services offered"}, | ||||
{RPCResult::Type::STR, "address", | {RPCResult::Type::STR, "address", | ||||
"The address of the node"}, | "The address of the node"}, | ||||
{RPCResult::Type::NUM, "port", "The port of the node"}, | {RPCResult::Type::NUM, "port", "The port of the node"}, | ||||
}}, | }}, | ||||
}}, | }}, | ||||
RPCExamples{HelpExampleCli("getnodeaddresses", "8") + | RPCExamples{HelpExampleCli("getnodeaddresses", "8") + | ||||
HelpExampleRpc("getnodeaddresses", "8")}, | HelpExampleRpc("getnodeaddresses", "8")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.banman) { | if (!node.banman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
int count = 1; | int count = 1; | ||||
if (!request.params[0].isNull()) { | if (!request.params[0].isNull()) { | ||||
count = request.params[0].get_int(); | count = request.params[0].get_int(); | ||||
if (count < 0) { | if (count < 0) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Address count out of range"); | "Address count out of range"); | ||||
} | } | ||||
} | } | ||||
// returns a shuffled list of CAddress | // returns a shuffled list of CAddress | ||||
std::vector<CAddress> vAddr = | std::vector<CAddress> vAddr = | ||||
node.connman->GetAddresses(count, /* max_pct */ 0); | node.connman->GetAddresses(count, /* max_pct */ 0); | ||||
UniValue ret(UniValue::VARR); | UniValue ret(UniValue::VARR); | ||||
for (const CAddress &addr : vAddr) { | for (const CAddress &addr : vAddr) { | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
obj.pushKV("time", int(addr.nTime)); | obj.pushKV("time", int(addr.nTime)); | ||||
obj.pushKV("services", uint64_t(addr.nServices)); | obj.pushKV("services", uint64_t(addr.nServices)); | ||||
obj.pushKV("address", addr.ToStringIP()); | obj.pushKV("address", addr.ToStringIP()); | ||||
obj.pushKV("port", addr.GetPort()); | obj.pushKV("port", addr.GetPort()); | ||||
ret.push_back(obj); | ret.push_back(obj); | ||||
} | } | ||||
return ret; | return ret; | ||||
}, | |||||
}; | |||||
} | } | ||||
static UniValue addpeeraddress(const Config &config, | static RPCHelpMan addpeeraddress() { | ||||
const JSONRPCRequest &request) { | return RPCHelpMan{ | ||||
RPCHelpMan{ | |||||
"addpeeraddress", | "addpeeraddress", | ||||
"Add the address of a potential peer to the address manager. This " | "Add the address of a potential peer to the address manager. This " | ||||
"RPC is for testing only.\n", | "RPC is for testing only.\n", | ||||
{ | { | ||||
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, | {"address", RPCArg::Type::STR, RPCArg::Optional::NO, | ||||
"The IP address of the peer"}, | "The IP address of the peer"}, | ||||
{"port", RPCArg::Type::NUM, RPCArg::Optional::NO, | {"port", RPCArg::Type::NUM, RPCArg::Optional::NO, | ||||
"The port of the peer"}, | "The port of the peer"}, | ||||
}, | }, | ||||
RPCResult{ | RPCResult{ | ||||
RPCResult::Type::OBJ, | RPCResult::Type::OBJ, | ||||
"", | "", | ||||
"", | "", | ||||
{ | { | ||||
{RPCResult::Type::BOOL, "success", | {RPCResult::Type::BOOL, "success", | ||||
"whether the peer address was successfully added to the " | "whether the peer address was successfully added to the " | ||||
"address manager"}, | "address manager"}, | ||||
}, | }, | ||||
}, | }, | ||||
RPCExamples{HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333") + | RPCExamples{HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333") + | ||||
HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333")}, | HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333")}, | ||||
} | [&](const RPCHelpMan &self, const Config &config, | ||||
.Check(request); | const JSONRPCRequest &request) -> UniValue { | ||||
NodeContext &node = EnsureNodeContext(request.context); | NodeContext &node = EnsureNodeContext(request.context); | ||||
if (!node.connman) { | if (!node.connman) { | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_CLIENT_P2P_DISABLED, | RPC_CLIENT_P2P_DISABLED, | ||||
"Error: Peer-to-peer functionality missing or disabled"); | "Error: Peer-to-peer functionality missing or disabled"); | ||||
} | } | ||||
UniValue obj(UniValue::VOBJ); | UniValue obj(UniValue::VOBJ); | ||||
std::string addr_string = request.params[0].get_str(); | std::string addr_string = request.params[0].get_str(); | ||||
uint16_t port = request.params[1].get_int(); | uint16_t port = request.params[1].get_int(); | ||||
CNetAddr net_addr; | CNetAddr net_addr; | ||||
if (!LookupHost(addr_string, net_addr, false)) { | if (!LookupHost(addr_string, net_addr, false)) { | ||||
obj.pushKV("success", false); | obj.pushKV("success", false); | ||||
return obj; | return obj; | ||||
} | } | ||||
CAddress address = CAddress({net_addr, port}, ServiceFlags(NODE_NETWORK)); | CAddress address = | ||||
CAddress({net_addr, port}, ServiceFlags(NODE_NETWORK)); | |||||
address.nTime = GetAdjustedTime(); | address.nTime = GetAdjustedTime(); | ||||
// The source address is set equal to the address. This is equivalent to the | // The source address is set equal to the address. This is | ||||
// peer announcing itself. | // equivalent to the peer announcing itself. | ||||
if (!node.connman->AddNewAddresses({address}, address)) { | if (!node.connman->AddNewAddresses({address}, address)) { | ||||
obj.pushKV("success", false); | obj.pushKV("success", false); | ||||
return obj; | return obj; | ||||
} | } | ||||
obj.pushKV("success", true); | obj.pushKV("success", true); | ||||
return obj; | return obj; | ||||
}, | |||||
}; | |||||
} | } | ||||
void RegisterNetRPCCommands(CRPCTable &t) { | void RegisterNetRPCCommands(CRPCTable &t) { | ||||
// clang-format off | // clang-format off | ||||
static const CRPCCommand commands[] = { | static const CRPCCommand commands[] = { | ||||
// category name actor (function) argNames | // category name actor (function) argNames | ||||
// ------------------- ------------------------ ---------------------- ---------- | // ------------------- ------------------------ ---------------------- ---------- | ||||
{ "network", "getconnectioncount", getconnectioncount, {} }, | { "network", "getconnectioncount", getconnectioncount, {} }, | ||||
Show All 19 Lines |
That's a good reminder