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

added --nodes-whitelist param to CLI and NodeWhitelistController #346

Merged
merged 5 commits into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.ethereum.permissioning;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class PermissioningConfiguration {
lucassaldanha marked this conversation as resolved.
Show resolved Hide resolved
private List<String> nodeWhitelist;
private boolean nodeWhitelistSet;

public List<String> getNodeWhitelist() {
return nodeWhitelist;
}

public static PermissioningConfiguration createDefault() {
final PermissioningConfiguration config = new PermissioningConfiguration();
config.nodeWhitelist = new ArrayList<>();
return config;
}

public void setNodeWhitelist(final Collection<String> nodeWhitelist) {
if (nodeWhitelist != null) {
this.nodeWhitelist.addAll(nodeWhitelist);
this.nodeWhitelistSet = true;
}
}

public boolean isNodeWhitelistSet() {
return nodeWhitelistSet;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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.ethereum.permissioning;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;

import org.junit.Test;

public class PermissioningConfigurationTest {

@Test
public void defaultConfiguration() {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
assertThat(configuration.getNodeWhitelist()).isEmpty();
assertThat(configuration.isNodeWhitelistSet()).isFalse();
}

@Test
public void setNodeWhitelist() {
final String[] nodes = {"enode://001@123:4567", "enode://002@123:4567", "enode://003@123:4567"};
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: should we validate if the enode in the config file is valid? We are planning to validate it in the JSON-RPC API so maybe it makes sense to do the same when reading from the file.
Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
configuration.setNodeWhitelist(Arrays.asList(nodes));
assertThat(configuration.getNodeWhitelist()).containsExactlyInAnyOrder(nodes);
assertThat(configuration.isNodeWhitelistSet()).isTrue();
}

@Test
public void setNodeWhiteListPassingNull() {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
configuration.setNodeWhitelist(null);
assertThat(configuration.getNodeWhitelist()).isEmpty();
assertThat(configuration.isNodeWhitelistSet()).isFalse();
}
}
7 changes: 6 additions & 1 deletion pantheon/src/main/java/tech/pegasys/pantheon/Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package tech.pegasys.pantheon;

import tech.pegasys.pantheon.controller.NodeWhitelistController;
import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcHttpService;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketService;
Expand Down Expand Up @@ -46,19 +47,23 @@ public class Runner implements AutoCloseable {
private final PantheonController<?> pantheonController;
private final Path dataDir;

private final NodeWhitelistController nodeWhitelistController;

Runner(
final Vertx vertx,
final NetworkRunner networkRunner,
final Optional<JsonRpcHttpService> jsonRpc,
final Optional<WebSocketService> websocketRpc,
final PantheonController<?> pantheonController,
final Path dataDir) {
final Path dataDir,
final NodeWhitelistController nodeWhitelistController) {
this.vertx = vertx;
this.networkRunner = networkRunner;
this.jsonRpc = jsonRpc;
this.websocketRpc = websocketRpc;
this.pantheonController = pantheonController;
this.dataDir = dataDir;
this.nodeWhitelistController = nodeWhitelistController;
}

public void execute() {
Expand Down
20 changes: 19 additions & 1 deletion pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package tech.pegasys.pantheon;

import tech.pegasys.pantheon.controller.NodeWhitelistController;
import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext;
Expand Down Expand Up @@ -50,6 +51,7 @@
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;
Expand Down Expand Up @@ -78,6 +80,7 @@ public class RunnerBuilder {
private WebSocketConfiguration webSocketConfiguration;
private Path dataDir;
private Collection<String> bannedNodeIds;
private PermissioningConfiguration permissioningConfiguration;

public RunnerBuilder vertx(final Vertx vertx) {
this.vertx = vertx;
Expand Down Expand Up @@ -124,6 +127,12 @@ public RunnerBuilder webSocketConfiguration(final WebSocketConfiguration webSock
return this;
}

public RunnerBuilder permissioningConfiguration(
final PermissioningConfiguration permissioningConfiguration) {
this.permissioningConfiguration = permissioningConfiguration;
return this;
}

public RunnerBuilder dataDir(final Path dataDir) {
this.dataDir = dataDir;
return this;
Expand Down Expand Up @@ -259,8 +268,17 @@ public Runner build() {
vertx, webSocketConfiguration, subscriptionManager, webSocketsJsonRpcMethods));
}

NodeWhitelistController nodeWhitelistController =
new NodeWhitelistController(permissioningConfiguration);

return new Runner(
vertx, networkRunner, jsonRpcHttpService, webSocketService, pantheonController, dataDir);
vertx,
networkRunner,
jsonRpcHttpService,
webSocketService,
pantheonController,
dataDir,
nodeWhitelistController);
}

private FilterManager createFilterManager(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException;
import tech.pegasys.pantheon.util.BlockImporter;
import tech.pegasys.pantheon.util.bytes.BytesValue;
Expand Down Expand Up @@ -377,6 +378,17 @@ public static class RpcApisConversionException extends Exception {
)
private final BytesValue extraData = DEFAULT_EXTRA_DATA;

// Permissioning: A list of whitelist nodes can be passed.
@Option(
names = {"--nodes-whitelist"},
paramLabel = "<enode://id@host:port>",
description =
"Comma separated enode URLs for permissioned networks. You may specify an empty list.",
split = ",",
arity = "0..*"
)
private final Collection<String> nodesWhitelist = null;

public PantheonCommand(
final BlockImporter blockImporter,
final RunnerBuilder runnerBuilder,
Expand Down Expand Up @@ -442,7 +454,8 @@ public void run() {
maxPeers,
p2pHostAndPort,
jsonRpcConfiguration(),
webSocketConfiguration());
webSocketConfiguration(),
permissioningConfiguration());
}

PantheonController<?> buildController() {
Expand Down Expand Up @@ -487,6 +500,13 @@ private WebSocketConfiguration webSocketConfiguration() {
return webSocketConfiguration;
}

private PermissioningConfiguration permissioningConfiguration() {
final PermissioningConfiguration permissioningConfiguration =
lucassaldanha marked this conversation as resolved.
Show resolved Hide resolved
PermissioningConfiguration.createDefault();
permissioningConfiguration.setNodeWhitelist(nodesWhitelist);
return permissioningConfiguration;
}

private SynchronizerConfiguration buildSyncConfig(final SyncMode syncMode) {
checkNotNull(syncMode);
synchronizerConfigurationBuilder.syncMode(syncMode);
Expand All @@ -502,11 +522,12 @@ private void synchronize(
final int maxPeers,
final HostAndPort discoveryHostAndPort,
final JsonRpcConfiguration jsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration) {
final WebSocketConfiguration webSocketConfiguration,
final PermissioningConfiguration permissioningConfiguration) {

checkNotNull(runnerBuilder);

final Runner runner =
Runner runner =
runnerBuilder
.vertx(Vertx.vertx())
.pantheonController(controller)
Expand All @@ -520,6 +541,7 @@ private void synchronize(
.webSocketConfiguration(webSocketConfiguration)
.dataDir(dataDir)
.bannedNodeIds(bannedNodeIds)
.permissioningConfiguration(permissioningConfiguration)
.build();

addShutdownHook(runner);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.controller;

import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;

import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class NodeWhitelistController {

private static final Logger LOG = LogManager.getLogger();

private static List<String> nodeWhitelist;
lucassaldanha marked this conversation as resolved.
Show resolved Hide resolved
private static boolean nodeWhitelistSet = false;

public NodeWhitelistController(final PermissioningConfiguration configuration) {
nodeWhitelist = new ArrayList<>();
if (configuration != null && configuration.getNodeWhitelist() != null) {
nodeWhitelist.addAll(configuration.getNodeWhitelist());
nodeWhitelistSet = true;
}
}

public boolean addNode(final String nodeId) {
return nodeWhitelist.add(nodeId);
}

public boolean removeNode(final String nodeId) {
return nodeWhitelist.remove(nodeId);
}

public static boolean isNodeWhitelistSet() {
return nodeWhitelistSet;
}
}
8 changes: 8 additions & 0 deletions pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.storage.StorageProvider;
import tech.pegasys.pantheon.ethereum.storage.keyvalue.RocksDbStorageProvider;
import tech.pegasys.pantheon.util.uint.UInt256;
Expand Down Expand Up @@ -118,6 +119,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration();
final WebSocketConfiguration aheadWebSocketConfiguration = wsRpcConfiguration();
final PermissioningConfiguration aheadPermissioningConfiguration = permissioningConfiguration();
final RunnerBuilder runnerBuilder =
new RunnerBuilder()
.vertx(Vertx.vertx())
Expand All @@ -134,6 +136,7 @@ private void syncFromGenesis(final SyncMode mode) throws Exception {
.jsonRpcConfiguration(aheadJsonRpcConfiguration)
.webSocketConfiguration(aheadWebSocketConfiguration)
.dataDir(dbAhead)
.permissioningConfiguration(aheadPermissioningConfiguration)
.build();
try {

Expand Down Expand Up @@ -251,6 +254,11 @@ private WebSocketConfiguration wsRpcConfiguration() {
return configuration;
}

private PermissioningConfiguration permissioningConfiguration() {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
return configuration;
}

private static void setupState(
final int count,
final ProtocolSchedule<Void> protocolSchedule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.util.BlockImporter;

import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -71,6 +72,7 @@ public abstract class CommandTestAbstract {
@Captor ArgumentCaptor<Integer> intArgumentCaptor;
@Captor ArgumentCaptor<JsonRpcConfiguration> jsonRpcConfigArgumentCaptor;
@Captor ArgumentCaptor<WebSocketConfiguration> wsRpcConfigArgumentCaptor;
@Captor ArgumentCaptor<PermissioningConfiguration> permissioningConfigurationArgumentCaptor;

@Before
public void initMocks() throws Exception {
Expand Down
Loading