Coverage Report

Created: 2026-09-14 20:36

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