Skip to content

Commit ff3497c

Browse files
committed
merge bitcoin#21843: enable GetAddr, GetAddresses, and getnodeaddresses by network
continuation of cf27db8 from dash#5491 includes: - 6c98c09 - 3f89c0e - ce6bca8
1 parent 51edeb0 commit ff3497c

File tree

3 files changed

+45
-22
lines changed

3 files changed

+45
-22
lines changed

doc/release-notes-5978.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ RPC changes
33

44
- The `getnodeaddresses` RPC now returns a "network" field indicating the
55
network type (ipv4, ipv6, onion, or i2p) for each address.
6+
7+
- `getnodeaddresses` now also accepts a "network" argument (ipv4, ipv6, onion,
8+
or i2p) to return only addresses of the specified network.

src/rpc/net.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ static RPCHelpMan getnodeaddresses()
904904
"\nReturn known addresses, which can potentially be used to find new nodes in the network.\n",
905905
{
906906
{"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."},
907+
{"network", RPCArg::Type::STR, /* default */ "all networks", "Return only addresses of the specified network. Can be one of: " + Join(GetNetworkNames(), ", ") + "."},
907908
},
908909
RPCResult{
909910
RPCResult::Type::ARR, "", "",
@@ -920,7 +921,10 @@ static RPCHelpMan getnodeaddresses()
920921
},
921922
RPCExamples{
922923
HelpExampleCli("getnodeaddresses", "8")
923-
+ HelpExampleRpc("getnodeaddresses", "8")
924+
+ HelpExampleCli("getnodeaddresses", "4 \"i2p\"")
925+
+ HelpExampleCli("-named getnodeaddresses", "network=onion count=12")
926+
+ HelpExampleRpc("getnodeaddresses", "8")
927+
+ HelpExampleRpc("getnodeaddresses", "4, \"i2p\"")
924928
},
925929
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
926930
{
@@ -932,8 +936,13 @@ static RPCHelpMan getnodeaddresses()
932936
const int count{request.params[0].isNull() ? 1 : request.params[0].get_int()};
933937
if (count < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range");
934938

939+
const std::optional<Network> network{request.params[1].isNull() ? std::nullopt : std::optional<Network>{ParseNetwork(request.params[1].get_str())}};
940+
if (network == NET_UNROUTABLE) {
941+
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Network not recognized: %s", request.params[1].get_str()));
942+
}
943+
935944
// returns a shuffled list of CAddress
936-
const std::vector<CAddress> vAddr{node.connman->GetAddresses(count, /* max_pct */ 0, /* network */ std::nullopt)};
945+
const std::vector<CAddress> vAddr{node.connman->GetAddresses(count, /* max_pct */ 0, network)};
937946
UniValue ret(UniValue::VARR);
938947

939948
for (const CAddress& addr : vAddr) {
@@ -1020,7 +1029,7 @@ static const CRPCCommand commands[] =
10201029
{ "network", "clearbanned", &clearbanned, {} },
10211030
{ "network", "cleardiscouraged", &cleardiscouraged, {} },
10221031
{ "network", "setnetworkactive", &setnetworkactive, {"state"} },
1023-
{ "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
1032+
{ "network", "getnodeaddresses", &getnodeaddresses, {"count", "network"} },
10241033

10251034
{ "hidden", "addconnection", &addconnection, {"address", "connection_type"} },
10261035
{ "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },

test/functional/rpc_net.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -204,43 +204,54 @@ def test_service_flags(self):
204204
def test_getnodeaddresses(self):
205205
self.log.info("Test getnodeaddresses")
206206
self.nodes[0].add_p2p_connection(P2PInterface())
207+
services = NODE_NETWORK
207208

208-
# Add some addresses to the Address Manager over RPC. Due to the way
209-
# bucket and bucket position are calculated, some of these addresses
210-
# will collide.
209+
# Add an IPv6 address to the address manager.
210+
ipv6_addr = "1233:3432:2434:2343:3234:2345:6546:4534"
211+
self.nodes[0].addpeeraddress(address=ipv6_addr, port=8333)
212+
213+
# Add 10,000 IPv4 addresses to the address manager. Due to the way bucket
214+
# and bucket positions are calculated, some of these addresses will collide.
211215
imported_addrs = []
212216
for i in range(10000):
213217
first_octet = i >> 8
214218
second_octet = i % 256
215-
a = "{}.{}.1.1".format(first_octet, second_octet) # IPV4
219+
a = f"{first_octet}.{second_octet}.1.1"
216220
imported_addrs.append(a)
217221
self.nodes[0].addpeeraddress(a, 8333)
218222

219-
# Obtain addresses via rpc call and check they were ones sent in before.
220-
#
221-
# Maximum possible addresses in addrman is 10000, although actual
222-
# number will usually be less due to bucket and bucket position
223-
# collisions.
224-
node_addresses = self.nodes[0].getnodeaddresses(0)
223+
# Fetch the addresses via the RPC and test the results.
224+
assert_equal(len(self.nodes[0].getnodeaddresses()), 1) # default count is 1
225+
assert_equal(len(self.nodes[0].getnodeaddresses(count=2)), 2)
226+
assert_equal(len(self.nodes[0].getnodeaddresses(network="ipv4", count=8)), 8)
227+
228+
# Maximum possible addresses in AddrMan is 10000. The actual number will
229+
# usually be less due to bucket and bucket position collisions.
230+
node_addresses = self.nodes[0].getnodeaddresses(0, "ipv4")
225231
assert_greater_than(len(node_addresses), 5000)
226232
assert_greater_than(10000, len(node_addresses))
227233
for a in node_addresses:
228234
assert_equal(a["time"], self.mocktime)
229-
assert_equal(a["services"], NODE_NETWORK)
235+
assert_equal(a["services"], services)
230236
assert a["address"] in imported_addrs
231237
assert_equal(a["port"], 8333)
232238
assert_equal(a["network"], "ipv4")
233239

234-
node_addresses = self.nodes[0].getnodeaddresses(1)
235-
assert_equal(len(node_addresses), 1)
240+
# Test the IPv6 address.
241+
res = self.nodes[0].getnodeaddresses(0, "ipv6")
242+
assert_equal(len(res), 1)
243+
assert_equal(res[0]["address"], ipv6_addr)
244+
assert_equal(res[0]["network"], "ipv6")
245+
assert_equal(res[0]["port"], 8333)
246+
assert_equal(res[0]["services"], services)
236247

237-
assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1)
248+
# Test for the absence of onion and I2P addresses.
249+
for network in ["onion", "i2p"]:
250+
assert_equal(self.nodes[0].getnodeaddresses(0, network), [])
238251

239-
# addrman's size cannot be known reliably after insertion, as hash collisions may occur
240-
# so only test that requesting a large number of addresses returns less than that
241-
LARGE_REQUEST_COUNT = 10000
242-
node_addresses = self.nodes[0].getnodeaddresses(LARGE_REQUEST_COUNT)
243-
assert_greater_than(LARGE_REQUEST_COUNT, len(node_addresses))
252+
# Test invalid arguments.
253+
assert_raises_rpc_error(-8, "Address count out of range", self.nodes[0].getnodeaddresses, -1)
254+
assert_raises_rpc_error(-8, "Network not recognized: Foo", self.nodes[0].getnodeaddresses, 1, "Foo")
244255

245256

246257
if __name__ == '__main__':

0 commit comments

Comments
 (0)