From d35ddca91ebbcf8d8b790c3b9f8cf218fafb7a53 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 2 May 2021 18:44:17 +0200 Subject: p2p: enable CAddrMan::GetAddr_() by network, add doxygen --- src/addrman.cpp | 14 +++++++++++--- src/addrman.h | 12 ++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index f91121f156..ae2f1c23a2 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -7,9 +7,11 @@ #include #include +#include #include #include +#include int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector &asmap) const { @@ -481,7 +483,7 @@ int CAddrMan::Check_() } #endif -void CAddrMan::GetAddr_(std::vector& vAddr, size_t max_addresses, size_t max_pct) +void CAddrMan::GetAddr_(std::vector& vAddr, size_t max_addresses, size_t max_pct, std::optional network) { size_t nNodes = vRandom.size(); if (max_pct != 0) { @@ -501,8 +503,14 @@ void CAddrMan::GetAddr_(std::vector& vAddr, size_t max_addresses, size assert(mapInfo.count(vRandom[n]) == 1); const CAddrInfo& ai = mapInfo[vRandom[n]]; - if (!ai.IsTerrible()) - vAddr.push_back(ai); + + // Filter by network (optional) + if (network != std::nullopt && ai.GetNetClass() != network) continue; + + // Filter for quality + if (ai.IsTerrible()) continue; + + vAddr.push_back(ai); } } diff --git a/src/addrman.h b/src/addrman.h index 92a5570953..cf059478a5 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -278,8 +279,15 @@ protected: int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs); #endif - //! Select several addresses at once. - void GetAddr_(std::vector &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs); + /** + * Return all or many randomly selected addresses, optionally by network. + * + * @param[out] vAddr Vector of randomly selected addresses from vRandom. + * @param[in] max_addresses Maximum number of addresses to return (0 = all). + * @param[in] max_pct Maximum percentage of addresses to return (0 = all). + * @param[in] network Select only addresses of this network (nullopt = all). + */ + void GetAddr_(std::vector& vAddr, size_t max_addresses, size_t max_pct, std::optional network = std::nullopt) EXCLUSIVE_LOCKS_REQUIRED(cs); /** We have successfully connected to this peer. Calling this function * updates the CAddress's nTime, which is used in our IsTerrible() -- cgit v1.2.3 From c38981e748f438d972ba12ba998c8a8a597e01c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 12 May 2021 16:53:25 +0200 Subject: p2p: pull time call out of loop in CAddrMan::GetAddr_() --- src/addrman.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/addrman.cpp b/src/addrman.cpp index ae2f1c23a2..ceab1689d7 100644 --- a/src/addrman.cpp +++ b/src/addrman.cpp @@ -494,6 +494,7 @@ void CAddrMan::GetAddr_(std::vector& vAddr, size_t max_addresses, size } // gather a list of random nodes, skipping those of low quality + const int64_t now{GetAdjustedTime()}; for (unsigned int n = 0; n < vRandom.size(); n++) { if (vAddr.size() >= nNodes) break; @@ -508,7 +509,7 @@ void CAddrMan::GetAddr_(std::vector& vAddr, size_t max_addresses, size if (network != std::nullopt && ai.GetNetClass() != network) continue; // Filter for quality - if (ai.IsTerrible()) continue; + if (ai.IsTerrible(now)) continue; vAddr.push_back(ai); } -- cgit v1.2.3 From a49f3ddbbabfb971a537f0a6c7affb24e20ff192 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 2 May 2021 19:03:49 +0200 Subject: p2p: allow CAddrMan::GetAddr() by network, add doxygen --- src/addrman.h | 14 ++++++++++---- src/bench/addrman.cpp | 3 ++- src/net.cpp | 2 +- src/test/addrman_tests.cpp | 13 +++++++------ src/test/fuzz/addrman.cpp | 5 ++++- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/addrman.h b/src/addrman.h index cf059478a5..eaedfd318c 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -287,7 +287,7 @@ protected: * @param[in] max_pct Maximum percentage of addresses to return (0 = all). * @param[in] network Select only addresses of this network (nullopt = all). */ - void GetAddr_(std::vector& vAddr, size_t max_addresses, size_t max_pct, std::optional network = std::nullopt) EXCLUSIVE_LOCKS_REQUIRED(cs); + void GetAddr_(std::vector& vAddr, size_t max_addresses, size_t max_pct, std::optional network) EXCLUSIVE_LOCKS_REQUIRED(cs); /** We have successfully connected to this peer. Calling this function * updates the CAddress's nTime, which is used in our IsTerrible() @@ -723,14 +723,20 @@ public: return addrRet; } - //! Return a bunch of addresses, selected at random. - std::vector GetAddr(size_t max_addresses, size_t max_pct) + /** + * Return all or many randomly selected addresses, optionally by network. + * + * @param[in] max_addresses Maximum number of addresses to return (0 = all). + * @param[in] max_pct Maximum percentage of addresses to return (0 = all). + * @param[in] network Select only addresses of this network (nullopt = all). + */ + std::vector GetAddr(size_t max_addresses, size_t max_pct, std::optional network) { Check(); std::vector vAddr; { LOCK(cs); - GetAddr_(vAddr, max_addresses, max_pct); + GetAddr_(vAddr, max_addresses, max_pct, network); } Check(); return vAddr; diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp index ebdad5a4b8..b7bd8a3261 100644 --- a/src/bench/addrman.cpp +++ b/src/bench/addrman.cpp @@ -7,6 +7,7 @@ #include #include +#include #include /* A "source" is a source address from which we have received a bunch of other addresses. */ @@ -98,7 +99,7 @@ static void AddrManGetAddr(benchmark::Bench& bench) FillAddrMan(addrman); bench.run([&] { - const auto& addresses = addrman.GetAddr(2500, 23); + const auto& addresses = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt); assert(addresses.size() > 0); }); } diff --git a/src/net.cpp b/src/net.cpp index 909b7622e3..dfdf9eb8fa 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2671,7 +2671,7 @@ CConnman::~CConnman() std::vector CConnman::GetAddresses(size_t max_addresses, size_t max_pct) const { - std::vector addresses = addrman.GetAddr(max_addresses, max_pct); + std::vector addresses = addrman.GetAddr(max_addresses, max_pct, /* network */ std::nullopt); if (m_banman) { addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}), diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index d438537606..49b40924e0 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -12,6 +12,7 @@ #include +#include #include class CAddrManTest : public CAddrMan @@ -392,7 +393,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) // Test: Sanity check, GetAddr should never return anything if addrman // is empty. BOOST_CHECK_EQUAL(addrman.size(), 0U); - std::vector vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */0); + std::vector vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt); BOOST_CHECK_EQUAL(vAddr1.size(), 0U); CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE); @@ -415,15 +416,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) BOOST_CHECK(addrman.Add(addr4, source2)); BOOST_CHECK(addrman.Add(addr5, source1)); - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0).size(), 5U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U); // Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down. - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23).size(), 1U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U); // Test: Ensure GetAddr works with new and tried addresses. addrman.Good(CAddress(addr1, NODE_NONE)); addrman.Good(CAddress(addr2, NODE_NONE)); - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0).size(), 5U); - BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23).size(), 1U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U); + BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U); // Test: Ensure GetAddr still returns 23% when addrman has many addrs. for (unsigned int i = 1; i < (8 * 256); i++) { @@ -438,7 +439,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) if (i % 8 == 0) addrman.Good(addr); } - std::vector vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23); + std::vector vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt); size_t percent23 = (addrman.size() * 23) / 100; BOOST_CHECK_EQUAL(vAddr.size(), percent23); diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index 0baf30aef6..98ae32a8d0 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -60,7 +60,10 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman) (void)addr_man.Select(fuzzed_data_provider.ConsumeBool()); }, [&] { - (void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange(0, 4096)); + (void)addr_man.GetAddr( + /* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange(0, 4096), + /* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange(0, 4096), + /* network */ std::nullopt); }, [&] { const std::optional opt_address = ConsumeDeserializable(fuzzed_data_provider); -- cgit v1.2.3 From 80ba294854e5025bcada58f1403858e6ea1d4380 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 2 May 2021 19:05:42 +0200 Subject: p2p: allow CConnman::GetAddresses() by network, add doxygen --- src/net.cpp | 7 ++++--- src/net.h | 9 ++++++++- src/net_processing.cpp | 2 +- src/rpc/net.cpp | 4 +++- src/test/fuzz/connman.cpp | 10 ++++++++-- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index dfdf9eb8fa..1322c971fb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -2669,9 +2670,9 @@ CConnman::~CConnman() Stop(); } -std::vector CConnman::GetAddresses(size_t max_addresses, size_t max_pct) const +std::vector CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional network) const { - std::vector addresses = addrman.GetAddr(max_addresses, max_pct, /* network */ std::nullopt); + std::vector addresses = addrman.GetAddr(max_addresses, max_pct, network); if (m_banman) { addresses.erase(std::remove_if(addresses.begin(), addresses.end(), [this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}), @@ -2691,7 +2692,7 @@ std::vector CConnman::GetAddresses(CNode& requestor, size_t max_addres auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{}); CachedAddrResponse& cache_entry = r.first->second; if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0. - cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct); + cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct, /* network */ std::nullopt); // Choosing a proper cache lifetime is a trade-off between the privacy leak minimization // and the usefulness of ADDR responses to honest users. // diff --git a/src/net.h b/src/net.h index 65b262e573..28f2d9ace6 100644 --- a/src/net.h +++ b/src/net.h @@ -923,7 +923,14 @@ public: }; // Addrman functions - std::vector GetAddresses(size_t max_addresses, size_t max_pct) const; + /** + * Return all or many randomly selected addresses, optionally by network. + * + * @param[in] max_addresses Maximum number of addresses to return (0 = all). + * @param[in] max_pct Maximum percentage of addresses to return (0 = all). + * @param[in] network Select only addresses of this network (nullopt = all). + */ + std::vector GetAddresses(size_t max_addresses, size_t max_pct, std::optional network) const; /** * Cache is used to minimize topology leaks, so it should * be used for all non-trusted calls, for example, p2p. diff --git a/src/net_processing.cpp b/src/net_processing.cpp index fdd36835c2..cee2419610 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3586,7 +3586,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, pfrom.vAddrToSend.clear(); std::vector vAddr; if (pfrom.HasPermission(NetPermissionFlags::Addr)) { - vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND); + vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND, /* network */ std::nullopt); } else { vAddr = m_connman.GetAddresses(pfrom, MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 1f6b6e8d7e..18e4355e88 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include const std::vector CONNECTION_TYPE_DOC{ @@ -878,7 +880,7 @@ static RPCHelpMan getnodeaddresses() if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); // returns a shuffled list of CAddress - const std::vector vAddr{connman.GetAddresses(count, /* max_pct */ 0)}; + const std::vector vAddr{connman.GetAddresses(count, /* max_pct */ 0, /* network */ std::nullopt)}; UniValue ret(UniValue::VARR); for (const CAddress& addr : vAddr) { diff --git a/src/test/fuzz/connman.cpp b/src/test/fuzz/connman.cpp index e07f25dedf..3e9998af30 100644 --- a/src/test/fuzz/connman.cpp +++ b/src/test/fuzz/connman.cpp @@ -71,10 +71,16 @@ FUZZ_TARGET_INIT(connman, initialize_connman) (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); }); }, [&] { - (void)connman.GetAddresses(fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral()); + (void)connman.GetAddresses( + /* max_addresses */ fuzzed_data_provider.ConsumeIntegral(), + /* max_pct */ fuzzed_data_provider.ConsumeIntegral(), + /* network */ std::nullopt); }, [&] { - (void)connman.GetAddresses(random_node, fuzzed_data_provider.ConsumeIntegral(), fuzzed_data_provider.ConsumeIntegral()); + (void)connman.GetAddresses( + /* requestor */ random_node, + /* max_addresses */ fuzzed_data_provider.ConsumeIntegral(), + /* max_pct */ fuzzed_data_provider.ConsumeIntegral()); }, [&] { (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral()); -- cgit v1.2.3 From 6c98c099918bd20e2d3aa123643d6e3594e080e4 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 2 May 2021 17:15:25 +0200 Subject: rpc: enable filtering getnodeaddresses by network --- src/rpc/net.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 18e4355e88..07b085ce74 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -853,6 +853,7 @@ static RPCHelpMan getnodeaddresses() "\nReturn known addresses, which can potentially be used to find new nodes in the network.\n", { {"count", RPCArg::Type::NUM, RPCArg::Default{1}, "The maximum number of addresses to return. Specify 0 to return all known addresses."}, + {"network", RPCArg::Type::STR, RPCArg::DefaultHint{"all networks"}, "Return only addresses of the specified network. Can be one of: " + Join(GetNetworkNames(), ", ") + "."}, }, RPCResult{ RPCResult::Type::ARR, "", "", @@ -869,7 +870,10 @@ static RPCHelpMan getnodeaddresses() }, RPCExamples{ HelpExampleCli("getnodeaddresses", "8") - + HelpExampleRpc("getnodeaddresses", "8") + + HelpExampleCli("getnodeaddresses", "4 \"i2p\"") + + HelpExampleCli("-named getnodeaddresses", "network=onion count=12") + + HelpExampleRpc("getnodeaddresses", "8") + + HelpExampleRpc("getnodeaddresses", "4, \"i2p\"") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -879,8 +883,13 @@ static RPCHelpMan getnodeaddresses() const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()}; if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); + const std::optional network{request.params[1].isNull() ? std::nullopt : std::optional{ParseNetwork(request.params[1].get_str())}}; + if (network == NET_UNROUTABLE) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str())); + } + // returns a shuffled list of CAddress - const std::vector vAddr{connman.GetAddresses(count, /* max_pct */ 0, /* network */ std::nullopt)}; + const std::vector vAddr{connman.GetAddresses(count, /* max_pct */ 0, network)}; UniValue ret(UniValue::VARR); for (const CAddress& addr : vAddr) { -- cgit v1.2.3 From 3f89c0e9902338ad8a507a938dceeeb3191eece6 Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Sun, 2 May 2021 19:42:29 +0200 Subject: test: improve getnodeaddresses coverage, test by network --- test/functional/rpc_net.py | 49 ++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 16d7958712..2a58f8b3f7 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -187,43 +187,54 @@ class NetTest(BitcoinTestFramework): def test_getnodeaddresses(self): self.log.info("Test getnodeaddresses") self.nodes[0].add_p2p_connection(P2PInterface()) + services = NODE_NETWORK | NODE_WITNESS - # Add some addresses to the Address Manager over RPC. Due to the way - # bucket and bucket position are calculated, some of these addresses - # will collide. + # Add an IPv6 address to the address manager. + ipv6_addr = "1233:3432:2434:2343:3234:2345:6546:4534" + self.nodes[0].addpeeraddress(address=ipv6_addr, port=8333) + + # Add 10,000 IPv4 addresses to the address manager. Due to the way bucket + # and bucket positions are calculated, some of these addresses will collide. imported_addrs = [] for i in range(10000): first_octet = i >> 8 second_octet = i % 256 - a = "{}.{}.1.1".format(first_octet, second_octet) # IPV4 + a = f"{first_octet}.{second_octet}.1.1" imported_addrs.append(a) self.nodes[0].addpeeraddress(a, 8333) - # Obtain addresses via rpc call and check they were ones sent in before. - # - # Maximum possible addresses in addrman is 10000, although actual - # number will usually be less due to bucket and bucket position - # collisions. - node_addresses = self.nodes[0].getnodeaddresses(0) + # Fetch the addresses via the RPC and test the results. + assert_equal(len(self.nodes[0].getnodeaddresses()), 1) # default count is 1 + assert_equal(len(self.nodes[0].getnodeaddresses(count=2)), 2) + assert_equal(len(self.nodes[0].getnodeaddresses(network="ipv4", count=8)), 8) + + # Maximum possible addresses in AddrMan is 10000. The actual number will + # usually be less due to bucket and bucket position collisions. + node_addresses = self.nodes[0].getnodeaddresses(0, "ipv4") assert_greater_than(len(node_addresses), 5000) assert_greater_than(10000, len(node_addresses)) for a in node_addresses: assert_greater_than(a["time"], 1527811200) # 1st June 2018 - assert_equal(a["services"], NODE_NETWORK | NODE_WITNESS) + assert_equal(a["services"], services) assert a["address"] in imported_addrs assert_equal(a["port"], 8333) assert_equal(a["network"], "ipv4") - node_addresses = self.nodes[0].getnodeaddresses(1) - assert_equal(len(node_addresses), 1) + # Test the IPv6 address. + res = self.nodes[0].getnodeaddresses(0, "ipv6") + assert_equal(len(res), 1) + assert_equal(res[0]["address"], ipv6_addr) + assert_equal(res[0]["network"], "ipv6") + assert_equal(res[0]["port"], 8333) + assert_equal(res[0]["services"], services) - assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1) + # Test for the absence of onion and I2P addresses. + for network in ["onion", "i2p"]: + assert_equal(self.nodes[0].getnodeaddresses(0, network), []) - # addrman's size cannot be known reliably after insertion, as hash collisions may occur - # so only test that requesting a large number of addresses returns less than that - LARGE_REQUEST_COUNT = 10000 - node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT) - assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses)) + # Test invalid arguments. + assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1) + assert_raises_rpc_error(-8, "Network not recognized: Foo", self.nodes[0].getnodeaddresses, 1, "Foo") if __name__ == '__main__': -- cgit v1.2.3 From ce6bca88e8c685c69686e0b8dc095ffc3e2ac34d Mon Sep 17 00:00:00 2001 From: Jon Atack Date: Mon, 3 May 2021 21:09:21 +0200 Subject: doc: release note for getnodeaddresses by network --- doc/release-notes.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index 5c70bc91db..53106c9f82 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -108,6 +108,12 @@ Updated RPCs Respectively, these new fields indicate the duration of a ban and the time remaining until a ban expires, both in seconds. Additionally, the `ban_created` field is repositioned to come before `banned_until`. (#21602) +- The `getnodeaddresses` RPC now returns a "network" field indicating the + network type (ipv4, ipv6, onion, or i2p) for each address. (#21594) + +- `getnodeaddresses` now also accepts a "network" argument (ipv4, ipv6, onion, + or i2p) to return only addresses of the specified network. (#21843) + Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section below. New RPCs @@ -130,9 +136,6 @@ Changes to Wallet or GUI related settings can be found in the GUI or Wallet sect - Passing an invalid `-rpcauth` argument now cause bitcoind to fail to start. (#20461) -- The `getnodeaddresses` RPC now returns a "network" field indicating the - network type (ipv4, ipv6, onion, or i2p) for each address. (#21594) - Tools and Utilities ------------------- -- cgit v1.2.3