-
Notifications
You must be signed in to change notification settings - Fork 37.7k
[rpc] Add getnodeaddresses RPC command #13152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Concept ACK, this would indeed be useful. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not extend getpeerinfo
?
src/rpc/net.cpp
Outdated
UniValue ret(UniValue::VARR); | ||
|
||
int address_return_count = std::min(count, (int)vAddr.size()); | ||
for(int i = 0; i < address_return_count; ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, space after for
.
src/rpc/net.cpp
Outdated
"getaddress ( count )\n" | ||
"\nReturn known addresses which can potentially be used to find new nodes in the network\n" | ||
"\nArguments:\n" | ||
"1. \"count\" (numeric, optional) How many addresses to return, if available (default = 1)\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not return all?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning all would typically result in a massive json array with thousands of entries, about 2500 or so depending. Normally applications only need to connect to a few nodes, they don't need anywhere near that many.
At least it can test arguments (valid and invalid) and result format and fields (their presence and types). |
I think this call should be called differently.
You misunderstand what this does. It doesn't return currently conneced nodes, but potentially connectable addresses. |
a5e0fc8
to
892daca
Compare
Renamed to Looks like something went wrong with the rebase and now other people's commits are involved too. Does anyone know how I can fix this. (edit: fixed)
I think in the test suite the node won't know about any other addresses, so this RPC will return an empty json object, so it can't be tested. What would be the best way around this? Maybe to populate the |
a28d1cf
to
c83ccf7
Compare
Fixed git weirdness (thanks to viasil). |
Please rename PR. |
Does getnodeaddresses command return a list of reachable nodes in the network known by a node? like the result of getaddr message? is getaddress/getnodeaddresses RPC command currently available in v0.16.0rc4? |
@MasterGrad17 Yes the result is very similar as from the p2p getaddr method. The addresses come from gossiping between nodes, so the IP address may be reachable but that isn't guaranteed. |
@MasterGrad17 You're commenting on the request to get it merged into Bitcoin Core, so obviously no. |
src/rpc/net.cpp
Outdated
" \"time\": ttt, (numeric) Address timestamp in seconds since epoch (Jan 1 1970 GMT)\n" | ||
" \"services\": n, (numeric) The services offered\n" | ||
" \"servicesHex\": \"xxxxxxxxxxxxxxxx\", (string) The hex string of services offered\n" | ||
" \"addr\": \"host\", (string) The IP address of the peer\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: could also be a tor address
src/rpc/net.cpp
Outdated
CAddress addr = vAddr[i]; | ||
obj.pushKV("time", (int)addr.nTime); | ||
obj.pushKV("services", addr.nServices); | ||
obj.pushKV("servicesHex", strprintf("%016x", addr.nServices)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be handy to have a string representation here. Like ("NODE_NETWORK | NODE_NETWORK_LIMITED | NODE_BLOOM"
, etc.). But can be done later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost utACK c83ccf7.
Please rename command.
Maybe listpeeraddresses()
@jonasschnelli |
Good point. |
|
Yes, I intentionally avoided 'peer' in my suggested name for that reason, as it's easy to confuse and a lot of people confused it already. Also let's stop asking the guy to rename his RPC call :) |
73f046d
to
9e6cac2
Compare
Fixed nit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few nits inline.
You should be able to test this in the functional test framework as follows:
- start a node
- add a P2PConnection to the node
- send a msg_addr to the node with some addresses
- call the new
getnodeaddresses
RPC - assert that the node addresses returned are the same as those sent in the p2p ADDR message.
Take a look at example_test.py for some pointers on how to write test cases. I think it makes sense to add this new test case to the rpc_net.py script.
Feel free to reach me on irc (jnewbery) if you need any pointers.
src/rpc/net.cpp
Outdated
"getnodeaddresses ( count )\n" | ||
"\nReturn known addresses which can potentially be used to find new nodes in the network\n" | ||
"\nArguments:\n" | ||
"1. \"count\" (numeric, optional) How many addresses to return, if available (default = 1)\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should document that the maximum number of nodes to return is:
- 2500 (due to
ADDRMAN_GETADDR_MAX
inCAddrMan::GetAddr_()
); or - 23% of all known nodes.
(whichever is smaller)
src/rpc/net.cpp
Outdated
"\nResult:\n" | ||
"[\n" | ||
" {\n" | ||
" \"time\": ttt, (numeric) Address timestamp in seconds since epoch (Jan 1 1970 GMT)\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does 'address timestamp' mean here?
src/rpc/net.cpp
Outdated
" {\n" | ||
" \"time\": ttt, (numeric) Address timestamp in seconds since epoch (Jan 1 1970 GMT)\n" | ||
" \"services\": n, (numeric) The services offered\n" | ||
" \"servicesHex\": \"xxxxxxxxxxxxxxxx\", (string) The hex string of services offered\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return fields should be named in camel_case
src/rpc/net.cpp
Outdated
" \"time\": ttt, (numeric) Address timestamp in seconds since epoch (Jan 1 1970 GMT)\n" | ||
" \"services\": n, (numeric) The services offered\n" | ||
" \"servicesHex\": \"xxxxxxxxxxxxxxxx\", (string) The hex string of services offered\n" | ||
" \"addr\": \"host\", (string) The address of the peer\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer to name this address
. No need to save characters!
src/rpc/net.cpp
Outdated
"[\n" | ||
" {\n" | ||
" \"time\": ttt, (numeric) Address timestamp in seconds since epoch (Jan 1 1970 GMT)\n" | ||
" \"services\": n, (numeric) The services offered\n" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is useful. Services is a bitfield. Displaying it as an int doesn't give any useful information to the user. Just display the hex version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends on what 'the user' is. Programmatic RPC users will want the int, not have to do an additional step of parsing a hex string (though I don't care deeply in this case, just be mindful that manual command-line users are not the only clients of the RPC interface).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
be mindful that manual command-line users are not the only clients of the RPC interface
Yes good point. In general though, I think we should avoid RPCs returning the same data in multiple formats.
9e6cac2
to
f0aca19
Compare
f0aca19
to
dd7e1e6
Compare
Fixed nits and created a test in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New test is great. Thanks for adding it!
A few nits inline. Feel free to take or leave them.
src/rpc/net.cpp
Outdated
@@ -624,6 +624,55 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) | |||
return g_connman->GetNetworkActive(); | |||
} | |||
|
|||
UniValue getnodeaddresses(const JSONRPCRequest& request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should be static
test/functional/rpc_net.py
Outdated
@@ -16,6 +17,8 @@ | |||
p2p_port, | |||
wait_until, | |||
) | |||
from test_framework.mininode import P2PInterface, network_thread_start |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: sort imports (in PEP-8 ordering)
test/functional/rpc_net.py
Outdated
for a in imported_addrs: | ||
addr = CAddress() | ||
addr.time = now | ||
addr.services = NODE_NETWORK | NODE_WITNESS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be nServices
test/functional/rpc_net.py
Outdated
self.nodes[0].p2p.wait_for_verack() | ||
|
||
# send some addresses to the node via the p2p message addr | ||
imported_addrs = set(["123.123." + str(i//255) + "." + str(i%255) for i in range(1000)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: move this into the range loop below and use string formatters rather than concatenation:
# send some addresses to the node via the p2p message addr
now = int(time.time())
msg = msg_addr()
imported_addrs = []
for i in range(1000):
a = "123.123.{}.{}".format(i // 255, i % 256)
imported_addrs.append(a)
addr = CAddress()
...
test/functional/rpc_net.py
Outdated
NODE_ADDRESSES_REQUEST_COUNT = 10 | ||
node_addresses = self.nodes[0].getnodeaddresses(NODE_ADDRESSES_REQUEST_COUNT) | ||
assert len(node_addresses) == NODE_ADDRESSES_REQUEST_COUNT | ||
assert set([addr["address"] for addr in node_addresses]).issubset(imported_addrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: drop the set comparisons, loop over the return items and test all fields, eg:
for a in node_addresses:
assert a["address"] in imported_addrs
assert_equal(a["services"], NODE_NETWORK | NODE_WITNESS)
assert_equal(a["time"], now)
assert_equal(a["port"], 8333)
c131694
to
a3fd879
Compare
a3fd879
to
b3512ba
Compare
b3512ba
to
8b96ebe
Compare
Looks good to me, utACK 8b96ebe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to nit at this late stage. Thanks so much for sticking with this. I know it's taken a long time!
One tiny code-style change and I think this is ready for merge.
src/rpc/net.cpp
Outdated
if (!request.params[0].isNull()) { | ||
count = request.params[0].get_int(); | ||
if (count <= 0) | ||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Address count out of range"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really sorry to code-style nit when this PR has been through so much review, but all then clauses should be in braces or on the same line (https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#coding-style-c)
test/functional/rpc_net.py
Outdated
assert_equal(len(node_addresses), REQUEST_COUNT) | ||
for a in node_addresses: | ||
# the timestamps are usually offset by a few hours, so only check existence | ||
assert "time" in a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, can be removed — since @jnewbery nit'ed
New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method. Tests the new rpc call by feeding IP address to a test node via the p2p protocol, then obtaining someone of those addresses with getnodeaddresses and checking that they are a subset.
8b96ebe
to
a2eb6f5
Compare
Fixed those nits |
utACK a2eb6f5 |
1 similar comment
utACK a2eb6f5 |
utACK a2eb6f5. Please fix PR description: "New getaddress call gives ..." |
a2eb6f5 [rpc] Add getnodeaddresses RPC command (chris-belcher) Pull request description: Implements issue bitcoin#9463 New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method. Please advise me on the best approach for writing an automated test. By my reading the getaddr p2p method also isn't really tested. Tree-SHA512: ad03abf518847476495b76a2f5394b8030aa86654429167fa618e21460abb505c10ef9817ec1b80472320d41d0aff5dc94a8efce023aaaaf5e81386aa92b852b
a2eb6f5 [rpc] Add getnodeaddresses RPC command (chris-belcher) Pull request description: Implements issue bitcoin#9463 New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method. Please advise me on the best approach for writing an automated test. By my reading the getaddr p2p method also isn't really tested. Tree-SHA512: ad03abf518847476495b76a2f5394b8030aa86654429167fa618e21460abb505c10ef9817ec1b80472320d41d0aff5dc94a8efce023aaaaf5e81386aa92b852b # Conflicts: # src/rpc/client.cpp # src/rpc/net.cpp
a2eb6f5 [rpc] Add getnodeaddresses RPC command (chris-belcher) Pull request description: Implements issue bitcoin#9463 New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method. Please advise me on the best approach for writing an automated test. By my reading the getaddr p2p method also isn't really tested. Tree-SHA512: ad03abf518847476495b76a2f5394b8030aa86654429167fa618e21460abb505c10ef9817ec1b80472320d41d0aff5dc94a8efce023aaaaf5e81386aa92b852b
a2eb6f5 [rpc] Add getnodeaddresses RPC command (chris-belcher) Pull request description: Implements issue bitcoin#9463 New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method. Please advise me on the best approach for writing an automated test. By my reading the getaddr p2p method also isn't really tested. Tree-SHA512: ad03abf518847476495b76a2f5394b8030aa86654429167fa618e21460abb505c10ef9817ec1b80472320d41d0aff5dc94a8efce023aaaaf5e81386aa92b852b
This reverts commit 54e38eca Signed-off-by: pasta <pasta@dashboost.org>
e9d28da [Doc] Document getnodeaddresses in release notes (Fuzzbawls) ebe2a46 test: improve getnodeaddresses coverage, test by network (Fuzzbawls) 91ac5c7 rpc: enable filtering getnodeaddresses by network (Fuzzbawls) badfc49 p2p: allow CConnman::GetAddresses() by network, add doxygen (Fuzzbawls) fa78233 p2p: allow CAddrMan::GetAddr() by network, add doxygen (Fuzzbawls) a4d2733 p2p: pull time call out of loop in CAddrMan::GetAddr_() (Fuzzbawls) d5c1250 p2p: enable CAddrMan::GetAddr_() by network, add doxygen (Fuzzbawls) 67e2c2f [RPC] add network field to getnodeaddresses (Fuzzbawls) b4832b2 [Net] Add addpeeraddress RPC method (Fuzzbawls) 1a31b67 [test] Test that getnodeaddresses() can return all known addresses (Fuzzbawls) e83fd0e [Addrman] Specify max addresses and pct when calling GetAddresses() (Fuzzbawls) 792655d [RPC] Add getnodeaddresses RPC command (chris-belcher) Pull request description: Implement a new RPC command (`getnodeaddresses`) that provides RPC access to the node's addrman. It may be useful for PIVX wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. I've included upstream improvements to this feature here as well, and this RPC command was used to scrape the Tor v3 hardcoded seed nodes added in #2502 --------- Based on the following upstream PRs: * bitcoin#13152 * bitcoin#19658 * bitcoin#21594 * bitcoin#21843 ACKs for top commit: furszy: all good, tested ACK e9d28da. random-zebra: utACK e9d28da and merging... Tree-SHA512: 2e50108504ac8e172c2e31eb64813d6aae6b6819cf197eace2e4e15686906708b2f82262909faad00ce64af0f61945089a36b857064d3ce2398b3acb14e4ad7d
Implements issue #9463
New getnodeaddresses call gives access via RPC to the peers known by the node. It may be useful for bitcoin wallets to broadcast their transactions over tor for improved privacy without using the centralized DNS seeds. getnodeaddresses is very similar to the getaddr p2p method.
Please advise me on the best approach for writing an automated test. By my reading the getaddr p2p method also isn't really tested.