Skip to content

Commit 1f4e26b

Browse files
laanwjPastaPastaPasta
authored andcommitted
Merge bitcoin#21595: cli: create -addrinfo
06c4320 cli: use C++17 std::array class template argument deduction (CTAD) (Jon Atack) edf3167 addrinfo: raise helpfully on server error or incompatible server version (Jon Atack) bb85cbc doc: add cli -addrinfo release note (Jon Atack) 5056a37 cli: add -addrinfo command (Jon Atack) db4d2c2 cli: create AddrinfoRequestHandler class (Jon Atack) Pull request description: While looking at issue bitcoin#21351, it turned out that the problem was a lack of tor v3 addresses known to the node. It became clear (e.g. bitcoin#21351 (comment)) that a CLI command returning the number of addresses the node knows per network (with a tor v2 / v3 breakdown) would be very helpful. This patch adds that. `-addrinfo` is useful to see if your node knows enough addresses in a network to use options like `-onlynet=<network>`, or to upgrade to the upcoming tor release that no longer supports tor v2, for which you'll need to be sure your node knows enough tor v3 peers. ``` $ bitcoin-cli --help | grep -A1 addrinfo -addrinfo Get the number of addresses known to the node, per network and total. $ bitcoin-cli -addrinfo { "addresses_known": { "ipv4": 14406, "ipv6": 2511, "torv2": 5563, "torv3": 2842, "i2p": 8, "total": 25330 } } $ bitcoin-cli -addrinfo 1 error: -addrinfo takes no arguments ``` This can be manually tested, for example, with commands like this: ``` $ bitcoin-cli getnodeaddresses 0 | jq '.[] | (select(.address | contains(".onion")) | select(.address | length <= 22)) | .address' | wc -l 5563 $ bitcoin-cli getnodeaddresses 0 | jq '.[] | (select(.address | contains(".onion")) | select(.address | length > 22)) | .address' | wc -l 2842 $ bitcoin-cli getnodeaddresses 0 | jq '.[] | .address' | wc -l 25330 ``` ACKs for top commit: laanwj: Tested ACK 06c4320 Tree-SHA512: b668b47718a4ce052aff218789f3da629bca730592c18fcce9a51034d95a0a65f8e6da33dd47443cdd8f60c056c02696db175b0fe09a688e4385a76c1d8b7aeb
1 parent 6a45e72 commit 1f4e26b

File tree

2 files changed

+79
-14
lines changed

2 files changed

+79
-14
lines changed

doc/release-notes-21595.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Tools and Utilities
2+
-------------------
3+
4+
- A new CLI `-addrinfo` command returns the number of addresses known to the
5+
node per network type (including Tor v2 versus v3) and total. This can be
6+
useful to see if the node knows enough addresses in a network to use options
7+
like `-onlynet=<network>` or to upgrade to current and future Tor releases
8+
that support Tor v3 addresses only. (#5904)
9+

src/bitcoin-cli.cpp

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
4646
static constexpr int DEFAULT_WAIT_CLIENT_TIMEOUT = 0;
4747
static const bool DEFAULT_NAMED=false;
4848
static const int CONTINUE_EXECUTION=-1;
49+
static constexpr int8_t UNKNOWN_NETWORK{-1};
4950

5051
/** Default number of blocks to generate for RPC generatetoaddress. */
5152
static const std::string DEFAULT_NBLOCKS = "1";
@@ -62,6 +63,7 @@ static void SetupCliArgs(ArgsManager& argsman)
6263
argsman.AddArg("-conf=<file>", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
6364
argsman.AddArg("-datadir=<dir>", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
6465
argsman.AddArg("-generate", strprintf("Generate blocks immediately, equivalent to RPC getnewaddress followed by RPC generatetoaddress. Optional positional integer arguments are number of blocks to generate (default: %s) and maximum iterations to try (default: %s), equivalent to RPC generatetoaddress nblocks and maxtries arguments. Example: dash-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
66+
argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
6567
argsman.AddArg("-getinfo", "Get general information from the remote server. Note that unlike server-side RPC calls, the results of -getinfo is the result of multiple non-atomic requests. Some entries in the result may represent results from different states (e.g. wallet balance may be as of a different block from the chain state reported)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
6668
argsman.AddArg("-netinfo", "Get network peer connection information from the remote server. An optional integer argument from 0 to 4 can be passed for different peers listings (default: 0). Pass \"help\" for detailed help documentation.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
6769
argsman.AddArg("-named", strprintf("Pass named instead of positional arguments (default: %s)", DEFAULT_NAMED), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -243,6 +245,60 @@ class BaseRequestHandler
243245
virtual UniValue ProcessReply(const UniValue &batch_in) = 0;
244246
};
245247

248+
/** Process addrinfo requests */
249+
class AddrinfoRequestHandler : public BaseRequestHandler
250+
{
251+
private:
252+
static constexpr std::array m_networks{"ipv4", "ipv6", "torv2", "torv3", "i2p"};
253+
int8_t NetworkStringToId(const std::string& str) const
254+
{
255+
for (size_t i = 0; i < m_networks.size(); ++i) {
256+
if (str == m_networks.at(i)) return i;
257+
}
258+
return UNKNOWN_NETWORK;
259+
}
260+
261+
public:
262+
UniValue PrepareRequest(const std::string& method, const std::vector<std::string>& args) override
263+
{
264+
if (!args.empty()) {
265+
throw std::runtime_error("-addrinfo takes no arguments");
266+
}
267+
UniValue params{RPCConvertValues("getnodeaddresses", std::vector<std::string>{{"0"}})};
268+
return JSONRPCRequestObj("getnodeaddresses", params, 1);
269+
}
270+
271+
UniValue ProcessReply(const UniValue& reply) override
272+
{
273+
if (!reply["error"].isNull()) return reply;
274+
const std::vector<UniValue>& nodes{reply["result"].getValues()};
275+
if (!nodes.empty() && nodes.at(0)["network"].isNull()) {
276+
throw std::runtime_error("-addrinfo requires dashd server to be running v21.0 and up");
277+
}
278+
// Count the number of peers we know by network, including torv2 versus torv3.
279+
std::array<uint64_t, m_networks.size()> counts{{}};
280+
for (const UniValue& node : nodes) {
281+
std::string network_name{node["network"].get_str()};
282+
if (network_name == "onion") {
283+
network_name = node["address"].get_str().size() > 22 ? "torv3" : "torv2";
284+
}
285+
const int8_t network_id{NetworkStringToId(network_name)};
286+
if (network_id == UNKNOWN_NETWORK) continue;
287+
++counts.at(network_id);
288+
}
289+
// Prepare result to return to user.
290+
UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ};
291+
uint64_t total{0}; // Total address count
292+
for (size_t i = 0; i < m_networks.size(); ++i) {
293+
addresses.pushKV(m_networks.at(i), counts.at(i));
294+
total += counts.at(i);
295+
}
296+
addresses.pushKV("total", total);
297+
result.pushKV("addresses_known", addresses);
298+
return JSONRPCReplyObj(result, NullUniValue, 1);
299+
}
300+
};
301+
246302
/** Process getinfo requests */
247303
class GetinfoRequestHandler: public BaseRequestHandler
248304
{
@@ -318,14 +374,12 @@ class GetinfoRequestHandler: public BaseRequestHandler
318374
class NetinfoRequestHandler : public BaseRequestHandler
319375
{
320376
private:
321-
static constexpr int8_t UNKNOWN_NETWORK{-1};
322-
static constexpr uint8_t m_networks_size{3};
323377
static constexpr uint8_t MAX_DETAIL_LEVEL{4};
324-
const std::array<std::string, m_networks_size> m_networks{{"ipv4", "ipv6", "onion"}};
325-
std::array<std::array<uint16_t, m_networks_size + 2>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total/block-relay)
378+
static constexpr std::array m_networks{"ipv4", "ipv6", "onion"};
379+
std::array<std::array<uint16_t, m_networks.size() + 2>, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total/block-relay)
326380
int8_t NetworkStringToId(const std::string& str) const
327381
{
328-
for (uint8_t i = 0; i < m_networks_size; ++i) {
382+
for (size_t i = 0; i < m_networks.size(); ++i) {
329383
if (str == m_networks.at(i)) return i;
330384
}
331385
return UNKNOWN_NETWORK;
@@ -472,13 +526,13 @@ class NetinfoRequestHandler : public BaseRequestHandler
472526
if (network_id == UNKNOWN_NETWORK) continue;
473527
const bool is_outbound{!peer["inbound"].get_bool()};
474528
const bool is_block_relay{!peer["relaytxes"].get_bool()};
475-
++m_counts.at(is_outbound).at(network_id); // in/out by network
476-
++m_counts.at(is_outbound).at(m_networks_size); // in/out overall
477-
++m_counts.at(2).at(network_id); // total by network
478-
++m_counts.at(2).at(m_networks_size); // total overall
529+
++m_counts.at(is_outbound).at(network_id); // in/out by network
530+
++m_counts.at(is_outbound).at(m_networks.size()); // in/out overall
531+
++m_counts.at(2).at(network_id); // total by network
532+
++m_counts.at(2).at(m_networks.size()); // total overall
479533
if (is_block_relay) {
480-
++m_counts.at(is_outbound).at(m_networks_size + 1); // in/out block-relay
481-
++m_counts.at(2).at(m_networks_size + 1); // total block-relay
534+
++m_counts.at(is_outbound).at(m_networks.size() + 1); // in/out block-relay
535+
++m_counts.at(2).at(m_networks.size() + 1); // total block-relay
482536
}
483537
if (DetailsRequested()) {
484538
// Push data for this peer to the peers vector.
@@ -540,9 +594,9 @@ class NetinfoRequestHandler : public BaseRequestHandler
540594

541595
// Report peer connection totals by type.
542596
result += " ipv4 ipv6 onion total block-relay\n";
543-
const std::array<std::string, 3> rows{{"in", "out", "total"}};
544-
for (uint8_t i = 0; i < m_networks_size; ++i) {
545-
result += strprintf("%-5s %5i %5i %5i %5i %5i\n", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2), m_counts.at(i).at(m_networks_size), m_counts.at(i).at(m_networks_size + 1));
597+
const std::array rows{"in", "out", "total"};
598+
for (uint8_t i = 0; i < m_networks.size(); ++i) {
599+
result += strprintf("%-5s %5i %5i %5i %5i %5i\n", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2), m_counts.at(i).at(m_networks.size()), m_counts.at(i).at(m_networks.size() + 1));
546600
}
547601

548602
// Report local addresses, ports, and scores.
@@ -909,6 +963,8 @@ static int CommandLineRPC(int argc, char *argv[])
909963
} else {
910964
ParseError(error, strPrint, nRet);
911965
}
966+
} else if (gArgs.GetBoolArg("-addrinfo", false)) {
967+
rh.reset(new AddrinfoRequestHandler());
912968
} else {
913969
rh.reset(new DefaultRequestHandler());
914970
if (args.size() < 1) {

0 commit comments

Comments
 (0)