Skip to content

Commit 37e9f07

Browse files
committed
Merge bitcoin/bitcoin#21843: p2p, rpc: enable GetAddr, GetAddresses, and getnodeaddresses by network
ce6bca8 doc: release note for getnodeaddresses by network (Jon Atack) 3f89c0e test: improve getnodeaddresses coverage, test by network (Jon Atack) 6c98c09 rpc: enable filtering getnodeaddresses by network (Jon Atack) 80ba294 p2p: allow CConnman::GetAddresses() by network, add doxygen (Jon Atack) a49f3dd p2p: allow CAddrMan::GetAddr() by network, add doxygen (Jon Atack) c38981e p2p: pull time call out of loop in CAddrMan::GetAddr_() (João Barbosa) d35ddca p2p: enable CAddrMan::GetAddr_() by network, add doxygen (Jon Atack) Pull request description: This patch allows passing a network argument to CAddrMan::GetAddr(), CConnman::GetAddresses(), and rpc getnodeaddresses to return only addresses of that network. It also contains a performance optimisation by promag. ACKs for top commit: laanwj: Code review and lightly tested ACK ce6bca8 vasild: ACK ce6bca8 Tree-SHA512: 40e700d97091248429c73cbc0639a1f03ab7288e636a7b9026ad253e9708253c6b2ec98e7d9fb2d56136c0f762313dd648915ac98d723ee330d713813a43f99d
2 parents ea8b2e8 + ce6bca8 commit 37e9f07

File tree

12 files changed

+114
-47
lines changed

12 files changed

+114
-47
lines changed

doc/release-notes.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ Updated RPCs
108108
Respectively, these new fields indicate the duration of a ban and the time remaining until a ban expires,
109109
both in seconds. Additionally, the `ban_created` field is repositioned to come before `banned_until`. (#21602)
110110

111+
- The `getnodeaddresses` RPC now returns a "network" field indicating the
112+
network type (ipv4, ipv6, onion, or i2p) for each address. (#21594)
113+
114+
- `getnodeaddresses` now also accepts a "network" argument (ipv4, ipv6, onion,
115+
or i2p) to return only addresses of the specified network. (#21843)
116+
111117
Changes to Wallet or GUI related RPCs can be found in the GUI or Wallet section below.
112118

113119
New RPCs
@@ -130,9 +136,6 @@ Changes to Wallet or GUI related settings can be found in the GUI or Wallet sect
130136

131137
- Passing an invalid `-rpcauth` argument now cause bitcoind to fail to start. (#20461)
132138

133-
- The `getnodeaddresses` RPC now returns a "network" field indicating the
134-
network type (ipv4, ipv6, onion, or i2p) for each address. (#21594)
135-
136139
Tools and Utilities
137140
-------------------
138141

src/addrman.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77

88
#include <hash.h>
99
#include <logging.h>
10+
#include <netaddress.h>
1011
#include <serialize.h>
1112

1213
#include <cmath>
14+
#include <optional>
1315

1416
int CAddrInfo::GetTriedBucket(const uint256& nKey, const std::vector<bool> &asmap) const
1517
{
@@ -481,7 +483,7 @@ int CAddrMan::Check_()
481483
}
482484
#endif
483485

484-
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct)
486+
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network)
485487
{
486488
size_t nNodes = vRandom.size();
487489
if (max_pct != 0) {
@@ -492,6 +494,7 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
492494
}
493495

494496
// gather a list of random nodes, skipping those of low quality
497+
const int64_t now{GetAdjustedTime()};
495498
for (unsigned int n = 0; n < vRandom.size(); n++) {
496499
if (vAddr.size() >= nNodes)
497500
break;
@@ -501,8 +504,14 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
501504
assert(mapInfo.count(vRandom[n]) == 1);
502505

503506
const CAddrInfo& ai = mapInfo[vRandom[n]];
504-
if (!ai.IsTerrible())
505-
vAddr.push_back(ai);
507+
508+
// Filter by network (optional)
509+
if (network != std::nullopt && ai.GetNetClass() != network) continue;
510+
511+
// Filter for quality
512+
if (ai.IsTerrible(now)) continue;
513+
514+
vAddr.push_back(ai);
506515
}
507516
}
508517

src/addrman.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <hash.h>
2121
#include <iostream>
2222
#include <map>
23+
#include <optional>
2324
#include <set>
2425
#include <stdint.h>
2526
#include <streams.h>
@@ -278,8 +279,15 @@ friend class CAddrManTest;
278279
int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);
279280
#endif
280281

281-
//! Select several addresses at once.
282-
void GetAddr_(std::vector<CAddress> &vAddr, size_t max_addresses, size_t max_pct) EXCLUSIVE_LOCKS_REQUIRED(cs);
282+
/**
283+
* Return all or many randomly selected addresses, optionally by network.
284+
*
285+
* @param[out] vAddr Vector of randomly selected addresses from vRandom.
286+
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
287+
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
288+
* @param[in] network Select only addresses of this network (nullopt = all).
289+
*/
290+
void GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network) EXCLUSIVE_LOCKS_REQUIRED(cs);
283291

284292
/** We have successfully connected to this peer. Calling this function
285293
* updates the CAddress's nTime, which is used in our IsTerrible()
@@ -715,14 +723,20 @@ friend class CAddrManTest;
715723
return addrRet;
716724
}
717725

718-
//! Return a bunch of addresses, selected at random.
719-
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct)
726+
/**
727+
* Return all or many randomly selected addresses, optionally by network.
728+
*
729+
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
730+
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
731+
* @param[in] network Select only addresses of this network (nullopt = all).
732+
*/
733+
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network)
720734
{
721735
Check();
722736
std::vector<CAddress> vAddr;
723737
{
724738
LOCK(cs);
725-
GetAddr_(vAddr, max_addresses, max_pct);
739+
GetAddr_(vAddr, max_addresses, max_pct, network);
726740
}
727741
Check();
728742
return vAddr;

src/bench/addrman.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <random.h>
88
#include <util/time.h>
99

10+
#include <optional>
1011
#include <vector>
1112

1213
/* 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)
9899
FillAddrMan(addrman);
99100

100101
bench.run([&] {
101-
const auto& addresses = addrman.GetAddr(2500, 23);
102+
const auto& addresses = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt);
102103
assert(addresses.size() > 0);
103104
});
104105
}

src/net.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <crypto/sha256.h>
1717
#include <i2p.h>
1818
#include <net_permissions.h>
19+
#include <netaddress.h>
1920
#include <netbase.h>
2021
#include <node/ui_interface.h>
2122
#include <protocol.h>
@@ -2669,9 +2670,9 @@ CConnman::~CConnman()
26692670
Stop();
26702671
}
26712672

2672-
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct) const
2673+
std::vector<CAddress> CConnman::GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
26732674
{
2674-
std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct);
2675+
std::vector<CAddress> addresses = addrman.GetAddr(max_addresses, max_pct, network);
26752676
if (m_banman) {
26762677
addresses.erase(std::remove_if(addresses.begin(), addresses.end(),
26772678
[this](const CAddress& addr){return m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr);}),
@@ -2691,7 +2692,7 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
26912692
auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
26922693
CachedAddrResponse& cache_entry = r.first->second;
26932694
if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
2694-
cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct);
2695+
cache_entry.m_addrs_response_cache = GetAddresses(max_addresses, max_pct, /* network */ std::nullopt);
26952696
// Choosing a proper cache lifetime is a trade-off between the privacy leak minimization
26962697
// and the usefulness of ADDR responses to honest users.
26972698
//

src/net.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,14 @@ class CConnman
923923
};
924924

925925
// Addrman functions
926-
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct) const;
926+
/**
927+
* Return all or many randomly selected addresses, optionally by network.
928+
*
929+
* @param[in] max_addresses Maximum number of addresses to return (0 = all).
930+
* @param[in] max_pct Maximum percentage of addresses to return (0 = all).
931+
* @param[in] network Select only addresses of this network (nullopt = all).
932+
*/
933+
std::vector<CAddress> GetAddresses(size_t max_addresses, size_t max_pct, std::optional<Network> network) const;
927934
/**
928935
* Cache is used to minimize topology leaks, so it should
929936
* be used for all non-trusted calls, for example, p2p.

src/net_processing.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3586,7 +3586,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
35863586
pfrom.vAddrToSend.clear();
35873587
std::vector<CAddress> vAddr;
35883588
if (pfrom.HasPermission(NetPermissionFlags::Addr)) {
3589-
vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
3589+
vAddr = m_connman.GetAddresses(MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND, /* network */ std::nullopt);
35903590
} else {
35913591
vAddr = m_connman.GetAddresses(pfrom, MAX_ADDR_TO_SEND, MAX_PCT_ADDR_TO_SEND);
35923592
}

src/rpc/net.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <version.h>
2929
#include <warnings.h>
3030

31+
#include <optional>
32+
3133
#include <univalue.h>
3234

3335
const std::vector<std::string> CONNECTION_TYPE_DOC{
@@ -851,6 +853,7 @@ static RPCHelpMan getnodeaddresses()
851853
"\nReturn known addresses, which can potentially be used to find new nodes in the network.\n",
852854
{
853855
{"count", RPCArg::Type::NUM, RPCArg::Default{1}, "The maximum number of addresses to return. Specify 0 to return all known addresses."},
856+
{"network", RPCArg::Type::STR, RPCArg::DefaultHint{"all networks"}, "Return only addresses of the specified network. Can be one of: " + Join(GetNetworkNames(), ", ") + "."},
854857
},
855858
RPCResult{
856859
RPCResult::Type::ARR, "", "",
@@ -867,7 +870,10 @@ static RPCHelpMan getnodeaddresses()
867870
},
868871
RPCExamples{
869872
HelpExampleCli("getnodeaddresses", "8")
870-
+ HelpExampleRpc("getnodeaddresses", "8")
873+
+ HelpExampleCli("getnodeaddresses", "4 \"i2p\"")
874+
+ HelpExampleCli("-named getnodeaddresses", "network=onion count=12")
875+
+ HelpExampleRpc("getnodeaddresses", "8")
876+
+ HelpExampleRpc("getnodeaddresses", "4, \"i2p\"")
871877
},
872878
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
873879
{
@@ -877,8 +883,13 @@ static RPCHelpMan getnodeaddresses()
877883
const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()};
878884
if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
879885

886+
const std::optional<Network> network{request.params[1].isNull() ? std::nullopt : std::optional<Network>{ParseNetwork(request.params[1].get_str())}};
887+
if (network == NET_UNROUTABLE) {
888+
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str()));
889+
}
890+
880891
// returns a shuffled list of CAddress
881-
const std::vector<CAddress> vAddr{connman.GetAddresses(count, /* max_pct */ 0)};
892+
const std::vector<CAddress> vAddr{connman.GetAddresses(count, /* max_pct */ 0, network)};
882893
UniValue ret(UniValue::VARR);
883894

884895
for (const CAddress& addr : vAddr) {

src/test/addrman_tests.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <boost/test/unit_test.hpp>
1414

15+
#include <optional>
1516
#include <string>
1617

1718
class CAddrManTest : public CAddrMan
@@ -392,7 +393,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
392393
// Test: Sanity check, GetAddr should never return anything if addrman
393394
// is empty.
394395
BOOST_CHECK_EQUAL(addrman.size(), 0U);
395-
std::vector<CAddress> vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */0);
396+
std::vector<CAddress> vAddr1 = addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt);
396397
BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
397398

398399
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
@@ -415,15 +416,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
415416
BOOST_CHECK(addrman.Add(addr4, source2));
416417
BOOST_CHECK(addrman.Add(addr5, source1));
417418

418-
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0).size(), 5U);
419+
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U);
419420
// Net processing asks for 23% of addresses. 23% of 5 is 1 rounded down.
420-
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23).size(), 1U);
421+
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U);
421422

422423
// Test: Ensure GetAddr works with new and tried addresses.
423424
addrman.Good(CAddress(addr1, NODE_NONE));
424425
addrman.Good(CAddress(addr2, NODE_NONE));
425-
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0).size(), 5U);
426-
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23).size(), 1U);
426+
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 0, /* max_pct */ 0, /* network */ std::nullopt).size(), 5U);
427+
BOOST_CHECK_EQUAL(addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt).size(), 1U);
427428

428429
// Test: Ensure GetAddr still returns 23% when addrman has many addrs.
429430
for (unsigned int i = 1; i < (8 * 256); i++) {
@@ -438,7 +439,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
438439
if (i % 8 == 0)
439440
addrman.Good(addr);
440441
}
441-
std::vector<CAddress> vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23);
442+
std::vector<CAddress> vAddr = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt);
442443

443444
size_t percent23 = (addrman.size() * 23) / 100;
444445
BOOST_CHECK_EQUAL(vAddr.size(), percent23);

src/test/fuzz/addrman.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
6060
(void)addr_man.Select(fuzzed_data_provider.ConsumeBool());
6161
},
6262
[&] {
63-
(void)addr_man.GetAddr(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096), fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096));
63+
(void)addr_man.GetAddr(
64+
/* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
65+
/* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
66+
/* network */ std::nullopt);
6467
},
6568
[&] {
6669
const std::optional<CAddress> opt_address = ConsumeDeserializable<CAddress>(fuzzed_data_provider);

0 commit comments

Comments
 (0)