[NC-2005] Implemented --p2p-enabled configuration item (#619)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
mark-terry 6 years ago committed by GitHub
parent a0ce15568e
commit a1ef038865
  1. 57
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/P2pDisabledAcceptanceTest.java
  2. 36
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/condition/net/AwaitNetPeerCountException.java
  3. 5
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/jsonrpc/Net.java
  4. 10
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java
  5. 1
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java
  6. 9
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfiguration.java
  7. 9
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfigurationBuilder.java
  8. 13
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonNodeFactory.java
  9. 5
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AdminPeers.java
  10. 9
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/NetPeerCount.java
  11. 3
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelist.java
  12. 19
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelist.java
  13. 3
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelist.java
  14. 1
      ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/response/JsonRpcError.java
  15. 14
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/AdminPeersTest.java
  16. 14
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermAddNodesToWhitelistTest.java
  17. 13
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermGetNodesWhitelistTest.java
  18. 13
      ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/permissioning/PermRemoveNodesFromWhitelistTest.java
  19. 90
      ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/NoopP2PNetwork.java
  20. 19
      ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/P2pDisabledException.java
  21. 4
      pantheon/src/main/java/tech/pegasys/pantheon/Runner.java
  22. 38
      pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java
  23. 17
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  24. 30
      pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java
  25. 1
      pantheon/src/test/resources/everything_config.toml

@ -0,0 +1,57 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* 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.tests.acceptance;
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.Cluster;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.ClusterConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.ClusterConfigurationBuilder;
import org.junit.Before;
import org.junit.Test;
public class P2pDisabledAcceptanceTest extends AcceptanceTestBase {
private Node node;
private Cluster p2pDisabledCluster;
@Before
public void setUp() throws Exception {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().setAwaitPeerDiscovery(false).build();
p2pDisabledCluster = new Cluster(clusterConfiguration, net);
node = pantheon.createArchiveNodeWithP2pDisabled("node1");
p2pDisabledCluster.start(node);
}
@Override
public void tearDownAcceptanceTestBase() {
p2pDisabledCluster.stop();
super.tearDownAcceptanceTestBase();
}
@Test
public void shouldSucceedExecutingUnaffectedJsonRpcCall() {
final String input = "0x68656c6c6f20776f726c64";
final String expectedHash =
"0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad";
node.verify(web3.sha3(input, expectedHash));
}
@Test
public void shouldFailExecutingAffectedJsonRpcCall() {
node.verify(net.awaitPeerCountExceptional());
}
}

@ -0,0 +1,36 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* 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.tests.acceptance.dsl.condition.net;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.net.NetPeerCountTransaction;
public class AwaitNetPeerCountException implements Condition {
private final NetPeerCountTransaction transaction;
public AwaitNetPeerCountException(final NetPeerCountTransaction transaction) {
this.transaction = transaction;
}
@Override
public void verify(final Node node) {
final Throwable thrown = catchThrowable(() -> node.execute(transaction));
assertThat(thrown).isInstanceOf(RuntimeException.class);
assertThat(thrown).hasMessageContaining("P2P has been disabled.");
}
}

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.AwaitNetPeerCount;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.AwaitNetPeerCountException;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.ExpectNetVersionConnectionException;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.ExpectNetVersionConnectionExceptionWithCause;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.ExpectNetVersionIsNotBlank;
@ -44,4 +45,8 @@ public class Net {
public Condition netVersionExceptional(final Class<? extends Throwable> cause) {
return new ExpectNetVersionConnectionExceptionWithCause(transactions.netVersion(), cause);
}
public Condition awaitPeerCountExceptional() {
return new AwaitNetPeerCountException(transactions.peerCount());
}
}

@ -65,6 +65,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
private final KeyPair keyPair;
private final int p2pPort;
private final Properties portsProperties = new Properties();
private final Boolean p2pEnabled;
private final String name;
private final MiningParameters miningParameters;
@ -88,7 +89,8 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
final PermissioningConfiguration permissioningConfiguration,
final boolean devMode,
final GenesisConfigProvider genesisConfigProvider,
final int p2pPort)
final int p2pPort,
final Boolean p2pEnabled)
throws IOException {
this.homeDirectory = Files.createTempDirectory("acctest");
this.keyPair = KeyPairUtil.loadKeyPair(homeDirectory);
@ -101,6 +103,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
this.permissioningConfiguration = permissioningConfiguration;
this.genesisConfigProvider = genesisConfigProvider;
this.devMode = devMode;
this.p2pEnabled = p2pEnabled;
LOG.info("Created PantheonNode {}", this.toString());
}
@ -313,6 +316,10 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
.collect(Collectors.toList());
}
Boolean p2pEnabled() {
return p2pEnabled;
}
@Override
public void bootnodes(final List<String> bootnodes) {
this.bootnodes = bootnodes;
@ -337,6 +344,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
.add("p2pPort", p2pPort)
.add("homeDirectory", homeDirectory)
.add("keyPair", keyPair)
.add("p2pEnabled", p2pEnabled)
.toString();
}

@ -89,6 +89,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner {
.metricsSystem(noOpMetricsSystem)
.metricsConfiguration(node.metricsConfiguration())
.permissioningConfiguration(node.getPermissioningConfiguration())
.p2pEnabled(node.p2pEnabled())
.build();
nodeExecutor.submit(runner::execute);

@ -29,6 +29,7 @@ class PantheonFactoryConfiguration {
private final PermissioningConfiguration permissioningConfiguration;
private final boolean devMode;
private final GenesisConfigProvider genesisConfigProvider;
private final Boolean p2pEnabled;
PantheonFactoryConfiguration(
final String name,
@ -38,7 +39,8 @@ class PantheonFactoryConfiguration {
final MetricsConfiguration metricsConfiguration,
final PermissioningConfiguration permissioningConfiguration,
final boolean devMode,
final GenesisConfigProvider genesisConfigProvider) {
final GenesisConfigProvider genesisConfigProvider,
final Boolean p2pEnabled) {
this.name = name;
this.miningParameters = miningParameters;
this.jsonRpcConfiguration = jsonRpcConfiguration;
@ -47,6 +49,7 @@ class PantheonFactoryConfiguration {
this.permissioningConfiguration = permissioningConfiguration;
this.devMode = devMode;
this.genesisConfigProvider = genesisConfigProvider;
this.p2pEnabled = p2pEnabled;
}
public String getName() {
@ -80,4 +83,8 @@ class PantheonFactoryConfiguration {
public GenesisConfigProvider getGenesisConfigProvider() {
return genesisConfigProvider;
}
public Boolean getP2pEnabled() {
return p2pEnabled;
}
}

@ -36,6 +36,7 @@ public class PantheonFactoryConfigurationBuilder {
PermissioningConfiguration.createDefault();
private boolean devMode = true;
private GenesisConfigProvider genesisConfigProvider = ignore -> Optional.empty();
private Boolean p2pEnabled = true;
public PantheonFactoryConfigurationBuilder setName(final String name) {
this.name = name;
@ -107,6 +108,11 @@ public class PantheonFactoryConfigurationBuilder {
return this;
}
public PantheonFactoryConfigurationBuilder setP2pEnabled(final Boolean p2pEnabled) {
this.p2pEnabled = p2pEnabled;
return this;
}
public PantheonFactoryConfiguration build() {
return new PantheonFactoryConfiguration(
name,
@ -116,6 +122,7 @@ public class PantheonFactoryConfigurationBuilder {
metricsConfiguration,
permissioningConfiguration,
devMode,
genesisConfigProvider);
genesisConfigProvider,
p2pEnabled);
}
}

@ -57,7 +57,8 @@ public class PantheonNodeFactory {
config.getPermissioningConfiguration(),
config.isDevMode(),
config.getGenesisConfigProvider(),
serverSocket.getLocalPort());
serverSocket.getLocalPort(),
config.getP2pEnabled());
serverSocket.close();
return node;
@ -97,6 +98,16 @@ public class PantheonNodeFactory {
.build());
}
public PantheonNode createArchiveNodeWithP2pDisabled(final String name) throws IOException {
return create(
new PantheonFactoryConfigurationBuilder()
.setName(name)
.setP2pEnabled(false)
.setJsonRpcConfiguration(jsonRpcConfigWithPermissioning())
.webSocketEnabled()
.build());
}
public PantheonNode createArchiveNodeWithCustomRefreshDelay(
final String name, final Long refreshDelay) throws IOException {
WebSocketConfiguration wsConfig = createWebSocketEnabledConfig();

@ -13,9 +13,12 @@
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
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.jsonrpc.internal.results.PeerResult;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import java.util.List;
@ -45,6 +48,8 @@ public class AdminPeers implements JsonRpcMethod {
peerDiscoveryAgent.getPeers().stream().map(PeerResult::new).collect(Collectors.toList());
final JsonRpcResponse result = new JsonRpcSuccessResponse(req.getId(), peers);
return result;
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
} catch (final Exception e) {
LOG.error("Error processing request: " + req, e);
throw e;

@ -13,9 +13,12 @@
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
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.jsonrpc.internal.results.Quantity;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
public class NetPeerCount implements JsonRpcMethod {
@ -32,6 +35,10 @@ public class NetPeerCount implements JsonRpcMethod {
@Override
public JsonRpcResponse response(final JsonRpcRequest req) {
return new JsonRpcSuccessResponse(req.getId(), Quantity.create(p2pNetwork.getPeers().size()));
try {
return new JsonRpcSuccessResponse(req.getId(), Quantity.create(p2pNetwork.getPeers().size()));
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
}
}
}

@ -20,6 +20,7 @@ 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.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -69,6 +70,8 @@ public class PermAddNodesToWhitelist implements JsonRpcMethod {
}
} catch (IllegalArgumentException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY);
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
} catch (Exception e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INTERNAL_ERROR);
}

@ -18,6 +18,7 @@ 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.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
@ -43,15 +44,19 @@ public class PermGetNodesWhitelist implements JsonRpcMethod {
@Override
public JsonRpcResponse response(final JsonRpcRequest req) {
if (p2pNetwork.getNodeWhitelistController().nodeWhitelistSet()) {
List<Peer> nodesWhitelist = p2pNetwork.getNodeWhitelistController().getNodesWhitelist();
try {
if (p2pNetwork.getNodeWhitelistController().nodeWhitelistSet()) {
List<Peer> nodesWhitelist = p2pNetwork.getNodeWhitelistController().getNodesWhitelist();
List<String> enodeList =
nodesWhitelist.parallelStream().map(this::buildEnodeURI).collect(Collectors.toList());
List<String> enodeList =
nodesWhitelist.parallelStream().map(this::buildEnodeURI).collect(Collectors.toList());
return new JsonRpcSuccessResponse(req.getId(), enodeList);
} else {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_NOT_SET);
return new JsonRpcSuccessResponse(req.getId(), enodeList);
} else {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_NOT_SET);
}
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
}
}

@ -20,6 +20,7 @@ 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.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -69,6 +70,8 @@ public class PermRemoveNodesFromWhitelist implements JsonRpcMethod {
}
} catch (IllegalArgumentException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY);
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
} catch (Exception e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INTERNAL_ERROR);
}

@ -25,6 +25,7 @@ public enum JsonRpcError {
METHOD_NOT_FOUND(-32601, "Method not found"),
INVALID_PARAMS(-32602, "Invalid params"),
INTERNAL_ERROR(-32603, "Internal error"),
P2P_DISABLED(-32000, "P2P has been disabled. This functionality is not available."),
// Filter & Subscription Errors
FILTER_NOT_FOUND(-32000, "Filter not found"),

@ -17,9 +17,12 @@ import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.jsonrpc.MockPeerConnection;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest;
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.jsonrpc.internal.results.PeerResult;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection;
import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
@ -83,6 +86,17 @@ public class AdminPeersTest {
assertThat(response).isEqualToComparingFieldByFieldRecursively(expectedResponse);
}
@Test
public void shouldFailIfP2pDisabled() {
when(p2pNetwork.getPeers()).thenThrow(new P2pDisabledException("P2P disabled."));
final JsonRpcRequest request = adminPeers();
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getId(), JsonRpcError.P2P_DISABLED);
assertThat(adminPeers.response(request)).isEqualToComparingFieldByField(expectedResponse);
}
private Collection<PeerConnection> peerList() {
final PeerInfo peerInfo =
new PeerInfo(5, "0x0", Collections.emptyList(), 30303, BytesValue.EMPTY);

@ -27,6 +27,7 @@ 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.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -133,6 +134,19 @@ public class PermAddNodesToWhitelistTest {
verifyNoMoreInteractions(nodeWhitelistController);
}
@Test
public void shouldFailWhenP2pDisabled() {
when(p2pNetwork.getNodeWhitelistController())
.thenThrow(new P2pDisabledException("P2P disabled."));
final JsonRpcRequest request = buildRequest(Lists.newArrayList(enode1, enode2, enode3));
;
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getId(), JsonRpcError.P2P_DISABLED);
assertThat(method.response(request)).isEqualToComparingFieldByField(expectedResponse);
}
private JsonRpcRequest buildRequest(final List<String> enodeList) {
return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {enodeList});
}

@ -23,6 +23,7 @@ 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.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;
@ -120,6 +121,18 @@ public class PermGetNodesWhitelistTest {
verifyNoMoreInteractions(nodeWhitelistController);
}
@Test
public void shouldFailWhenP2pDisabled() {
when(p2pNetwork.getNodeWhitelistController())
.thenThrow(new P2pDisabledException("P2P disabled."));
final JsonRpcRequest request = buildRequest();
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getId(), JsonRpcError.P2P_DISABLED);
assertThat(method.response(request)).isEqualToComparingFieldByField(expectedResponse);
}
private JsonRpcRequest buildRequest() {
return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {});
}

@ -27,6 +27,7 @@ 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.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -123,6 +124,18 @@ public class PermRemoveNodesFromWhitelistTest {
verifyNoMoreInteractions(nodeWhitelistController);
}
@Test
public void shouldFailWhenP2pDisabled() {
when(p2pNetwork.getNodeWhitelistController())
.thenThrow(new P2pDisabledException("P2P disabled."));
final JsonRpcRequest request = buildRequest(Lists.newArrayList(enode1, enode2, enode3));
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(request.getId(), JsonRpcError.P2P_DISABLED);
assertThat(method.response(request)).isEqualToComparingFieldByField(expectedResponse);
}
private JsonRpcRequest buildRequest(final List<String> enodeList) {
return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {enodeList});
}

@ -0,0 +1,90 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* 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;
import tech.pegasys.pantheon.ethereum.p2p.api.DisconnectCallback;
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 java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
public class NoopP2PNetwork implements P2PNetwork {
@Override
public Collection<PeerConnection> getPeers() {
throw new P2pDisabledException("P2P networking disabled. Peers list unavailable.");
}
@Override
public CompletableFuture<PeerConnection> connect(final Peer peer) {
throw new P2pDisabledException("P2P networking disabled. Unable to connect to network.");
}
@Override
public void subscribe(final Capability capability, final Consumer<Message> consumer) {}
@Override
public void subscribeConnect(final Consumer<PeerConnection> consumer) {}
@Override
public void subscribeDisconnect(final DisconnectCallback consumer) {}
@Override
public boolean addMaintainConnectionPeer(final Peer peer) {
throw new P2pDisabledException("P2P networking disabled. Unable to connect to add peer.");
}
@Override
public void checkMaintainedConnectionPeers() {}
@Override
public void stop() {}
@Override
public void awaitStop() {}
@Override
public InetSocketAddress getDiscoverySocketAddress() {
throw new P2pDisabledException(
"P2P networking disabled. Discovery socket address unavailable.");
}
@Override
public PeerInfo getLocalPeerInfo() {
throw new P2pDisabledException("P2P networking disabled. Local peer info unavailable.");
}
@Override
public boolean isListening() {
return false;
}
@Override
public NodeWhitelistController getNodeWhitelistController() {
throw new P2pDisabledException("P2P networking disabled. Node whitelist unavailable.");
}
@Override
public void close() throws IOException {}
@Override
public void run() {}
}

@ -0,0 +1,19 @@
/*
* Copyright 2019 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* 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;
public class P2pDisabledException extends RuntimeException {
public P2pDisabledException(final String message) {
super(message);
}
}

@ -40,7 +40,6 @@ public class Runner implements AutoCloseable {
private final ExecutorService exec = Executors.newCachedThreadPool();
private final NetworkRunner networkRunner;
private final Optional<JsonRpcHttpService> jsonRpc;
private final Optional<WebSocketService> websocketRpc;
private final Optional<MetricsHttpService> metrics;
@ -89,6 +88,7 @@ public class Runner implements AutoCloseable {
public void close() throws Exception {
networkRunner.stop();
networkRunner.awaitStop();
exec.shutdown();
try {
jsonRpc.ifPresent(service -> service.stop().join());
@ -109,10 +109,12 @@ public class Runner implements AutoCloseable {
private void writePantheonPortsToFile() {
final Properties properties = new Properties();
if (networkRunner.getNetwork().isListening()) {
properties.setProperty("discovery", String.valueOf(getP2pUdpPort()));
properties.setProperty("p2p", String.valueOf(getP2pTcpPort()));
}
if (getJsonRpcPort().isPresent()) {
properties.setProperty("json-rpc", String.valueOf(getJsonRpcPort().get()));
}

@ -39,6 +39,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.subscription.pending.Pen
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.subscription.syncing.SyncingSubscriptionService;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.NetworkRunner;
import tech.pegasys.pantheon.ethereum.p2p.NoopP2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration;
@ -73,6 +75,7 @@ public class RunnerBuilder {
private Vertx vertx;
private PantheonController<?> pantheonController;
private boolean p2pEnabled = true;
private boolean discovery;
private Collection<?> bootstrapPeers;
private String discoveryHost;
@ -96,6 +99,11 @@ public class RunnerBuilder {
return this;
}
public RunnerBuilder p2pEnabled(final boolean p2pEnabled) {
this.p2pEnabled = p2pEnabled;
return this;
}
public RunnerBuilder discovery(final boolean discovery) {
this.discovery = discovery;
return this;
@ -213,16 +221,18 @@ public class RunnerBuilder {
.protocolManagers(protocolManagers)
.subProtocols(subProtocols)
.network(
caps ->
new NettyP2PNetwork(
vertx,
keyPair,
networkConfig,
caps,
PeerRequirement.aggregateOf(protocolManagers),
peerBlacklist,
metricsSystem,
nodeWhitelistController))
p2pEnabled
? caps ->
new NettyP2PNetwork(
vertx,
keyPair,
networkConfig,
caps,
PeerRequirement.aggregateOf(protocolManagers),
peerBlacklist,
metricsSystem,
nodeWhitelistController)
: caps -> new NoopP2PNetwork())
.metricsSystem(metricsSystem)
.build();
@ -245,7 +255,7 @@ public class RunnerBuilder {
context,
protocolSchedule,
pantheonController,
networkRunner,
networkRunner.getNetwork(),
synchronizer,
transactionPool,
miningCoordinator,
@ -267,7 +277,7 @@ public class RunnerBuilder {
context,
protocolSchedule,
pantheonController,
networkRunner,
networkRunner.getNetwork(),
synchronizer,
transactionPool,
miningCoordinator,
@ -326,7 +336,7 @@ public class RunnerBuilder {
final ProtocolContext<?> context,
final ProtocolSchedule<?> protocolSchedule,
final PantheonController<?> pantheonController,
final NetworkRunner networkRunner,
final P2PNetwork network,
final Synchronizer synchronizer,
final TransactionPool transactionPool,
final MiningCoordinator miningCoordinator,
@ -339,7 +349,7 @@ public class RunnerBuilder {
new JsonRpcMethodsFactory()
.methods(
PantheonInfo.version(),
networkRunner.getNetwork(),
network,
context.getBlockchain(),
context.getWorldStateArchive(),
synchronizer,

@ -156,6 +156,15 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
)
private final File nodePrivateKeyFile = null;
// Completely disables p2p within Pantheon.
@Option(
names = {"--p2p-enabled"},
description = "Enable/disable all p2p functionality (default: {DEFAULT-VALUE})",
arity = "0..1"
)
@SuppressWarnings("FieldCanBeFinal")
private Boolean p2pEnabled = true;
// Boolean option to indicate if peers should NOT be discovered, default to false indicates that
// the peers should be discovered by default.
//
@ -497,6 +506,11 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
Configurator.setAllLevels("", logLevel);
}
if (!p2pEnabled && (bootstrapNodes != null && !bootstrapNodes.isEmpty())) {
throw new ParameterException(
new CommandLine(this), "Unable to specify bootnodes if p2p is disabled.");
}
//noinspection ConstantConditions
if (isMiningEnabled && coinbase == null) {
throw new ParameterException(
@ -516,6 +530,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
synchronize(
buildController(),
p2pEnabled,
noPeerDiscovery,
ethNetworkConfig.getBootNodes(),
maxPeers,
@ -627,6 +642,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
// Blockchain synchronisation from peers.
private void synchronize(
final PantheonController<?> controller,
final boolean p2pEnabled,
final boolean noPeerDiscovery,
final Collection<?> bootstrapNodes,
final int maxPeers,
@ -642,6 +658,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
runnerBuilder
.vertx(Vertx.vertx())
.pantheonController(controller)
.p2pEnabled(p2pEnabled)
// BEWARE: Peer discovery boolean must be inverted as it's negated in the options !
.discovery(!noPeerDiscovery)
.bootstrapPeers(bootstrapNodes)

@ -122,6 +122,7 @@ public class PantheonCommandTest extends CommandTestAbstract {
when(mockRunnerBuilder.discoveryHost(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.discoveryPort(anyInt())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.maxPeers(anyInt())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.p2pEnabled(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.jsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.webSocketConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder);
@ -528,6 +529,35 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString()).isEmpty();
}
@Test
public void p2pEnabledOptionFlagDefaultTrue() {
parseCommand("--p2p-enabled");
verify(mockRunnerBuilder.p2pEnabled(eq(true))).build();
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void p2pEnabledOptionValueMustBeUsed() {
parseCommand("--p2p-enabled", "false");
verify(mockRunnerBuilder.p2pEnabled(eq(false))).build();
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void p2pEnabledOptionFalseValueCannotAlsoHaveBootnodesSpecified() {
parseCommand("--p2p-enabled", "false", "--bootnodes", String.join(",", validENodeStrings));
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString())
.contains("Unable to specify bootnodes if p2p is disabled.");
}
@Test
public void discoveryOptionMustBeUsed() {
parseCommand("--no-discovery");

@ -14,6 +14,7 @@ logging="INFO"
node-private-key="./path/to/privateKey"
# P2P network
p2p-enabled=true
no-discovery=true
bootnodes=[
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.1:4567",

Loading…
Cancel
Save