net.cpp raw

   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(/*addrConnect=*/addr,
 362                                        /*fCountFailure=*/false,
 363                                        /*grant_outbound=*/{},
 364                                        /*pszDest=*/std::string{node_arg}.c_str(),
 365                                        /*conn_type=*/ConnectionType::MANUAL,
 366                                        /*use_v2transport=*/use_v2transport,
 367                                        /*proxy_override=*/std::nullopt);
 368          return UniValue::VNULL;
 369      }
 370  
 371      if (command == "add")
 372      {
 373          if (!connman.AddNode({std::string{node_arg}, use_v2transport})) {
 374              throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
 375          }
 376      }
 377      else if (command == "remove")
 378      {
 379          if (!connman.RemoveAddedNode(node_arg)) {
 380              throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node could not be removed. It has not been added previously.");
 381          }
 382      }
 383  
 384      return UniValue::VNULL;
 385  },
 386      };
 387  }
 388  
 389  static RPCMethod addconnection()
 390  {
 391      return RPCMethod{
 392          "addconnection",
 393          "Open an outbound connection to a specified node. This RPC is for testing only.\n",
 394          {
 395              {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."},
 396              {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open (\"outbound-full-relay\", \"block-relay-only\", \"addr-fetch\" or \"feeler\")."},
 397              {"v2transport", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Attempt to connect using BIP324 v2 transport protocol"},
 398          },
 399          RPCResult{
 400              RPCResult::Type::OBJ, "", "",
 401              {
 402                  { RPCResult::Type::STR, "address", "Address of newly added connection." },
 403                  { RPCResult::Type::STR, "connection_type", "Type of connection opened." },
 404              }},
 405          RPCExamples{
 406              HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true")
 407              + HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\" true")
 408          },
 409          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 410  {
 411      if (Params().GetChainType() != ChainType::REGTEST) {
 412          throw std::runtime_error("addconnection is for regression testing (-regtest mode) only.");
 413      }
 414  
 415      const std::string address = request.params[0].get_str();
 416      auto conn_type_in{util::TrimStringView(self.Arg<std::string_view>("connection_type"))};
 417      ConnectionType conn_type{};
 418      if (conn_type_in == "outbound-full-relay") {
 419          conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
 420      } else if (conn_type_in == "block-relay-only") {
 421          conn_type = ConnectionType::BLOCK_RELAY;
 422      } else if (conn_type_in == "addr-fetch") {
 423          conn_type = ConnectionType::ADDR_FETCH;
 424      } else if (conn_type_in == "feeler") {
 425          conn_type = ConnectionType::FEELER;
 426      } else {
 427          throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());
 428      }
 429      bool use_v2transport{self.Arg<bool>("v2transport")};
 430  
 431      NodeContext& node = EnsureAnyNodeContext(request.context);
 432      CConnman& connman = EnsureConnman(node);
 433  
 434      if (use_v2transport && !(connman.GetLocalServices() & NODE_P2P_V2)) {
 435          throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Adding v2transport connections requires -v2transport init flag to be set.");
 436      }
 437  
 438      const bool success = connman.AddConnection(address, conn_type, use_v2transport);
 439      if (!success) {
 440          throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type.");
 441      }
 442  
 443      UniValue info(UniValue::VOBJ);
 444      info.pushKV("address", address);
 445      info.pushKV("connection_type", conn_type_in);
 446  
 447      return info;
 448  },
 449      };
 450  }
 451  
 452  static RPCMethod disconnectnode()
 453  {
 454      return RPCMethod{
 455          "disconnectnode",
 456          "Immediately disconnects from the specified peer node.\n"
 457                  "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n"
 458                  "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n",
 459                  {
 460                      {"address", RPCArg::Type::STR, RPCArg::DefaultHint{"fallback to nodeid"}, "The IP address/port of the node"},
 461                      {"nodeid", RPCArg::Type::NUM, RPCArg::DefaultHint{"fallback to address"}, "The node ID (see getpeerinfo for node IDs)"},
 462                  },
 463                  RPCResult{RPCResult::Type::NONE, "", ""},
 464                  RPCExamples{
 465                      HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
 466              + HelpExampleCli("disconnectnode", "\"\" 1")
 467              + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
 468              + HelpExampleRpc("disconnectnode", "\"\", 1")
 469                  },
 470          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 471  {
 472      NodeContext& node = EnsureAnyNodeContext(request.context);
 473      CConnman& connman = EnsureConnman(node);
 474  
 475      bool success;
 476      auto address{self.MaybeArg<std::string_view>("address")};
 477      auto node_id{self.MaybeArg<int64_t>("nodeid")};
 478  
 479      if (address && !node_id) {
 480          /* handle disconnect-by-address */
 481          success = connman.DisconnectNode(*address);
 482      } else if (node_id && (!address || address->empty())) {
 483          /* handle disconnect-by-id */
 484          success = connman.DisconnectNode(*node_id);
 485      } else {
 486          throw JSONRPCError(RPC_INVALID_PARAMS, "Only one of address and nodeid should be provided.");
 487      }
 488  
 489      if (!success) {
 490          throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
 491      }
 492  
 493      return UniValue::VNULL;
 494  },
 495      };
 496  }
 497  
 498  static RPCMethod getaddednodeinfo()
 499  {
 500      return RPCMethod{
 501          "getaddednodeinfo",
 502          "Returns information about the given added node, or all added nodes\n"
 503                  "(note that onetry addnodes are not listed here)\n",
 504                  {
 505                      {"node", RPCArg::Type::STR, RPCArg::DefaultHint{"all nodes"}, "If provided, return information about this specific node, otherwise all nodes are returned."},
 506                  },
 507                  RPCResult{
 508                      RPCResult::Type::ARR, "", "",
 509                      {
 510                          {RPCResult::Type::OBJ, "", "",
 511                          {
 512                              {RPCResult::Type::STR, "addednode", "The node IP address or name (as provided to addnode)"},
 513                              {RPCResult::Type::BOOL, "connected", "If connected"},
 514                              {RPCResult::Type::ARR, "addresses", "Only when connected = true",
 515                              {
 516                                  {RPCResult::Type::OBJ, "", "",
 517                                  {
 518                                      {RPCResult::Type::STR, "address", "The bitcoin server IP and port we're connected to"},
 519                                      {RPCResult::Type::STR, "connected", "connection, inbound or outbound"},
 520                                  }},
 521                              }},
 522                          }},
 523                      }
 524                  },
 525                  RPCExamples{
 526                      HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"")
 527              + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"")
 528                  },
 529          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 530  {
 531      NodeContext& node = EnsureAnyNodeContext(request.context);
 532      const CConnman& connman = EnsureConnman(node);
 533  
 534      std::vector<AddedNodeInfo> vInfo = connman.GetAddedNodeInfo(/*include_connected=*/true);
 535  
 536      if (auto node{self.MaybeArg<std::string_view>("node")}) {
 537          bool found = false;
 538          for (const AddedNodeInfo& info : vInfo) {
 539              if (info.m_params.m_added_node == *node) {
 540                  vInfo.assign(1, info);
 541                  found = true;
 542                  break;
 543              }
 544          }
 545          if (!found) {
 546              throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
 547          }
 548      }
 549  
 550      UniValue ret(UniValue::VARR);
 551  
 552      for (const AddedNodeInfo& info : vInfo) {
 553          UniValue obj(UniValue::VOBJ);
 554          obj.pushKV("addednode", info.m_params.m_added_node);
 555          obj.pushKV("connected", info.fConnected);
 556          UniValue addresses(UniValue::VARR);
 557          if (info.fConnected) {
 558              UniValue address(UniValue::VOBJ);
 559              address.pushKV("address", info.resolvedAddress.ToStringAddrPort());
 560              address.pushKV("connected", info.fInbound ? "inbound" : "outbound");
 561              addresses.push_back(std::move(address));
 562          }
 563          obj.pushKV("addresses", std::move(addresses));
 564          ret.push_back(std::move(obj));
 565      }
 566  
 567      return ret;
 568  },
 569      };
 570  }
 571  
 572  static RPCMethod getnettotals()
 573  {
 574      return RPCMethod{"getnettotals",
 575          "Returns information about network traffic, including bytes in, bytes out,\n"
 576          "and current system time.",
 577          {},
 578                  RPCResult{
 579                     RPCResult::Type::OBJ, "", "",
 580                     {
 581                         {RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"},
 582                         {RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"},
 583                         {RPCResult::Type::NUM_TIME, "timemillis", "Current system " + UNIX_EPOCH_TIME + " in milliseconds"},
 584                         {RPCResult::Type::OBJ, "uploadtarget", "",
 585                         {
 586                             {RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"},
 587                             {RPCResult::Type::NUM, "target", "Target in bytes"},
 588                             {RPCResult::Type::BOOL, "target_reached", "True if target is reached"},
 589                             {RPCResult::Type::BOOL, "serve_historical_blocks", "True if serving historical blocks"},
 590                             {RPCResult::Type::NUM, "bytes_left_in_cycle", "Bytes left in current time cycle"},
 591                             {RPCResult::Type::NUM, "time_left_in_cycle", "Seconds left in current time cycle"},
 592                          }},
 593                      }
 594                  },
 595                  RPCExamples{
 596                      HelpExampleCli("getnettotals", "")
 597              + HelpExampleRpc("getnettotals", "")
 598                  },
 599          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 600  {
 601      NodeContext& node = EnsureAnyNodeContext(request.context);
 602      const CConnman& connman = EnsureConnman(node);
 603  
 604      UniValue obj(UniValue::VOBJ);
 605      obj.pushKV("totalbytesrecv", connman.GetTotalBytesRecv());
 606      obj.pushKV("totalbytessent", connman.GetTotalBytesSent());
 607      obj.pushKV("timemillis", TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()));
 608  
 609      UniValue outboundLimit(UniValue::VOBJ);
 610      outboundLimit.pushKV("timeframe", count_seconds(connman.GetMaxOutboundTimeframe()));
 611      outboundLimit.pushKV("target", connman.GetMaxOutboundTarget());
 612      outboundLimit.pushKV("target_reached", connman.OutboundTargetReached(false));
 613      outboundLimit.pushKV("serve_historical_blocks", !connman.OutboundTargetReached(true));
 614      outboundLimit.pushKV("bytes_left_in_cycle", connman.GetOutboundTargetBytesLeft());
 615      outboundLimit.pushKV("time_left_in_cycle", count_seconds(connman.GetMaxOutboundTimeLeftInCycle()));
 616      obj.pushKV("uploadtarget", std::move(outboundLimit));
 617      return obj;
 618  },
 619      };
 620  }
 621  
 622  static UniValue GetNetworksInfo()
 623  {
 624      UniValue networks(UniValue::VARR);
 625      for (int n = 0; n < NET_MAX; ++n) {
 626          enum Network network = static_cast<enum Network>(n);
 627          if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
 628          UniValue obj(UniValue::VOBJ);
 629          obj.pushKV("name", GetNetworkName(network));
 630          obj.pushKV("limited", !g_reachable_nets.Contains(network));
 631          obj.pushKV("reachable", g_reachable_nets.Contains(network));
 632          if (const auto proxy = GetProxy(network)) {
 633              obj.pushKV("proxy", proxy->ToString());
 634              obj.pushKV("proxy_randomize_credentials", proxy->m_tor_stream_isolation);
 635          } else {
 636              obj.pushKV("proxy", std::string());
 637              obj.pushKV("proxy_randomize_credentials", false);
 638          }
 639          networks.push_back(std::move(obj));
 640      }
 641      return networks;
 642  }
 643  
 644  static RPCMethod getnetworkinfo()
 645  {
 646      return RPCMethod{"getnetworkinfo",
 647                  "Returns an object containing various state info regarding P2P networking.\n",
 648                  {},
 649                  RPCResult{
 650                      RPCResult::Type::OBJ, "", "",
 651                      {
 652                          {RPCResult::Type::NUM, "version", "the server version"},
 653                          {RPCResult::Type::STR, "subversion", "the server subversion string"},
 654                          {RPCResult::Type::NUM, "protocolversion", "the protocol version"},
 655                          {RPCResult::Type::STR_HEX, "localservices", "the services we offer to the network"},
 656                          {RPCResult::Type::ARR, "localservicesnames", "the services we offer to the network, in human-readable form",
 657                          {
 658                              {RPCResult::Type::STR, "SERVICE_NAME", "the service name"},
 659                          }},
 660                          {RPCResult::Type::BOOL, "localrelay", "true if transaction relay is requested from peers"},
 661                          {RPCResult::Type::NUM, "timeoffset", "the time offset"},
 662                          {RPCResult::Type::NUM, "connections", "the total number of connections"},
 663                          {RPCResult::Type::NUM, "connections_in", "the number of inbound connections"},
 664                          {RPCResult::Type::NUM, "connections_out", "the number of outbound connections"},
 665                          {RPCResult::Type::BOOL, "networkactive", "whether p2p networking is enabled"},
 666                          {RPCResult::Type::ARR, "networks", "information per network",
 667                          {
 668                              {RPCResult::Type::OBJ, "", "",
 669                              {
 670                                  {RPCResult::Type::STR, "name", "network (" + Join(GetNetworkNames(), ", ") + ")"},
 671                                  {RPCResult::Type::BOOL, "limited", "is the network limited using -onlynet?"},
 672                                  {RPCResult::Type::BOOL, "reachable", "is the network reachable?"},
 673                                  {RPCResult::Type::STR, "proxy", "(\"host:port\") the proxy that is used for this network, or empty if none"},
 674                                  {RPCResult::Type::BOOL, "proxy_randomize_credentials", "Whether randomized credentials are used"},
 675                              }},
 676                          }},
 677                          {RPCResult::Type::NUM, "relayfee", "minimum relay fee rate for transactions in " + CURRENCY_UNIT + "/kvB"},
 678                          {RPCResult::Type::NUM, "incrementalfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
 679                          {RPCResult::Type::ARR, "localaddresses", "list of local addresses",
 680                          {
 681                              {RPCResult::Type::OBJ, "", "",
 682                              {
 683                                  {RPCResult::Type::STR, "address", "network address"},
 684                                  {RPCResult::Type::NUM, "port", "network port"},
 685                                  {RPCResult::Type::NUM, "score", "relative score"},
 686                              }},
 687                          }},
 688                          (IsDeprecatedRPCEnabled("warnings") ?
 689                              RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
 690                              RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
 691                              {
 692                                  {RPCResult::Type::STR, "", "warning"},
 693                              }
 694                              }
 695                          ),
 696                      }
 697                  },
 698                  RPCExamples{
 699                      HelpExampleCli("getnetworkinfo", "")
 700              + HelpExampleRpc("getnetworkinfo", "")
 701                  },
 702          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 703  {
 704      LOCK(cs_main);
 705      UniValue obj(UniValue::VOBJ);
 706      obj.pushKV("version",       CLIENT_VERSION);
 707      obj.pushKV("subversion",    strSubVersion);
 708      obj.pushKV("protocolversion",PROTOCOL_VERSION);
 709      NodeContext& node = EnsureAnyNodeContext(request.context);
 710      if (node.connman) {
 711          ServiceFlags services = node.connman->GetLocalServices();
 712          obj.pushKV("localservices", strprintf("%016x", services));
 713          obj.pushKV("localservicesnames", GetServicesNames(services));
 714      }
 715      if (node.peerman) {
 716          auto peerman_info{node.peerman->GetInfo()};
 717          obj.pushKV("localrelay", !peerman_info.ignores_incoming_txs);
 718          obj.pushKV("timeoffset", Ticks<std::chrono::seconds>(peerman_info.median_outbound_time_offset));
 719      }
 720      if (node.connman) {
 721          obj.pushKV("networkactive", node.connman->GetNetworkActive());
 722          obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both));
 723          obj.pushKV("connections_in", node.connman->GetNodeCount(ConnectionDirection::In));
 724          obj.pushKV("connections_out", node.connman->GetNodeCount(ConnectionDirection::Out));
 725      }
 726      obj.pushKV("networks",      GetNetworksInfo());
 727      if (node.mempool) {
 728          // Those fields can be deprecated, to be replaced by the getmempoolinfo fields
 729          obj.pushKV("relayfee", ValueFromAmount(node.mempool->m_opts.min_relay_feerate.GetFeePerK()));
 730          obj.pushKV("incrementalfee", ValueFromAmount(node.mempool->m_opts.incremental_relay_feerate.GetFeePerK()));
 731      }
 732      UniValue localAddresses(UniValue::VARR);
 733      {
 734          LOCK(g_maplocalhost_mutex);
 735          for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost)
 736          {
 737              UniValue rec(UniValue::VOBJ);
 738              rec.pushKV("address", item.first.ToStringAddr());
 739              rec.pushKV("port", item.second.nPort);
 740              rec.pushKV("score", item.second.nScore);
 741              localAddresses.push_back(std::move(rec));
 742          }
 743      }
 744      obj.pushKV("localaddresses", std::move(localAddresses));
 745      obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
 746      return obj;
 747  },
 748      };
 749  }
 750  
 751  static RPCMethod setban()
 752  {
 753      return RPCMethod{
 754          "setban",
 755          "Attempts to add or remove an IP/Subnet from the banned list.\n",
 756                  {
 757                      {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"},
 758                      {"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"},
 759                      {"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)"},
 760                      {"absolute", RPCArg::Type::BOOL, RPCArg::Default{false}, "If set, the bantime must be an absolute timestamp expressed in " + UNIX_EPOCH_TIME},
 761                  },
 762                  RPCResult{RPCResult::Type::NONE, "", ""},
 763                  RPCExamples{
 764                      HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
 765                              + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
 766                              + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400")
 767                  },
 768          [](const RPCMethod& help, const JSONRPCRequest& request) -> UniValue
 769  {
 770      auto command{help.Arg<std::string_view>("command")};
 771      if (command != "add" && command != "remove") {
 772          throw std::runtime_error(help.ToString());
 773      }
 774      NodeContext& node = EnsureAnyNodeContext(request.context);
 775      BanMan& banman = EnsureBanman(node);
 776  
 777      CSubNet subNet;
 778      CNetAddr netAddr;
 779      std::string subnet_arg{help.Arg<std::string_view>("subnet")};
 780      const bool isSubnet{subnet_arg.find('/') != subnet_arg.npos};
 781  
 782      if (!isSubnet) {
 783          const std::optional<CNetAddr> addr{LookupHost(subnet_arg, false)};
 784          if (addr.has_value()) {
 785              netAddr = static_cast<CNetAddr>(MaybeFlipIPv6toCJDNS(CService{addr.value(), /*port=*/0}));
 786          }
 787      } else {
 788          subNet = LookupSubNet(subnet_arg);
 789      }
 790  
 791      if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) ) {
 792          throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Invalid IP/Subnet");
 793      }
 794  
 795      if (command == "add") {
 796          if (isSubnet ? banman.IsBanned(subNet) : banman.IsBanned(netAddr)) {
 797              throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
 798          }
 799  
 800          int64_t banTime = 0; //use standard bantime if not specified
 801          if (!request.params[2].isNull())
 802              banTime = request.params[2].getInt<int64_t>();
 803  
 804          const bool absolute{request.params[3].isNull() ? false : request.params[3].get_bool()};
 805  
 806          if (absolute && banTime < GetTime()) {
 807              throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: Absolute timestamp is in the past");
 808          }
 809  
 810          if (isSubnet) {
 811              banman.Ban(subNet, banTime, absolute);
 812              if (node.connman) {
 813                  node.connman->DisconnectNode(subNet);
 814              }
 815          } else {
 816              banman.Ban(netAddr, banTime, absolute);
 817              if (node.connman) {
 818                  node.connman->DisconnectNode(netAddr);
 819              }
 820          }
 821      } else if(command == "remove") {
 822          if (!( isSubnet ? banman.Unban(subNet) : banman.Unban(netAddr) )) {
 823              throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Error: Unban failed. Requested address/subnet was not previously manually banned.");
 824          }
 825      }
 826      return UniValue::VNULL;
 827  },
 828      };
 829  }
 830  
 831  static RPCMethod listbanned()
 832  {
 833      return RPCMethod{
 834          "listbanned",
 835          "List all manually banned IPs/Subnets.\n",
 836                  {},
 837          RPCResult{RPCResult::Type::ARR, "", "",
 838              {
 839                  {RPCResult::Type::OBJ, "", "",
 840                      {
 841                          {RPCResult::Type::STR, "address", "The IP/Subnet of the banned node"},
 842                          {RPCResult::Type::NUM_TIME, "ban_created", "The " + UNIX_EPOCH_TIME + " the ban was created"},
 843                          {RPCResult::Type::NUM_TIME, "banned_until", "The " + UNIX_EPOCH_TIME + " the ban expires"},
 844                          {RPCResult::Type::NUM_TIME, "ban_duration", "The ban duration, in seconds"},
 845                          {RPCResult::Type::NUM_TIME, "time_remaining", "The time remaining until the ban expires, in seconds"},
 846                      }},
 847              }},
 848                  RPCExamples{
 849                      HelpExampleCli("listbanned", "")
 850                              + HelpExampleRpc("listbanned", "")
 851                  },
 852          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 853  {
 854      BanMan& banman = EnsureAnyBanman(request.context);
 855  
 856      banmap_t banMap;
 857      banman.GetBanned(banMap);
 858      const int64_t current_time{GetTime()};
 859  
 860      UniValue bannedAddresses(UniValue::VARR);
 861      for (const auto& entry : banMap)
 862      {
 863          const CBanEntry& banEntry = entry.second;
 864          UniValue rec(UniValue::VOBJ);
 865          rec.pushKV("address", entry.first.ToString());
 866          rec.pushKV("ban_created", banEntry.nCreateTime);
 867          rec.pushKV("banned_until", banEntry.nBanUntil);
 868          rec.pushKV("ban_duration", (banEntry.nBanUntil - banEntry.nCreateTime));
 869          rec.pushKV("time_remaining", (banEntry.nBanUntil - current_time));
 870  
 871          bannedAddresses.push_back(std::move(rec));
 872      }
 873  
 874      return bannedAddresses;
 875  },
 876      };
 877  }
 878  
 879  static RPCMethod clearbanned()
 880  {
 881      return RPCMethod{
 882          "clearbanned",
 883          "Clear all banned IPs.\n",
 884                  {},
 885                  RPCResult{RPCResult::Type::NONE, "", ""},
 886                  RPCExamples{
 887                      HelpExampleCli("clearbanned", "")
 888                              + HelpExampleRpc("clearbanned", "")
 889                  },
 890          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 891  {
 892      BanMan& banman = EnsureAnyBanman(request.context);
 893  
 894      banman.ClearBanned();
 895  
 896      return UniValue::VNULL;
 897  },
 898      };
 899  }
 900  
 901  static RPCMethod setnetworkactive()
 902  {
 903      return RPCMethod{
 904          "setnetworkactive",
 905          "Disable/enable all p2p network activity.\n",
 906                  {
 907                      {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"},
 908                  },
 909                  RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"},
 910                  RPCExamples{""},
 911          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 912  {
 913      NodeContext& node = EnsureAnyNodeContext(request.context);
 914      CConnman& connman = EnsureConnman(node);
 915  
 916      connman.SetNetworkActive(request.params[0].get_bool());
 917  
 918      return connman.GetNetworkActive();
 919  },
 920      };
 921  }
 922  
 923  static RPCMethod getnodeaddresses()
 924  {
 925      return RPCMethod{"getnodeaddresses",
 926                  "Return known addresses, after filtering for quality and recency.\n"
 927                  "These can potentially be used to find new peers in the network.\n"
 928                  "The total number of addresses known to the node may be higher.",
 929                  {
 930                      {"count", RPCArg::Type::NUM, RPCArg::Default{1}, "The maximum number of addresses to return. Specify 0 to return all known addresses."},
 931                      {"network", RPCArg::Type::STR, RPCArg::DefaultHint{"all networks"}, "Return only addresses of the specified network. Can be one of: " + Join(GetNetworkNames(), ", ") + "."},
 932                  },
 933                  RPCResult{
 934                      RPCResult::Type::ARR, "", "",
 935                      {
 936                          {RPCResult::Type::OBJ, "", "",
 937                          {
 938                              {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " when the node was last seen"},
 939                              {RPCResult::Type::NUM, "services", "The services offered by the node"},
 940                              {RPCResult::Type::STR, "address", "The address of the node"},
 941                              {RPCResult::Type::NUM, "port", "The port number of the node"},
 942                              {RPCResult::Type::STR, "network", "The network (" + Join(GetNetworkNames(), ", ") + ") the node connected through"},
 943                          }},
 944                      }
 945                  },
 946                  RPCExamples{
 947                      HelpExampleCli("getnodeaddresses", "8")
 948                      + HelpExampleCli("getnodeaddresses", "4 \"i2p\"")
 949                      + HelpExampleCli("-named getnodeaddresses", "network=onion count=12")
 950                      + HelpExampleRpc("getnodeaddresses", "8")
 951                      + HelpExampleRpc("getnodeaddresses", "4, \"i2p\"")
 952                  },
 953          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
 954  {
 955      NodeContext& node = EnsureAnyNodeContext(request.context);
 956      const CConnman& connman = EnsureConnman(node);
 957  
 958      const int count{request.params[0].isNull() ? 1 : request.params[0].getInt<int>()};
 959      if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
 960  
 961      const std::optional<Network> network{request.params[1].isNull() ? std::nullopt : std::optional<Network>{ParseNetwork(request.params[1].get_str())}};
 962      if (network == NET_UNROUTABLE) {
 963          throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str()));
 964      }
 965  
 966      // returns a shuffled list of CAddress
 967      const std::vector<CAddress> vAddr{connman.GetAddressesUnsafe(count, /*max_pct=*/0, network)};
 968      UniValue ret(UniValue::VARR);
 969  
 970      for (const CAddress& addr : vAddr) {
 971          UniValue obj(UniValue::VOBJ);
 972          obj.pushKV("time", TicksSinceEpoch<std::chrono::seconds>(addr.nTime));
 973          obj.pushKV("services", static_cast<std::underlying_type_t<decltype(addr.nServices)>>(addr.nServices));
 974          obj.pushKV("address", addr.ToStringAddr());
 975          obj.pushKV("port", addr.GetPort());
 976          obj.pushKV("network", GetNetworkName(addr.GetNetClass()));
 977          ret.push_back(std::move(obj));
 978      }
 979      return ret;
 980  },
 981      };
 982  }
 983  
 984  static RPCMethod addpeeraddress()
 985  {
 986      return RPCMethod{"addpeeraddress",
 987          "Add the address of a potential peer to an address manager table. This RPC is for testing only.",
 988          {
 989              {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"},
 990              {"port", RPCArg::Type::NUM, RPCArg::Optional::NO, "The port of the peer"},
 991              {"tried", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, attempt to add the peer to the tried addresses table"},
 992          },
 993          RPCResult{
 994              RPCResult::Type::OBJ, "", "",
 995              {
 996                  {RPCResult::Type::BOOL, "success", "whether the peer address was successfully added to the address manager table"},
 997                  {RPCResult::Type::STR, "error", /*optional=*/true, "error description, if the address could not be added"},
 998              },
 999          },
1000          RPCExamples{
1001              HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 8333 true")
1002      + HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 8333, true")
1003          },
1004          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
1005  {
1006      AddrMan& addrman = EnsureAnyAddrman(request.context);
1007  
1008      const std::string& addr_string{request.params[0].get_str()};
1009      const auto port{request.params[1].getInt<uint16_t>()};
1010      const bool tried{request.params[2].isNull() ? false : request.params[2].get_bool()};
1011  
1012      UniValue obj(UniValue::VOBJ);
1013      std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)};
1014      if (!net_addr.has_value()) {
1015          throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Invalid IP address");
1016      }
1017  
1018      bool success{false};
1019  
1020      CService service{net_addr.value(), port};
1021      CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
1022      address.nTime = Now<NodeSeconds>();
1023      // The source address is set equal to the address. This is equivalent to the peer
1024      // announcing itself.
1025      if (addrman.Add({address}, address)) {
1026          success = true;
1027          if (tried) {
1028              // Attempt to move the address to the tried addresses table.
1029              if (!addrman.Good(address)) {
1030                  success = false;
1031                  obj.pushKV("error", "failed-adding-to-tried");
1032              }
1033          }
1034      } else {
1035          obj.pushKV("error", "failed-adding-to-new");
1036      }
1037  
1038      obj.pushKV("success", success);
1039      return obj;
1040  },
1041      };
1042  }
1043  
1044  static RPCMethod sendmsgtopeer()
1045  {
1046      return RPCMethod{
1047          "sendmsgtopeer",
1048          "Send a p2p message to a peer specified by id.\n"
1049          "The message type and body must be provided, the message header will be generated.\n"
1050          "This RPC is for testing only.",
1051          {
1052              {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to send the message to."},
1053              {"msg_type", RPCArg::Type::STR, RPCArg::Optional::NO, strprintf("The message type (maximum length %i)", CMessageHeader::MESSAGE_TYPE_SIZE)},
1054              {"msg", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The serialized message body to send, in hex, without a message header"},
1055          },
1056          RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
1057          RPCExamples{
1058              HelpExampleCli("sendmsgtopeer", "0 \"addr\" \"ffffff\"") + HelpExampleRpc("sendmsgtopeer", "0 \"addr\" \"ffffff\"")},
1059          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
1060              const NodeId peer_id{request.params[0].getInt<int64_t>()};
1061              const auto msg_type{self.Arg<std::string_view>("msg_type")};
1062              if (msg_type.size() > CMessageHeader::MESSAGE_TYPE_SIZE) {
1063                  throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Error: msg_type too long, max length is %i", CMessageHeader::MESSAGE_TYPE_SIZE));
1064              }
1065              auto msg{TryParseHex<unsigned char>(self.Arg<std::string_view>("msg"))};
1066              if (!msg.has_value()) {
1067                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Error parsing input for msg");
1068              }
1069  
1070              NodeContext& node = EnsureAnyNodeContext(request.context);
1071              CConnman& connman = EnsureConnman(node);
1072  
1073              CSerializedNetMsg msg_ser;
1074              msg_ser.data = msg.value();
1075              msg_ser.m_type = msg_type;
1076  
1077              bool success = connman.ForNode(peer_id, [&](CNode* node) {
1078                  connman.PushMessage(node, std::move(msg_ser));
1079                  return true;
1080              });
1081  
1082              if (!success) {
1083                  throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not send message to peer");
1084              }
1085  
1086              UniValue ret{UniValue::VOBJ};
1087              return ret;
1088          },
1089      };
1090  }
1091  
1092  static RPCMethod getaddrmaninfo()
1093  {
1094      return RPCMethod{
1095          "getaddrmaninfo",
1096          "Provides information about the node's address manager by returning the number of "
1097          "addresses in the `new` and `tried` tables and their sum for all networks.\n",
1098          {},
1099          RPCResult{
1100              RPCResult::Type::OBJ_DYN, "", "json object with network type as keys", {
1101                  {RPCResult::Type::OBJ, "network", "the network (" + Join(GetNetworkNames(), ", ") + ", all_networks)", {
1102                  {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."},
1103                  {RPCResult::Type::NUM, "tried", "number of addresses in the tried table, which represent peers the node has successfully connected to in the past."},
1104                  {RPCResult::Type::NUM, "total", "total number of addresses in both new/tried tables"},
1105              }},
1106          }},
1107          RPCExamples{HelpExampleCli("getaddrmaninfo", "") + HelpExampleRpc("getaddrmaninfo", "")},
1108          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
1109              AddrMan& addrman = EnsureAnyAddrman(request.context);
1110  
1111              UniValue ret(UniValue::VOBJ);
1112              for (int n = 0; n < NET_MAX; ++n) {
1113                  enum Network network = static_cast<enum Network>(n);
1114                  if (network == NET_UNROUTABLE || network == NET_INTERNAL) continue;
1115                  UniValue obj(UniValue::VOBJ);
1116                  obj.pushKV("new", addrman.Size(network, true));
1117                  obj.pushKV("tried", addrman.Size(network, false));
1118                  obj.pushKV("total", addrman.Size(network));
1119                  ret.pushKV(GetNetworkName(network), std::move(obj));
1120              }
1121              UniValue obj(UniValue::VOBJ);
1122              obj.pushKV("new", addrman.Size(std::nullopt, true));
1123              obj.pushKV("tried", addrman.Size(std::nullopt, false));
1124              obj.pushKV("total", addrman.Size());
1125              ret.pushKV("all_networks", std::move(obj));
1126              return ret;
1127          },
1128      };
1129  }
1130  
1131  static RPCMethod exportasmap()
1132  {
1133      return RPCMethod{
1134          "exportasmap",
1135          "Export the embedded ASMap data to a file. Any existing file at the path will be overwritten.\n",
1136          {
1137              {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
1138          },
1139          RPCResult{
1140              RPCResult::Type::OBJ, "", "",
1141              {
1142                  {RPCResult::Type::STR, "path", "the absolute path that the ASMap data was written to"},
1143                  {RPCResult::Type::NUM, "bytes_written", "the number of bytes written to the file"},
1144                  {RPCResult::Type::STR_HEX, "file_hash", "the SHA256 hash of the exported ASMap data"},
1145              }
1146          },
1147          RPCExamples{
1148              HelpExampleCli("exportasmap", "\"asmap.dat\"") + HelpExampleRpc("exportasmap", "\"asmap.dat\"")},
1149          [&](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
1150  #ifndef ENABLE_EMBEDDED_ASMAP
1151              throw JSONRPCError(RPC_MISC_ERROR, "No embedded ASMap data available");
1152  #else
1153              if (node::data::ip_asn.empty() || !CheckStandardAsmap(node::data::ip_asn)) {
1154                  throw JSONRPCError(RPC_MISC_ERROR, "Embedded ASMap data appears to be corrupted");
1155              }
1156  
1157              const ArgsManager& args{EnsureAnyArgsman(request.context)};
1158              const fs::path export_path{fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(self.Arg<std::string_view>("path")))};
1159  
1160              AutoFile file{fsbridge::fopen(export_path, "wb")};
1161              if (file.IsNull()) {
1162                  throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to open asmap file: %s", fs::PathToString(export_path)));
1163              }
1164  
1165              file << node::data::ip_asn;
1166  
1167              if (file.fclose() != 0) {
1168                  throw JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to close asmap file: %s", fs::PathToString(export_path)));
1169              }
1170  
1171              HashWriter hasher;
1172              hasher.write(node::data::ip_asn);
1173  
1174              UniValue result(UniValue::VOBJ);
1175              result.pushKV("path", export_path.utf8string());
1176              result.pushKV("bytes_written", node::data::ip_asn.size());
1177              result.pushKV("file_hash", HexStr(hasher.GetSHA256()));
1178              return result;
1179  #endif
1180          },
1181      };
1182  }
1183  
1184  UniValue AddrmanEntryToJSON(const AddrInfo& info, const CConnman& connman)
1185  {
1186      UniValue ret(UniValue::VOBJ);
1187      ret.pushKV("address", info.ToStringAddr());
1188      const uint32_t mapped_as{connman.GetMappedAS(info)};
1189      if (mapped_as) {
1190          ret.pushKV("mapped_as", mapped_as);
1191      }
1192      ret.pushKV("port", info.GetPort());
1193      ret.pushKV("services", static_cast<std::underlying_type_t<decltype(info.nServices)>>(info.nServices));
1194      ret.pushKV("time", TicksSinceEpoch<std::chrono::seconds>(info.nTime));
1195      ret.pushKV("network", GetNetworkName(info.GetNetClass()));
1196      ret.pushKV("source", info.source.ToStringAddr());
1197      ret.pushKV("source_network", GetNetworkName(info.source.GetNetClass()));
1198      const uint32_t source_mapped_as{connman.GetMappedAS(info.source)};
1199      if (source_mapped_as) {
1200          ret.pushKV("source_mapped_as", source_mapped_as);
1201      }
1202      return ret;
1203  }
1204  
1205  UniValue AddrmanTableToJSON(const std::vector<std::pair<AddrInfo, AddressPosition>>& tableInfos, const CConnman& connman)
1206  {
1207      UniValue table(UniValue::VOBJ);
1208      for (const auto& e : tableInfos) {
1209          AddrInfo info = e.first;
1210          AddressPosition location = e.second;
1211          std::ostringstream key;
1212          key << location.bucket << "/" << location.position;
1213          // Address manager tables have unique entries so there is no advantage
1214          // in using UniValue::pushKV, which checks if the key already exists
1215          // in O(N). UniValue::pushKVEnd is used instead which currently is O(1).
1216          table.pushKVEnd(key.str(), AddrmanEntryToJSON(info, connman));
1217      }
1218      return table;
1219  }
1220  
1221  static RPCMethod getrawaddrman()
1222  {
1223      return RPCMethod{"getrawaddrman",
1224          "EXPERIMENTAL warning: this call may be changed in future releases.\n"
1225          "\nReturns information on all address manager entries for the new and tried tables.\n",
1226          {},
1227          RPCResult{
1228              RPCResult::Type::OBJ_DYN, "", "", {
1229                  {RPCResult::Type::OBJ_DYN, "table", "buckets with addresses in the address manager table ( new, tried )", {
1230                      {RPCResult::Type::OBJ, "bucket/position", "the location in the address manager table (<bucket>/<position>)", {
1231                          {RPCResult::Type::STR, "address", "The address of the node"},
1232                          {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)"},
1233                          {RPCResult::Type::NUM, "port", "The port number of the node"},
1234                          {RPCResult::Type::STR, "network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the address"},
1235                          {RPCResult::Type::NUM, "services", "The services offered by the node"},
1236                          {RPCResult::Type::NUM_TIME, "time", "The " + UNIX_EPOCH_TIME + " when the node was last seen"},
1237                          {RPCResult::Type::STR, "source", "The address that relayed the address to us"},
1238                          {RPCResult::Type::STR, "source_network", "The network (" + Join(GetNetworkNames(), ", ") + ") of the source address"},
1239                          {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)"}
1240                      }}
1241                  }}
1242              }
1243          },
1244          RPCExamples{
1245              HelpExampleCli("getrawaddrman", "")
1246              + HelpExampleRpc("getrawaddrman", "")
1247          },
1248          [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
1249              AddrMan& addrman = EnsureAnyAddrman(request.context);
1250              NodeContext& node_context = EnsureAnyNodeContext(request.context);
1251              CConnman& connman = EnsureConnman(node_context);
1252  
1253              UniValue ret(UniValue::VOBJ);
1254              ret.pushKV("new", AddrmanTableToJSON(addrman.GetEntries(false), connman));
1255              ret.pushKV("tried", AddrmanTableToJSON(addrman.GetEntries(true), connman));
1256              return ret;
1257          },
1258      };
1259  }
1260  
1261  void RegisterNetRPCCommands(CRPCTable& t)
1262  {
1263      static const CRPCCommand commands[]{
1264          {"network", &getconnectioncount},
1265          {"network", &ping},
1266          {"network", &getpeerinfo},
1267          {"network", &addnode},
1268          {"network", &disconnectnode},
1269          {"network", &getaddednodeinfo},
1270          {"network", &getnettotals},
1271          {"network", &getnetworkinfo},
1272          {"network", &setban},
1273          {"network", &listbanned},
1274          {"network", &clearbanned},
1275          {"network", &setnetworkactive},
1276          {"network", &getnodeaddresses},
1277          {"network", &getaddrmaninfo},
1278          {"network", &exportasmap},
1279          {"hidden", &addconnection},
1280          {"hidden", &addpeeraddress},
1281          {"hidden", &sendmsgtopeer},
1282          {"hidden", &getrawaddrman},
1283      };
1284      for (const auto& c : commands) {
1285          t.appendCommand(c.name, &c);
1286      }
1287  }
1288