Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

[PAN-2595] Consolidate local enode representation #1376

Merged

Conversation

mbaxter
Copy link
Contributor

@mbaxter mbaxter commented Apr 30, 2019

PR description

This PR consolidates local enode representations around a single canonical representation. Previously, there were a few places where we would construct EnodeURL instances to represent the local node. However, this representation is only truly accurate once the network starts up as ports can be chosen on startup.

Peers can be added to the maintained peer list before the network is
fully started and permissions can be properly checked.  So, for
consistency, don't gate addition to the maintained peer list using
permissions.  Just don't connect to peers who are currently not allowed.
@mbaxter mbaxter changed the title Pan 2595/consolidate local enode rep [PAN-2595] Consolidate local enode representation Apr 30, 2019
@@ -59,12 +59,6 @@ public TestNode create(
return node;
}

public void startNetworks() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Each individual network is already started here


/**
* A permissioning provider that only provides an answer when we have no peers outside of our
* bootnodes
*/
public class InsufficientPeersPermissioningProvider implements ContextualNodePermissioningProvider {
private final EnodeURL selfEnode;
private final Supplier<Optional<EnodeURL>> selfEnode;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously, we passed in a static EnodeURL constructed in RunnerBuilder. This enode wasn't 100% accurate as the network can be configured to choose a port on startup, and the representation constructed in the builder would not accurately reflect the real ports being used. We're now passing a supplier that returns the canonical local enode representation when available.

} else if (checkEnode(sourceEnode) && checkEnode(destinationEnode)) {
} else if (!maybeSelfEnode.isPresent()) {
// The local node is not yet ready, so we can't validate enodes yet
return Optional.empty();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We'll now only return an answer when the network is ready.

* @return boolean representing whether or not the peer has been added to the list or was already
* on it
* @return boolean representing whether or not the peer has been added to the list, false is
* returned if the peer was already on the list
*/
boolean addMaintainConnectionPeer(final Peer peer);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously, peer permission would be checked as peers were added to this list. The changes in this PR delay the point at which we're able to check permission to the point where our local node is up and running. As a result, if we were to gate entrance into the list based on permissions, there would be a period where no nodes could be added to this list while the node is starting up. So, this API has been updated such that a peer can be added to the "maintain connection" list whether or not it is permitted on the network. However, no peers will actually be connected to without first checking permissions.

@@ -346,7 +347,7 @@ protected void initChannel(final SocketChannel ch) {
return;
}

if (!isPeerConnectionAllowed(connection)) {
if (!isPeerAllowed(connection)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Permission checks have been centralized to one method.

void checkMaintainedConnectionPeers() {
peerMaintainConnectionList.stream()
.filter(p -> !isConnectingOrConnected(p))
.filter(this::isPeerAllowed)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check permissions before connecting :\

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we drop them from the maintained list if they aren't permitted?

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 so. The peer might later be permitted.

if (!blockAddedObserverId.isPresent()) {
blockAddedObserverId =
OptionalLong.of(blockchain.get().observeBlockAdded(this::handleBlockAddedEvent));
if (started.compareAndSet(false, true)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Start can be called at most once

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 we switch this to use an early exit pattern rather than wrapping the whole method in an if?

return false;
}

Optional<EnodeURL> maybeEnode = getLocalEnode();
if (!maybeEnode.isPresent()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Be restrictive around permissions until we have a valid representation of our local enode.

@mbaxter mbaxter marked this pull request as ready for review April 30, 2019 20:17
Copy link
Contributor

@ajsutton ajsutton left a comment

Choose a reason for hiding this comment

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

LGTM. Would just be good to confirm the permissioning related changes with someone from Bunyip.

if (!blockAddedObserverId.isPresent()) {
blockAddedObserverId =
OptionalLong.of(blockchain.get().observeBlockAdded(this::handleBlockAddedEvent));
if (started.compareAndSet(false, true)) {
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 we switch this to use an early exit pattern rather than wrapping the whole method in an if?

}

private EnodeURL buildSelfEnodeURL() {
private void setLocalEnode() {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: this probably should be createLocalEnode since it doesn't follow the typical setter pattern.

final Peer peer = mockPeer();
network.peerMaintainConnectionList.add(peer);

network.checkMaintainedConnectionPeers();
verify(network, times(1)).connect(peer);
}

@Test
public void checkMaintainedConnectionPeersDoesNotConnectToDisallowedPeer() {
Copy link
Contributor

Choose a reason for hiding this comment

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

@lucassaldanha can you confirm that the permissioning controls should prevent peers added via staticnodes.json or admin_addPeer from connecting? It makes sense to me but I seem to recall some discussions and details...

Copy link
Contributor

Choose a reason for hiding this comment

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

For the staticnodes.json list we apply the same rules as for bootnodes: they must be permitted.

For admin_addPeer is the same logic as connecting to another peer. If the peer is not allowed it won't connect to the peer (and I believe the addPeer method will give you a nice error response saying why).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The "admin_addPeer" method will no longer return error messages if a non-permitted peer is added. Discussed this with @lucassaldanha offline and we determined that there is no need to keep these error messages.

@lucassaldanha lucassaldanha self-assigned this Apr 30, 2019
Copy link
Contributor

@lucassaldanha lucassaldanha left a comment

Choose a reason for hiding this comment

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

LGTM. My only question is if we should remove peers not allowed from the maintained peer list at the moment we find out they aren't allowed.

void checkMaintainedConnectionPeers() {
peerMaintainConnectionList.stream()
.filter(p -> !isConnectingOrConnected(p))
.filter(this::isPeerAllowed)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we drop them from the maintained list if they aren't permitted?

@ajsutton
Copy link
Contributor

I'd be inclined to keep forbidden peers in the maintained list because they may become permitted later - especially with on-chain permissioning. You may have setup a new node, added it as a peer for your existing nodes and are now getting approvals from the consortium to allow it to actually connect.

@mbaxter mbaxter merged commit 694a44a into PegaSysEng:master May 1, 2019
notlesh pushed a commit to notlesh/pantheon that referenced this pull request May 4, 2019
notlesh pushed a commit to notlesh/pantheon that referenced this pull request May 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants