Coverage Report

Created: 2026-09-21 19:49

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