Skip to content

Conversation

@jnewbery
Copy link
Contributor

@jnewbery jnewbery commented Apr 3, 2017

The disconnectnode RPC can currently only be called with the IP address/port
of the node the user wishes to connect. This commit allows the node to
be disconnected using the nodeid returned by getpeerinfo().

@theuni
Copy link
Member

theuni commented Apr 3, 2017

Concept ACK. Though if we're going to be exposing this value to our apis, we need to define it sanely first.

ATM it's just an int, so it's tricky encode/decode it safely. I'd prefer change it to a uint32_t first, so that we can use ParseUInt32 here.

@gmaxwell
Copy link
Contributor

gmaxwell commented Apr 3, 2017

Concept ACK, I've wanted this many times before... but I'm concerned about the nodeid--- right now if it wraps bad things happen, and it will be harder to fix if we've made it a part of the API.

@theuni
Copy link
Member

theuni commented Apr 3, 2017

edit: Decided I didn't like this thought and bailed. Meant to cancel, closed instead. Sorry!

@theuni theuni closed this Apr 3, 2017
@theuni theuni reopened this Apr 3, 2017
@theuni
Copy link
Member

theuni commented Apr 3, 2017

I suppose it would be prudent to

  • determine where we assume nodeids are increasing in value, as opposed to just being unique. I should hope there are none of these, other than generally being able to assume that higher node == earlier connection
  • determine when we assume a nodeid to be globally unique. For example, if there's a global map<nodeid,int> that tallies sent bytes, that would be broken by duplicated values when ids wrapped.
  • determine when we assume that a nodeid is a unique identifier among current nodes.

The last one is what happens all over the place, and is fine as long as we ensure that the values really are unique. To do so, we can either:

  • maintain a set of currently used nodeids, and make sure that new values aren't in use before assigning a new one
  • disconnect all nodes when we hit max, forcing new connections starting from 0.

Obviously the first is cleaner, and would probably end up being simpler too.

@theuni
Copy link
Member

theuni commented Apr 4, 2017

See theuni@57ea0cc for the wrapping/defining changes. Still need to verify the first two points above, though.

@jnewbery If you don't object, I'll go ahead and PR that as a prerequisite for this one.

src/rpc/net.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

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

Concept ACK, but please make this API explicit.

  • APIs that switch based on magic heuristics on how a value 'looks'. Initially this seems user friendly, but it will quickly grow to maintainable, insecure monsters of obscure rules. It should be made completely explicit.

  • Also: do not encode integers as strings and use functions like std::stoi. Just use .get_int() if you need an int value and leave the encoding of values up to the RPC mechanism.

The most straightforward way would be to just add a function disconnectnodebyid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I agree that APIs shouldn't be magic. I thought it wouldn't be too problematic here because there can't be any ambiguity at all between nodeIds and IP addresses (and disconnectnode() is already a bit magic - it can take either IPv4 or IPv6 addresses).

I don't like the proliferation of additional RPCs that perform a very small function if we can avoid it.

How about we add a new argument to this RPC called "nodeId"? The RPC can be called with strictly one of the arguments. There's no magic or ambiguity, and the node disconnection logic is contained within one RPC.

Copy link
Member

@laanwj laanwj Apr 5, 2017

Choose a reason for hiding this comment

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

How about we add a new argument to this RPC called "nodeId"? The RPC can be called with strictly one of the arguments. There's no magic or ambiguity, and the node disconnection logic is contained within one RPC.

Sounds reasonable to me. To be clear: anything that doesn't encode the integer as a string is more reasonable to me than this (another reason: because it allows passing the 'id' value literally without having to string-encode it in the client). I don't have a strong opinion whether it should be one or multiple RPCs.

@laanwj
Copy link
Member

laanwj commented Apr 4, 2017

Concept ACK. Though if we're going to be exposing this value to our apis, we need to define it sanely first.

This value is already exposed in APIs since getpeerinfo added {"id": 14669}. Handling wrapping sanely is important, but I don't think this is a blocker for more usage on the RPC API. Client applications should treat these numbers as opaque identifiers and the only thing they can rely on is that that an ID won't be reused for a different node within a very short timespan.

@TheBlueMatt
Copy link
Contributor

Found myself wanting this for disconnect after reading debug.log many times, annoying to have to getpeerinfo for it.

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 4, 2017

@theuni - of course, no objection at all!

@sipa
Copy link
Member

sipa commented Apr 4, 2017

 there can't be any ambiguity at all between nodeIds and IP addresses

Well you can write an IPv4 address as a decimal integer... I guess we're excluding that (very uncommon) usage?

@laanwj
Copy link
Member

laanwj commented Apr 5, 2017

Well you can write an IPv4 address as a decimal integer... I guess we're excluding that (very uncommon) usage?

+1. Exactly. This is exactly why these things get ugly. There's always overlaps in representations that you may not be thinking about in the initial design, then get realized later. Let's just take the sane route here and make the ambiguity impossible.

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 5, 2017

Let's just take the sane route here and make the ambiguity impossible.

Yep, fine.

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 5, 2017

ok, another idea. I think it's reasonable that people might want to update node by id in other ways (ie switching whitelisting on and off, changing ban score, etc). How would you feel about an updatenode RPC to do those things? To begin with it will allow disconnecting and turning whitelisting on/off, and it can be added to later if people think further functionality is useful.

I already have a branch with an updatenode RPC here: jnewbery@5bbe24f . Adding a 'disconnect' argument to it is trivial.

We should keep this RPC hidden in order to not commit ourselves to a public API that we might want to change later (eg if we break out whitelisting into more granular behaviour at some point).

Thoughts?

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 5, 2017

I've added an updatepeer RPC here: #10160 which I think is better and more extensible, but I'd be interested to hear others' thoughts.

@laanwj
Copy link
Member

laanwj commented Apr 7, 2017

I don't think 'updatepeer X disconnect' is clearer than 'disconnectnode'. Having the RPC call as the verb is easier to use and remember.

We have an example of a very bad multiplexed call in the API: addnode X remove. Your proposal isn't half as crazy as that :) And the idea of having a updatenode makes sense for changing other per-node variables, certainly for testing/debugging, but I don't think it's a good place to place disconnect.

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 7, 2017

Yes, addnode X remove is nuts, and I agree that having the RPC call as the verb is sensible.

I'll reimplement this as an additional argument to disconnectnode.

Longer term, my thinking around updatepeer is that it'd be handy as a swiss army knife for peer interop. We may wish to disconnect/ban/whitelist/change other attributes/etc for peers, and having a single RPC that does all of that would be a sensible API, and certainly better than a different RPC for each attribute. On the other hand, I do agree that 'disconnect' is a verb, so naturally updatenode disconnect is a bit weird.

@jnewbery jnewbery force-pushed the disconnect_node_by_id branch from 5469596 to 3ed1bef Compare April 7, 2017 20:48
@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 7, 2017

I've pushed a version where disconnectnode now takes two arguments: address and nodeid. Strictly one argument must be given. (note: with named arguments, you can just supply a single argument, with positional arguments you need to set 'address' to the empty string if you want to use 'nodeid').

I changed the name of the existing argument from 'node' to 'address', since it only takes address. I think that's the right thing to do since the current name is misleading, but we'll need release notes to document the API change.

This should only be merged after @theuni's branch here: theuni@57ea0cc.

@jnewbery jnewbery mentioned this pull request Apr 7, 2017
src/rpc/net.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

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

Second argument is missing here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Help text now fixed. I'll squash the commit when this is ready for merge.

@luke-jr
Copy link
Member

luke-jr commented Apr 8, 2017

While you can write an IP as a decimal number, you can't specify an IP plus port in such a manner. Makes perfect sense to say String = IP and Number = nodeid IMO. Don't care too strongly if the current (two arguments) approach is used, but I wouldn't call it sane. :p

@jnewbery
Copy link
Contributor Author

@luke-jr thanks for the review. I agree that the two arguments approach looks a bit odd when used as positional arguments, but it makes perfect sense when using named arguments: call the RPC with address=

if you want to disconnect by address, or call with nodeid= if you want to disconnect by nodeid. The fact that it works at all with positional arguments is more a historical quirk of bitcoin's RPC rather than a feature.

I think any of the three approaches I've implemented are fine (overloading one argument, having a second argument or having a separate 'update peer' RPC). I really just want the functionality somewhere, and I'm happy to go along with the consensus view for where the best place to put it is.

@gmaxwell
Copy link
Contributor

(aside, the addnode thing isn't that nuts if you thing of it as a shortening of "addednodelist ", which is what it actually is :) )

@jnewbery
Copy link
Contributor Author

aside, the addnode thing isn't that nuts if ...

Yes, it makes sense if you're a scholar of Bitcoin Core code archaeology :)

It'd be nice if addnode could be renamed to trusted peer or persistent peer, but that's a lot of work (and a change to public APIs).

src/rpc/net.cpp Outdated
Copy link
Member

Choose a reason for hiding this comment

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

This is yet another breaking change. Needs rationale and mention in the release notes. Maybe backport.

JSONRPCException: Unknown named parameter address (-8)

luke-jr pushed a commit to luke-jr/bitcoin that referenced this pull request Jun 5, 2017
luke-jr pushed a commit to luke-jr/bitcoin that referenced this pull request Jun 5, 2017
luke-jr pushed a commit to luke-jr/bitcoin that referenced this pull request Jun 5, 2017
luke-jr pushed a commit to luke-jr/bitcoin that referenced this pull request Jun 5, 2017
luke-jr added a commit to luke-jr/bitcoin that referenced this pull request Jun 5, 2017
… branch 'disconnect_ban_fixes-0.14' into 0.14.2_fixes
luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Jun 15, 2017
disconnectnode() can currently only be called with the IP address/port
of the node the user wishes to connect. This commit allows the node to
be disconnected using the nodeid returned by getpeerinfo().

Github-Pull: bitcoin#10143
Rebased-From: 23e6e64
luke-jr pushed a commit to bitcoinknots/bitcoin that referenced this pull request Jun 15, 2017
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request May 23, 2019
… node id

d54297f [tests] disconnect_ban: add tests for disconnect-by-nodeid (John Newbery)
5cc3ee2 [tests] disconnect_ban: remove dependency on urllib (John Newbery)
12de2f2 [tests] disconnect_ban: use wait_until instead of sleep (John Newbery)
2077fda [tests] disconnect_ban: add logging (John Newbery)
395561b [tests] disconnectban test - only use two nodes (John Newbery)
e367ad5 [tests] rename nodehandling to disconnectban (John Newbery)
d6564a2 [tests] fix nodehandling.py flake8 warnings (John Newbery)
23e6e64 Allow disconnectnode() to be called with node id (John Newbery)

Tree-SHA512: a371bb05a24a91cdb16a7ac4fbb091d5d3bf6554b29bd69d74522cb7523d3f1c5b1989d5e7b03f3fc7369fb727098dd2a549de551b731dd480c121d9517d3576
@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.

10 participants