[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.Condition;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.AwaitNetPeerCount; 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.ExpectNetVersionConnectionException;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.ExpectNetVersionConnectionExceptionWithCause; import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.ExpectNetVersionConnectionExceptionWithCause;
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.net.ExpectNetVersionIsNotBlank; 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) { public Condition netVersionExceptional(final Class<? extends Throwable> cause) {
return new ExpectNetVersionConnectionExceptionWithCause(transactions.netVersion(), 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 KeyPair keyPair;
private final int p2pPort; private final int p2pPort;
private final Properties portsProperties = new Properties(); private final Properties portsProperties = new Properties();
private final Boolean p2pEnabled;
private final String name; private final String name;
private final MiningParameters miningParameters; private final MiningParameters miningParameters;
@ -88,7 +89,8 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
final PermissioningConfiguration permissioningConfiguration, final PermissioningConfiguration permissioningConfiguration,
final boolean devMode, final boolean devMode,
final GenesisConfigProvider genesisConfigProvider, final GenesisConfigProvider genesisConfigProvider,
final int p2pPort) final int p2pPort,
final Boolean p2pEnabled)
throws IOException { throws IOException {
this.homeDirectory = Files.createTempDirectory("acctest"); this.homeDirectory = Files.createTempDirectory("acctest");
this.keyPair = KeyPairUtil.loadKeyPair(homeDirectory); this.keyPair = KeyPairUtil.loadKeyPair(homeDirectory);
@ -101,6 +103,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
this.permissioningConfiguration = permissioningConfiguration; this.permissioningConfiguration = permissioningConfiguration;
this.genesisConfigProvider = genesisConfigProvider; this.genesisConfigProvider = genesisConfigProvider;
this.devMode = devMode; this.devMode = devMode;
this.p2pEnabled = p2pEnabled;
LOG.info("Created PantheonNode {}", this.toString()); LOG.info("Created PantheonNode {}", this.toString());
} }
@ -313,6 +316,10 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
Boolean p2pEnabled() {
return p2pEnabled;
}
@Override @Override
public void bootnodes(final List<String> bootnodes) { public void bootnodes(final List<String> bootnodes) {
this.bootnodes = bootnodes; this.bootnodes = bootnodes;
@ -337,6 +344,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
.add("p2pPort", p2pPort) .add("p2pPort", p2pPort)
.add("homeDirectory", homeDirectory) .add("homeDirectory", homeDirectory)
.add("keyPair", keyPair) .add("keyPair", keyPair)
.add("p2pEnabled", p2pEnabled)
.toString(); .toString();
} }

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

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

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

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

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

@ -13,9 +13,12 @@
package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; 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.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.Quantity;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
public class NetPeerCount implements JsonRpcMethod { public class NetPeerCount implements JsonRpcMethod {
@ -32,6 +35,10 @@ public class NetPeerCount implements JsonRpcMethod {
@Override @Override
public JsonRpcResponse response(final JsonRpcRequest req) { 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.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; 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.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -69,6 +70,8 @@ public class PermAddNodesToWhitelist implements JsonRpcMethod {
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY);
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
} catch (Exception e) { } catch (Exception e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INTERNAL_ERROR); 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.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; 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.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint; import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
@ -43,15 +44,19 @@ public class PermGetNodesWhitelist implements JsonRpcMethod {
@Override @Override
public JsonRpcResponse response(final JsonRpcRequest req) { public JsonRpcResponse response(final JsonRpcRequest req) {
if (p2pNetwork.getNodeWhitelistController().nodeWhitelistSet()) { try {
List<Peer> nodesWhitelist = p2pNetwork.getNodeWhitelistController().getNodesWhitelist(); if (p2pNetwork.getNodeWhitelistController().nodeWhitelistSet()) {
List<Peer> nodesWhitelist = p2pNetwork.getNodeWhitelistController().getNodesWhitelist();
List<String> enodeList = List<String> enodeList =
nodesWhitelist.parallelStream().map(this::buildEnodeURI).collect(Collectors.toList()); nodesWhitelist.parallelStream().map(this::buildEnodeURI).collect(Collectors.toList());
return new JsonRpcSuccessResponse(req.getId(), enodeList); return new JsonRpcSuccessResponse(req.getId(), enodeList);
} else { } else {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_NOT_SET); 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.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; 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.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -69,6 +70,8 @@ public class PermRemoveNodesFromWhitelist implements JsonRpcMethod {
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY); return new JsonRpcErrorResponse(req.getId(), JsonRpcError.NODE_WHITELIST_INVALID_ENTRY);
} catch (P2pDisabledException e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.P2P_DISABLED);
} catch (Exception e) { } catch (Exception e) {
return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INTERNAL_ERROR); return new JsonRpcErrorResponse(req.getId(), JsonRpcError.INTERNAL_ERROR);
} }

@ -25,6 +25,7 @@ public enum JsonRpcError {
METHOD_NOT_FOUND(-32601, "Method not found"), METHOD_NOT_FOUND(-32601, "Method not found"),
INVALID_PARAMS(-32602, "Invalid params"), INVALID_PARAMS(-32602, "Invalid params"),
INTERNAL_ERROR(-32603, "Internal error"), INTERNAL_ERROR(-32603, "Internal error"),
P2P_DISABLED(-32000, "P2P has been disabled. This functionality is not available."),
// Filter & Subscription Errors // Filter & Subscription Errors
FILTER_NOT_FOUND(-32000, "Filter not found"), 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.MockPeerConnection;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; 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.JsonRpcResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.PeerResult; 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.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection; import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection;
import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo; import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
@ -83,6 +86,17 @@ public class AdminPeersTest {
assertThat(response).isEqualToComparingFieldByFieldRecursively(expectedResponse); 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() { private Collection<PeerConnection> peerList() {
final PeerInfo peerInfo = final PeerInfo peerInfo =
new PeerInfo(5, "0x0", Collections.emptyList(), 30303, BytesValue.EMPTY); 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.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; 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.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -133,6 +134,19 @@ public class PermAddNodesToWhitelistTest {
verifyNoMoreInteractions(nodeWhitelistController); 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) { private JsonRpcRequest buildRequest(final List<String> enodeList) {
return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {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.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; 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.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer; import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
@ -120,6 +121,18 @@ public class PermGetNodesWhitelistTest {
verifyNoMoreInteractions(nodeWhitelistController); 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() { private JsonRpcRequest buildRequest() {
return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {}); 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.JsonRpcErrorResponse;
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.response.JsonRpcResponse; 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.response.JsonRpcSuccessResponse;
import tech.pegasys.pantheon.ethereum.p2p.P2pDisabledException;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork; import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController; import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
@ -123,6 +124,18 @@ public class PermRemoveNodesFromWhitelistTest {
verifyNoMoreInteractions(nodeWhitelistController); 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) { private JsonRpcRequest buildRequest(final List<String> enodeList) {
return new JsonRpcRequest("2.0", METHOD_NAME, new Object[] {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 ExecutorService exec = Executors.newCachedThreadPool();
private final NetworkRunner networkRunner; private final NetworkRunner networkRunner;
private final Optional<JsonRpcHttpService> jsonRpc; private final Optional<JsonRpcHttpService> jsonRpc;
private final Optional<WebSocketService> websocketRpc; private final Optional<WebSocketService> websocketRpc;
private final Optional<MetricsHttpService> metrics; private final Optional<MetricsHttpService> metrics;
@ -89,6 +88,7 @@ public class Runner implements AutoCloseable {
public void close() throws Exception { public void close() throws Exception {
networkRunner.stop(); networkRunner.stop();
networkRunner.awaitStop(); networkRunner.awaitStop();
exec.shutdown(); exec.shutdown();
try { try {
jsonRpc.ifPresent(service -> service.stop().join()); jsonRpc.ifPresent(service -> service.stop().join());
@ -109,10 +109,12 @@ public class Runner implements AutoCloseable {
private void writePantheonPortsToFile() { private void writePantheonPortsToFile() {
final Properties properties = new Properties(); final Properties properties = new Properties();
if (networkRunner.getNetwork().isListening()) { if (networkRunner.getNetwork().isListening()) {
properties.setProperty("discovery", String.valueOf(getP2pUdpPort())); properties.setProperty("discovery", String.valueOf(getP2pUdpPort()));
properties.setProperty("p2p", String.valueOf(getP2pTcpPort())); properties.setProperty("p2p", String.valueOf(getP2pTcpPort()));
} }
if (getJsonRpcPort().isPresent()) { if (getJsonRpcPort().isPresent()) {
properties.setProperty("json-rpc", String.valueOf(getJsonRpcPort().get())); 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.jsonrpc.websocket.subscription.syncing.SyncingSubscriptionService;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.p2p.NetworkRunner; 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.api.ProtocolManager;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration; import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration; import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration;
@ -73,6 +75,7 @@ public class RunnerBuilder {
private Vertx vertx; private Vertx vertx;
private PantheonController<?> pantheonController; private PantheonController<?> pantheonController;
private boolean p2pEnabled = true;
private boolean discovery; private boolean discovery;
private Collection<?> bootstrapPeers; private Collection<?> bootstrapPeers;
private String discoveryHost; private String discoveryHost;
@ -96,6 +99,11 @@ public class RunnerBuilder {
return this; return this;
} }
public RunnerBuilder p2pEnabled(final boolean p2pEnabled) {
this.p2pEnabled = p2pEnabled;
return this;
}
public RunnerBuilder discovery(final boolean discovery) { public RunnerBuilder discovery(final boolean discovery) {
this.discovery = discovery; this.discovery = discovery;
return this; return this;
@ -213,16 +221,18 @@ public class RunnerBuilder {
.protocolManagers(protocolManagers) .protocolManagers(protocolManagers)
.subProtocols(subProtocols) .subProtocols(subProtocols)
.network( .network(
caps -> p2pEnabled
new NettyP2PNetwork( ? caps ->
vertx, new NettyP2PNetwork(
keyPair, vertx,
networkConfig, keyPair,
caps, networkConfig,
PeerRequirement.aggregateOf(protocolManagers), caps,
peerBlacklist, PeerRequirement.aggregateOf(protocolManagers),
metricsSystem, peerBlacklist,
nodeWhitelistController)) metricsSystem,
nodeWhitelistController)
: caps -> new NoopP2PNetwork())
.metricsSystem(metricsSystem) .metricsSystem(metricsSystem)
.build(); .build();
@ -245,7 +255,7 @@ public class RunnerBuilder {
context, context,
protocolSchedule, protocolSchedule,
pantheonController, pantheonController,
networkRunner, networkRunner.getNetwork(),
synchronizer, synchronizer,
transactionPool, transactionPool,
miningCoordinator, miningCoordinator,
@ -267,7 +277,7 @@ public class RunnerBuilder {
context, context,
protocolSchedule, protocolSchedule,
pantheonController, pantheonController,
networkRunner, networkRunner.getNetwork(),
synchronizer, synchronizer,
transactionPool, transactionPool,
miningCoordinator, miningCoordinator,
@ -326,7 +336,7 @@ public class RunnerBuilder {
final ProtocolContext<?> context, final ProtocolContext<?> context,
final ProtocolSchedule<?> protocolSchedule, final ProtocolSchedule<?> protocolSchedule,
final PantheonController<?> pantheonController, final PantheonController<?> pantheonController,
final NetworkRunner networkRunner, final P2PNetwork network,
final Synchronizer synchronizer, final Synchronizer synchronizer,
final TransactionPool transactionPool, final TransactionPool transactionPool,
final MiningCoordinator miningCoordinator, final MiningCoordinator miningCoordinator,
@ -339,7 +349,7 @@ public class RunnerBuilder {
new JsonRpcMethodsFactory() new JsonRpcMethodsFactory()
.methods( .methods(
PantheonInfo.version(), PantheonInfo.version(),
networkRunner.getNetwork(), network,
context.getBlockchain(), context.getBlockchain(),
context.getWorldStateArchive(), context.getWorldStateArchive(),
synchronizer, synchronizer,

@ -156,6 +156,15 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
) )
private final File nodePrivateKeyFile = null; 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 // Boolean option to indicate if peers should NOT be discovered, default to false indicates that
// the peers should be discovered by default. // the peers should be discovered by default.
// //
@ -497,6 +506,11 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
Configurator.setAllLevels("", logLevel); 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 //noinspection ConstantConditions
if (isMiningEnabled && coinbase == null) { if (isMiningEnabled && coinbase == null) {
throw new ParameterException( throw new ParameterException(
@ -516,6 +530,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
synchronize( synchronize(
buildController(), buildController(),
p2pEnabled,
noPeerDiscovery, noPeerDiscovery,
ethNetworkConfig.getBootNodes(), ethNetworkConfig.getBootNodes(),
maxPeers, maxPeers,
@ -627,6 +642,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
// Blockchain synchronisation from peers. // Blockchain synchronisation from peers.
private void synchronize( private void synchronize(
final PantheonController<?> controller, final PantheonController<?> controller,
final boolean p2pEnabled,
final boolean noPeerDiscovery, final boolean noPeerDiscovery,
final Collection<?> bootstrapNodes, final Collection<?> bootstrapNodes,
final int maxPeers, final int maxPeers,
@ -642,6 +658,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
runnerBuilder runnerBuilder
.vertx(Vertx.vertx()) .vertx(Vertx.vertx())
.pantheonController(controller) .pantheonController(controller)
.p2pEnabled(p2pEnabled)
// BEWARE: Peer discovery boolean must be inverted as it's negated in the options ! // BEWARE: Peer discovery boolean must be inverted as it's negated in the options !
.discovery(!noPeerDiscovery) .discovery(!noPeerDiscovery)
.bootstrapPeers(bootstrapNodes) .bootstrapPeers(bootstrapNodes)

@ -122,6 +122,7 @@ public class PantheonCommandTest extends CommandTestAbstract {
when(mockRunnerBuilder.discoveryHost(anyString())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.discoveryHost(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.discoveryPort(anyInt())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.discoveryPort(anyInt())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.maxPeers(anyInt())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.maxPeers(anyInt())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.p2pEnabled(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.jsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.jsonRpcConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.webSocketConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.webSocketConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder); when(mockRunnerBuilder.permissioningConfiguration(any())).thenReturn(mockRunnerBuilder);
@ -528,6 +529,35 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString()).isEmpty(); 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 @Test
public void discoveryOptionMustBeUsed() { public void discoveryOptionMustBeUsed() {
parseCommand("--no-discovery"); parseCommand("--no-discovery");

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

Loading…
Cancel
Save