Nodes whitelist acceptance test (#472)

* Refactoring PantheonNodeFactory and adding PermissioningConfiguration

* Created ClusterConfiguration

* Acceptance test for nodes whitelist

* Fixing constructor

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Lucas Saldanha 6 years ago committed by GitHub
parent 5e53036799
commit 0ba0a05c2a
  1. 1
      acceptance-tests/build.gradle
  2. 4
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/AcceptanceTestBase.java
  3. 8
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java
  4. 8
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ProcessPantheonNodeRunner.java
  5. 1
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ThreadPantheonNodeRunner.java
  6. 14
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/cluster/Cluster.java
  7. 26
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/cluster/ClusterConfiguration.java
  8. 26
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/cluster/ClusterConfigurationBuilder.java
  9. 75
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfiguration.java
  10. 112
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfigurationBuilder.java
  11. 204
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonNodeFactory.java
  12. 65
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/permissioning/NodesWhitelistAcceptanceTest.java

@ -23,6 +23,7 @@ dependencies {
testImplementation project(':ethereum:core') testImplementation project(':ethereum:core')
testImplementation project(':ethereum:blockcreation') testImplementation project(':ethereum:blockcreation')
testImplementation project(':ethereum:jsonrpc') testImplementation project(':ethereum:jsonrpc')
testImplementation project(':ethereum:p2p')
testImplementation project(':metrics') testImplementation project(':metrics')
testImplementation project(':pantheon') testImplementation project(':pantheon')
testImplementation project(':util') testImplementation project(':util')

@ -19,8 +19,8 @@ import tech.pegasys.pantheon.tests.acceptance.dsl.contract.ContractVerifier;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eth; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Eth;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Net; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Net;
import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Web3; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Web3;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Cluster; import tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster.Cluster;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNodeFactory; import tech.pegasys.pantheon.tests.acceptance.dsl.node.factory.PantheonNodeFactory;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transactions; import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transactions;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions; import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.clique.CliqueTransactions;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions; import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthTransactions;

@ -22,6 +22,7 @@ import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
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.transaction.PantheonWeb3j; import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.PantheonWeb3j;
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction;
@ -68,6 +69,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
private final MiningParameters miningParameters; private final MiningParameters miningParameters;
private final JsonRpcConfiguration jsonRpcConfiguration; private final JsonRpcConfiguration jsonRpcConfiguration;
private final WebSocketConfiguration webSocketConfiguration; private final WebSocketConfiguration webSocketConfiguration;
private final PermissioningConfiguration permissioningConfiguration;
private final GenesisConfigProvider genesisConfigProvider; private final GenesisConfigProvider genesisConfigProvider;
private final boolean devMode; private final boolean devMode;
@ -80,6 +82,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
final MiningParameters miningParameters, final MiningParameters miningParameters,
final JsonRpcConfiguration jsonRpcConfiguration, final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration, final WebSocketConfiguration webSocketConfiguration,
final PermissioningConfiguration permissioningConfiguration,
final boolean devMode, final boolean devMode,
final GenesisConfigProvider genesisConfigProvider, final GenesisConfigProvider genesisConfigProvider,
final int p2pPort) final int p2pPort)
@ -91,6 +94,7 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
this.miningParameters = miningParameters; this.miningParameters = miningParameters;
this.jsonRpcConfiguration = jsonRpcConfiguration; this.jsonRpcConfiguration = jsonRpcConfiguration;
this.webSocketConfiguration = webSocketConfiguration; this.webSocketConfiguration = webSocketConfiguration;
this.permissioningConfiguration = permissioningConfiguration;
this.genesisConfigProvider = genesisConfigProvider; this.genesisConfigProvider = genesisConfigProvider;
this.devMode = devMode; this.devMode = devMode;
LOG.info("Created PantheonNode {}", this.toString()); LOG.info("Created PantheonNode {}", this.toString());
@ -314,6 +318,10 @@ public class PantheonNode implements Node, NodeConfiguration, RunnableNode, Auto
return devMode; return devMode;
} }
PermissioningConfiguration getPermissioningConfiguration() {
return permissioningConfiguration;
}
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)

@ -17,6 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import tech.pegasys.pantheon.cli.EthNetworkConfig; import tech.pegasys.pantheon.cli.EthNetworkConfig;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -69,6 +70,13 @@ public class ProcessPantheonNodeRunner implements PantheonNodeRunner {
params.add("--bootnodes"); params.add("--bootnodes");
params.add(String.join(",", node.bootnodes().toString())); params.add(String.join(",", node.bootnodes().toString()));
final PermissioningConfiguration permissioningConfiguration =
node.getPermissioningConfiguration();
if (permissioningConfiguration.isNodeWhitelistSet()) {
params.add("--nodes-whitelist");
params.add(String.join(",", permissioningConfiguration.getNodeWhitelist().toString()));
}
if (node.jsonRpcEnabled()) { if (node.jsonRpcEnabled()) {
params.add("--rpc-enabled"); params.add("--rpc-enabled");
params.add("--rpc-listen"); params.add("--rpc-listen");

@ -86,6 +86,7 @@ public class ThreadPantheonNodeRunner implements PantheonNodeRunner {
.dataDir(node.homeDirectory()) .dataDir(node.homeDirectory())
.bannedNodeIds(Collections.emptySet()) .bannedNodeIds(Collections.emptySet())
.metricsSystem(noOpMetricsSystem) .metricsSystem(noOpMetricsSystem)
.permissioningConfiguration(node.getPermissioningConfiguration())
.build(); .build();
nodeExecutor.submit(runner::execute); nodeExecutor.submit(runner::execute);

@ -10,13 +10,17 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 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. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.tests.acceptance.dsl.node; package tech.pegasys.pantheon.tests.acceptance.dsl.node.cluster;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import tech.pegasys.pantheon.cli.EthNetworkConfig; import tech.pegasys.pantheon.cli.EthNetworkConfig;
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.jsonrpc.Net; import tech.pegasys.pantheon.tests.acceptance.dsl.jsonrpc.Net;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNodeRunner;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.RunnableNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition.WaitCondition; import tech.pegasys.pantheon.tests.acceptance.dsl.waitcondition.WaitCondition;
import java.util.ArrayList; import java.util.ArrayList;
@ -33,8 +37,14 @@ public class Cluster implements AutoCloseable {
private final Map<String, RunnableNode> nodes = new HashMap<>(); private final Map<String, RunnableNode> nodes = new HashMap<>();
private final PantheonNodeRunner pantheonNodeRunner = PantheonNodeRunner.instance(); private final PantheonNodeRunner pantheonNodeRunner = PantheonNodeRunner.instance();
private final Net net; private final Net net;
private final ClusterConfiguration clusterConfiguration;
public Cluster(final Net net) { public Cluster(final Net net) {
this(new ClusterConfigurationBuilder().build(), net);
}
public Cluster(final ClusterConfiguration clusterConfiguration, final Net net) {
this.clusterConfiguration = clusterConfiguration;
this.net = net; this.net = net;
} }
@ -70,10 +80,12 @@ public class Cluster implements AutoCloseable {
node.start(pantheonNodeRunner); node.start(pantheonNodeRunner);
} }
if (clusterConfiguration.isAwaitPeerDiscovery()) {
for (final RunnableNode node : nodes) { for (final RunnableNode node : nodes) {
node.awaitPeerDiscovery(net.awaitPeerCount(nodes.size() - 1)); node.awaitPeerDiscovery(net.awaitPeerCount(nodes.size() - 1));
} }
} }
}
public void stop() { public void stop() {
for (final RunnableNode node : nodes.values()) { for (final RunnableNode node : nodes.values()) {

@ -0,0 +1,26 @@
/*
* 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.node.cluster;
public class ClusterConfiguration {
private final boolean awaitPeerDiscovery;
ClusterConfiguration(final boolean awaitPeerDiscovery) {
this.awaitPeerDiscovery = awaitPeerDiscovery;
}
public boolean isAwaitPeerDiscovery() {
return awaitPeerDiscovery;
}
}

@ -0,0 +1,26 @@
/*
* 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.node.cluster;
public class ClusterConfigurationBuilder {
private boolean awaitPeerDiscovery = true;
public ClusterConfigurationBuilder setAwaitPeerDiscovery(final boolean awaitPeerDiscovery) {
this.awaitPeerDiscovery = awaitPeerDiscovery;
return this;
}
public ClusterConfiguration build() {
return new ClusterConfiguration(awaitPeerDiscovery);
}
}

@ -0,0 +1,75 @@
/*
* 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.node.factory;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
class PantheonFactoryConfiguration {
private final String name;
private final MiningParameters miningParameters;
private final JsonRpcConfiguration jsonRpcConfiguration;
private final WebSocketConfiguration webSocketConfiguration;
private final PermissioningConfiguration permissioningConfiguration;
private final boolean devMode;
private final GenesisConfigProvider genesisConfigProvider;
PantheonFactoryConfiguration(
final String name,
final MiningParameters miningParameters,
final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration,
final PermissioningConfiguration permissioningConfiguration,
final boolean devMode,
final GenesisConfigProvider genesisConfigProvider) {
this.name = name;
this.miningParameters = miningParameters;
this.jsonRpcConfiguration = jsonRpcConfiguration;
this.webSocketConfiguration = webSocketConfiguration;
this.permissioningConfiguration = permissioningConfiguration;
this.devMode = devMode;
this.genesisConfigProvider = genesisConfigProvider;
}
public String getName() {
return name;
}
public MiningParameters getMiningParameters() {
return miningParameters;
}
public JsonRpcConfiguration getJsonRpcConfiguration() {
return jsonRpcConfiguration;
}
public WebSocketConfiguration getWebSocketConfiguration() {
return webSocketConfiguration;
}
public PermissioningConfiguration getPermissioningConfiguration() {
return permissioningConfiguration;
}
public boolean isDevMode() {
return devMode;
}
public GenesisConfigProvider getGenesisConfigProvider() {
return genesisConfigProvider;
}
}

@ -0,0 +1,112 @@
/*
* 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.node.factory;
import static java.util.Collections.singletonList;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import java.util.Optional;
public class PantheonFactoryConfigurationBuilder {
private String name;
private MiningParameters miningParameters =
new MiningParametersTestBuilder().enabled(false).build();
private JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createDefault();
private WebSocketConfiguration webSocketConfiguration = WebSocketConfiguration.createDefault();
private PermissioningConfiguration permissioningConfiguration =
PermissioningConfiguration.createDefault();
private boolean devMode = true;
private GenesisConfigProvider genesisConfigProvider = ignore -> Optional.empty();
public PantheonFactoryConfigurationBuilder setName(final String name) {
this.name = name;
return this;
}
public PantheonFactoryConfigurationBuilder setMiningParameters(
final MiningParameters miningParameters) {
this.miningParameters = miningParameters;
return this;
}
public PantheonFactoryConfigurationBuilder miningEnabled() {
this.miningParameters = new MiningParametersTestBuilder().enabled(true).build();
return this;
}
public PantheonFactoryConfigurationBuilder setJsonRpcConfiguration(
final JsonRpcConfiguration jsonRpcConfiguration) {
this.jsonRpcConfiguration = jsonRpcConfiguration;
return this;
}
public PantheonFactoryConfigurationBuilder jsonRpcEnabled() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
config.setHostsWhitelist(singletonList("*"));
this.jsonRpcConfiguration = config;
return this;
}
public PantheonFactoryConfigurationBuilder setWebSocketConfiguration(
final WebSocketConfiguration webSocketConfiguration) {
this.webSocketConfiguration = webSocketConfiguration;
return this;
}
public PantheonFactoryConfigurationBuilder webSocketEnabled() {
final WebSocketConfiguration config = WebSocketConfiguration.createDefault();
config.setEnabled(true);
config.setPort(0);
this.webSocketConfiguration = config;
return this;
}
public PantheonFactoryConfigurationBuilder setPermissioningConfiguration(
final PermissioningConfiguration permissioningConfiguration) {
this.permissioningConfiguration = permissioningConfiguration;
return this;
}
public PantheonFactoryConfigurationBuilder setDevMode(final boolean devMode) {
this.devMode = devMode;
return this;
}
public PantheonFactoryConfigurationBuilder setGenesisConfigProvider(
final GenesisConfigProvider genesisConfigProvider) {
this.genesisConfigProvider = genesisConfigProvider;
return this;
}
public PantheonFactoryConfiguration build() {
return new PantheonFactoryConfiguration(
name,
miningParameters,
jsonRpcConfiguration,
webSocketConfiguration,
permissioningConfiguration,
devMode,
genesisConfigProvider);
}
}

@ -10,7 +10,7 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 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. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.tests.acceptance.dsl.node; package tech.pegasys.pantheon.tests.acceptance.dsl.node.factory;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
@ -19,11 +19,12 @@ import static tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis.CLIQU
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.RunnableNode;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -47,6 +48,7 @@ public class PantheonNodeFactory {
config.getMiningParameters(), config.getMiningParameters(),
config.getJsonRpcConfiguration(), config.getJsonRpcConfiguration(),
config.getWebSocketConfiguration(), config.getWebSocketConfiguration(),
config.getPermissioningConfiguration(),
config.isDevMode(), config.isDevMode(),
config.getGenesisConfigProvider(), config.getGenesisConfigProvider(),
serverSocket.getLocalPort()); serverSocket.getLocalPort());
@ -57,76 +59,94 @@ public class PantheonNodeFactory {
public PantheonNode createMinerNode(final String name) throws IOException { public PantheonNode createMinerNode(final String name) throws IOException {
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, createMiningParameters(true), createJsonRpcConfig(), createWebSocketConfig())); .setName(name)
.miningEnabled()
.jsonRpcEnabled()
.webSocketEnabled()
.build());
} }
public PantheonNode createMinerNodeWithCustomRefreshDelay( public PantheonNode createMinerNodeWithCustomRefreshDelay(
final String name, final Long refreshDelay) throws IOException { final String name, final Long refreshDelay) throws IOException {
WebSocketConfiguration wsConfig = createWebSocketConfig();
WebSocketConfiguration wsConfig = createWebSocketEnabledConfig();
wsConfig.setRefreshDelay(refreshDelay); wsConfig.setRefreshDelay(refreshDelay);
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, createMiningParameters(true), createJsonRpcConfig(), wsConfig)); .setName(name)
.miningEnabled()
.setJsonRpcConfiguration(createJsonRpcEnabledConfig())
.setWebSocketConfiguration(wsConfig)
.build());
} }
public PantheonNode createArchiveNode(final String name) throws IOException { public PantheonNode createArchiveNode(final String name) throws IOException {
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, createMiningParameters(false), createJsonRpcConfig(), createWebSocketConfig())); .setName(name)
.jsonRpcEnabled()
.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 = createWebSocketConfig(); WebSocketConfiguration wsConfig = createWebSocketEnabledConfig();
wsConfig.setRefreshDelay(refreshDelay); wsConfig.setRefreshDelay(refreshDelay);
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, createMiningParameters(false), createJsonRpcConfig(), wsConfig)); .setName(name)
.setJsonRpcConfiguration(createJsonRpcEnabledConfig())
.setWebSocketConfiguration(wsConfig)
.build());
} }
public PantheonNode createArchiveNodeWithRpcDisabled(final String name) throws IOException { public PantheonNode createArchiveNodeWithRpcDisabled(final String name) throws IOException {
return create( return create(new PantheonFactoryConfigurationBuilder().setName(name).build());
new PantheonFactoryConfiguration(
name,
createMiningParameters(false),
JsonRpcConfiguration.createDefault(),
WebSocketConfiguration.createDefault()));
} }
public PantheonNode createArchiveNodeWithRpcApis( public PantheonNode createArchiveNodeWithRpcApis(
final String name, final RpcApi... enabledRpcApis) throws IOException { final String name, final RpcApi... enabledRpcApis) throws IOException {
final JsonRpcConfiguration jsonRpcConfig = createJsonRpcConfig(); final JsonRpcConfiguration jsonRpcConfig = createJsonRpcEnabledConfig();
jsonRpcConfig.setRpcApis(asList(enabledRpcApis)); jsonRpcConfig.setRpcApis(asList(enabledRpcApis));
final WebSocketConfiguration webSocketConfig = createWebSocketConfig(); final WebSocketConfiguration webSocketConfig = createWebSocketEnabledConfig();
webSocketConfig.setRpcApis(asList(enabledRpcApis)); webSocketConfig.setRpcApis(asList(enabledRpcApis));
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, createMiningParameters(false), jsonRpcConfig, webSocketConfig)); .setName(name)
.setJsonRpcConfiguration(jsonRpcConfig)
.setWebSocketConfiguration(webSocketConfig)
.build());
} }
public PantheonNode createCliqueNode(final String name) throws IOException { public PantheonNode createNodeWithNodesWhitelist(
final String name, final List<URI> nodesWhitelist) throws IOException {
PermissioningConfiguration permissioningConfiguration =
PermissioningConfiguration.createDefault();
permissioningConfiguration.setNodeWhitelist(nodesWhitelist);
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, .setName(name)
createMiningParameters(true), .jsonRpcEnabled()
jsonRpcConfigWithClique(), .setPermissioningConfiguration(permissioningConfiguration)
createWebSocketConfig(), .build());
false,
this::createCliqueGenesisConfig));
} }
public PantheonNode createCliqueNodeWithValidators(final String name, final String... validators) public PantheonNode createCliqueNode(final String name) throws IOException {
throws IOException {
return create( return create(
new PantheonFactoryConfiguration( new PantheonFactoryConfigurationBuilder()
name, .setName(name)
createMiningParameters(true), .miningEnabled()
jsonRpcConfigWithClique(), .setJsonRpcConfiguration(jsonRpcConfigWithClique())
createWebSocketConfig(), .setWebSocketConfiguration(createWebSocketEnabledConfig())
false, .setDevMode(false)
nodes -> createCliqueGenesisConfigForValidators(asList(validators), nodes))); .setGenesisConfigProvider(this::createCliqueGenesisConfig)
.build());
} }
private Optional<String> createCliqueGenesisConfig(final Collection<RunnableNode> validators) { private Optional<String> createCliqueGenesisConfig(final Collection<RunnableNode> validators) {
@ -136,11 +156,9 @@ public class PantheonNodeFactory {
return Optional.of(genesis); return Optional.of(genesis);
} }
private Optional<String> createCliqueGenesisConfigForValidators( private String encodeCliqueExtraData(final Collection<RunnableNode> nodes) {
final Collection<String> validators, final Collection<RunnableNode> pantheonNodes) { final List<Address> addresses = nodes.stream().map(RunnableNode::getAddress).collect(toList());
List<RunnableNode> collect = return CliqueExtraData.createGenesisExtraDataString(addresses);
pantheonNodes.stream().filter(n -> validators.contains(n.getName())).collect(toList());
return createCliqueGenesisConfig(collect);
} }
private String cliqueGenesisTemplateConfig() { private String cliqueGenesisTemplateConfig() {
@ -152,24 +170,37 @@ public class PantheonNodeFactory {
} }
} }
private String encodeCliqueExtraData(final Collection<RunnableNode> nodes) { public PantheonNode createCliqueNodeWithValidators(final String name, final String... validators)
final List<Address> addresses = nodes.stream().map(RunnableNode::getAddress).collect(toList()); throws IOException {
return CliqueExtraData.createGenesisExtraDataString(addresses);
return create(
new PantheonFactoryConfigurationBuilder()
.setName(name)
.miningEnabled()
.setJsonRpcConfiguration(jsonRpcConfigWithClique())
.setWebSocketConfiguration(createWebSocketEnabledConfig())
.setDevMode(false)
.setGenesisConfigProvider(
nodes -> createCliqueGenesisConfigForValidators(asList(validators), nodes))
.build());
}
private Optional<String> createCliqueGenesisConfigForValidators(
final Collection<String> validators, final Collection<RunnableNode> pantheonNodes) {
List<RunnableNode> collect =
pantheonNodes.stream().filter(n -> validators.contains(n.getName())).collect(toList());
return createCliqueGenesisConfig(collect);
} }
private JsonRpcConfiguration jsonRpcConfigWithClique() { private JsonRpcConfiguration jsonRpcConfigWithClique() {
final JsonRpcConfiguration jsonRpcConfig = createJsonRpcConfig(); final JsonRpcConfiguration jsonRpcConfig = createJsonRpcEnabledConfig();
final List<RpcApi> rpcApis = new ArrayList<>(jsonRpcConfig.getRpcApis()); final List<RpcApi> rpcApis = new ArrayList<>(jsonRpcConfig.getRpcApis());
rpcApis.add(CLIQUE); rpcApis.add(CLIQUE);
jsonRpcConfig.setRpcApis(rpcApis); jsonRpcConfig.setRpcApis(rpcApis);
return jsonRpcConfig; return jsonRpcConfig;
} }
private MiningParameters createMiningParameters(final boolean miner) { private JsonRpcConfiguration createJsonRpcEnabledConfig() {
return new MiningParametersTestBuilder().enabled(miner).build();
}
private JsonRpcConfiguration createJsonRpcConfig() {
final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault(); final JsonRpcConfiguration config = JsonRpcConfiguration.createDefault();
config.setEnabled(true); config.setEnabled(true);
config.setPort(0); config.setPort(0);
@ -177,73 +208,10 @@ public class PantheonNodeFactory {
return config; return config;
} }
private WebSocketConfiguration createWebSocketConfig() { private WebSocketConfiguration createWebSocketEnabledConfig() {
final WebSocketConfiguration config = WebSocketConfiguration.createDefault(); final WebSocketConfiguration config = WebSocketConfiguration.createDefault();
config.setEnabled(true); config.setEnabled(true);
config.setPort(0); config.setPort(0);
return config; return config;
} }
static class PantheonFactoryConfiguration {
private final String name;
private final MiningParameters miningParameters;
private final JsonRpcConfiguration jsonRpcConfiguration;
private final WebSocketConfiguration webSocketConfiguration;
private final boolean devMode;
private final GenesisConfigProvider genesisConfigProvider;
public PantheonFactoryConfiguration(
final String name,
final MiningParameters miningParameters,
final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration) {
this(
name,
miningParameters,
jsonRpcConfiguration,
webSocketConfiguration,
true,
ignore -> Optional.empty());
}
public PantheonFactoryConfiguration(
final String name,
final MiningParameters miningParameters,
final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration,
final boolean devMode,
final GenesisConfigProvider genesisConfigProvider) {
this.name = name;
this.miningParameters = miningParameters;
this.jsonRpcConfiguration = jsonRpcConfiguration;
this.webSocketConfiguration = webSocketConfiguration;
this.devMode = devMode;
this.genesisConfigProvider = genesisConfigProvider;
}
public String getName() {
return name;
}
public MiningParameters getMiningParameters() {
return miningParameters;
}
public JsonRpcConfiguration getJsonRpcConfiguration() {
return jsonRpcConfiguration;
}
public WebSocketConfiguration getWebSocketConfiguration() {
return webSocketConfiguration;
}
public boolean isDevMode() {
return devMode;
}
public GenesisConfigProvider getGenesisConfigProvider() {
return genesisConfigProvider;
}
}
} }

@ -0,0 +1,65 @@
/*
* 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.permissioning;
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.PantheonNode;
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 java.net.URI;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
public class NodesWhitelistAcceptanceTest extends AcceptanceTestBase {
private Cluster permissionedCluster;
private Node forbiddenNode;
private Node allowedNode;
private Node permissionedNode;
@Before
public void setUp() throws Exception {
final ClusterConfiguration clusterConfiguration =
new ClusterConfigurationBuilder().setAwaitPeerDiscovery(false).build();
permissionedCluster = new Cluster(clusterConfiguration, net);
forbiddenNode = pantheon.createArchiveNode("forbidden-node");
allowedNode = pantheon.createArchiveNode("allowed-node");
permissionedNode =
pantheon.createNodeWithNodesWhitelist(
"permissioned-node", Collections.singletonList(getEnodeURI(allowedNode)));
permissionedCluster.start(allowedNode, forbiddenNode, permissionedNode);
}
@Test
public void permissionedNodeShouldDiscoverOnlyAllowedNode() {
allowedNode.verify(net.awaitPeerCount(2));
forbiddenNode.verify(net.awaitPeerCount(1));
permissionedNode.verify(net.awaitPeerCount(1));
}
private URI getEnodeURI(final Node node) {
return URI.create(((PantheonNode) node).getConfiguration().enodeUrl());
}
@Override
public void tearDownAcceptanceTestBase() {
permissionedCluster.stop();
super.tearDownAcceptanceTestBase();
}
}
Loading…
Cancel
Save