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