Nc 1942 Add account whitelisting and refactor into permissioning package (#460)

* WS sync subscription delay added

* WS sync subscription delay added with unit testing

* WS sync subscription delay added with unit testing

* changed number to a constant in constructor

* Use default from websocket class instead of making new one

* Removed magic numbers

* Added Controller

* Refactor permissioning config and account whitelist into permissioning package

* Refactor permissioning config and account whitelist into permissioning package

* Refactor permissioning config and account whitelist into permissioning package

* Merge branch 'master' of https://github.com/PegaSysEng/pantheon into NC-1942

# Conflicts:
#	consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftControllerTest.java
#	docs/Getting-Started/ExplorerBlockDetails.png
#	docs/Getting-Started/ExplorerSearch.png
#	docs/Getting-Started/ExplorerSummary.png
#	ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/PermissioningConfiguration.java
#	ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/PermissioningConfigurationTest.java
#	pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
#	pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java

* Merge branch 'master' of https://github.com/PegaSysEng/pantheon into NC-1942

# Conflicts:
#	consensus/ibft/src/test/java/tech/pegasys/pantheon/consensus/ibft/statemachine/IbftControllerTest.java
#	docs/Getting-Started/ExplorerBlockDetails.png
#	docs/Getting-Started/ExplorerSearch.png
#	docs/Getting-Started/ExplorerSummary.png
#	ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/PermissioningConfiguration.java
#	ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/PermissioningConfigurationTest.java
#	pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
#	pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java

* Iron out merge conflict introduced bugs

* Iron out merge conflict introduced bugs

* Iron out merge conflict introduced bugs

* PR Change request actioned

* PR Change request actioned

* PR Change request actioned

* PR Change request actioned

* updated node whitelist acceptance test to conform to refactored permissioning package

* text change

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Michael Connor 6 years ago committed by GitHub
parent 882acca983
commit 27c3ad5f78
  1. 2
      acceptance-tests/build.gradle
  2. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java
  3. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/ProcessPantheonNodeRunner.java
  4. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfiguration.java
  5. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonFactoryConfigurationBuilder.java
  6. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/factory/PantheonNodeFactory.java
  7. 1
      ethereum/core/build.gradle
  8. 28
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/TransactionPool.java
  9. 3
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/TransactionValidator.java
  10. 43
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/core/TransactionPoolTest.java
  11. 1
      ethereum/eth/build.gradle
  12. 2
      ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java
  13. 1
      ethereum/p2p/build.gradle
  14. 2
      ethereum/p2p/src/main/java/tech/pegasys/pantheon/ethereum/p2p/permissioning/NodeWhitelistController.java
  15. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NettyP2PNetworkTest.java
  16. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/NetworkingServiceLifecycleTest.java
  17. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/AbstractPeerDiscoveryTest.java
  18. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryAgentTest.java
  19. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryObserversTest.java
  20. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/PeerDiscoveryTimestampsTest.java
  21. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryControllerTest.java
  22. 2
      ethereum/p2p/src/test/java/tech/pegasys/pantheon/ethereum/p2p/discovery/internal/PeerDiscoveryTableRefreshTest.java
  23. 33
      ethereum/permissioning/build.gradle
  24. 51
      ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/AccountWhitelistController.java
  25. 20
      ethereum/permissioning/src/main/java/tech/pegasys/pantheon/ethereum/permissioning/PermissioningConfiguration.java
  26. 22
      ethereum/permissioning/src/test/java/tech/pegasys/pantheon/ethereum/permissioning/PermissioningConfigurationTest.java
  27. 1
      pantheon/build.gradle
  28. 9
      pantheon/src/main/java/tech/pegasys/pantheon/RunnerBuilder.java
  29. 17
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  30. 2
      pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
  31. 2
      pantheon/src/test/java/tech/pegasys/pantheon/cli/CommandTestAbstract.java
  32. 34
      pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java
  33. 1
      settings.gradle

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

@ -22,7 +22,7 @@ import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Util;
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.ethereum.permissioning.PermissioningConfiguration;
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.Transaction;

@ -17,7 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import tech.pegasys.pantheon.cli.EthNetworkConfig;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import java.io.File;
import java.io.IOException;

@ -15,7 +15,7 @@ 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.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
class PantheonFactoryConfiguration {

@ -18,7 +18,7 @@ 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.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.GenesisConfigProvider;
import java.util.Optional;

@ -22,7 +22,7 @@ import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode;
import tech.pegasys.pantheon.tests.acceptance.dsl.node.RunnableNode;

@ -30,6 +30,7 @@ dependencies {
implementation project(':crypto')
implementation project(':ethereum:rlp')
implementation project(':ethereum:trie')
implementation project(':ethereum:permissioning')
implementation project(':metrics')
implementation project(':services:kvstore')

@ -24,12 +24,14 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.logging.log4j.Logger;
@ -47,6 +49,7 @@ public class TransactionPool implements BlockAddedObserver {
private final ProtocolSchedule<?> protocolSchedule;
private final ProtocolContext<?> protocolContext;
private final TransactionBatchAddedListener transactionBatchAddedListener;
private Optional<AccountWhitelistController> accountWhitelistController = Optional.empty();
public TransactionPool(
final PendingTransactions pendingTransactions,
@ -131,6 +134,13 @@ public class TransactionPool implements BlockAddedObserver {
return basicValidationResult;
}
String sender = transaction.getSender().toString();
if (accountIsNotWhitelisted(sender)) {
return ValidationResult.invalid(
TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED,
String.format("Sender %s is not on the Account Whitelist", sender));
}
final BlockHeader chainHeadBlockHeader = getChainHeadBlockHeader();
if (transaction.getGasLimit() > chainHeadBlockHeader.getGasLimit()) {
return ValidationResult.invalid(
@ -147,6 +157,20 @@ public class TransactionPool implements BlockAddedObserver {
pendingTransactions.getNextNonceForSender(transaction.getSender()));
}
private boolean accountIsNotWhitelisted(final String account) {
if (useWhitelist()) {
if (!accountWhitelistController.get().contains(account)) {
return true;
}
}
return false;
}
public boolean useWhitelist() {
return (accountWhitelistController.isPresent()
&& accountWhitelistController.get().isAccountWhiteListSet());
}
private Account getSenderAccount(
final Transaction transaction, final BlockHeader chainHeadHeader) {
final WorldState worldState =
@ -163,4 +187,8 @@ public class TransactionPool implements BlockAddedObserver {
void onTransactionsAdded(Iterable<Transaction> transactions);
}
public void setAccountWhitelist(AccountWhitelistController accountWhitelist) {
accountWhitelistController = Optional.of(accountWhitelist);
}
}

@ -55,6 +55,7 @@ public interface TransactionValidator {
NONCE_TOO_LOW,
INCORRECT_NONCE,
INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,
EXCEEDS_BLOCK_GAS_LIMIT
EXCEEDS_BLOCK_GAS_LIMIT,
TX_SENDER_NOT_AUTHORIZED
}
}

@ -30,6 +30,7 @@ import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT;
import static tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.NONCE_TOO_LOW;
import static tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator.TransactionInvalidReason.TX_SENDER_NOT_AUTHORIZED;
import static tech.pegasys.pantheon.ethereum.mainnet.ValidationResult.valid;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
@ -40,6 +41,7 @@ import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec;
import tech.pegasys.pantheon.ethereum.mainnet.TransactionValidator;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationResult;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
import tech.pegasys.pantheon.util.uint.UInt256;
import java.util.List;
@ -70,6 +72,8 @@ public class TransactionPoolTest {
private final Transaction transaction2 = createTransaction(2);
private TransactionPool transactionPool;
private long genesisBlockGasLimit;
private final AccountWhitelistController accountWhitelistController =
mock(AccountWhitelistController.class);
@Before
public void setUp() {
@ -355,6 +359,45 @@ public class TransactionPoolTest {
verifyZeroInteractions(batchAddedListener);
}
@Test
public void shouldAllowWhitelistedTransactionWhenWhitelistEnabled() {
transactionPool.setAccountWhitelist(accountWhitelistController);
givenTransactionIsValid(transaction1);
when(accountWhitelistController.isAccountWhiteListSet()).thenReturn(true);
when(accountWhitelistController.contains(transaction1.getSender().toString())).thenReturn(true);
assertThat(transactionPool.addLocalTransaction(transaction1)).isEqualTo(valid());
assertTransactionPending(transaction1);
}
@Test
public void shouldRejectNonWhitelistedTransactionWhenWhitelistEnabled() {
transactionPool.setAccountWhitelist(accountWhitelistController);
givenTransactionIsValid(transaction1);
when(accountWhitelistController.isAccountWhiteListSet()).thenReturn(true);
when(accountWhitelistController.contains(transaction1.getSender().toString()))
.thenReturn(false);
assertThat(transactionPool.addLocalTransaction(transaction1))
.isEqualTo(ValidationResult.invalid(TX_SENDER_NOT_AUTHORIZED));
assertTransactionNotPending(transaction1);
verifyZeroInteractions(batchAddedListener);
}
@Test
public void shouldAllowTransactionWhenAccountWhitelistControllerIsNotPresent() {
givenTransactionIsValid(transaction1);
assertThat(transactionPool.useWhitelist()).isFalse();
assertThat(transactionPool.addLocalTransaction(transaction1)).isEqualTo(valid());
assertTransactionPending(transaction1);
}
private void assertTransactionPending(final Transaction t) {
assertThat(transactions.getTransactionByHash(t.hash())).contains(t);
}

@ -29,6 +29,7 @@ dependencies {
implementation project(':ethereum:core')
implementation project(':ethereum:p2p')
implementation project(':ethereum:rlp')
implementation project(':ethereum:permissioning')
implementation project(':metrics')
implementation project(':services:kvstore')

@ -37,7 +37,6 @@ import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.RlpxConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.netty.NettyP2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
@ -46,6 +45,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;

@ -28,6 +28,7 @@ jar {
dependencies {
implementation project(':crypto')
implementation project(':ethereum:core')
implementation project(':ethereum:permissioning')
implementation project(':ethereum:rlp')
implementation project(':metrics')

@ -12,9 +12,9 @@
*/
package tech.pegasys.pantheon.ethereum.p2p.permissioning;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import java.net.URI;
import java.util.ArrayList;

@ -25,7 +25,6 @@ import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.RlpxConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.netty.NettyP2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.netty.exceptions.IncompatiblePeerException;
@ -38,6 +37,7 @@ import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol;
import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;

@ -22,11 +22,11 @@ import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.api.P2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryServiceException;
import tech.pegasys.pantheon.ethereum.p2p.netty.NettyP2PNetwork;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem;
import tech.pegasys.pantheon.util.NetworkUtility;

@ -16,13 +16,13 @@ import static io.vertx.core.Vertx.vertx;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.Packet;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PacketType;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PingPacketData;
import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.List;

@ -19,7 +19,6 @@ import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData;
import tech.pegasys.pantheon.ethereum.p2p.api.PeerConnection;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.FindNeighborsPacketData;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.NeighborsPacketData;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.Packet;
@ -31,6 +30,7 @@ import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.PeerInfo;
import tech.pegasys.pantheon.ethereum.p2p.wire.messages.DisconnectMessage.DisconnectReason;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.net.SocketAddress;

@ -19,11 +19,11 @@ import static org.awaitility.Awaitility.await;
import static tech.pegasys.pantheon.ethereum.p2p.NetworkingTestHelper.configWithRandomPorts;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryEvent.PeerBondedEvent;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import java.util.ArrayList;
import java.util.Collections;

@ -18,7 +18,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.Packet;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PacketType;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PeerDiscoveryController;
@ -26,6 +25,7 @@ import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PeerTable;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PingPacketData;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

@ -28,7 +28,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer;
import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryAgent;
import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryStatus;
@ -37,6 +36,7 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.Endpoint;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import tech.pegasys.pantheon.util.bytes.MutableBytesValue;

@ -23,12 +23,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.DiscoveryPeer;
import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryAgent;
import tech.pegasys.pantheon.ethereum.p2p.discovery.PeerDiscoveryTestHelper;
import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.ArrayList;

@ -0,0 +1,33 @@
/*
* 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.
*/
apply plugin: 'java-library'
jar {
baseName 'pantheon-permissioning'
manifest {
attributes(
'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
}
}
dependencies {
testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'
}

@ -0,0 +1,51 @@
/*
* 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.List;
public class AccountWhitelistController {
private final List<String> accountWhitelist;
private boolean accountWhitelistSet = false;
public AccountWhitelistController(final PermissioningConfiguration configuration) {
accountWhitelist = new ArrayList<>();
if (configuration != null && configuration.getAccountWhitelist() != null) {
for (String hexString : configuration.getAccountWhitelist()) {
accountWhitelist.add(hexString);
}
if (configuration.isNodeWhitelistSet()) {
accountWhitelistSet = true;
}
}
}
public boolean addAccount(final String account) {
accountWhitelistSet = true;
return accountWhitelist.add(account);
}
public boolean removeAccount(final String account) {
return accountWhitelist.remove(account);
}
public boolean contains(final String account) {
return (!accountWhitelistSet || (accountWhitelistSet && accountWhitelist.contains(account)));
}
public boolean isAccountWhiteListSet() {
return accountWhitelistSet;
}
}

@ -10,7 +10,7 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.ethereum.p2p.config;
package tech.pegasys.pantheon.ethereum.permissioning;
import java.net.URI;
import java.util.ArrayList;
@ -19,7 +19,9 @@ import java.util.List;
public class PermissioningConfiguration {
private List<URI> nodeWhitelist;
private List<String> accountWhitelist;
private boolean nodeWhitelistSet;
private boolean accountWhitelistSet;
public List<URI> getNodeWhitelist() {
return nodeWhitelist;
@ -28,6 +30,7 @@ public class PermissioningConfiguration {
public static PermissioningConfiguration createDefault() {
final PermissioningConfiguration config = new PermissioningConfiguration();
config.nodeWhitelist = new ArrayList<>();
config.accountWhitelist = new ArrayList<>();
return config;
}
@ -42,7 +45,18 @@ public class PermissioningConfiguration {
return nodeWhitelistSet;
}
public boolean contains(final URI node) {
return !isNodeWhitelistSet() || nodeWhitelist.contains(node);
public List<String> getAccountWhitelist() {
return accountWhitelist;
}
public void setAccountWhitelist(final Collection<String> accountWhitelist) {
if (accountWhitelist != null) {
this.accountWhitelist.addAll(accountWhitelist);
this.accountWhitelistSet = true;
}
}
public boolean isAccountWhitelistSet() {
return accountWhitelistSet;
}
}

@ -10,7 +10,7 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.ethereum.p2p.config;
package tech.pegasys.pantheon.ethereum.permissioning;
import static org.assertj.core.api.Assertions.assertThat;
@ -32,6 +32,8 @@ public class PermissioningConfigurationTest {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
assertThat(configuration.getNodeWhitelist()).isEmpty();
assertThat(configuration.isNodeWhitelistSet()).isFalse();
assertThat(configuration.getAccountWhitelist()).isEmpty();
assertThat(configuration.isAccountWhitelistSet()).isFalse();
}
@Test
@ -43,7 +45,7 @@ public class PermissioningConfigurationTest {
}
@Test
public void setNodeWhiteListPassingNullShouldNotChangeWhitelistSetFlag() {
public void setNodeWhiteListPassingNull() {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
configuration.setNodeWhitelist(null);
assertThat(configuration.getNodeWhitelist()).isEmpty();
@ -51,9 +53,19 @@ public class PermissioningConfigurationTest {
}
@Test
public void contains() {
public void setAccountWhitelist() {
final String[] accounts = {"1111111111111111", "2222222222222222", "ffffffffffffffff"};
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
configuration.setNodeWhitelist(Arrays.asList(nodes));
assertThat(configuration.contains(URI.create("enode://001@123:4567"))).isTrue();
configuration.setAccountWhitelist(Arrays.asList(accounts));
assertThat(configuration.getAccountWhitelist()).containsExactlyInAnyOrder(accounts);
assertThat(configuration.isAccountWhitelistSet()).isTrue();
}
@Test
public void setAccountWhiteListPassingNull() {
final PermissioningConfiguration configuration = PermissioningConfiguration.createDefault();
configuration.setAccountWhitelist(null);
assertThat(configuration.getAccountWhitelist()).isEmpty();
assertThat(configuration.isAccountWhitelistSet()).isFalse();
}
}

@ -36,6 +36,7 @@ dependencies {
implementation project(':ethereum:core')
implementation project(':ethereum:eth')
implementation project(':ethereum:jsonrpc')
implementation project(':ethereum:permissioning')
implementation project(':ethereum:p2p')
implementation project(':ethereum:rlp')
implementation project(':metrics')

@ -43,7 +43,6 @@ import tech.pegasys.pantheon.ethereum.p2p.NetworkRunner;
import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.NetworkingConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.RlpxConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.discovery.internal.PeerRequirement;
@ -52,6 +51,8 @@ import tech.pegasys.pantheon.ethereum.p2p.peers.PeerBlacklist;
import tech.pegasys.pantheon.ethereum.p2p.permissioning.NodeWhitelistController;
import tech.pegasys.pantheon.ethereum.p2p.wire.Capability;
import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol;
import tech.pegasys.pantheon.ethereum.permissioning.AccountWhitelistController;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.util.bytes.BytesValue;
@ -221,6 +222,12 @@ public class RunnerBuilder {
final TransactionPool transactionPool = pantheonController.getTransactionPool();
final MiningCoordinator miningCoordinator = pantheonController.getMiningCoordinator();
if (permissioningConfiguration.isAccountWhitelistSet()) {
AccountWhitelistController accountWhitelistController =
new AccountWhitelistController(permissioningConfiguration);
transactionPool.setAccountWhitelist(accountWhitelistController);
}
final FilterManager filterManager = createFilterManager(vertx, context, transactionPool);
Optional<JsonRpcHttpService> jsonRpcHttpService = Optional.empty();

@ -35,9 +35,9 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.DiscoveryConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer;
import tech.pegasys.pantheon.ethereum.p2p.peers.Peer;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException;
import tech.pegasys.pantheon.metrics.MetricsSystem;
import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem;
@ -404,13 +404,25 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
names = {"--nodes-whitelist"},
paramLabel = "<enode://id@host:port>",
description =
"Comma separated enode URLs for permissioned networks. Not intended to be used with mainnet or public testnets.",
"Comma separated enode URLs for permissioned networks. "
+ "Not intended to be used with mainnet or public testnets.",
split = ",",
arity = "0..*",
converter = EnodeToURIPropertyConverter.class
)
private final Collection<URI> nodesWhitelist = null;
@Option(
names = {"--accounts-whitelist"},
paramLabel = "<hex string of account public key>",
description =
"Comma separated hex strings of account public keys "
+ "for permissioned/role-based transactions. You may specify an empty list.",
split = ",",
arity = "0..*"
)
private final Collection<String> accountsWhitelist = null;
public PantheonCommand(
final BlockImporter blockImporter,
final RunnerBuilder runnerBuilder,
@ -570,6 +582,7 @@ public class PantheonCommand implements DefaultCommandValues, Runnable {
final PermissioningConfiguration permissioningConfiguration =
PermissioningConfiguration.createDefault();
permissioningConfiguration.setNodeWhitelist(nodesWhitelist);
permissioningConfiguration.setAccountWhitelist(accountsWhitelist);
return permissioningConfiguration;
}

@ -33,8 +33,8 @@ import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec;
import tech.pegasys.pantheon.ethereum.p2p.config.PermissioningConfiguration;
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.metrics.MetricsSystem;

@ -22,7 +22,7 @@ import tech.pegasys.pantheon.controller.PantheonController;
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.p2p.config.PermissioningConfiguration;
import tech.pegasys.pantheon.ethereum.permissioning.PermissioningConfiguration;
import tech.pegasys.pantheon.util.BlockImporter;
import java.io.ByteArrayOutputStream;

@ -533,6 +533,40 @@ public class PantheonCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void callingWithAccountsWhitelistOptionButNoValueMustNotError() {
parseCommand("--accounts-whitelist");
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(permissioningConfigurationArgumentCaptor.getValue().getAccountWhitelist()).isEmpty();
assertThat(permissioningConfigurationArgumentCaptor.getValue().isAccountWhitelistSet())
.isTrue();
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void accountsWhitelistOptionMustBeUsed() {
final String[] accounts = {"1111111111111111", "2222222222222222", "ffffffffffffffff"};
parseCommand("--accounts-whitelist", String.join(",", accounts));
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(permissioningConfigurationArgumentCaptor.getValue().getAccountWhitelist())
.containsExactlyInAnyOrder(accounts);
assertThat(permissioningConfigurationArgumentCaptor.getValue().isAccountWhitelistSet())
.isTrue();
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString()).isEmpty();
}
@Test
public void nodesWhitelistOptionMustIncludeBootnodes() {
parseCommand(

@ -25,6 +25,7 @@ include 'crypto'
include 'ethereum:p2p'
include 'ethereum:mock-p2p'
include 'ethereum:jsonrpc'
include 'ethereum:permissioning'
include 'ethereum:referencetests'
include 'ethereum:core'
include 'ethereum:blockcreation'

Loading…
Cancel
Save