diff --git a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java index 36a74c925a..e49b96490d 100644 --- a/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java +++ b/acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java @@ -138,7 +138,12 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto @Override public String enodeUrl() { - return "enode://" + keyPair.getPublicKey().toString() + "@" + LOCALHOST + ":" + p2pPort; + return "enode://" + + keyPair.getPublicKey().toString().substring(2) + + "@" + + LOCALHOST + + ":" + + p2pPort; } private Optional jsonRpcBaseUrl() { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelist.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelist.java index 821498e75e..51a21043fd 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelist.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelist.java @@ -22,12 +22,9 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; -import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; -import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import java.util.List; -import java.util.stream.Collectors; public class PermAddNodesToWhitelist implements JsonRpcMethod { @@ -52,15 +49,9 @@ public class PermAddNodesToWhitelist implements JsonRpcMethod { try { if (p2pNetwork.getNodeWhitelistController().isPresent()) { try { - List peers = - enodeListParam - .getStringList() - .parallelStream() - .map(this::parsePeer) - .collect(Collectors.toList()); - - NodeWhitelistController.NodesWhitelistResult nodesWhitelistResult = - p2pNetwork.getNodeWhitelistController().get().addNodes(peers); + final List enodeURLs = enodeListParam.getStringList(); + final NodeWhitelistController.NodesWhitelistResult nodesWhitelistResult = + p2pNetwork.getNodeWhitelistController().get().addNodes(enodeURLs); switch (nodesWhitelistResult.result()) { case SUCCESS: @@ -92,8 +83,4 @@ public class PermAddNodesToWhitelist implements JsonRpcMethod { return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED); } } - - private DefaultPeer parsePeer(final String enodeURI) { - return DefaultPeer.fromURI(enodeURI); - } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelist.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelist.java index e8ddb9f0e4..daea852464 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelist.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelist.java @@ -20,10 +20,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; -import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import java.util.List; -import java.util.stream.Collectors; public class PermGetNodesWhitelist implements JsonRpcMethod { @@ -42,10 +40,8 @@ public class PermGetNodesWhitelist implements JsonRpcMethod { public JsonRpcResponse response(final JsonRpcRequest req) { try { if (p2pNetwork.getNodeWhitelistController().isPresent()) { - List nodesWhitelist = + final List enodeList = p2pNetwork.getNodeWhitelistController().get().getNodesWhitelist(); - List enodeList = - nodesWhitelist.parallelStream().map(Peer::getEnodeURI).collect(Collectors.toList()); return new JsonRpcSuccessResponse(req.getId(), enodeList); } else { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java index a7d1a0d3a7..3026d75dfd 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFile.java @@ -18,8 +18,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import java.util.Optional; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelist.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelist.java index a77517532e..218953beb2 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelist.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelist.java @@ -22,12 +22,9 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; -import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; -import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import java.util.List; -import java.util.stream.Collectors; public class PermRemoveNodesFromWhitelist implements JsonRpcMethod { @@ -52,15 +49,9 @@ public class PermRemoveNodesFromWhitelist implements JsonRpcMethod { try { if (p2pNetwork.getNodeWhitelistController().isPresent()) { try { - List peers = - enodeListParam - .getStringList() - .parallelStream() - .map(this::parsePeer) - .collect(Collectors.toList()); - - NodeWhitelistController.NodesWhitelistResult nodesWhitelistResult = - p2pNetwork.getNodeWhitelistController().get().removeNodes(peers); + final List enodeURLs = enodeListParam.getStringList(); + final NodeWhitelistController.NodesWhitelistResult nodesWhitelistResult = + p2pNetwork.getNodeWhitelistController().get().removeNodes(enodeURLs); switch (nodesWhitelistResult.result()) { case SUCCESS: @@ -92,8 +83,4 @@ public class PermRemoveNodesFromWhitelist implements JsonRpcMethod { return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED); } } - - private DefaultPeer parsePeer(final String enodeURI) { - return DefaultPeer.fromURI(enodeURI); - } } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java index 843dbe8daa..57fa202a3f 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java @@ -19,7 +19,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController.NodesWhitelistResult; +import static tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController.NodesWhitelistResult; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; @@ -29,7 +29,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.WhitelistOperationResult; import java.util.ArrayList; @@ -74,11 +74,13 @@ public class PermAddNodesToWhitelistTest { @Test public void shouldThrowInvalidJsonRpcParametersExceptionWhenOnlyBadEnode() { - final JsonRpcRequest request = buildRequest(Lists.newArrayList(badEnode)); + final ArrayList enodeList = Lists.newArrayList(badEnode); + final JsonRpcRequest request = buildRequest(enodeList); final JsonRpcResponse expected = new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); when(p2pNetwork.getNodeWhitelistController()).thenReturn(Optional.of(nodeWhitelistController)); + when(nodeWhitelistController.addNodes(eq(enodeList))).thenThrow(IllegalArgumentException.class); final JsonRpcResponse actual = method.response(request); @@ -87,11 +89,13 @@ public class PermAddNodesToWhitelistTest { @Test public void shouldThrowInvalidJsonRpcParametersExceptionWhenBadEnodeInList() { - final JsonRpcRequest request = buildRequest(Lists.newArrayList(enode2, badEnode, enode1)); + final ArrayList enodeList = Lists.newArrayList(enode2, badEnode, enode1); + final JsonRpcRequest request = buildRequest(enodeList); final JsonRpcResponse expected = new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); when(p2pNetwork.getNodeWhitelistController()).thenReturn(Optional.of(nodeWhitelistController)); + when(nodeWhitelistController.addNodes(eq(enodeList))).thenThrow(IllegalArgumentException.class); final JsonRpcResponse actual = method.response(request); @@ -99,12 +103,14 @@ public class PermAddNodesToWhitelistTest { } @Test - public void shouldThrowInvalidJsonRpcParametersExceptionWhenNoEnode() { - final JsonRpcRequest request = buildRequest(Lists.newArrayList("")); + public void shouldThrowInvalidJsonRpcParametersExceptionWhenEmptyEnode() { + final JsonRpcRequest request = buildRequest(Lists.emptyList()); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); + new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_EMPTY_ENTRY); when(p2pNetwork.getNodeWhitelistController()).thenReturn(Optional.of(nodeWhitelistController)); + when(nodeWhitelistController.addNodes(eq(Lists.emptyList()))) + .thenReturn(new NodesWhitelistResult(WhitelistOperationResult.ERROR_EMPTY_ENTRY)); final JsonRpcResponse actual = method.response(request); diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java index d7eaa8b549..a6f57bcff6 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java @@ -25,14 +25,10 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; -import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; -import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; -import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import org.assertj.core.util.Lists; import org.junit.Before; @@ -118,7 +114,7 @@ public class PermGetNodesWhitelistTest { return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {}); } - private List buildNodesList(final String... enodes) { - return Arrays.stream(enodes).parallel().map(DefaultPeer::fromURI).collect(Collectors.toList()); + private List buildNodesList(final String... enodes) { + return Lists.newArrayList(enodes); } } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java index 1a53c25d6a..4f5aeadcfb 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermReloadPermissionsFromFileTest.java @@ -21,8 +21,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcError; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcErrorResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import java.util.Optional; diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java index 8dfbeb684b..ca4896fb36 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java @@ -19,7 +19,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController.NodesWhitelistResult; +import static tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController.NodesWhitelistResult; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; @@ -29,7 +29,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.WhitelistOperationResult; import java.util.ArrayList; @@ -79,6 +79,8 @@ public class PermRemoveNodesFromWhitelistTest { new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); when(p2pNetwork.getNodeWhitelistController()).thenReturn(Optional.of(nodeWhitelistController)); + when(nodeWhitelistController.removeNodes(eq(Lists.newArrayList(badEnode)))) + .thenThrow(IllegalArgumentException.class); final JsonRpcResponse actual = method.response(request); @@ -86,12 +88,14 @@ public class PermRemoveNodesFromWhitelistTest { } @Test - public void shouldThrowInvalidJsonRpcParametersExceptionWhenNoEnode() { - final JsonRpcRequest request = buildRequest(Lists.newArrayList("")); + public void shouldThrowInvalidJsonRpcParametersExceptionWhenEmptyList() { + final JsonRpcRequest request = buildRequest(Lists.emptyList()); final JsonRpcResponse expected = - new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); + new JsonRpcErrorResponse(request.getId(), JsonRpcError.NODE_WHITELIST_EMPTY_ENTRY); when(p2pNetwork.getNodeWhitelistController()).thenReturn(Optional.of(nodeWhitelistController)); + when(nodeWhitelistController.removeNodes(eq(Lists.emptyList()))) + .thenReturn(new NodesWhitelistResult(WhitelistOperationResult.ERROR_EMPTY_ENTRY)); final JsonRpcResponse actual = method.response(request); diff --git a/ethereum/mock-p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/testing/MockNetwork.java b/ethereum/mock-p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/testing/MockNetwork.java index e5a4e88a1c..136f431760 100644 --- a/ethereum/mock-p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/testing/MockNetwork.java +++ b/ethereum/mock-p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/testing/MockNetwork.java @@ -18,11 +18,11 @@ import tech.pegasys.pantheon.ethereum.p2p.api.MessageData; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.DefaultMessage; import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.Subscribers; import java.net.InetSocketAddress; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/NoopP2PNetwork.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/NoopP2PNetwork.java index 1aaaf4a682..7a0c01a71c 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/NoopP2PNetwork.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/NoopP2PNetwork.java @@ -17,9 +17,9 @@ import tech.pegasys.pantheon.ethereum.p2p.api.Message; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/api/P2PNetwork.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/api/P2PNetwork.java index 7905f9e98a..97d88f7c31 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/api/P2PNetwork.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/api/P2PNetwork.java @@ -13,9 +13,9 @@ package tech.pegasys.pantheon.ethereum.p2p.api; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import java.io.Closeable; import java.net.InetSocketAddress; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java index afe7da4dd2..32b720c4da 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgent.java @@ -32,8 +32,8 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.TimerUtil; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeerId; import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.NetworkUtility; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.BytesValue; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java index c1833e3178..5032ba72b6 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/VertxPeerDiscoveryAgent.java @@ -23,7 +23,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.TimerUtil; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.VertxTimerUtil; import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.NetworkUtility; import tech.pegasys.pantheon.util.Preconditions; diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java index 91ed132739..768fead1c3 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryController.java @@ -24,7 +24,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryEvent.PeerBonde import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryStatus; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -201,7 +201,7 @@ public class PeerDiscoveryController { private boolean whitelistIfPresentIsNodePermitted(final DiscoveryPeer sender) { return nodeWhitelistController - .map(nodeWhitelistController -> nodeWhitelistController.isPermitted(sender)) + .map(nodeWhitelistController -> nodeWhitelistController.isPermitted(sender.getEnodeURI())) .orElse(true); } diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java index 6a8f971d7e..5930464de8 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshState.java @@ -17,7 +17,7 @@ import static tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PeerDistance import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer; import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryStatus; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.List; @@ -183,7 +183,9 @@ public class RecursivePeerRefreshState { private boolean satisfiesMapAdditionCriteria(final DiscoveryPeer discoPeer) { return !oneTrueMap.containsKey(discoPeer.getId()) && !peerBlacklist.contains(discoPeer) - && peerWhitelist.map(whitelist -> whitelist.isPermitted(discoPeer)).orElse(true) + && peerWhitelist + .map(whitelist -> whitelist.isPermitted(discoPeer.getEnodeURI())) + .orElse(true) && (initialPeers.contains(discoPeer) || !peerTable.get(discoPeer).isPresent()) && !discoPeer.getId().equals(localPeerId); } diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/netty/NettyP2PNetwork.java b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/netty/NettyP2PNetwork.java index c139158a76..266b5be8e3 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/netty/NettyP2PNetwork.java +++ b/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/netty/NettyP2PNetwork.java @@ -28,11 +28,11 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol; import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.metrics.Counter; import tech.pegasys.pantheon.metrics.LabelledMetric; import tech.pegasys.pantheon.metrics.MetricCategory; @@ -304,10 +304,11 @@ public class NettyP2PNetwork implements P2PNetwork { nwc -> nwc.isPermitted( new DefaultPeer( - connection.getPeer().getNodeId(), - ch.remoteAddress().getAddress().getHostAddress(), - connection.getPeer().getPort(), - connection.getPeer().getPort()))) + connection.getPeer().getNodeId(), + ch.remoteAddress().getAddress().getHostAddress(), + connection.getPeer().getPort(), + connection.getPeer().getPort()) + .getEnodeURI())) .orElse(true); } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NettyP2PNetworkTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NettyP2PNetworkTest.java index 38e8f01830..5d637864e3 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NettyP2PNetworkTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NettyP2PNetworkTest.java @@ -35,17 +35,18 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol; import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.net.InetAddress; import java.nio.file.Files; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.OptionalInt; @@ -416,7 +417,7 @@ public final class NettyP2PNetworkTest { Files.createTempFile("test", "test").toAbsolutePath().toString()); final NodeWhitelistController localWhitelistController = new NodeWhitelistController(config); // turn on whitelisting by adding a different node NOT remote node - localWhitelistController.addNode(mockPeer()); + localWhitelistController.addNodes(Arrays.asList(mockPeer().getEnodeURI())); final SubProtocol subprotocol = subProtocol(); final Capability cap = Capability.create(subprotocol.getName(), 63); @@ -646,8 +647,19 @@ public final class NettyP2PNetworkTest { private Peer mockPeer() { final Peer peer = mock(Peer.class); final BytesValue id = SECP256K1.KeyPair.generate().getPublicKey().getEncodedBytes(); + final Endpoint endpoint = new Endpoint("127.0.0.1", 30303, OptionalInt.of(30303)); + final String enodeURL = + String.format( + "enode://%s@%s:%d?discport=%d", + id.toString().substring(2), + endpoint.getHost(), + endpoint.getUdpPort(), + endpoint.getTcpPort().getAsInt()); + when(peer.getId()).thenReturn(id); - when(peer.getEndpoint()).thenReturn(new Endpoint("127.0.0.1", 30303, OptionalInt.of(30303))); + when(peer.getEndpoint()).thenReturn(endpoint); + when(peer.getEnodeURI()).thenReturn(enodeURL); + return peer; } } diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java index 257c11641b..3a0fa05907 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTestHelper.java @@ -20,7 +20,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.Packet; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PacketType; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PingPacketData; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.Arrays; diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java index 0b1ae98722..79907f91aa 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/MockPeerDiscoveryAgent.java @@ -17,7 +17,7 @@ import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration; import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer; import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryAgent; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.net.InetSocketAddress; diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java index 1044196317..94e23aad50 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java @@ -35,7 +35,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryTestHelper; import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.bytes.Bytes32; @@ -947,8 +947,8 @@ public class PeerDiscoveryControllerTest { final NodeWhitelistController nodeWhitelistController = new NodeWhitelistController(config); // Whitelist peers - nodeWhitelistController.addNode(discoPeer); - nodeWhitelistController.addNode(otherPeer2); + nodeWhitelistController.addNodes(Arrays.asList(discoPeer.getEnodeURI())); + nodeWhitelistController.addNodes(Arrays.asList(otherPeer2.getEnodeURI())); final OutboundMessageHandler outboundMessageHandler = mock(OutboundMessageHandler.class); controller = diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java index 56a0221de8..b40f2b7aed 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java +++ b/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/RecursivePeerRefreshStateTest.java @@ -27,11 +27,12 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryStatus; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.RecursivePeerRefreshState.BondingAgent; import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.RecursivePeerRefreshState.FindNeighbourDispatcher; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.nio.file.Files; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -486,7 +487,7 @@ public class RecursivePeerRefreshStateTest { final NodeWhitelistController peerWhitelist = new NodeWhitelistController(permissioningConfiguration); - peerWhitelist.addNode(peerA); + peerWhitelist.addNodes(Arrays.asList(peerA.getEnodeURI())); recursivePeerRefreshState = new RecursivePeerRefreshState( diff --git a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistController.java b/ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/NodeWhitelistController.java similarity index 68% rename from ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistController.java rename to ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/NodeWhitelistController.java index 6dbef2c6b8..7c515f4ccd 100644 --- a/ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistController.java +++ b/ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/NodeWhitelistController.java @@ -10,15 +10,9 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ -package tech.pegasys.pantheon.ethereum.p2p.permissioning; +package tech.pegasys.pantheon.ethereum.permissioning; -import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; -import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; -import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfigurationBuilder; -import tech.pegasys.pantheon.ethereum.permissioning.WhitelistFileSyncException; -import tech.pegasys.pantheon.ethereum.permissioning.WhitelistOperationResult; -import tech.pegasys.pantheon.ethereum.permissioning.WhitelistPersistor; +import tech.pegasys.pantheon.util.enode.EnodeURL; import java.io.IOException; import java.net.URI; @@ -38,7 +32,7 @@ public class NodeWhitelistController { private static final Logger LOG = LogManager.getLogger(); private PermissioningConfiguration configuration; - private List nodesWhitelist = new ArrayList<>(); + private List nodesWhitelist = new ArrayList<>(); private final WhitelistPersistor whitelistPersistor; public NodeWhitelistController(final PermissioningConfiguration permissioningConfiguration) { @@ -57,70 +51,72 @@ public class NodeWhitelistController { private void readNodesFromConfig(final PermissioningConfiguration configuration) { if (configuration.isNodeWhitelistEnabled() && configuration.getNodeWhitelist() != null) { for (URI uri : configuration.getNodeWhitelist()) { - nodesWhitelist.add(DefaultPeer.fromURI(uri)); + nodesWhitelist.add(new EnodeURL(uri.toString())); } } } - public boolean addNode(final Peer node) { - return nodesWhitelist.add(node); - } - - private boolean removeNode(final Peer node) { - return nodesWhitelist.remove(node); - } - - public NodesWhitelistResult addNodes(final List peers) { - final NodesWhitelistResult inputValidationResult = validInput(peers); + public NodesWhitelistResult addNodes(final List enodeURLs) { + final NodesWhitelistResult inputValidationResult = validInput(enodeURLs); if (inputValidationResult.result() != WhitelistOperationResult.SUCCESS) { return inputValidationResult; } + final List peers = enodeURLs.stream().map(EnodeURL::new).collect(Collectors.toList()); - for (Peer peer : peers) { + for (EnodeURL peer : peers) { if (nodesWhitelist.contains(peer)) { return new NodesWhitelistResult( WhitelistOperationResult.ERROR_EXISTING_ENTRY, - String.format("Specified peer: %s already exists in whitelist.", peer.getId())); + String.format("Specified peer: %s already exists in whitelist.", peer.getNodeId())); } } - final List oldWhitelist = new ArrayList<>(this.nodesWhitelist); - + final List oldWhitelist = new ArrayList<>(this.nodesWhitelist); peers.forEach(this::addNode); - try { - verifyConfigurationFileState(peerToEnodeURI(oldWhitelist)); - updateConfigurationFile(peerToEnodeURI(nodesWhitelist)); - verifyConfigurationFileState(peerToEnodeURI(nodesWhitelist)); - } catch (IOException e) { - revertState(oldWhitelist); - return new NodesWhitelistResult(WhitelistOperationResult.ERROR_WHITELIST_PERSIST_FAIL); - } catch (WhitelistFileSyncException e) { - return new NodesWhitelistResult(WhitelistOperationResult.ERROR_WHITELIST_FILE_SYNC); + + final NodesWhitelistResult updateConfigFileResult = updateWhitelistInConfigFile(oldWhitelist); + if (updateConfigFileResult.result() != WhitelistOperationResult.SUCCESS) { + return updateConfigFileResult; } + return new NodesWhitelistResult(WhitelistOperationResult.SUCCESS); } - private boolean peerListHasDuplicates(final List peers) { - return !peers.stream().allMatch(new HashSet<>()::add); + private boolean addNode(final EnodeURL enodeURL) { + return nodesWhitelist.add(enodeURL); } - public NodesWhitelistResult removeNodes(final List peers) { - final NodesWhitelistResult inputValidationResult = validInput(peers); + public NodesWhitelistResult removeNodes(final List enodeURLs) { + final NodesWhitelistResult inputValidationResult = validInput(enodeURLs); if (inputValidationResult.result() != WhitelistOperationResult.SUCCESS) { return inputValidationResult; } + final List peers = enodeURLs.stream().map(EnodeURL::new).collect(Collectors.toList()); - for (Peer peer : peers) { + for (EnodeURL peer : peers) { if (!(nodesWhitelist.contains(peer))) { return new NodesWhitelistResult( WhitelistOperationResult.ERROR_ABSENT_ENTRY, - String.format("Specified peer: %s does not exist in whitelist.", peer.getId())); + String.format("Specified peer: %s does not exist in whitelist.", peer.getNodeId())); } } - final List oldWhitelist = new ArrayList<>(this.nodesWhitelist); - + final List oldWhitelist = new ArrayList<>(this.nodesWhitelist); peers.forEach(this::removeNode); + + final NodesWhitelistResult updateConfigFileResult = updateWhitelistInConfigFile(oldWhitelist); + if (updateConfigFileResult.result() != WhitelistOperationResult.SUCCESS) { + return updateConfigFileResult; + } + + return new NodesWhitelistResult(WhitelistOperationResult.SUCCESS); + } + + private boolean removeNode(final EnodeURL enodeURL) { + return nodesWhitelist.remove(enodeURL); + } + + private NodesWhitelistResult updateWhitelistInConfigFile(final List oldWhitelist) { try { verifyConfigurationFileState(peerToEnodeURI(oldWhitelist)); updateConfigurationFile(peerToEnodeURI(nodesWhitelist)); @@ -131,10 +127,11 @@ public class NodeWhitelistController { } catch (WhitelistFileSyncException e) { return new NodesWhitelistResult(WhitelistOperationResult.ERROR_WHITELIST_FILE_SYNC); } + return new NodesWhitelistResult(WhitelistOperationResult.SUCCESS); } - private NodesWhitelistResult validInput(final List peers) { + private NodesWhitelistResult validInput(final List peers) { if (peers == null || peers.isEmpty()) { return new NodesWhitelistResult( WhitelistOperationResult.ERROR_EMPTY_ENTRY, String.format("Null/empty peers list")); @@ -149,6 +146,10 @@ public class NodeWhitelistController { return new NodesWhitelistResult(WhitelistOperationResult.SUCCESS); } + private boolean peerListHasDuplicates(final List peers) { + return !peers.stream().allMatch(new HashSet<>()::add); + } + private void verifyConfigurationFileState(final Collection oldNodes) throws IOException, WhitelistFileSyncException { whitelistPersistor.verifyConfigFileMatchesState( @@ -159,40 +160,41 @@ public class NodeWhitelistController { whitelistPersistor.updateConfig(WhitelistPersistor.WHITELIST_TYPE.NODES, nodes); } - private void revertState(final List nodesWhitelist) { + private void revertState(final List nodesWhitelist) { this.nodesWhitelist = nodesWhitelist; } - private Collection peerToEnodeURI(final Collection peers) { - return peers.parallelStream().map(Peer::getEnodeURI).collect(Collectors.toList()); + private Collection peerToEnodeURI(final Collection peers) { + return peers.parallelStream().map(EnodeURL::toString).collect(Collectors.toList()); + } + + public boolean isPermitted(final String enodeURL) { + return isPermitted(new EnodeURL(enodeURL)); } - public boolean isPermitted(final Peer node) { + private boolean isPermitted(final EnodeURL node) { return nodesWhitelist.stream() .anyMatch( p -> { - boolean idsMatch = node.getId().equals(p.getId()); - boolean hostsMatch = node.getEndpoint().getHost().equals(p.getEndpoint().getHost()); - boolean udpPortsMatch = - node.getEndpoint().getUdpPort() == p.getEndpoint().getUdpPort(); + boolean idsMatch = node.getNodeId().equals(p.getNodeId()); + boolean hostsMatch = node.getIp().equals(p.getIp()); + boolean udpPortsMatch = node.getListeningPort().equals(p.getListeningPort()); boolean tcpPortsMatchIfPresent = true; - if (node.getEndpoint().getTcpPort().isPresent() - && p.getEndpoint().getTcpPort().isPresent()) { + if (node.getDiscoveryPort().isPresent() && p.getDiscoveryPort().isPresent()) { tcpPortsMatchIfPresent = - node.getEndpoint().getTcpPort().getAsInt() - == p.getEndpoint().getTcpPort().getAsInt(); + node.getDiscoveryPort().getAsInt() == p.getDiscoveryPort().getAsInt(); } return idsMatch && hostsMatch && udpPortsMatch && tcpPortsMatchIfPresent; }); } - public List getNodesWhitelist() { - return nodesWhitelist; + public List getNodesWhitelist() { + return nodesWhitelist.stream().map(Object::toString).collect(Collectors.toList()); } public synchronized void reload() throws RuntimeException { - final List currentAccountsList = new ArrayList<>(nodesWhitelist); + final List currentAccountsList = new ArrayList<>(nodesWhitelist); nodesWhitelist.clear(); try { diff --git a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistControllerTest.java b/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeWhitelistControllerTest.java similarity index 63% rename from ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistControllerTest.java rename to ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeWhitelistControllerTest.java index 28301cbe2c..c02dfdf5cb 100644 --- a/ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistControllerTest.java +++ b/ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/NodeWhitelistControllerTest.java @@ -10,7 +10,7 @@ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ -package tech.pegasys.pantheon.ethereum.p2p.permissioning; +package tech.pegasys.pantheon.ethereum.permissioning; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; @@ -22,15 +22,9 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; -import static tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController.NodesWhitelistResult; +import static tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController.NodesWhitelistResult; -import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; -import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; -import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; -import tech.pegasys.pantheon.ethereum.permissioning.WhitelistFileSyncException; -import tech.pegasys.pantheon.ethereum.permissioning.WhitelistOperationResult; -import tech.pegasys.pantheon.ethereum.permissioning.WhitelistPersistor; -import tech.pegasys.pantheon.util.bytes.BytesValue; +import tech.pegasys.pantheon.util.enode.EnodeURL; import java.io.IOException; import java.net.URI; @@ -67,13 +61,11 @@ public class NodeWhitelistControllerTest { @Test public void whenAddNodesInputHasExistingNodeShouldReturnAddErrorExistingEntry() { - controller.addNode(DefaultPeer.fromURI(enode1)); + controller.addNodes(Arrays.asList(enode1)); NodesWhitelistResult expected = new NodesWhitelistResult(WhitelistOperationResult.ERROR_EXISTING_ENTRY); - NodesWhitelistResult actualResult = - controller.addNodes( - Lists.newArrayList(DefaultPeer.fromURI(enode1), DefaultPeer.fromURI(enode2))); + NodesWhitelistResult actualResult = controller.addNodes(Lists.newArrayList(enode1, enode2)); assertThat(actualResult).isEqualToComparingOnlyGivenFields(expected, "result"); } @@ -83,9 +75,7 @@ public class NodeWhitelistControllerTest { NodesWhitelistResult expected = new NodesWhitelistResult(WhitelistOperationResult.ERROR_DUPLICATED_ENTRY); - NodesWhitelistResult actualResult = - controller.addNodes( - Arrays.asList(DefaultPeer.fromURI(enode1), DefaultPeer.fromURI(enode1))); + NodesWhitelistResult actualResult = controller.addNodes(Arrays.asList(enode1, enode1)); assertThat(actualResult).isEqualToComparingOnlyGivenFields(expected, "result"); } @@ -112,9 +102,7 @@ public class NodeWhitelistControllerTest { public void whenRemoveNodesInputHasAbsentNodeShouldReturnRemoveErrorAbsentEntry() { NodesWhitelistResult expected = new NodesWhitelistResult(WhitelistOperationResult.ERROR_ABSENT_ENTRY); - NodesWhitelistResult actualResult = - controller.removeNodes( - Lists.newArrayList(DefaultPeer.fromURI(enode1), DefaultPeer.fromURI(enode2))); + NodesWhitelistResult actualResult = controller.removeNodes(Lists.newArrayList(enode1, enode2)); assertThat(actualResult).isEqualToComparingOnlyGivenFields(expected, "result"); } @@ -123,9 +111,7 @@ public class NodeWhitelistControllerTest { public void whenRemoveNodesInputHasDuplicateNodesShouldReturnErrorDuplicatedEntry() { NodesWhitelistResult expected = new NodesWhitelistResult(WhitelistOperationResult.ERROR_DUPLICATED_ENTRY); - NodesWhitelistResult actualResult = - controller.removeNodes( - Lists.newArrayList(DefaultPeer.fromURI(enode1), DefaultPeer.fromURI(enode1))); + NodesWhitelistResult actualResult = controller.removeNodes(Lists.newArrayList(enode1, enode1)); assertThat(actualResult).isEqualToComparingOnlyGivenFields(expected, "result"); } @@ -150,103 +136,60 @@ public class NodeWhitelistControllerTest { @Test public void whenNodeIdsAreDifferentItShouldNotBePermitted() { - Peer peer1 = - new DefaultPeer( - BytesValue.fromHexString( - "0xaaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303); - Peer peer2 = - new DefaultPeer( - BytesValue.fromHexString( - "0xbbba80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303); - - controller.addNode(peer1); + String peer1 = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303"; + String peer2 = + "enode://bbbb80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303"; + + controller.addNodes(Arrays.asList(peer1)); assertThat(controller.isPermitted(peer2)).isFalse(); } @Test public void whenNodesHostsAreDifferentItShouldNotBePermitted() { - Peer peer1 = - new DefaultPeer( - BytesValue.fromHexString( - "0xaaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303); - Peer peer2 = - new DefaultPeer( - BytesValue.fromHexString( - "0xaaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.2", - 30303); - - controller.addNode(peer1); + String peer1 = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303"; + String peer2 = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.2:30303"; + + controller.addNodes(Arrays.asList(peer1)); assertThat(controller.isPermitted(peer2)).isFalse(); } @Test public void whenNodesUdpPortsAreDifferentItShouldNotBePermitted() { - Peer peer1 = - new DefaultPeer( - BytesValue.fromHexString( - "0xaaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30301); - Peer peer2 = - new DefaultPeer( - BytesValue.fromHexString( - "0xaaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30302); - - controller.addNode(peer1); + String peer1 = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30301"; + String peer2 = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30302"; + + controller.addNodes(Arrays.asList(peer1)); assertThat(controller.isPermitted(peer2)).isFalse(); } @Test public void whenCheckingIfNodeIsPermittedTcpPortShouldNotBeConsideredIfAbsent() { - Peer peerWithTcpPortSet = - new DefaultPeer( - BytesValue.fromHexString( - "0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303, - 10001); - Peer peerWithoutTcpPortSet = - new DefaultPeer( - BytesValue.fromHexString( - "0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303); - - controller.addNode(peerWithoutTcpPortSet); - - assertThat(controller.isPermitted(peerWithTcpPortSet)).isTrue(); + String peerWithTcpPortSet = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303?discport=10001"; + String peerWithoutTcpPortSet = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303"; + + controller.addNodes(Arrays.asList(peerWithTcpPortSet)); + + assertThat(controller.isPermitted(peerWithoutTcpPortSet)).isTrue(); } @Test public void whenCheckingIfNodeIsPermittedTcpPortShouldBeConsideredIfPresent() { - Peer peerWithTcpPortSet = - new DefaultPeer( - BytesValue.fromHexString( - "0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303, - 10001); - Peer peerWithDifferentTcpPortSet = - new DefaultPeer( - BytesValue.fromHexString( - "0x6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"), - "127.0.0.1", - 30303, - 10002); - - controller.addNode(peerWithDifferentTcpPortSet); + String peerWithTcpPortSet = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303?discport=10001"; + String peerWithDifferentTcpPortSet = + "enode://aaaa80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@127.0.0.1:30303?discport=10002"; + + controller.addNodes(Arrays.asList(peerWithDifferentTcpPortSet)); assertThat(controller.isPermitted(peerWithTcpPortSet)).isFalse(); } @@ -254,8 +197,8 @@ public class NodeWhitelistControllerTest { @Test public void stateShouldRevertIfWhitelistPersistFails() throws IOException, WhitelistFileSyncException { - List newNode1 = singletonList(DefaultPeer.fromURI(enode1)); - List newNode2 = singletonList(DefaultPeer.fromURI(enode2)); + List newNode1 = singletonList(new EnodeURL(enode1).toString()); + List newNode2 = singletonList(new EnodeURL(enode2).toString()); assertThat(controller.getNodesWhitelist().size()).isEqualTo(0); @@ -289,8 +232,7 @@ public class NodeWhitelistControllerTest { controller.reload(); - assertThat(controller.getNodesWhitelist()) - .containsExactly(DefaultPeer.fromURI(expectedEnodeURL)); + assertThat(controller.getNodesWhitelist()).containsExactly(expectedEnodeURL); } @Test @@ -311,8 +253,7 @@ public class NodeWhitelistControllerTest { .isInstanceOf(RuntimeException.class) .hasMessageContaining("Unable to read permissions TOML config file"); - assertThat(controller.getNodesWhitelist()) - .containsExactly(DefaultPeer.fromURI(expectedEnodeURI)); + assertThat(controller.getNodesWhitelist()).containsExactly(expectedEnodeURI); } private Path createPermissionsFileWithNode(final String node) throws IOException { diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java index dd2cc0509c..565b17c85d 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java @@ -49,10 +49,10 @@ import tech.pegasys.pantheon.ethereum.p2p.config.RlpxConfiguration; import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import tech.pegasys.pantheon.ethereum.p2p.netty.NettyP2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist; -import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.wire.Capability; import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol; import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController; +import tech.pegasys.pantheon.ethereum.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration; import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionHandler; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive; diff --git a/util/src/main/java/tech/pegasys/pantheon/util/enode/EnodeURL.java b/util/src/main/java/tech/pegasys/pantheon/util/enode/EnodeURL.java index 17602a11b6..0ebb759671 100644 --- a/util/src/main/java/tech/pegasys/pantheon/util/enode/EnodeURL.java +++ b/util/src/main/java/tech/pegasys/pantheon/util/enode/EnodeURL.java @@ -143,6 +143,22 @@ public class EnodeURL { return value.contains("discport"); } + public String getNodeId() { + return nodeId; + } + + public String getIp() { + return ip; + } + + public Integer getListeningPort() { + return listeningPort; + } + + public OptionalInt getDiscoveryPort() { + return discoveryPort; + } + @Override public boolean equals(final Object o) { if (this == o) { @@ -162,4 +178,9 @@ public class EnodeURL { public int hashCode() { return Objects.hashCode(nodeId, ip, listeningPort, discoveryPort); } + + @Override + public String toString() { + return this.toURI().toString(); + } }