Coverage Report

Created: 2026-10-07 13:27

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