net.cpp raw

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