Coverage Report

Created: 2026-08-25 19:22

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