Coverage Report

Created: 2026-04-29 19:21

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