Skip to content

Commit

Permalink
Merge bitcoin#21843: p2p, rpc: enable GetAddr, GetAddresses, and getn…
Browse files Browse the repository at this point in the history
…odeaddresses 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
  • Loading branch information
laanwj authored and vijaydasmp committed Feb 23, 2024
1 parent 28c07c0 commit 71bde60
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 20 deletions.
8 changes: 8 additions & 0 deletions doc/release-notes-21843.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Updated RPCs
------------------------
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)

1 change: 1 addition & 0 deletions src/bench/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <random.h>
#include <util/time.h>

#include <optional>
#include <vector>

/* A "source" is a source address from which we have received a bunch of other addresses. */
Expand Down
7 changes: 6 additions & 1 deletion src/rpc/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <version.h>
#include <warnings.h>

#include <optional>

#include <univalue.h>

const std::vector<std::string> CONNECTION_TYPE_DOC{
Expand Down Expand Up @@ -822,7 +824,10 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
},
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\"")
},
}.Check(request);
const NodeContext& node = EnsureAnyNodeContext(request.context);
Expand Down
1 change: 1 addition & 0 deletions src/test/addrman_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <boost/test/unit_test.hpp>

#include <optional>
#include <string>

class CAddrManTest : public CAddrMan
Expand Down
49 changes: 30 additions & 19 deletions test/functional/rpc_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,42 +190,53 @@ def test_service_flags(self):
def test_getnodeaddresses(self):
self.log.info("Test getnodeaddresses")
self.nodes[0].add_p2p_connection(P2PInterface())
services = NODE_NETWORK

# 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)
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_equal(a["time"], self.mocktime)
assert_equal(a["services"], NODE_NETWORK)
assert_equal(a["services"], services)
assert a["address"] in imported_addrs
assert_equal(a["port"], 8333)

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__':
Expand Down

0 comments on commit 71bde60

Please sign in to comment.