Skip to content

Conversation

jnewbery
Copy link
Contributor

@jnewbery jnewbery commented Apr 5, 2017

Adds an updatepeer RPC to update peer config and carry out actions on the peer by NodeId. At the moment, the actions are just changing whether the peer is whitelisted and whether the peer is a manual_connection (previously called an addnode). Future possible actions would be changing banscore, banning, and so on.

This is designed to be called using named arguments, but due to the RPC infrastructure can also be called with positional arguments (although doing so would be very fiddly).

I've set the category to hidden for now. We may want to make the whitelisting behaviour more granular in future and I don't want to commit us to a public API that we can't then change.

@theuni
Copy link
Member

theuni commented Apr 6, 2017

I'm not sure I like the idea of adding a command that changes the implied state of a peer via its attributes, rather than performing actions explicitly. The whitelist side-effects are especially hazy, see the brief discussion here: #10051 (comment).

@jonasschnelli
Copy link
Contributor

@jnewbery:
Can you elaborate the use-case for disconnect? IMO setban provides a similar interface, with disconnecting & banning for a specific timespan (1h, etc.) because, a pure disconnect does not prevent the peer from a direct re-connect.

@jonasschnelli
Copy link
Contributor

jonasschnelli commented Apr 6, 2017

Ah... an there is already the disconnectnode RPC call.

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 6, 2017

@jonasschnelli see #2729 and #6271 for history of the disconnectnode RPC. It's also useful in testing to be able to control the topology of the test nodes.

@theuni - I agree that whitelisting is a mess and should be broken out into bits for controlling individual behaviours. Hence my original comment: "I have a feeling we may want to make the whitelisting behaviour more granular and I don't want to commit us to a public API that we can't then change." I was thinking of your comment in #10051 but couldn't find the reference.

the idea of adding a command that changes the implied state of a peer via its attributes, rather than performing actions explicitly

I don't understand what this means in the context of whitelisting. The idea is to update the peer's whitelist behaviour. What would performing actions explicitly entail?

@jnewbery
Copy link
Contributor Author

jnewbery commented Apr 7, 2017

Closing in favour of #10143 for the immediate need (disconnect node by id), but I think this could still be a useful RPC in the future.

@jnewbery
Copy link
Contributor Author

Reopening with just the ability to update:

  • fWhitelisted
  • m_manual_connection

The net_processing functionality for the v0.15.0.2 PRs is disabled for manual connections, so this PR could be helpful for testing those changes.

@sdaftuar

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.

Concept ACK. Will test.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Is null instead.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

If not then raise invalid parameter?

Copy link
Contributor

Choose a reason for hiding this comment

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

Missing test for invalid node.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Not null instead.

@jnewbery jnewbery force-pushed the updatepeer branch 2 times, most recently from 172e302 to c799a6c Compare October 27, 2017 14:05
@jnewbery jnewbery changed the title [WIP] updatepeer RPC updatepeer RPC Oct 27, 2017
@jnewbery
Copy link
Contributor Author

Thanks for the review @promag . I've addressed all your comments.

@NicolasDorier
Copy link
Contributor

NicolasDorier commented Oct 27, 2017

whitelisting via rpc?? BIG BIG concept ACK. I am excited. It will make configuration of services depending on Bitcoin Core RPC and P2P so much easier.

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.

Nit, rename PR to Add updatepeer RPC. Squash [RPC] Allow manual_connection to be updated using updatepeer into [RPC] Add updatenode RPC.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

if (!...) {
    throw ...;
}

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, > 1.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, same line or { }.

src/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, missing spaces after for.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

src/rpc/net.cpp Outdated
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 if.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Same validation of getpeerinfo.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Needs release notes.

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Actually I think this is more correct:

  • raise RPC_INVALID_PARAMETER if node_id < 0;
  • raise RPC_INVALID_ADDRESS_OR_KEY if !GetNodeStats(...).

Note: if you do this then add a test for 1st case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it's too important, but feel free to open a follow-up PR if you think it's required.

Copy link
Contributor

Choose a reason for hiding this comment

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

Missing failure tests for getpeerinfo (maybe unrelated to this PR).

@jnewbery jnewbery changed the title updatepeer RPC Add updatepeer RPC Oct 27, 2017
@jnewbery
Copy link
Contributor Author

@promag nits addressed in latest commit.

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.

utACK after squash.

Nit, how about updatepeer id setting value (setting value ...):

updatepeer 1 whitelisted true
updatepeer 1 manual_connection false

It works well without named arguments with the cli, and scales well for other settings.

Note, I always prefer named arguments, specially in these calls. But we do support index arguments and this approach doesn't help for future settings.

src/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, missing space after for. Same below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove lock or am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you're right - I don't think this is required

@NicolasDorier
Copy link
Contributor

I agree with @promag updatepeer id setting value (setting value ...) would be easier to extend later.

@jnewbery
Copy link
Contributor Author

Nit, how about updatepeer id setting value (setting value ...)

This is a different scheme from all of the existing RPCs. I expect that there would need to be changes to the rpc framework to make this work.

It doesn't make sense to me have a completely different scheme for just this RPC method, since we already have named arguments.

If you disagree, perhaps you could implement the scheme you're talking about in a new branch?

@NicolasDorier
Copy link
Contributor

NicolasDorier commented Nov 2, 2017

@jnewbery how so? This is just 3 differents parameters of 3 strings.

The way you are doing now, if there is like 60 settings for one peer, we will have 60 parameters to this function. This does not seem very maintainable. In such case even updatewhitelist id true would be better. We would have 60 functions, which is still better than 60 parameters.

@promag
Copy link
Contributor

promag commented Nov 2, 2017

This is designed to be called using named arguments, but due to the RPC infrastructure can also be called with positional arguments (although doing so would be very fiddly).

@jnewbery you too agree that this is by design bad for positional arguments (considering the possible settings can be extended).

Another approach is to use something like sendmany: updatepeer {\"setting\":value, ...}.

FWIW I already gave my utACK 😄

src/rpc/net.cpp Outdated
Copy link
Contributor

@NicolasDorier NicolasDorier Nov 30, 2017

Choose a reason for hiding this comment

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

See my above comment, by fetching once the node at the start of this method, you can remove all those if as you already know if the CNode with such id already exist. It makes things a bit easier to test and prevent monkey coding each time we want to add a new field.

This RPC error is also untestable as it makes you reproduce a difficult race condition. (need to drop the node after the previosu GetNodeStates but before this call)

src/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

This method would also be removed if fetching CNode was done at the updatepeer level.

@NicolasDorier
Copy link
Contributor

@jnewbery do you need more help on this PR? I am really interested into seeing it merged.

@jnewbery
Copy link
Contributor Author

jnewbery commented Dec 7, 2017

@NicolasDorier: Sorry for dropping this - I've rebased on master and squashed all nits.

I'm not sure about your suggestion for locking in updatepeer and fetching the CNode. cs_vNodes isn't currently locked anywhere outsdie CConman, which I think is a good property to maintain.

@NicolasDorier
Copy link
Contributor

NicolasDorier commented Dec 8, 2017

@jnewbery in this case, I would suggest to have a method on CConman bool CConman::UpdateSetting(nodeid, str,value) because there is high ratio of ceremonial monkey copy pasta code everytimes we will need to add one property here.

@TheBlueMatt
Copy link
Contributor

I'm still with @theuni on this one, not super happy with the idea of changing properties about peers that net_processing/net both consider "constant". Would prefer we add some (undocumented?) options to addnode (or a new RPC) which lets you control the flags of a peer as you create a connection.

@jnewbery
Copy link
Contributor Author

jnewbery commented Dec 8, 2017

@theuni's comment was:

the idea of adding a command that changes the implied state of a peer via its attributes, rather than performing actions explicitly

I don't understand what's meant by 'performing actions explicitly', but I'm happy to modify this PR if there are concrete suggestions.

not super happy with the idea of changing properties about peers that net_processing/net both consider "constant"

Can you articulate what makes you not happy? Being able to change the properties of a connection without having to delete/recreate that object is generally very useful, since cycling a connection has many side-effects. As far as I can see, the only stateful impact of starting with fWhitelisted rather than updating it later is this call to AddLocal() in BindListenPort():

    if (addrBind.IsRoutable() && fDiscover && !fWhitelisted)
        AddLocal(addrBind, LOCAL_BIND);

I can't see any other reason to be concerned about updating fWhitelisted dynamically.

@TheBlueMatt
Copy link
Contributor

TheBlueMatt commented Dec 8, 2017

I might be slightly more OK with changing fWhitelisted on a peer after its up, as that may be useful "in the real world" outside of tests, but I'm super not a fan of changing manual_connection. One thing @theuni and I have talked about is being more aggressive about CNode representing a "connection handle" where its potentially allowed to have a few constant members which are general information about the connection, eg whether it was automatically or manually added, the remote address, etc.
One thing you might imagine is inserting a peer into a set/map (eg compact blocks HB mode peers set, the (implied) set of nPreferredDownload peers (which we currently track with fPreferredDownload, but we could actually take it as implication based on const values in CNode)) or otherwise performing (between-message-)stateful behavior on a peer based on such (constant) information about a connection. In each of these cases, having such constant information change out from under you could potentially introduce races/bugs.

cycling a connection has many side-effects.

I'm not sure what side-effects there are that couldn't be reproduced on a new connection after cycling the connection. It ends up being an unrealistic test if you dont do that anyway. Maybe I'm just missing the motivation of cases that wouldnt be better tested by cycling a connection?

@jnewbery
Copy link
Contributor Author

jnewbery commented Dec 8, 2017

One thing you might imagine...

You're describing things that may happen in future changes in abstract terms, particularly when you talk about between-message-stateful behaviour.

m_manual_connection is certainly a better name than fAddNode, but I still don't think it really captures what the property means. Really it's something like 'preferred_peer' - it's a peer that we don't want to disconnect or punish for bad behaviour. How it was connected isn't really relevant. We may want to prefer a peer that has connected inbound to us, and we may want to connect outbound to a peer without preferring it. In that context, I think it makes sense to want to set this property manually after connection, without having to disconnect and go through the version-verack-getheaders-headers handshaking.

This is undoubtedly useful for testing, but I could also imagine it being useful, for example in a business that has more than one bitcoin node and wants to be able to manage their network topology.

Thinking forward a bit more, I think it'd also be beneficial to break out the whitelist behaviour to be more granular, and again be able to update those properties dynamically.

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

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

Haven't been following discussion in much detail but if the problem is fAddNode having both const and non-const interpretations, maybe it should just be split into two variables: m_connection_type that would be const and record origin of connection and m_preferred_peer that would be mutable.

Copy link
Contributor

@kallewoof kallewoof left a comment

Choose a reason for hiding this comment

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

utACK

Needs rebase.

src/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you maybe make an (optionally inline) method find_node_by_id that the above methods use? Looks a bit copy-pastey.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

refactored out

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: No period at end (seems to be the norm). Also add this to the first line ("getpeerinfo \"id\"\n")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

"updatepeer \"id\" ( \"whitelisted\" \"manual_connection\" )\n"

src/rpc/net.cpp Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: node_id is an int, so %d not %u.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@jnewbery jnewbery force-pushed the updatepeer branch 2 times, most recently from 16900c5 to fd18f4e Compare May 24, 2018 19:57
@jnewbery
Copy link
Contributor Author

Fixed @kallewoof review comments.

jnewbery added 5 commits July 23, 2018 10:37
…N().

This commit refactors getpeerinfo() to call a helper function
NodeStatsToJSON() to build a JSON object with peer information.
GetNodeStats() can now be called for a single node.
The getpeerinfo RPC can now be called for a single node by specifying the
node id.
This commit adds an updatepeer RPC for updating a single peer node.

Currently, updatepeer can be used to update the whitelisting and
manual_connection settings for the node. It could potentially be
extended in future to allow updating other attributes of the peer node.
@jnewbery
Copy link
Contributor Author

There doesn't seem to much appetite for this. Closing.

@jnewbery jnewbery closed this Jul 23, 2018
@NicolasDorier
Copy link
Contributor

I liked it :(

@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
@maflcko
Copy link
Member

maflcko commented May 4, 2022

Marked "up for grabs". (Conversation is locked, so a new pull will need to be opened either way).

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