Coverage Report

Created: 2026-07-23 20:35

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