net.cpp
1 // Copyright (c) 2009-2022 The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <rpc/server.h> 6 7 #include <addrman.h> 8 #include <addrman_impl.h> 9 #include <banman.h> 10 #include <chainparams.h> 11 #include <clientversion.h> 12 #include <core_io.h> 13 #include <net_permissions.h> 14 #include <net_processing.h> 15 #include <net_types.h> // For banmap_t 16 #include <netbase.h> 17 #include <node/context.h> 18 #include <node/protocol_version.h> 19 #include <policy/settings.h> 20 #include <protocol.h> 21 #include <rpc/blockchain.h> 22 #include <rpc/protocol.h> 23 #include <rpc/server_util.h> 24 #include <rpc/util.h> 25 #include <sync.h> 26 #include <timedata.h> 27 #include <util/chaintype.h> 28 #include <util/strencodings.h> 29 #include <util/string.h> 30 #include <util/time.h> 31 #include <util/translation.h> 32 #include <validation.h> 33 #include <warnings.h> 34 35 #include <optional> 36 37 #include <univalue.h> 38 39 using node::NodeContext; 40 41 const std::vector<std::string> CONNECTION_TYPE_DOC{ 42 "outbound-full-relay (default automatic connections)", 43 "block-relay-only (does not relay transactions or addresses)", 44 "inbound (initiated by the peer)", 45 "manual (added via addnode RPC or -addnode/-connect configuration options)", 46 "addr-fetch (short-lived automatic connection for soliciting addresses)", 47 "feeler (short-lived automatic connection for testing addresses)" 48 }; 49 50 const std::vector<std::string> TRANSPORT_TYPE_DOC{ 51 "detecting (peer could be v1 or v2)", 52 "v1 (plaintext transport protocol)", 53 "v2 (BIP324 encrypted transport protocol)" 54 }; 55 56 static RPCHelpMan getconnectioncount() 57 { 58 return RPCHelpMan{"getconnectioncount", 59 "\nReturns the number of connections to other nodes.\n", 60 {}, 61 RPCResult{ 62 RPCResult::Type::NUM, "", "The connection count" 63 }, 64 RPCExamples{ 65 HelpExampleCli("getconnectioncount", "") 66 + HelpExampleRpc("getconnectioncount", "") 67 }, 68 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 69 { 70 NodeContext& node = EnsureAnyNodeContext(request.context); 71 const CConnman& connman = EnsureConnman(node); 72 73 return connman.GetNodeCount(ConnectionDirection::Both); 74 }, 75 }; 76 } 77 78 static RPCHelpMan ping() 79 { 80 return RPCHelpMan{"ping", 81 "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" 82 "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" 83 "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n", 84 {}, 85 RPCResult{RPCResult::Type::NONE, "", ""}, 86 RPCExamples{ 87 HelpExampleCli("ping", "") 88 + HelpExampleRpc("ping", "") 89 }, 90 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 91 { 92 NodeContext& node = EnsureAnyNodeContext(request.context); 93 PeerManager& peerman = EnsurePeerman(node); 94 95 // Request that each node send a ping during next message processing pass 96 peerman.SendPings(); 97 return UniValue::VNULL; 98 }, 99 }; 100 } 101 102 /** Returns, given services flags, a list of humanly readable (known) network services */ 103 static UniValue GetServicesNames(ServiceFlags services) 104 { 105 UniValue servicesNames(UniValue::VARR); 106 107 for (const auto& flag : serviceFlagsToStr(services)) { 108 servicesNames.push_back(flag); 109 } 110 111 return servicesNames; 112 } 113 114 static RPCHelpMan getpeerinfo() 115 { 116 return RPCHelpMan{ 117 "getpeerinfo", 118 "Returns data about each connected network peer as a json array of objects.", 119 {}, 120 RPCResult{ 121 RPCResult::Type::ARR, "", "", 122 { 123 {RPCResult::Type::OBJ, "", "", 124 { 125 { 126 {RPCResult::Type::NUM, "id", "Peer index"}, 127 {RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"}, 128 {RPCResult::Type::STR, "addrbind", /*optional=*/true, "(ip:port) Bind address of the connection to the peer"}, 129 {RPCResult::Type::STR, "addrlocal", /*optional=*/true, "(ip:port) Local address as reported by the peer"}, 130 {RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/*append_unroutable=*/true), ", ") + ")"}, 131 {RPCResult::Type::NUM, "mapped_as", /*optional=*/true, "The AS in the BGP route to the peer used for diversifying\n" 132 "peer selection (only available if the asmap config flag is set)"}, 133 {RPCResult::Type::STR_HEX, "services", "The services offered"}, 134 {RPCResult::Type::ARR, "servicesnames", "the services offered, in human-readable form", 135 { 136 {RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"} 137 }}, 138 {RPCResult::Type::BOOL, "relaytxes", "Whether we relay transactions to this peer"}, 139 {RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"}, 140 {RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"}, 141 {RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"}, 142 {RPCResult::Type::NUM_TIME, "last_block", "The " + UNIX_EPOCH_TIME + " of the last block received from this peer"}, 143 {RPCResult::Type::NUM, "bytessent", "The total bytes sent"}, 144 {RPCResult::Type::NUM, "bytesrecv", "The total bytes received"}, 145 {RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"}, 146 {RPCResult::Type::NUM, "timeoffset", "The time offset in seconds"}, 147 {RPCResult::Type::NUM, "pingtime", /*optional=*/true, "The last ping time in milliseconds (ms), if any"}, 148 {RPCResult::Type::NUM, "minping", /*optional=*/true, "The minimum observed ping time in milliseconds (ms), if any"}, 149 {RPCResult::Type::NUM, "pingwait", /*optional=*/true, "The duration in milliseconds (ms) of an outstanding ping (if non-zero)"}, 150 {RPCResult::Type::NUM, "version", "The peer version, such as 70001"}, 151 {RPCResult::Type::STR, "subver", "The string version"}, 152 {RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"}, 153 {RPCResult::Type::BOOL, "bip152_hb_to", "Whether we selected peer as (compact blocks) high-bandwidth peer"}, 154 {RPCResult::Type::BOOL, "bip152_hb_from", "Whether peer selected us as (compact blocks) high-bandwidth peer"}, 155 {RPCResult::Type::NUM, "startingheight", "The starting height (block) of the peer"}, 156 {RPCResult::Type::NUM, "presynced_headers", "The current height of header pre-synchronization with this peer, or -1 if no low-work sync is in progress"}, 157 {RPCResult::Type::NUM, "synced_headers", "The last header we have in common with this peer"}, 158 {RPCResult::Type::NUM, "synced_blocks", "The last block we have in common with this peer"}, 159 {RPCResult::Type::ARR, "inflight", "", 160 { 161 {RPCResult::Type::NUM, "n", "The heights of blocks we're currently asking from this peer"}, 162 }}, 163 {RPCResult::Type::BOOL, "addr_relay_enabled", "Whether we participate in address relay with this peer"}, 164 {RPCResult::Type::NUM, "addr_processed", "The total number of addresses processed, excluding those dropped due to rate limiting"}, 165 {RPCResult::Type::NUM, "addr_rate_limited", "The total number of addresses dropped due to rate limiting"}, 166 {RPCResult::Type::ARR, "permissions", "Any special permissions that have been granted to this peer", 167 { 168 {RPCResult::Type::STR, "permission_type", Join(NET_PERMISSIONS_DOC, ",\n") + ".\n"}, 169 }}, 170 {RPCResult::Type::NUM, "minfeefilter", "The minimum fee rate for transactions this peer accepts"}, 171 {RPCResult::Type::OBJ_DYN, "bytessent_per_msg", "", 172 { 173 {RPCResult::Type::NUM, "msg", "The total bytes sent aggregated by message type\n" 174 "When a message type is not listed in this json object, the bytes sent are 0.\n" 175 "Only known message types can appear as keys in the object."} 176 }}, 177 {RPCResult::Type::OBJ_DYN, "bytesrecv_per_msg", "", 178 { 179 {RPCResult::Type::NUM, "msg", "The total bytes received aggregated by message type\n" 180 "When a message type is not listed in this json object, the bytes received are 0.\n" 181 "Only known message types can appear as keys in the object and all bytes received\n" 182 "of unknown message types are listed under '"+NET_MESSAGE_TYPE_OTHER+"'."} 183 }}, 184 {RPCResult::Type::STR, "connection_type", "Type of connection: \n" + Join(CONNECTION_TYPE_DOC, ",\n") + ".\n" 185 "Please note this output is unlikely to be stable in upcoming releases as we iterate to\n" 186 "best capture connection behaviors."}, 187 {RPCResult::Type::STR, "transport_protocol_type", "Type of transport protocol: \n" + Join(TRANSPORT_TYPE_DOC, ",\n") + ".\n"}, 188 {RPCResult::Type::STR, "session_id", "The session ID for this connection, or \"\" if there is none (\"v2\" transport protocol only).\n"}, 189 }}, 190 }}, 191 }, 192 RPCExamples{ 193 HelpExampleCli("getpeerinfo", "") 194 + HelpExampleRpc("getpeerinfo", "") 195 }, 196 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 197 { 198 NodeContext& node = EnsureAnyNodeContext(request.context); 199 const CConnman& connman = EnsureConnman(node); 200 const PeerManager& peerman = EnsurePeerman(node); 201 202 std::vector<CNodeStats> vstats; 203 connman.GetNodeStats(vstats); 204 205 UniValue ret(UniValue::VARR); 206 207 for (const CNodeStats& stats : vstats) { 208 UniValue obj(UniValue::VOBJ); 209 CNodeStateStats statestats; 210 bool fStateStats = peerman.GetNodeStateStats(stats.nodeid, statestats); 211 // GetNodeStateStats() requires the existence of a CNodeState and a Peer object 212 // to succeed for this peer. These are created at connection initialisation and 213 // exist for the duration of the connection - except if there is a race where the 214 // peer got disconnected in between the GetNodeStats() and the GetNodeStateStats() 215 // calls. In this case, the peer doesn't need to be reported here. 216 if (!fStateStats) { 217 continue; 218 } 219 obj.pushKV("id", stats.nodeid); 220 obj.pushKV("addr", stats.m_addr_name); 221 if (stats.addrBind.IsValid()) { 222 obj.pushKV("addrbind", stats.addrBind.ToStringAddrPort()); 223 } 224 if (!(stats.addrLocal.empty())) { 225 obj.pushKV("addrlocal", stats.addrLocal); 226 } 227 obj.pushKV("network", GetNetworkName(stats.m_network)); 228 if (stats.m_mapped_as != 0) { 229 obj.pushKV("mapped_as", uint64_t(stats.m_mapped_as)); 230 } 231 ServiceFlags services{statestats.their_services}; 232 obj.pushKV("services", strprintf("%016x", services)); 233 obj.pushKV("servicesnames", GetServicesNames(services)); 234 obj.pushKV("relaytxes", statestats.m_relay_txs); 235 obj.pushKV("lastsend", count_seconds(stats.m_last_send)); 236 obj.pushKV("lastrecv", count_seconds(stats.m_last_recv)); 237 obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time)); 238 obj.pushKV("last_block", count_seconds(stats.m_last_block_time)); 239 obj.pushKV("bytessent", stats.nSendBytes); 240 obj.pushKV("bytesrecv", stats.nRecvBytes); 241 obj.pushKV("conntime", count_seconds(stats.m_connected)); 242 obj.pushKV("timeoffset", stats.nTimeOffset); 243 if (stats.m_last_ping_time > 0us) { 244 obj.pushKV("pingtime", Ticks<SecondsDouble>(stats.m_last_ping_time)); 245 } 246 if (stats.m_min_ping_time < std::chrono::microseconds::max()) { 247 obj.pushKV("minping", Ticks<SecondsDouble>(stats.m_min_ping_time)); 248 } 249 if (statestats.m_ping_wait > 0s) { 250 obj.pushKV("pingwait", Ticks<SecondsDouble>(statestats.m_ping_wait)); 251 } 252 obj.pushKV("version", stats.nVersion); 253 // Use the sanitized form of subver here, to avoid tricksy remote peers from 254 // corrupting or modifying the JSON output by putting special characters in 255 // their ver message. 256 obj.pushKV("subver", stats.cleanSubVer); 257 obj.pushKV("inbound", stats.fInbound); 258 obj.pushKV("bip152_hb_to", stats.m_bip152_highbandwidth_to); 259 obj.pushKV("bip152_hb_from", stats.m_bip152_highbandwidth_from); 260 obj.pushKV("startingheight", statestats.m_starting_height); 261 obj.pushKV("presynced_headers", statestats.presync_height); 262 obj.pushKV("synced_headers", statestats.nSyncHeight); 263 obj.pushKV("synced_blocks", statestats.nCommonHeight); 264 UniValue heights(UniValue::VARR); 265 for (const int height : statestats.vHeightInFlight) { 266 heights.push_back(height); 267 } 268 obj.pushKV("inflight", heights); 269 obj.pushKV("addr_relay_enabled", statestats.m_addr_relay_enabled); 270 obj.pushKV("addr_processed", statestats.m_addr_processed); 271 obj.pushKV("addr_rate_limited", statestats.m_addr_rate_limited); 272 UniValue permissions(UniValue::VARR); 273 for (const auto& permission : NetPermissions::ToStrings(stats.m_permission_flags)) { 274 permissions.push_back(permission); 275 } 276 obj.pushKV("permissions", permissions); 277 obj.pushKV("minfeefilter", ValueFromAmount(statestats.m_fee_filter_received)); 278 279 UniValue sendPerMsgType(UniValue::VOBJ); 280 for (const auto& i : stats.mapSendBytesPerMsgType) { 281 if (i.second > 0) 282 sendPerMsgType.pushKV(i.first, i.second); 283 } 284 obj.pushKV("bytessent_per_msg", sendPerMsgType); 285 286 UniValue recvPerMsgType(UniValue::VOBJ); 287 for (const auto& i : stats.mapRecvBytesPerMsgType) { 288 if (i.second > 0) 289 recvPerMsgType.pushKV(i.first, i.second); 290 } 291 obj.pushKV("bytesrecv_per_msg", recvPerMsgType); 292 obj.pushKV("connection_type", ConnectionTypeAsString(stats.m_conn_type)); 293 obj.pushKV("transport_protocol_type", TransportTypeAsString(stats.m_transport_type)); 294 obj.pushKV("session_id", stats.m_session_id); 295 296 ret.push_back(obj); 297 } 298 299 return ret; 300 }, 301 }; 302 } 303 304 static RPCHelpMan addnode() 305 { 306 return RPCHelpMan{"addnode", 307 "\nAttempts to add or remove a node from the addnode list.\n" 308 "Or try a connection to a node once.\n" 309 "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n" 310 "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n" + 311 strprintf("Addnode connections are limited to %u at a time", MAX_ADDNODE_CONNECTIONS) + 312 " and are counted separately from the -maxconnections limit.\n", 313 { 314 {"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The address of the peer to connect to"}, 315 {"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"}, 316 {"v2transport", RPCArg::Type::BOOL, RPCArg::DefaultHint{"set by -v2transport"}, "Attempt to connect using BIP324 v2 transport protocol (ignored for 'remove' command)"}, 317 }, 318 RPCResult{RPCResult::Type::NONE, "", ""}, 319 RPCExamples{ 320 HelpExampleCli("addnode", "\"192.168.0.6:8333\" \"onetry\" true") 321 + HelpExampleRpc("addnode", "\"192.168.0.6:8333\", \"onetry\" true") 322 }, 323 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 324 { 325 const std::string command{request.params[1].get_str()}; 326 if (command != "onetry" && command != "add" && command != "remove") { 327 throw std::runtime_error( 328 self.ToString()); 329 } 330 331 NodeContext& node = EnsureAnyNodeContext(request.context); 332 CConnman& connman = EnsureConnman(node); 333 334 const std::string node_arg{request.params[0].get_str()}; 335 bool node_v2transport = connman.GetLocalServices() & NODE_P2P_V2; 336 bool use_v2transport = self.MaybeArg<bool>(2).value_or(node_v2transport); 337 338 if (use_v2transport && !node_v2transport) { 339 throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: v2transport requested but not enabled (see -v2transport)"); 340 } 341 342 if (command == "onetry") 343 { 344 CAddress addr; 345 connman.OpenNetworkConnection(addr, /*fCountFailure=*/false, /*grant_outbound=*/{}, node_arg.c_str(), ConnectionType::MANUAL, use_v2transport); 346 return UniValue::VNULL; 347 } 348 349 if (command == "add") 350 { 351 if (!connman.AddNode({node_arg, use_v2transport})) { 352 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added"); 353 } 354 } 355 else if (command == "remove") 356 { 357 if (!connman.RemoveAddedNode(node_arg)) { 358 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously."); 359 } 360 } 361 362 return UniValue::VNULL; 363 }, 364 }; 365 } 366 367 static RPCHelpMan addconnection() 368 { 369 return RPCHelpMan{"addconnection", 370 "\nOpen an outbound connection to a specified node. This RPC is for testing only.\n", 371 { 372 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."}, 373 {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open (\"outbound-full-relay\", \"block-relay-only\", \"addr-fetch\" or \"feeler\")."}, 374 {"v2transport", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Attempt to connect using BIP324 v2 transport protocol"}, 375 }, 376 RPCResult{ 377 RPCResult::Type::OBJ, "", "", 378 { 379 { RPCResult::Type::STR, "address", "Address of newly added connection." }, 380 { RPCResult::Type::STR, "connection_type", "Type of connection opened." }, 381 }}, 382 RPCExamples{ 383 HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true") 384 + HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true") 385 }, 386 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 387 { 388 if (Params().GetChainType() != ChainType::REGTEST) { 389 throw std::runtime_error("addconnection is for regression testing (-regtest mode) only."); 390 } 391 392 const std::string address = request.params[0].get_str(); 393 const std::string conn_type_in{TrimString(request.params[1].get_str())}; 394 ConnectionType conn_type{}; 395 if (conn_type_in == "outbound-full-relay") { 396 conn_type = ConnectionType::OUTBOUND_FULL_RELAY; 397 } else if (conn_type_in == "block-relay-only") { 398 conn_type = ConnectionType::BLOCK_RELAY; 399 } else if (conn_type_in == "addr-fetch") { 400 conn_type = ConnectionType::ADDR_FETCH; 401 } else if (conn_type_in == "feeler") { 402 conn_type = ConnectionType::FEELER; 403 } else { 404 throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString()); 405 } 406 bool use_v2transport = self.Arg<bool>(2); 407 408 NodeContext& node = EnsureAnyNodeContext(request.context); 409 CConnman& connman = EnsureConnman(node); 410 411 if (use_v2transport && !(connman.GetLocalServices() & NODE_P2P_V2)) { 412 throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Adding v2transport connections requires -v2transport init flag to be set."); 413 } 414 415 const bool success = connman.AddConnection(address, conn_type, use_v2transport); 416 if (!success) { 417 throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type."); 418 } 419 420 UniValue info(UniValue::VOBJ); 421 info.pushKV("address", address); 422 info.pushKV("connection_type", conn_type_in); 423 424 return info; 425 }, 426 }; 427 } 428 429 static RPCHelpMan disconnectnode() 430 { 431 return RPCHelpMan{"disconnectnode", 432 "\nImmediately disconnects from the specified peer node.\n" 433 "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n" 434 "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n", 435 { 436 {"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node"}, 437 {"nodeid", RPCArg::Type::NUM, RPCArg::DefaultHint{"fallback to address"}, "The node ID (see getpeerinfo for node IDs)"}, 438 }, 439 RPCResult{RPCResult::Type::NONE, "", ""}, 440 RPCExamples{ 441 HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"") 442 + HelpExampleCli("disconnectnode", "\"\" 1") 443 + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"") 444 + HelpExampleRpc("disconnectnode", "\"\", 1") 445 }, 446 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 447 { 448 NodeContext& node = EnsureAnyNodeContext(request.context); 449 CConnman& connman = EnsureConnman(node); 450 451 bool success; 452 const UniValue &address_arg = request.params[0]; 453 const UniValue &id_arg = request.params[1]; 454 455 if (!address_arg.isNull() && id_arg.isNull()) { 456 /* handle disconnect-by-address */ 457 success = connman.DisconnectNode(address_arg.get_str()); 458 } else if (!id_arg.isNull() && (address_arg.isNull() || (address_arg.isStr() && address_arg.get_str().empty()))) { 459 /* handle disconnect-by-id */ 460 NodeId nodeid = (NodeId) id_arg.getInt<int64_t>(); 461 success = connman.DisconnectNode(nodeid); 462 } else { 463 throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided."); 464 } 465 466 if (!success) { 467 throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes"); 468 } 469 470 return UniValue::VNULL; 471 }, 472 }; 473 } 474 475 static RPCHelpMan getaddednodeinfo() 476 { 477 return RPCHelpMan{"getaddednodeinfo", 478 "\nReturns information about the given added node, or all added nodes\n" 479 "(note that onetry addnodes are not listed here)\n", 480 { 481 {"node", RPCArg::Type::STR, RPCArg::DefaultHint{"all nodes"}, "If provided, return information about this specific node, otherwise all nodes are returned."}, 482 }, 483 RPCResult{ 484 RPCResult::Type::ARR, "", "", 485 { 486 {RPCResult::Type::OBJ, "", "", 487 { 488 {RPCResult::Type::STR, "addednode", "The node IP address or name (as provided to addnode)"}, 489 {RPCResult::Type::BOOL, "connected", "If connected"}, 490 {RPCResult::Type::ARR, "addresses", "Only when connected = true", 491 { 492 {RPCResult::Type::OBJ, "", "", 493 { 494 {RPCResult::Type::STR, "address", "The bitcoin server IP and port we're connected to"}, 495 {RPCResult::Type::STR, "connected", "connection, inbound or outbound"}, 496 }}, 497 }}, 498 }}, 499 } 500 }, 501 RPCExamples{ 502 HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") 503 + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"") 504 }, 505 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 506 { 507 NodeContext& node = EnsureAnyNodeContext(request.context); 508 const CConnman& connman = EnsureConnman(node); 509 510 std::vector<AddedNodeInfo> vInfo = connman.GetAddedNodeInfo(/*include_connected=*/true); 511 512 if (!request.params[0].isNull()) { 513 bool found = false; 514 for (const AddedNodeInfo& info : vInfo) { 515 if (info.m_params.m_added_node == request.params[0].get_str()) { 516 vInfo.assign(1, info); 517 found = true; 518 break; 519 } 520 } 521 if (!found) { 522 throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added."); 523 } 524 } 525 526 UniValue ret(UniValue::VARR); 527 528 for (const AddedNodeInfo& info : vInfo) { 529 UniValue obj(UniValue::VOBJ); 530 obj.pushKV("addednode", info.m_params.m_added_node); 531 obj.pushKV("connected", info.fConnected); 532 UniValue addresses(UniValue::VARR); 533 if (info.fConnected) { 534 UniValue address(UniValue::VOBJ); 535 address.pushKV("address", info.resolvedAddress.ToStringAddrPort()); 536 address.pushKV("connected", info.fInbound ? "inbound" : "outbound"); 537 addresses.push_back(address); 538 } 539 obj.pushKV("addresses", addresses); 540 ret.push_back(obj); 541 } 542 543 return ret; 544 }, 545 }; 546 } 547 548 static RPCHelpMan getnettotals() 549 { 550 return RPCHelpMan{"getnettotals", 551 "Returns information about network traffic, including bytes in, bytes out,\n" 552 "and current system time.", 553 {}, 554 RPCResult{ 555 RPCResult::Type::OBJ, "", "", 556 { 557 {RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"}, 558 {RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"}, 559 {RPCResult::Type::NUM_TIME, "timemillis", "Current system " + UNIX_EPOCH_TIME + " in milliseconds"}, 560 {RPCResult::Type::OBJ, "uploadtarget", "", 561 { 562 {RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"}, 563 {RPCResult::Type::NUM, "target", "Target in bytes"}, 564 {RPCResult::Type::BOOL, "target_reached", "True if target is reached"}, 565 {RPCResult::Type::BOOL, "serve_historical_blocks", "True if serving historical blocks"}, 566 {RPCResult::Type::NUM, "bytes_left_in_cycle", "Bytes left in current time cycle"}, 567 {RPCResult::Type::NUM, "time_left_in_cycle", "Seconds left in current time cycle"}, 568 }}, 569 } 570 }, 571 RPCExamples{ 572 HelpExampleCli("getnettotals", "") 573 + HelpExampleRpc("getnettotals", "") 574 }, 575 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 576 { 577 NodeContext& node = EnsureAnyNodeContext(request.context); 578 const CConnman& connman = EnsureConnman(node); 579 580 UniValue obj(UniValue::VOBJ); 581 obj.pushKV("totalbytesrecv", connman.GetTotalBytesRecv()); 582 obj.pushKV("totalbytessent", connman.GetTotalBytesSent()); 583 obj.pushKV("timemillis", TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now())); 584 585 UniValue outboundLimit(UniValue::VOBJ); 586 outboundLimit.pushKV("timeframe", count_seconds(connman.GetMaxOutboundTimeframe())); 587 outboundLimit.pushKV("target", connman.GetMaxOutboundTarget()); 588 outboundLimit.pushKV("target_reached", connman.OutboundTargetReached(false)); 589 outboundLimit.pushKV("serve_historical_blocks", !connman.OutboundTargetReached(true)); 590 outboundLimit.pushKV("bytes_left_in_cycle", connman.GetOutboundTargetBytesLeft()); 591 outboundLimit.pushKV("time_left_in_cycle", count_seconds(connman.GetMaxOutboundTimeLeftInCycle())); 592 obj.pushKV("uploadtarget", outboundLimit); 593 return obj; 594 }, 595 }; 596 } 597 598 static UniValue GetNetworksInfo() 599 { 600 UniValue networks(UniValue::VARR); 601 for (int n = 0; n < NET_MAX; ++n) { 602 enum Network network = static_cast<enum Network>(n); 603 if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue; 604 Proxy proxy; 605 UniValue obj(UniValue::VOBJ); 606 GetProxy(network, proxy); 607 obj.pushKV("name", GetNetworkName(network)); 608 obj.pushKV("limited", !g_reachable_nets.Contains(network)); 609 obj.pushKV("reachable", g_reachable_nets.Contains(network)); 610 obj.pushKV("proxy", proxy.IsValid() ? proxy.ToString() : std::string()); 611 obj.pushKV("proxy_randomize_credentials", proxy.m_randomize_credentials); 612 networks.push_back(obj); 613 } 614 return networks; 615 } 616 617 static RPCHelpMan getnetworkinfo() 618 { 619 return RPCHelpMan{"getnetworkinfo", 620 "Returns an object containing various state info regarding P2P networking.\n", 621 {}, 622 RPCResult{ 623 RPCResult::Type::OBJ, "", "", 624 { 625 {RPCResult::Type::NUM, "version", "the server version"}, 626 {RPCResult::Type::STR, "subversion", "the server subversion string"}, 627 {RPCResult::Type::NUM, "protocolversion", "the protocol version"}, 628 {RPCResult::Type::STR_HEX, "localservices", "the services we offer to the network"}, 629 {RPCResult::Type::ARR, "localservicesnames", "the services we offer to the network, in human-readable form", 630 { 631 {RPCResult::Type::STR, "SERVICE_NAME", "the service name"}, 632 }}, 633 {RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"}, 634 {RPCResult::Type::NUM, "timeoffset", "the time offset"}, 635 {RPCResult::Type::NUM, "connections", "the total number of connections"}, 636 {RPCResult::Type::NUM, "connections_in", "the number of inbound connections"}, 637 {RPCResult::Type::NUM, "connections_out", "the number of outbound connections"}, 638 {RPCResult::Type::BOOL, "networkactive", "whether p2p networking is enabled"}, 639 {RPCResult::Type::ARR, "networks", "information per network", 640 { 641 {RPCResult::Type::OBJ, "", "", 642 { 643 {RPCResult::Type::STR, "name", "network (" + Join(GetNetworkNames(), ", ") + ")"}, 644 {RPCResult::Type::BOOL, "limited", "is the network limited using -onlynet?"}, 645 {RPCResult::Type::BOOL, "reachable", "is the network reachable?"}, 646 {RPCResult::Type::STR, "proxy", "(\"host:port\") the proxy that is used for this network, or empty if none"}, 647 {RPCResult::Type::BOOL, "proxy_randomize_credentials", "Whether randomized credentials are used"}, 648 }}, 649 }}, 650 {RPCResult::Type::NUM, "relayfee", "minimum relay fee rate for transactions in " + CURRENCY_UNIT + "/kvB"}, 651 {RPCResult::Type::NUM, "incrementalfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"}, 652 {RPCResult::Type::ARR, "localaddresses", "list of local addresses", 653 { 654 {RPCResult::Type::OBJ, "", "", 655 { 656 {RPCResult::Type::STR, "address", "network address"}, 657 {RPCResult::Type::NUM, "port", "network port"}, 658 {RPCResult::Type::NUM, "score", "relative score"}, 659 }}, 660 }}, 661 {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"}, 662 } 663 }, 664 RPCExamples{ 665 HelpExampleCli("getnetworkinfo", "") 666 + HelpExampleRpc("getnetworkinfo", "") 667 }, 668 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 669 { 670 LOCK(cs_main); 671 UniValue obj(UniValue::VOBJ); 672 obj.pushKV("version", CLIENT_VERSION); 673 obj.pushKV("subversion", strSubVersion); 674 obj.pushKV("protocolversion",PROTOCOL_VERSION); 675 NodeContext& node = EnsureAnyNodeContext(request.context); 676 if (node.connman) { 677 ServiceFlags services = node.connman->GetLocalServices(); 678 obj.pushKV("localservices", strprintf("%016x", services)); 679 obj.pushKV("localservicesnames", GetServicesNames(services)); 680 } 681 if (node.peerman) { 682 obj.pushKV("localrelay", !node.peerman->IgnoresIncomingTxs()); 683 } 684 obj.pushKV("timeoffset", GetTimeOffset()); 685 if (node.connman) { 686 obj.pushKV("networkactive", node.connman->GetNetworkActive()); 687 obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both)); 688 obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In)); 689 obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out)); 690 } 691 obj.pushKV("networks", GetNetworksInfo()); 692 if (node.mempool) { 693 // Those fields can be deprecated, to be replaced by the getmempoolinfo fields 694 obj.pushKV("relayfee", ValueFromAmount(node.mempool->m_min_relay_feerate.GetFeePerK())); 695 obj.pushKV("incrementalfee", ValueFromAmount(node.mempool->m_incremental_relay_feerate.GetFeePerK())); 696 } 697 UniValue localAddresses(UniValue::VARR); 698 { 699 LOCK(g_maplocalhost_mutex); 700 for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost) 701 { 702 UniValue rec(UniValue::VOBJ); 703 rec.pushKV("address", item.first.ToStringAddr()); 704 rec.pushKV("port", item.second.nPort); 705 rec.pushKV("score", item.second.nScore); 706 localAddresses.push_back(rec); 707 } 708 } 709 obj.pushKV("localaddresses", localAddresses); 710 obj.pushKV("warnings", GetWarnings(false).original); 711 return obj; 712 }, 713 }; 714 } 715 716 static RPCHelpMan setban() 717 { 718 return RPCHelpMan{"setban", 719 "\nAttempts to add or remove an IP/Subnet from the banned list.\n", 720 { 721 {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"}, 722 {"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"}, 723 {"bantime", RPCArg::Type::NUM, RPCArg::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)"}, 724 {"absolute", RPCArg::Type::BOOL, RPCArg::Default{false}, "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME}, 725 }, 726 RPCResult{RPCResult::Type::NONE, "", ""}, 727 RPCExamples{ 728 HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400") 729 + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") 730 + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") 731 }, 732 [&](const RPCHelpMan& help, const JSONRPCRequest& request) -> UniValue 733 { 734 std::string strCommand; 735 if (!request.params[1].isNull()) 736 strCommand = request.params[1].get_str(); 737 if (strCommand != "add" && strCommand != "remove") { 738 throw std::runtime_error(help.ToString()); 739 } 740 NodeContext& node = EnsureAnyNodeContext(request.context); 741 BanMan& banman = EnsureBanman(node); 742 743 CSubNet subNet; 744 CNetAddr netAddr; 745 bool isSubnet = false; 746 747 if (request.params[0].get_str().find('/') != std::string::npos) 748 isSubnet = true; 749 750 if (!isSubnet) { 751 const std::optional<CNetAddr> addr{LookupHost(request.params[0].get_str(), false)}; 752 if (addr.has_value()) { 753 netAddr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0})); 754 } 755 } 756 else 757 subNet = LookupSubNet(request.params[0].get_str()); 758 759 if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) 760 throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet"); 761 762 if (strCommand == "add") 763 { 764 if (isSubnet ? banman.IsBanned(subNet) : banman.IsBanned(netAddr)) { 765 throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned"); 766 } 767 768 int64_t banTime = 0; //use standard bantime if not specified 769 if (!request.params[2].isNull()) 770 banTime = request.params[2].getInt<int64_t>(); 771 772 const bool absolute{request.params[3].isNull() ? false : request.params[3].get_bool()}; 773 774 if (absolute && banTime < GetTime()) { 775 throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Absolute timestamp is in the past"); 776 } 777 778 if (isSubnet) { 779 banman.Ban(subNet, banTime, absolute); 780 if (node.connman) { 781 node.connman->DisconnectNode(subNet); 782 } 783 } else { 784 banman.Ban(netAddr, banTime, absolute); 785 if (node.connman) { 786 node.connman->DisconnectNode(netAddr); 787 } 788 } 789 } 790 else if(strCommand == "remove") 791 { 792 if (!( isSubnet ? banman.Unban(subNet) : banman.Unban(netAddr) )) { 793 throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned."); 794 } 795 } 796 return UniValue::VNULL; 797 }, 798 }; 799 } 800 801 static RPCHelpMan listbanned() 802 { 803 return RPCHelpMan{"listbanned", 804 "\nList all manually banned IPs/Subnets.\n", 805 {}, 806 RPCResult{RPCResult::Type::ARR, "", "", 807 { 808 {RPCResult::Type::OBJ, "", "", 809 { 810 {RPCResult::Type::STR, "address", "The IP/Subnet of the banned node"}, 811 {RPCResult::Type::NUM_TIME, "ban_created", "The " + UNIX_EPOCH_TIME + " the ban was created"}, 812 {RPCResult::Type::NUM_TIME, "banned_until", "The " + UNIX_EPOCH_TIME + " the ban expires"}, 813 {RPCResult::Type::NUM_TIME, "ban_duration", "The ban duration, in seconds"}, 814 {RPCResult::Type::NUM_TIME, "time_remaining", "The time remaining until the ban expires, in seconds"}, 815 }}, 816 }}, 817 RPCExamples{ 818 HelpExampleCli("listbanned", "") 819 + HelpExampleRpc("listbanned", "") 820 }, 821 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 822 { 823 BanMan& banman = EnsureAnyBanman(request.context); 824 825 banmap_t banMap; 826 banman.GetBanned(banMap); 827 const int64_t current_time{GetTime()}; 828 829 UniValue bannedAddresses(UniValue::VARR); 830 for (const auto& entry : banMap) 831 { 832 const CBanEntry& banEntry = entry.second; 833 UniValue rec(UniValue::VOBJ); 834 rec.pushKV("address", entry.first.ToString()); 835 rec.pushKV("ban_created", banEntry.nCreateTime); 836 rec.pushKV("banned_until", banEntry.nBanUntil); 837 rec.pushKV("ban_duration", (banEntry.nBanUntil - banEntry.nCreateTime)); 838 rec.pushKV("time_remaining", (banEntry.nBanUntil - current_time)); 839 840 bannedAddresses.push_back(rec); 841 } 842 843 return bannedAddresses; 844 }, 845 }; 846 } 847 848 static RPCHelpMan clearbanned() 849 { 850 return RPCHelpMan{"clearbanned", 851 "\nClear all banned IPs.\n", 852 {}, 853 RPCResult{RPCResult::Type::NONE, "", ""}, 854 RPCExamples{ 855 HelpExampleCli("clearbanned", "") 856 + HelpExampleRpc("clearbanned", "") 857 }, 858 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 859 { 860 BanMan& banman = EnsureAnyBanman(request.context); 861 862 banman.ClearBanned(); 863 864 return UniValue::VNULL; 865 }, 866 }; 867 } 868 869 static RPCHelpMan setnetworkactive() 870 { 871 return RPCHelpMan{"setnetworkactive", 872 "\nDisable/enable all p2p network activity.\n", 873 { 874 {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"}, 875 }, 876 RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"}, 877 RPCExamples{""}, 878 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 879 { 880 NodeContext& node = EnsureAnyNodeContext(request.context); 881 CConnman& connman = EnsureConnman(node); 882 883 connman.SetNetworkActive(request.params[0].get_bool()); 884 885 return connman.GetNetworkActive(); 886 }, 887 }; 888 } 889 890 static RPCHelpMan getnodeaddresses() 891 { 892 return RPCHelpMan{"getnodeaddresses", 893 "Return known addresses, after filtering for quality and recency.\n" 894 "These can potentially be used to find new peers in the network.\n" 895 "The total number of addresses known to the node may be higher.", 896 { 897 {"count", RPCArg::Type::NUM, RPCArg::Default{1}, "The maximum number of addresses to return. Specify 0 to return all known addresses."}, 898 {"network", RPCArg::Type::STR, RPCArg::DefaultHint{"all networks"}, "Return only addresses of the specified network. Can be one of: " + Join(GetNetworkNames(), ", ") + "."}, 899 }, 900 RPCResult{ 901 RPCResult::Type::ARR, "", "", 902 { 903 {RPCResult::Type::OBJ, "", "", 904 { 905 {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " when the node was last seen"}, 906 {RPCResult::Type::NUM, "services", "The services offered by the node"}, 907 {RPCResult::Type::STR, "address", "The address of the node"}, 908 {RPCResult::Type::NUM, "port", "The port number of the node"}, 909 {RPCResult::Type::STR, "network", "The network (" + Join(GetNetworkNames(), ", ") + ") the node connected through"}, 910 }}, 911 } 912 }, 913 RPCExamples{ 914 HelpExampleCli("getnodeaddresses", "8") 915 + HelpExampleCli("getnodeaddresses", "4 \"i2p\"") 916 + HelpExampleCli("-named getnodeaddresses", "network=onion count=12") 917 + HelpExampleRpc("getnodeaddresses", "8") 918 + HelpExampleRpc("getnodeaddresses", "4, \"i2p\"") 919 }, 920 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 921 { 922 NodeContext& node = EnsureAnyNodeContext(request.context); 923 const CConnman& connman = EnsureConnman(node); 924 925 const int count{request.params[0].isNull() ? 1 : request.params[0].getInt<int>()}; 926 if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); 927 928 const std::optional<Network> network{request.params[1].isNull() ? std::nullopt : std::optional<Network>{ParseNetwork(request.params[1].get_str())}}; 929 if (network == NET_UNROUTABLE) { 930 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str())); 931 } 932 933 // returns a shuffled list of CAddress 934 const std::vector<CAddress> vAddr{connman.GetAddresses(count, /*max_pct=*/0, network)}; 935 UniValue ret(UniValue::VARR); 936 937 for (const CAddress& addr : vAddr) { 938 UniValue obj(UniValue::VOBJ); 939 obj.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(addr.nTime)}); 940 obj.pushKV("services", (uint64_t)addr.nServices); 941 obj.pushKV("address", addr.ToStringAddr()); 942 obj.pushKV("port", addr.GetPort()); 943 obj.pushKV("network", GetNetworkName(addr.GetNetClass())); 944 ret.push_back(obj); 945 } 946 return ret; 947 }, 948 }; 949 } 950 951 static RPCHelpMan addpeeraddress() 952 { 953 return RPCHelpMan{"addpeeraddress", 954 "Add the address of a potential peer to an address manager table. This RPC is for testing only.", 955 { 956 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"}, 957 {"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"}, 958 {"tried", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, attempt to add the peer to the tried addresses table"}, 959 }, 960 RPCResult{ 961 RPCResult::Type::OBJ, "", "", 962 { 963 {RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager table"}, 964 {RPCResult::Type::STR, "error", /*optional=*/true, "error description, if the address could not be added"}, 965 }, 966 }, 967 RPCExamples{ 968 HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333 true") 969 + HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333, true") 970 }, 971 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue 972 { 973 AddrMan& addrman = EnsureAnyAddrman(request.context); 974 975 const std::string& addr_string{request.params[0].get_str()}; 976 const auto port{request.params[1].getInt<uint16_t>()}; 977 const bool tried{request.params[2].isNull() ? false : request.params[2].get_bool()}; 978 979 UniValue obj(UniValue::VOBJ); 980 std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)}; 981 bool success{false}; 982 983 if (net_addr.has_value()) { 984 CService service{net_addr.value(), port}; 985 CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}}; 986 address.nTime = Now<NodeSeconds>(); 987 // The source address is set equal to the address. This is equivalent to the peer 988 // announcing itself. 989 if (addrman.Add({address}, address)) { 990 success = true; 991 if (tried) { 992 // Attempt to move the address to the tried addresses table. 993 if (!addrman.Good(address)) { 994 success = false; 995 obj.pushKV("error", "failed-adding-to-tried"); 996 } 997 } 998 } else { 999 obj.pushKV("error", "failed-adding-to-new"); 1000 } 1001 } 1002 1003 obj.pushKV("success", success); 1004 return obj; 1005 }, 1006 }; 1007 } 1008 1009 static RPCHelpMan sendmsgtopeer() 1010 { 1011 return RPCHelpMan{ 1012 "sendmsgtopeer", 1013 "Send a p2p message to a peer specified by id.\n" 1014 "The message type and body must be provided, the message header will be generated.\n" 1015 "This RPC is for testing only.", 1016 { 1017 {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to send the message to."}, 1018 {"msg_type", RPCArg::Type::STR, RPCArg::Optional::NO, strprintf("The message type (maximum length %i)", CMessageHeader::COMMAND_SIZE)}, 1019 {"msg", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The serialized message body to send, in hex, without a message header"}, 1020 }, 1021 RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}}, 1022 RPCExamples{ 1023 HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", "0 \"addr\" \"ffffff\"")}, 1024 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { 1025 const NodeId peer_id{request.params[0].getInt<int64_t>()}; 1026 const std::string& msg_type{request.params[1].get_str()}; 1027 if (msg_type.size() > CMessageHeader::COMMAND_SIZE) { 1028 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Error: msg_type too long, max length is %i", CMessageHeader::COMMAND_SIZE)); 1029 } 1030 auto msg{TryParseHex<unsigned char>(request.params[2].get_str())}; 1031 if (!msg.has_value()) { 1032 throw JSONRPCError(RPC_INVALID_PARAMETER, "Error parsing input for msg"); 1033 } 1034 1035 NodeContext& node = EnsureAnyNodeContext(request.context); 1036 CConnman& connman = EnsureConnman(node); 1037 1038 CSerializedNetMsg msg_ser; 1039 msg_ser.data = msg.value(); 1040 msg_ser.m_type = msg_type; 1041 1042 bool success = connman.ForNode(peer_id, [&](CNode* node) { 1043 connman.PushMessage(node, std::move(msg_ser)); 1044 return true; 1045 }); 1046 1047 if (!success) { 1048 throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not send message to peer"); 1049 } 1050 1051 UniValue ret{UniValue::VOBJ}; 1052 return ret; 1053 }, 1054 }; 1055 } 1056 1057 static RPCHelpMan getaddrmaninfo() 1058 { 1059 return RPCHelpMan{ 1060 "getaddrmaninfo", 1061 "\nProvides information about the node's address manager by returning the number of " 1062 "addresses in the `new` and `tried` tables and their sum for all networks.\n", 1063 {}, 1064 RPCResult{ 1065 RPCResult::Type::OBJ_DYN, "", "json object with network type as keys", { 1066 {RPCResult::Type::OBJ, "network", "the network (" + Join(GetNetworkNames(), ", ") + ", all_networks)", { 1067 {RPCResult::Type::NUM, "new", "number of addresses in the new table, which represent potential peers the node has discovered but hasn't yet successfully connected to."}, 1068 {RPCResult::Type::NUM, "tried", "number of addresses in the tried table, which represent peers the node has successfully connected to in the past."}, 1069 {RPCResult::Type::NUM, "total", "total number of addresses in both new/tried tables"}, 1070 }}, 1071 }}, 1072 RPCExamples{HelpExampleCli("getaddrmaninfo", "") + HelpExampleRpc("getaddrmaninfo", "")}, 1073 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { 1074 AddrMan& addrman = EnsureAnyAddrman(request.context); 1075 1076 UniValue ret(UniValue::VOBJ); 1077 for (int n = 0; n < NET_MAX; ++n) { 1078 enum Network network = static_cast<enum Network>(n); 1079 if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue; 1080 UniValue obj(UniValue::VOBJ); 1081 obj.pushKV("new", addrman.Size(network, true)); 1082 obj.pushKV("tried", addrman.Size(network, false)); 1083 obj.pushKV("total", addrman.Size(network)); 1084 ret.pushKV(GetNetworkName(network), obj); 1085 } 1086 UniValue obj(UniValue::VOBJ); 1087 obj.pushKV("new", addrman.Size(std::nullopt, true)); 1088 obj.pushKV("tried", addrman.Size(std::nullopt, false)); 1089 obj.pushKV("total", addrman.Size()); 1090 ret.pushKV("all_networks", obj); 1091 return ret; 1092 }, 1093 }; 1094 } 1095 1096 UniValue AddrmanEntryToJSON(const AddrInfo& info) 1097 { 1098 UniValue ret(UniValue::VOBJ); 1099 ret.pushKV("address", info.ToStringAddr()); 1100 ret.pushKV("port", info.GetPort()); 1101 ret.pushKV("services", (uint64_t)info.nServices); 1102 ret.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(info.nTime)}); 1103 ret.pushKV("network", GetNetworkName(info.GetNetClass())); 1104 ret.pushKV("source", info.source.ToStringAddr()); 1105 ret.pushKV("source_network", GetNetworkName(info.source.GetNetClass())); 1106 return ret; 1107 } 1108 1109 UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos) 1110 { 1111 UniValue table(UniValue::VOBJ); 1112 for (const auto& e : tableInfos) { 1113 AddrInfo info = e.first; 1114 AddressPosition location = e.second; 1115 std::ostringstream key; 1116 key << location.bucket << "/" << location.position; 1117 // Address manager tables have unique entries so there is no advantage 1118 // in using UniValue::pushKV, which checks if the key already exists 1119 // in O(N). UniValue::pushKVEnd is used instead which currently is O(1). 1120 table.pushKVEnd(key.str(), AddrmanEntryToJSON(info)); 1121 } 1122 return table; 1123 } 1124 1125 static RPCHelpMan getrawaddrman() 1126 { 1127 return RPCHelpMan{"getrawaddrman", 1128 "EXPERIMENTAL warning: this call may be changed in future releases.\n" 1129 "\nReturns information on all address manager entries for the new and tried tables.\n", 1130 {}, 1131 RPCResult{ 1132 RPCResult::Type::OBJ_DYN, "", "", { 1133 {RPCResult::Type::OBJ_DYN, "table", "buckets with addresses in the address manager table ( new, tried )", { 1134 {RPCResult::Type::OBJ, "bucket/position", "the location in the address manager table (<bucket>/<position>)", { 1135 {RPCResult::Type::STR, "address", "The address of the node"}, 1136 {RPCResult::Type::NUM, "port", "The port number of the node"}, 1137 {RPCResult::Type::STR, "network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the address"}, 1138 {RPCResult::Type::NUM, "services", "The services offered by the node"}, 1139 {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " when the node was last seen"}, 1140 {RPCResult::Type::STR, "source", "The address that relayed the address to us"}, 1141 {RPCResult::Type::STR, "source_network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the source address"}, 1142 }} 1143 }} 1144 } 1145 }, 1146 RPCExamples{ 1147 HelpExampleCli("getrawaddrman", "") 1148 + HelpExampleRpc("getrawaddrman", "") 1149 }, 1150 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { 1151 AddrMan& addrman = EnsureAnyAddrman(request.context); 1152 1153 UniValue ret(UniValue::VOBJ); 1154 ret.pushKV("new", AddrmanTableToJSON(addrman.GetEntries(false))); 1155 ret.pushKV("tried", AddrmanTableToJSON(addrman.GetEntries(true))); 1156 return ret; 1157 }, 1158 }; 1159 } 1160 1161 void RegisterNetRPCCommands(CRPCTable& t) 1162 { 1163 static const CRPCCommand commands[]{ 1164 {"network", &getconnectioncount}, 1165 {"network", &ping}, 1166 {"network", &getpeerinfo}, 1167 {"network", &addnode}, 1168 {"network", &disconnectnode}, 1169 {"network", &getaddednodeinfo}, 1170 {"network", &getnettotals}, 1171 {"network", &getnetworkinfo}, 1172 {"network", &setban}, 1173 {"network", &listbanned}, 1174 {"network", &clearbanned}, 1175 {"network", &setnetworkactive}, 1176 {"network", &getnodeaddresses}, 1177 {"network", &getaddrmaninfo}, 1178 {"hidden", &addconnection}, 1179 {"hidden", &addpeeraddress}, 1180 {"hidden", &sendmsgtopeer}, 1181 {"hidden", &getrawaddrman}, 1182 }; 1183 for (const auto& c : commands) { 1184 t.appendCommand(c.name, &c); 1185 } 1186 }