Coverage Report

Created: 2026-07-29 23:27

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