Skip to content

Conversation

chris-belcher
Copy link
Contributor

@chris-belcher chris-belcher commented May 2, 2018

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.

@laanwj
Copy link
Member

laanwj commented May 2, 2018

Concept ACK, this would indeed be useful.

Copy link
Contributor

@promag promag left a 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) {
Copy link
Contributor

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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not return all?

Copy link
Contributor Author

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.

@promag
Copy link
Contributor

promag commented May 2, 2018

Please advise me on the best approach for writing an automated test

At least it can test arguments (valid and invalid) and result format and fields (their presence and types).

@laanwj
Copy link
Member

laanwj commented May 2, 2018

I think this call should be called differently. getaddress is too easy to confuse with a bitcoin address (e.g. getnewaddress). Maybe getnodeaddresses?

Why not extend getpeerinfo?

You misunderstand what this does. It doesn't return currently conneced nodes, but potentially connectable addresses.

@chris-belcher chris-belcher force-pushed the 2018-04-rpc-getaddress branch from a5e0fc8 to 892daca Compare May 2, 2018 14:11
@chris-belcher
Copy link
Contributor Author

chris-belcher commented May 2, 2018

Renamed to getnodeaddresses and fixed nits.

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)

At least it can test arguments (valid and invalid) and result format and fields (their presence and types).

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 vAddr somehow.

@chris-belcher chris-belcher force-pushed the 2018-04-rpc-getaddress branch 2 times, most recently from a28d1cf to c83ccf7 Compare May 2, 2018 15:30
@chris-belcher
Copy link
Contributor Author

chris-belcher commented May 2, 2018

Fixed git weirdness (thanks to viasil).

@promag
Copy link
Contributor

promag commented May 2, 2018

Please rename PR.

@chris-belcher chris-belcher changed the title [WIP] [rpc] Add getaddress RPC command [WIP] [rpc] Add getnodeaddresses RPC command May 2, 2018
@MasterGrad17
Copy link

MasterGrad17 commented May 2, 2018

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?

@chris-belcher
Copy link
Contributor Author

chris-belcher commented May 2, 2018

@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.

@sipa
Copy link
Member

sipa commented May 2, 2018

@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"
Copy link
Contributor

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));
Copy link
Contributor

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.

Copy link
Contributor

@jonasschnelli jonasschnelli left a 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()

@sipa
Copy link
Member

sipa commented May 3, 2018

@jonasschnelli listpeeraddresses sounds like it's somehow exhaustive, or at least a complete specific subset of addresses. It's just giving a bunch of random ones; getpeeraddresses sounds clearer to me. Am i missing something?

@jonasschnelli
Copy link
Contributor

listpeeraddresses sounds like it's somehow exhaustive, or at least a complete specific subset of addresses. It's just giving a bunch of random ones; getpeeraddresses sounds clearer to me. Am I missing something?

Good point.

@chris-belcher
Copy link
Contributor Author

peer implies it returns addresses of peers you're actually connected to. Like how getpeerinfo gives information only about connected peers. How about getpossiblepeeraddresses? It's a bit of a mouthful admittedly. Other options could be getgossipedpeeraddresses or getpotentialpeeraddresses.

@laanwj
Copy link
Member

laanwj commented May 3, 2018

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 :)
I think getnodeaddresses is fine, just make sure that the documentation explains the functionality.

@chris-belcher chris-belcher force-pushed the 2018-04-rpc-getaddress branch 2 times, most recently from 73f046d to 9e6cac2 Compare May 3, 2018 12:51
@chris-belcher
Copy link
Contributor Author

Fixed nit

Copy link
Contributor

@jnewbery jnewbery left a 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"
Copy link
Contributor

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 in CAddrMan::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"
Copy link
Contributor

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"
Copy link
Contributor

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"
Copy link
Contributor

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"
Copy link
Contributor

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.

Copy link
Member

@laanwj laanwj May 7, 2018

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).

Copy link
Contributor

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.

@chris-belcher chris-belcher force-pushed the 2018-04-rpc-getaddress branch from 9e6cac2 to f0aca19 Compare May 10, 2018 18:39
@chris-belcher chris-belcher force-pushed the 2018-04-rpc-getaddress branch from f0aca19 to dd7e1e6 Compare May 21, 2018 15:31
@chris-belcher
Copy link
Contributor Author

Fixed nits and created a test in rpc_net.py.

Copy link
Contributor

@jnewbery jnewbery left a 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should be static

@@ -16,6 +17,8 @@
p2p_port,
wait_until,
)
from test_framework.mininode import P2PInterface, network_thread_start
Copy link
Contributor

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)

for a in imported_addrs:
addr = CAddress()
addr.time = now
addr.services = NODE_NETWORK | NODE_WITNESS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be nServices

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)])
Copy link
Contributor

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()
            ...

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)
Copy link
Contributor

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)

@promag
Copy link
Contributor

promag commented Sep 13, 2018

Looks good to me, utACK 8b96ebe.

Copy link
Contributor

@jnewbery jnewbery left a 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");
Copy link
Contributor

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)

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
Copy link
Contributor

@promag promag Sep 13, 2018

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 :trollface:

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.
@chris-belcher
Copy link
Contributor Author

Fixed those nits

@ajtowns
Copy link
Contributor

ajtowns commented Sep 18, 2018

utACK a2eb6f5

1 similar comment
@maflcko
Copy link
Member

maflcko commented Sep 18, 2018

utACK a2eb6f5

@promag
Copy link
Contributor

promag commented Sep 18, 2018

utACK a2eb6f5. Please fix PR description: "New getaddress call gives ..."

maflcko pushed a commit to maflcko/bitcoin-core that referenced this pull request Sep 18, 2018
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
@maflcko maflcko merged commit a2eb6f5 into bitcoin:master Sep 18, 2018
@chris-belcher chris-belcher deleted the 2018-04-rpc-getaddress branch September 27, 2018 09:18
Munkybooty pushed a commit to Munkybooty/dash that referenced this pull request Jul 9, 2021
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
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Jul 19, 2021
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
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Jul 20, 2021
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
PastaPastaPasta added a commit to PastaPastaPasta/dash that referenced this pull request Jul 20, 2021
This reverts commit 54e38eca

Signed-off-by: pasta <pasta@dashboost.org>
random-zebra added a commit to PIVX-Project/PIVX that referenced this pull request Aug 12, 2021
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
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.