From db4d2c282afd46709792aaf2d36ffbfc1745b776 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Thu, 1 Apr 2021 10:46:20 +0200 Subject: cli: create AddrinfoRequestHandler class --- src/bitcoin-cli.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 4f3d7a4ffe..3b0caef39a 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -42,6 +42,7 @@ static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; static const bool DEFAULT_NAMED=false; static const int CONTINUE_EXECUTION=-1; +static constexpr int8_t UNKNOWN_NETWORK{-1}; /** Default number of blocks to generate for RPC generatetoaddress. */ static const std::string DEFAULT_NBLOCKS = "1"; @@ -228,6 +229,56 @@ public: virtual UniValue ProcessReply(const UniValue &batch_in) = 0; }; +/** Process addrinfo requests */ +class AddrinfoRequestHandler : public BaseRequestHandler +{ +private: + static constexpr uint8_t m_networks_size{5}; + const std::array m_networks{{"ipv4", "ipv6", "torv2", "torv3", "i2p"}}; + int8_t NetworkStringToId(const std::string& str) const + { + for (uint8_t i = 0; i < m_networks_size; ++i) { + if (str == m_networks.at(i)) return i; + } + return UNKNOWN_NETWORK; + } + +public: + UniValue PrepareRequest(const std::string& method, const std::vector& args) override + { + if (!args.empty()) { + throw std::runtime_error("-addrinfo takes no arguments"); + } + UniValue params{RPCConvertValues("getnodeaddresses", std::vector{{"0"}})}; + return JSONRPCRequestObj("getnodeaddresses", params, 1); + } + + UniValue ProcessReply(const UniValue& reply) override + { + // Count the number of peers we know by network, including torv2 versus torv3. + std::array counts{{}}; + for (const UniValue& node : reply["result"].getValues()) { + std::string network_name{node["network"].get_str()}; + if (network_name == "onion") { + network_name = node["address"].get_str().size() > 22 ? "torv3" : "torv2"; + } + const int8_t network_id{NetworkStringToId(network_name)}; + if (network_id == UNKNOWN_NETWORK) continue; + ++counts.at(network_id); + } + // Prepare result to return to user. + UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ}; + uint64_t total{0}; // Total address count + for (uint8_t i = 0; i < m_networks_size; ++i) { + addresses.pushKV(m_networks.at(i), counts.at(i)); + total += counts.at(i); + } + addresses.pushKV("total", total); + result.pushKV("addresses_known", addresses); + return JSONRPCReplyObj(result, NullUniValue, 1); + } +}; + /** Process getinfo requests */ class GetinfoRequestHandler: public BaseRequestHandler { @@ -299,7 +350,6 @@ public: class NetinfoRequestHandler : public BaseRequestHandler { private: - static constexpr int8_t UNKNOWN_NETWORK{-1}; static constexpr uint8_t m_networks_size{4}; static constexpr uint8_t MAX_DETAIL_LEVEL{4}; const std::array m_networks{{"ipv4", "ipv6", "onion", "i2p"}}; -- cgit v1.2.3 From 5056a37624b64588b277419f7ed8c325477a8ec7 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 4 Apr 2021 16:20:47 +0200 Subject: cli: add -addrinfo command --- src/bitcoin-cli.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 3b0caef39a..2f7e49eccb 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -60,6 +60,7 @@ static void SetupCliArgs(ArgsManager& argsman) argsman.AddArg("-conf=", strprintf("Specify configuration file. Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-datadir=", "Specify data directory", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 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: bitcoin-cli -generate 4 1000", DEFAULT_NBLOCKS, DEFAULT_MAX_TRIES), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); + argsman.AddArg("-addrinfo", "Get the number of addresses known to the node, per network and total.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 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); 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); @@ -964,6 +965,8 @@ static int CommandLineRPC(int argc, char *argv[]) } else { ParseError(error, strPrint, nRet); } + } else if (gArgs.GetBoolArg("-addrinfo", false)) { + rh.reset(new AddrinfoRequestHandler()); } else { rh.reset(new DefaultRequestHandler()); if (args.size() < 1) { -- cgit v1.2.3 From bb85cbc4f7638a85049658ed951a0e06e7959cd4 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 4 Apr 2021 18:02:44 +0200 Subject: doc: add cli -addrinfo release note --- doc/release-notes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/release-notes.md b/doc/release-notes.md index 4ef94cf754..f4d2794d31 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -132,6 +132,12 @@ Changes to Wallet or GUI related settings can be found in the GUI or Wallet sect Tools and Utilities ------------------- +- A new CLI `-addrinfo` command returns the number of addresses known to the + node per network type (including Tor v2 versus v3) and total. This can be + useful to see if the node knows enough addresses in a network to use options + like `-onlynet=` or to upgrade to current and future Tor releases + that support Tor v3 addresses only. (#21595) + Wallet ------ -- cgit v1.2.3 From edf3167151f7a6d08cf733b4e230e2d745819ac8 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Fri, 9 Apr 2021 09:40:57 +0200 Subject: addrinfo: raise helpfully on server error or incompatible server version --- src/bitcoin-cli.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 2f7e49eccb..2b541be83e 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -256,9 +256,14 @@ public: UniValue ProcessReply(const UniValue& reply) override { + if (!reply["error"].isNull()) return reply; + const std::vector& nodes{reply["result"].getValues()}; + if (!nodes.empty() && nodes.at(0)["network"].isNull()) { + throw std::runtime_error("-addrinfo requires bitcoind server to be running v22.0 and up"); + } // Count the number of peers we know by network, including torv2 versus torv3. std::array counts{{}}; - for (const UniValue& node : reply["result"].getValues()) { + for (const UniValue& node : nodes) { std::string network_name{node["network"].get_str()}; if (network_name == "onion") { network_name = node["address"].get_str().size() > 22 ? "torv3" : "torv2"; -- cgit v1.2.3 From 06c43201a714b0426cc68b2fd5c681e5df10af99 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Tue, 20 Apr 2021 10:19:31 +0200 Subject: cli: use C++17 std::array class template argument deduction (CTAD) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Credit to João Barbosa (promag) for the suggestions. Co-authored-by: João Barbosa --- src/bitcoin-cli.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index 2b541be83e..4a4710ea3a 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -234,11 +234,10 @@ public: class AddrinfoRequestHandler : public BaseRequestHandler { private: - static constexpr uint8_t m_networks_size{5}; - const std::array m_networks{{"ipv4", "ipv6", "torv2", "torv3", "i2p"}}; + static constexpr std::array m_networks{"ipv4", "ipv6", "torv2", "torv3", "i2p"}; int8_t NetworkStringToId(const std::string& str) const { - for (uint8_t i = 0; i < m_networks_size; ++i) { + for (size_t i = 0; i < m_networks.size(); ++i) { if (str == m_networks.at(i)) return i; } return UNKNOWN_NETWORK; @@ -262,7 +261,7 @@ public: throw std::runtime_error("-addrinfo requires bitcoind server to be running v22.0 and up"); } // Count the number of peers we know by network, including torv2 versus torv3. - std::array counts{{}}; + std::array counts{{}}; for (const UniValue& node : nodes) { std::string network_name{node["network"].get_str()}; if (network_name == "onion") { @@ -275,7 +274,7 @@ public: // Prepare result to return to user. UniValue result{UniValue::VOBJ}, addresses{UniValue::VOBJ}; uint64_t total{0}; // Total address count - for (uint8_t i = 0; i < m_networks_size; ++i) { + for (size_t i = 0; i < m_networks.size(); ++i) { addresses.pushKV(m_networks.at(i), counts.at(i)); total += counts.at(i); } @@ -356,15 +355,14 @@ public: class NetinfoRequestHandler : public BaseRequestHandler { private: - static constexpr uint8_t m_networks_size{4}; static constexpr uint8_t MAX_DETAIL_LEVEL{4}; - const std::array m_networks{{"ipv4", "ipv6", "onion", "i2p"}}; - std::array, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total) + static constexpr std::array m_networks{"ipv4", "ipv6", "onion", "i2p"}; + std::array, 3> m_counts{{{}}}; //!< Peer counts by (in/out/total, networks/total) uint8_t m_block_relay_peers_count{0}; uint8_t m_manual_peers_count{0}; int8_t NetworkStringToId(const std::string& str) const { - for (uint8_t i = 0; i < m_networks_size; ++i) { + for (size_t i = 0; i < m_networks.size(); ++i) { if (str == m_networks.at(i)) return i; } return UNKNOWN_NETWORK; @@ -461,10 +459,10 @@ public: const bool is_outbound{!peer["inbound"].get_bool()}; const bool is_block_relay{!peer["relaytxes"].get_bool()}; const std::string conn_type{peer["connection_type"].get_str()}; - ++m_counts.at(is_outbound).at(network_id); // in/out by network - ++m_counts.at(is_outbound).at(m_networks_size); // in/out overall - ++m_counts.at(2).at(network_id); // total by network - ++m_counts.at(2).at(m_networks_size); // total overall + ++m_counts.at(is_outbound).at(network_id); // in/out by network + ++m_counts.at(is_outbound).at(m_networks.size()); // in/out overall + ++m_counts.at(2).at(network_id); // total by network + ++m_counts.at(2).at(m_networks.size()); // total overall if (conn_type == "block-relay-only") ++m_block_relay_peers_count; if (conn_type == "manual") ++m_manual_peers_count; if (DetailsRequested()) { @@ -534,11 +532,11 @@ public: if (any_i2p_peers) result += " i2p"; result += " total block"; if (m_manual_peers_count) result += " manual"; - const std::array rows{{"in", "out", "total"}}; + const std::array rows{"in", "out", "total"}; for (uint8_t i = 0; i < 3; ++i) { result += strprintf("\n%-5s %5i %5i %5i", rows.at(i), m_counts.at(i).at(0), m_counts.at(i).at(1), m_counts.at(i).at(2)); // ipv4/ipv6/onion peers counts if (any_i2p_peers) result += strprintf(" %5i", m_counts.at(i).at(3)); // i2p peers count - result += strprintf(" %5i", m_counts.at(i).at(m_networks_size)); // total peers count + result += strprintf(" %5i", m_counts.at(i).at(m_networks.size())); // total peers count if (i == 1) { // the outbound row has two extra columns for block relay and manual peer counts result += strprintf(" %5i", m_block_relay_peers_count); if (m_manual_peers_count) result += strprintf(" %5i", m_manual_peers_count); -- cgit v1.2.3