Move permission options to itw own class (#6490)

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
pull/6487/head
Gabriel-Trintinalia 10 months ago committed by GitHub
parent 98ab26df2f
commit 9084bde9d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 176
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  2. 206
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/PermissionsOptions.java
  3. 412
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  4. 453
      besu/src/test/java/org/hyperledger/besu/cli/options/PermissionsOptionsTest.java

@ -56,6 +56,7 @@ import org.hyperledger.besu.cli.options.stable.JsonRpcHttpOptions;
import org.hyperledger.besu.cli.options.stable.LoggingLevelOption;
import org.hyperledger.besu.cli.options.stable.NodePrivateKeyFileOption;
import org.hyperledger.besu.cli.options.stable.P2PTLSConfigOptions;
import org.hyperledger.besu.cli.options.stable.PermissionsOptions;
import org.hyperledger.besu.cli.options.stable.RpcWebsocketOptions;
import org.hyperledger.besu.cli.options.unstable.ChainPruningOptions;
import org.hyperledger.besu.cli.options.unstable.DnsOptions;
@ -130,8 +131,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser;
import org.hyperledger.besu.ethereum.p2p.rlpx.connections.netty.TLSConfiguration;
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfigurationBuilder;
import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration;
import org.hyperledger.besu.ethereum.privacy.storage.keyvalue.PrivacyKeyValueStorageProvider;
import org.hyperledger.besu.ethereum.privacy.storage.keyvalue.PrivacyKeyValueStorageProviderBuilder;
import org.hyperledger.besu.ethereum.storage.StorageProvider;
@ -825,62 +824,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
// Permission Option Group
@CommandLine.ArgGroup(validate = false, heading = "@|bold Permissions Options|@%n")
PermissionsOptionGroup permissionsOptionGroup = new PermissionsOptionGroup();
static class PermissionsOptionGroup {
@Option(
names = {"--permissions-nodes-config-file-enabled"},
description = "Enable node level permissions (default: ${DEFAULT-VALUE})")
private final Boolean permissionsNodesEnabled = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--permissions-nodes-config-file"},
description =
"Node permissioning config TOML file (default: a file named \"permissions_config.toml\" in the Besu data folder)")
private String nodePermissionsConfigFile = null;
@Option(
names = {"--permissions-accounts-config-file-enabled"},
description = "Enable account level permissions (default: ${DEFAULT-VALUE})")
private final Boolean permissionsAccountsEnabled = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--permissions-accounts-config-file"},
description =
"Account permissioning config TOML file (default: a file named \"permissions_config.toml\" in the Besu data folder)")
private String accountPermissionsConfigFile = null;
@Option(
names = {"--permissions-nodes-contract-address"},
description = "Address of the node permissioning smart contract",
arity = "1")
private final Address permissionsNodesContractAddress = null;
@Option(
names = {"--permissions-nodes-contract-version"},
description = "Version of the EEA Node Permissioning interface (default: ${DEFAULT-VALUE})")
private final Integer permissionsNodesContractVersion = 1;
@Option(
names = {"--permissions-nodes-contract-enabled"},
description =
"Enable node level permissions via smart contract (default: ${DEFAULT-VALUE})")
private final Boolean permissionsNodesContractEnabled = false;
@Option(
names = {"--permissions-accounts-contract-address"},
description = "Address of the account permissioning smart contract",
arity = "1")
private final Address permissionsAccountsContractAddress = null;
@Option(
names = {"--permissions-accounts-contract-enabled"},
description =
"Enable account level permissions via smart contract (default: ${DEFAULT-VALUE})")
private final Boolean permissionsAccountsContractEnabled = false;
}
PermissionsOptions permissionsOptions = new PermissionsOptions();
@Option(
names = {"--revert-reason-enabled"},
@ -1852,6 +1796,16 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
logger.info("Security Module: {}", securityModuleName);
}
private Optional<PermissioningConfiguration> permissioningConfiguration() throws Exception {
return permissionsOptions.permissioningConfiguration(
jsonRpcHttpOptions,
rpcWebsocketOptions,
getEnodeDnsConfiguration(),
dataDir(),
logger,
commandLine);
}
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration(
final Boolean enabled, final Path ipcPath, final List<String> rpcIpcApis) {
final Path actualPath;
@ -2091,106 +2045,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.build();
}
private Optional<PermissioningConfiguration> permissioningConfiguration() throws Exception {
if (!(localPermissionsEnabled() || contractPermissionsEnabled())) {
if (jsonRpcHttpOptions.getRpcHttpApis().contains(RpcApis.PERM.name())
|| rpcWebsocketOptions.getRpcWsApis().contains(RpcApis.PERM.name())) {
logger.warn(
"Permissions are disabled. Cannot enable PERM APIs when not using Permissions.");
}
return Optional.empty();
}
final Optional<LocalPermissioningConfiguration> localPermissioningConfigurationOptional;
if (localPermissionsEnabled()) {
final Optional<String> nodePermissioningConfigFile =
Optional.ofNullable(permissionsOptionGroup.nodePermissionsConfigFile);
final Optional<String> accountPermissioningConfigFile =
Optional.ofNullable(permissionsOptionGroup.accountPermissionsConfigFile);
final LocalPermissioningConfiguration localPermissioningConfiguration =
PermissioningConfigurationBuilder.permissioningConfiguration(
permissionsOptionGroup.permissionsNodesEnabled,
getEnodeDnsConfiguration(),
nodePermissioningConfigFile.orElse(getDefaultPermissioningFilePath()),
permissionsOptionGroup.permissionsAccountsEnabled,
accountPermissioningConfigFile.orElse(getDefaultPermissioningFilePath()));
localPermissioningConfigurationOptional = Optional.of(localPermissioningConfiguration);
} else {
if (permissionsOptionGroup.nodePermissionsConfigFile != null
&& !permissionsOptionGroup.permissionsNodesEnabled) {
logger.warn(
"Node permissioning config file set {} but no permissions enabled",
permissionsOptionGroup.nodePermissionsConfigFile);
}
if (permissionsOptionGroup.accountPermissionsConfigFile != null
&& !permissionsOptionGroup.permissionsAccountsEnabled) {
logger.warn(
"Account permissioning config file set {} but no permissions enabled",
permissionsOptionGroup.accountPermissionsConfigFile);
}
localPermissioningConfigurationOptional = Optional.empty();
}
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
SmartContractPermissioningConfiguration.createDefault();
if (Boolean.TRUE.equals(permissionsOptionGroup.permissionsNodesContractEnabled)) {
if (permissionsOptionGroup.permissionsNodesContractAddress == null) {
throw new ParameterException(
this.commandLine,
"No node permissioning contract address specified. Cannot enable smart contract based node permissioning.");
} else {
smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(
permissionsOptionGroup.permissionsNodesContractEnabled);
smartContractPermissioningConfiguration.setNodeSmartContractAddress(
permissionsOptionGroup.permissionsNodesContractAddress);
smartContractPermissioningConfiguration.setNodeSmartContractInterfaceVersion(
permissionsOptionGroup.permissionsNodesContractVersion);
}
} else if (permissionsOptionGroup.permissionsNodesContractAddress != null) {
logger.warn(
"Node permissioning smart contract address set {} but smart contract node permissioning is disabled.",
permissionsOptionGroup.permissionsNodesContractAddress);
}
if (Boolean.TRUE.equals(permissionsOptionGroup.permissionsAccountsContractEnabled)) {
if (permissionsOptionGroup.permissionsAccountsContractAddress == null) {
throw new ParameterException(
this.commandLine,
"No account permissioning contract address specified. Cannot enable smart contract based account permissioning.");
} else {
smartContractPermissioningConfiguration.setSmartContractAccountAllowlistEnabled(
permissionsOptionGroup.permissionsAccountsContractEnabled);
smartContractPermissioningConfiguration.setAccountSmartContractAddress(
permissionsOptionGroup.permissionsAccountsContractAddress);
}
} else if (permissionsOptionGroup.permissionsAccountsContractAddress != null) {
logger.warn(
"Account permissioning smart contract address set {} but smart contract account permissioning is disabled.",
permissionsOptionGroup.permissionsAccountsContractAddress);
}
final PermissioningConfiguration permissioningConfiguration =
new PermissioningConfiguration(
localPermissioningConfigurationOptional,
Optional.of(smartContractPermissioningConfiguration));
return Optional.of(permissioningConfiguration);
}
private boolean localPermissionsEnabled() {
return permissionsOptionGroup.permissionsAccountsEnabled
|| permissionsOptionGroup.permissionsNodesEnabled;
}
private boolean contractPermissionsEnabled() {
return permissionsOptionGroup.permissionsNodesContractEnabled
|| permissionsOptionGroup.permissionsAccountsContractEnabled;
}
private PrivacyParameters privacyParameters() {
CommandLineUtils.checkOptionDependencies(
@ -2661,12 +2515,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.orElseGet(() -> KeyPairUtil.getDefaultKeyFile(dataDir()));
}
private String getDefaultPermissioningFilePath() {
return dataDir()
+ System.getProperty("file.separator")
+ DefaultCommandValues.PERMISSIONING_CONFIG_LOCATION;
}
/**
* Metrics System used by Besu
*

@ -0,0 +1,206 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options.stable;
import org.hyperledger.besu.cli.DefaultCommandValues;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration;
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfigurationBuilder;
import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration;
import java.nio.file.Path;
import java.util.Optional;
import org.slf4j.Logger;
import picocli.CommandLine;
/** Handles configuration options for permissions in Besu. */
public class PermissionsOptions {
@CommandLine.Option(
names = {"--permissions-nodes-config-file-enabled"},
description = "Enable node level permissions (default: ${DEFAULT-VALUE})")
private final Boolean permissionsNodesEnabled = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--permissions-nodes-config-file"},
description =
"Node permissioning config TOML file (default: a file named \"permissions_config.toml\" in the Besu data folder)")
private String nodePermissionsConfigFile = null;
@CommandLine.Option(
names = {"--permissions-accounts-config-file-enabled"},
description = "Enable account level permissions (default: ${DEFAULT-VALUE})")
private final Boolean permissionsAccountsEnabled = false;
@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings.
@CommandLine.Option(
names = {"--permissions-accounts-config-file"},
description =
"Account permissioning config TOML file (default: a file named \"permissions_config.toml\" in the Besu data folder)")
private String accountPermissionsConfigFile = null;
@CommandLine.Option(
names = {"--permissions-nodes-contract-address"},
description = "Address of the node permissioning smart contract",
arity = "1")
private final Address permissionsNodesContractAddress = null;
@CommandLine.Option(
names = {"--permissions-nodes-contract-version"},
description = "Version of the EEA Node Permissioning interface (default: ${DEFAULT-VALUE})")
private final Integer permissionsNodesContractVersion = 1;
@CommandLine.Option(
names = {"--permissions-nodes-contract-enabled"},
description = "Enable node level permissions via smart contract (default: ${DEFAULT-VALUE})")
private final Boolean permissionsNodesContractEnabled = false;
@CommandLine.Option(
names = {"--permissions-accounts-contract-address"},
description = "Address of the account permissioning smart contract",
arity = "1")
private final Address permissionsAccountsContractAddress = null;
@CommandLine.Option(
names = {"--permissions-accounts-contract-enabled"},
description =
"Enable account level permissions via smart contract (default: ${DEFAULT-VALUE})")
private final Boolean permissionsAccountsContractEnabled = false;
/**
* Creates a PermissioningConfiguration based on the provided options.
*
* @param jsonRpcHttpOptions The JSON-RPC HTTP options
* @param rpcWebsocketOptions The RPC websocket options
* @param enodeDnsConfiguration The enode DNS configuration
* @param dataPath The data path
* @param logger The logger
* @param commandLine The command line
* @return An Optional PermissioningConfiguration instance
* @throws Exception If an error occurs while creating the configuration
*/
public Optional<PermissioningConfiguration> permissioningConfiguration(
final JsonRpcHttpOptions jsonRpcHttpOptions,
final RpcWebsocketOptions rpcWebsocketOptions,
final EnodeDnsConfiguration enodeDnsConfiguration,
final Path dataPath,
final Logger logger,
final CommandLine commandLine)
throws Exception {
if (!(localPermissionsEnabled() || contractPermissionsEnabled())) {
if (jsonRpcHttpOptions.getRpcHttpApis().contains(RpcApis.PERM.name())
|| rpcWebsocketOptions.getRpcWsApis().contains(RpcApis.PERM.name())) {
logger.warn(
"Permissions are disabled. Cannot enable PERM APIs when not using Permissions.");
}
return Optional.empty();
}
final Optional<LocalPermissioningConfiguration> localPermissioningConfigurationOptional;
if (localPermissionsEnabled()) {
final Optional<String> nodePermissioningConfigFile =
Optional.ofNullable(nodePermissionsConfigFile);
final Optional<String> accountPermissioningConfigFile =
Optional.ofNullable(accountPermissionsConfigFile);
final LocalPermissioningConfiguration localPermissioningConfiguration =
PermissioningConfigurationBuilder.permissioningConfiguration(
permissionsNodesEnabled,
enodeDnsConfiguration,
nodePermissioningConfigFile.orElse(getDefaultPermissioningFilePath(dataPath)),
permissionsAccountsEnabled,
accountPermissioningConfigFile.orElse(getDefaultPermissioningFilePath(dataPath)));
localPermissioningConfigurationOptional = Optional.of(localPermissioningConfiguration);
} else {
if (nodePermissionsConfigFile != null && !permissionsNodesEnabled) {
logger.warn(
"Node permissioning config file set {} but no permissions enabled",
nodePermissionsConfigFile);
}
if (accountPermissionsConfigFile != null && !permissionsAccountsEnabled) {
logger.warn(
"Account permissioning config file set {} but no permissions enabled",
accountPermissionsConfigFile);
}
localPermissioningConfigurationOptional = Optional.empty();
}
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
SmartContractPermissioningConfiguration.createDefault();
if (Boolean.TRUE.equals(permissionsNodesContractEnabled)) {
if (permissionsNodesContractAddress == null) {
throw new CommandLine.ParameterException(
commandLine,
"No node permissioning contract address specified. Cannot enable smart contract based node permissioning.");
} else {
smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(
permissionsNodesContractEnabled);
smartContractPermissioningConfiguration.setNodeSmartContractAddress(
permissionsNodesContractAddress);
smartContractPermissioningConfiguration.setNodeSmartContractInterfaceVersion(
permissionsNodesContractVersion);
}
} else if (permissionsNodesContractAddress != null) {
logger.warn(
"Node permissioning smart contract address set {} but smart contract node permissioning is disabled.",
permissionsNodesContractAddress);
}
if (Boolean.TRUE.equals(permissionsAccountsContractEnabled)) {
if (permissionsAccountsContractAddress == null) {
throw new CommandLine.ParameterException(
commandLine,
"No account permissioning contract address specified. Cannot enable smart contract based account permissioning.");
} else {
smartContractPermissioningConfiguration.setSmartContractAccountAllowlistEnabled(
permissionsAccountsContractEnabled);
smartContractPermissioningConfiguration.setAccountSmartContractAddress(
permissionsAccountsContractAddress);
}
} else if (permissionsAccountsContractAddress != null) {
logger.warn(
"Account permissioning smart contract address set {} but smart contract account permissioning is disabled.",
permissionsAccountsContractAddress);
}
final PermissioningConfiguration permissioningConfiguration =
new PermissioningConfiguration(
localPermissioningConfigurationOptional,
Optional.of(smartContractPermissioningConfiguration));
return Optional.of(permissioningConfiguration);
}
private boolean localPermissionsEnabled() {
return permissionsAccountsEnabled || permissionsNodesEnabled;
}
private boolean contractPermissionsEnabled() {
return permissionsNodesContractEnabled || permissionsAccountsContractEnabled;
}
private String getDefaultPermissioningFilePath(final Path dataPath) {
return dataPath
+ System.getProperty("file.separator")
+ DefaultCommandValues.PERMISSIONING_CONFIG_LOCATION;
}
}

@ -51,7 +51,6 @@ import org.hyperledger.besu.cli.config.EthNetworkConfig;
import org.hyperledger.besu.config.GenesisConfigFile;
import org.hyperledger.besu.config.MergeConfigOptions;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
@ -67,9 +66,6 @@ import org.hyperledger.besu.ethereum.eth.sync.SyncMode;
import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration;
import org.hyperledger.besu.ethereum.trie.forest.pruner.PrunerConfiguration;
import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration;
import org.hyperledger.besu.evm.precompile.AbstractAltBnPrecompiledContract;
@ -96,7 +92,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -104,7 +99,6 @@ import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import io.vertx.core.json.JsonObject;
import org.apache.commons.io.FileUtils;
@ -129,7 +123,6 @@ public class BesuCommandTest extends CommandTestAbstract {
private static final String ENCLAVE_PUBLIC_KEY = "A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=";
private static final String VALID_NODE_ID =
"6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0";
private static final String PERMISSIONING_CONFIG_TOML = "/permissioning_config.toml";
private static final JsonRpcConfiguration DEFAULT_JSON_RPC_CONFIGURATION;
private static final GraphQLConfiguration DEFAULT_GRAPH_QL_CONFIGURATION;
private static final WebSocketConfiguration DEFAULT_WEB_SOCKET_CONFIGURATION;
@ -349,374 +342,6 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsSmartContractWithoutOptionMustError() {
parseCommand("--permissions-nodes-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith("Missing required parameter for option '--permissions-nodes-contract-address'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsEnabledWithoutContractAddressMustError() {
parseCommand("--permissions-nodes-contract-enabled");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.contains("No node permissioning contract address specified");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsEnabledWithInvalidContractAddressMustError() {
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
"invalid-smart-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsEnabledWithTooShortContractAddressMustError() {
parseCommand(
"--permissions-nodes-contract-enabled", "--permissions-nodes-contract-address", "0x1234");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsSmartContractMustUseOption() {
final String smartContractAddress = "0x0000000000000000000000000000000000001234";
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
smartContractAddress);
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
new SmartContractPermissioningConfiguration();
smartContractPermissioningConfiguration.setNodeSmartContractAddress(
Address.fromHexString(smartContractAddress));
smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(true);
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getSmartContractConfig().get())
.usingRecursiveComparison()
.isEqualTo(smartContractPermissioningConfiguration);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsContractVersionDefaultValue() {
final SmartContractPermissioningConfiguration expectedConfig =
new SmartContractPermissioningConfiguration();
expectedConfig.setNodeSmartContractAddress(
Address.fromHexString("0x0000000000000000000000000000000000001234"));
expectedConfig.setSmartContractNodeAllowlistEnabled(true);
expectedConfig.setNodeSmartContractInterfaceVersion(1);
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
"0x0000000000000000000000000000000000001234");
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getSmartContractConfig().get())
.usingRecursiveComparison()
.isEqualTo(expectedConfig);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsContractVersionSetsValue() {
final SmartContractPermissioningConfiguration expectedConfig =
new SmartContractPermissioningConfiguration();
expectedConfig.setNodeSmartContractAddress(
Address.fromHexString("0x0000000000000000000000000000000000001234"));
expectedConfig.setSmartContractNodeAllowlistEnabled(true);
expectedConfig.setNodeSmartContractInterfaceVersion(2);
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
"0x0000000000000000000000000000000000001234",
"--permissions-nodes-contract-version",
"2");
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getSmartContractConfig().get())
.usingRecursiveComparison()
.isEqualTo(expectedConfig);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsSmartContractWithoutOptionMustError() {
parseCommand("--permissions-accounts-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith(
"Missing required parameter for option '--permissions-accounts-contract-address'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsEnabledWithoutContractAddressMustError() {
parseCommand("--permissions-accounts-contract-enabled");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.contains("No account permissioning contract address specified");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsEnabledWithInvalidContractAddressMustError() {
parseCommand(
"--permissions-accounts-contract-enabled",
"--permissions-accounts-contract-address",
"invalid-smart-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsEnabledWithTooShortContractAddressMustError() {
parseCommand(
"--permissions-accounts-contract-enabled",
"--permissions-accounts-contract-address",
"0x1234");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsSmartContractMustUseOption() {
final String smartContractAddress = "0x0000000000000000000000000000000000001234";
parseCommand(
"--permissions-accounts-contract-enabled",
"--permissions-accounts-contract-address",
smartContractAddress);
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
new SmartContractPermissioningConfiguration();
smartContractPermissioningConfiguration.setAccountSmartContractAddress(
Address.fromHexString(smartContractAddress));
smartContractPermissioningConfiguration.setSmartContractAccountAllowlistEnabled(true);
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
final PermissioningConfiguration permissioningConfiguration =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(permissioningConfiguration.getSmartContractConfig()).isPresent();
final SmartContractPermissioningConfiguration effectiveSmartContractConfig =
permissioningConfiguration.getSmartContractConfig().get();
assertThat(effectiveSmartContractConfig.isSmartContractAccountAllowlistEnabled()).isTrue();
assertThat(effectiveSmartContractConfig.getAccountSmartContractAddress())
.isEqualTo(Address.fromHexString(smartContractAddress));
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningTomlPathWithoutOptionMustDisplayUsage() {
parseCommand("--permissions-nodes-config-file");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith("Missing required parameter for option '--permissions-nodes-config-file'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningTomlPathWithoutOptionMustDisplayUsage() {
parseCommand("--permissions-accounts-config-file");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith("Missing required parameter for option '--permissions-accounts-config-file'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningEnabledWithNonexistentConfigFileMustError() {
parseCommand(
"--permissions-nodes-config-file-enabled",
"--permissions-nodes-config-file",
"file-does-not-exist");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Configuration file does not exist");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningEnabledWithNonexistentConfigFileMustError() {
parseCommand(
"--permissions-accounts-config-file-enabled",
"--permissions-accounts-config-file",
"file-does-not-exist");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Configuration file does not exist");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningTomlFileWithNoPermissionsEnabledMustNotError() throws IOException {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
parseCommand("--permissions-nodes-config-file", permToml.toString());
verify(mockRunnerBuilder).build();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningTomlFileWithNoPermissionsEnabledMustNotError()
throws IOException {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
parseCommand("--permissions-accounts-config-file", permToml.toString());
verify(mockRunnerBuilder).build();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void defaultPermissionsTomlFileWithNoPermissionsEnabledMustNotError() {
parseCommand("--p2p-enabled", "false");
verify(mockRunnerBuilder).build();
assertThat(commandErrorOutput.toString(UTF_8)).doesNotContain("no permissions enabled");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningTomlPathMustUseOption() throws IOException {
final List<EnodeURL> allowedNodes =
Lists.newArrayList(
EnodeURLImpl.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.9:4567"),
EnodeURLImpl.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.169.0.9:4568"));
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
final String allowedNodesString =
allowedNodes.stream().map(Object::toString).collect(Collectors.joining(","));
parseCommand(
"--permissions-nodes-config-file-enabled",
"--permissions-nodes-config-file",
permToml.toString(),
"--bootnodes",
allowedNodesString);
final LocalPermissioningConfiguration localPermissioningConfiguration =
LocalPermissioningConfiguration.createDefault();
localPermissioningConfiguration.setNodePermissioningConfigFilePath(permToml.toString());
localPermissioningConfiguration.setNodeAllowlist(allowedNodes);
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getLocalConfig().get())
.usingRecursiveComparison()
.isEqualTo(localPermissioningConfiguration);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningTomlPathMustUseOption() throws IOException {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
parseCommand(
"--permissions-accounts-config-file-enabled",
"--permissions-accounts-config-file",
permToml.toString());
final LocalPermissioningConfiguration localPermissioningConfiguration =
LocalPermissioningConfiguration.createDefault();
localPermissioningConfiguration.setAccountPermissioningConfigFilePath(permToml.toString());
localPermissioningConfiguration.setAccountAllowlist(
Collections.singletonList("0x0000000000000000000000000000000000000009"));
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
final PermissioningConfiguration permissioningConfiguration =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(permissioningConfiguration.getLocalConfig()).isPresent();
final LocalPermissioningConfiguration effectiveLocalPermissioningConfig =
permissioningConfiguration.getLocalConfig().get();
assertThat(effectiveLocalPermissioningConfig.isAccountAllowlistEnabled()).isTrue();
assertThat(effectiveLocalPermissioningConfig.getAccountPermissioningConfigFilePath())
.isEqualTo(permToml.toString());
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void tomlThatConfiguresEverythingExceptPermissioningToml() throws IOException {
// Load a TOML that configures literally everything (except permissioning TOML config)
@ -3166,43 +2791,6 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void errorIsRaisedIfStaticNodesAreNotAllowed(final @TempDir Path testFolder)
throws IOException {
final Path staticNodesFile = testFolder.resolve("static-nodes.json");
final Path permissioningConfig = testFolder.resolve("permissioning.json");
final EnodeURL staticNodeURI =
EnodeURLImpl.builder()
.nodeId(
"50203c6bfca6874370e71aecc8958529fd723feb05013dc1abca8fc1fff845c5259faba05852e9dfe5ce172a7d6e7c2a3a5eaa8b541c8af15ea5518bbff5f2fa")
.ipAddress("127.0.0.1")
.useDefaultPorts()
.build();
final EnodeURL allowedNode =
EnodeURLImpl.builder()
.nodeId(
"50203c6bfca6874370e71aecc8958529fd723feb05013dc1abca8fc1fff845c5259faba05852e9dfe5ce172a7d6e7c2a3a5eaa8b541c8af15ea5518bbff5f2fa")
.useDefaultPorts()
.ipAddress("127.0.0.1")
.listeningPort(30304)
.build();
Files.write(staticNodesFile, ("[\"" + staticNodeURI.toString() + "\"]").getBytes(UTF_8));
Files.write(
permissioningConfig,
("nodes-allowlist=[\"" + allowedNode.toString() + "\"]").getBytes(UTF_8));
parseCommand(
"--data-path=" + testFolder,
"--bootnodes",
"--permissions-nodes-config-file-enabled=true",
"--permissions-nodes-config-file=" + permissioningConfig);
assertThat(commandErrorOutput.toString(UTF_8))
.contains(staticNodeURI.toString(), "not in nodes-allowlist");
}
@Test
public void tomlThatHasInvalidOptions() throws IOException {
final URL configFile = this.getClass().getResource("/complete_config.toml");

@ -0,0 +1,453 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.cli.options;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import org.hyperledger.besu.cli.CommandTestAbstract;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURLImpl;
import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration;
import org.hyperledger.besu.ethereum.permissioning.SmartContractPermissioningConfiguration;
import org.hyperledger.besu.plugin.data.EnodeURL;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class PermissionsOptionsTest extends CommandTestAbstract {
private static final String PERMISSIONING_CONFIG_TOML = "/permissioning_config.toml";
@Test
public void errorIsRaisedIfStaticNodesAreNotAllowed(final @TempDir Path testFolder)
throws IOException {
final Path staticNodesFile = testFolder.resolve("static-nodes.json");
final Path permissioningConfig = testFolder.resolve("permissioning.json");
final EnodeURL staticNodeURI =
EnodeURLImpl.builder()
.nodeId(
"50203c6bfca6874370e71aecc8958529fd723feb05013dc1abca8fc1fff845c5259faba05852e9dfe5ce172a7d6e7c2a3a5eaa8b541c8af15ea5518bbff5f2fa")
.ipAddress("127.0.0.1")
.useDefaultPorts()
.build();
final EnodeURL allowedNode =
EnodeURLImpl.builder()
.nodeId(
"50203c6bfca6874370e71aecc8958529fd723feb05013dc1abca8fc1fff845c5259faba05852e9dfe5ce172a7d6e7c2a3a5eaa8b541c8af15ea5518bbff5f2fa")
.useDefaultPorts()
.ipAddress("127.0.0.1")
.listeningPort(30304)
.build();
Files.write(staticNodesFile, ("[\"" + staticNodeURI.toString() + "\"]").getBytes(UTF_8));
Files.write(
permissioningConfig,
("nodes-allowlist=[\"" + allowedNode.toString() + "\"]").getBytes(UTF_8));
parseCommand(
"--data-path=" + testFolder,
"--bootnodes",
"--permissions-nodes-config-file-enabled=true",
"--permissions-nodes-config-file=" + permissioningConfig);
assertThat(commandErrorOutput.toString(UTF_8))
.contains(staticNodeURI.toString(), "not in nodes-allowlist");
}
@Test
public void nodePermissionsSmartContractWithoutOptionMustError() {
parseCommand("--permissions-nodes-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith("Missing required parameter for option '--permissions-nodes-contract-address'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsEnabledWithoutContractAddressMustError() {
parseCommand("--permissions-nodes-contract-enabled");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.contains("No node permissioning contract address specified");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsEnabledWithInvalidContractAddressMustError() {
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
"invalid-smart-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsEnabledWithTooShortContractAddressMustError() {
parseCommand(
"--permissions-nodes-contract-enabled", "--permissions-nodes-contract-address", "0x1234");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsSmartContractMustUseOption() {
final String smartContractAddress = "0x0000000000000000000000000000000000001234";
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
smartContractAddress);
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
new SmartContractPermissioningConfiguration();
smartContractPermissioningConfiguration.setNodeSmartContractAddress(
Address.fromHexString(smartContractAddress));
smartContractPermissioningConfiguration.setSmartContractNodeAllowlistEnabled(true);
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getSmartContractConfig().get())
.usingRecursiveComparison()
.isEqualTo(smartContractPermissioningConfiguration);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsContractVersionDefaultValue() {
final SmartContractPermissioningConfiguration expectedConfig =
new SmartContractPermissioningConfiguration();
expectedConfig.setNodeSmartContractAddress(
Address.fromHexString("0x0000000000000000000000000000000000001234"));
expectedConfig.setSmartContractNodeAllowlistEnabled(true);
expectedConfig.setNodeSmartContractInterfaceVersion(1);
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
"0x0000000000000000000000000000000000001234");
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getSmartContractConfig().get())
.usingRecursiveComparison()
.isEqualTo(expectedConfig);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissionsContractVersionSetsValue() {
final SmartContractPermissioningConfiguration expectedConfig =
new SmartContractPermissioningConfiguration();
expectedConfig.setNodeSmartContractAddress(
Address.fromHexString("0x0000000000000000000000000000000000001234"));
expectedConfig.setSmartContractNodeAllowlistEnabled(true);
expectedConfig.setNodeSmartContractInterfaceVersion(2);
parseCommand(
"--permissions-nodes-contract-enabled",
"--permissions-nodes-contract-address",
"0x0000000000000000000000000000000000001234",
"--permissions-nodes-contract-version",
"2");
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getSmartContractConfig().get())
.usingRecursiveComparison()
.isEqualTo(expectedConfig);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsSmartContractWithoutOptionMustError() {
parseCommand("--permissions-accounts-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith(
"Missing required parameter for option '--permissions-accounts-contract-address'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsEnabledWithoutContractAddressMustError() {
parseCommand("--permissions-accounts-contract-enabled");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.contains("No account permissioning contract address specified");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsEnabledWithInvalidContractAddressMustError() {
parseCommand(
"--permissions-accounts-contract-enabled",
"--permissions-accounts-contract-address",
"invalid-smart-contract-address");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsEnabledWithTooShortContractAddressMustError() {
parseCommand(
"--permissions-accounts-contract-enabled",
"--permissions-accounts-contract-address",
"0x1234");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Invalid value");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissionsSmartContractMustUseOption() {
final String smartContractAddress = "0x0000000000000000000000000000000000001234";
parseCommand(
"--permissions-accounts-contract-enabled",
"--permissions-accounts-contract-address",
smartContractAddress);
final SmartContractPermissioningConfiguration smartContractPermissioningConfiguration =
new SmartContractPermissioningConfiguration();
smartContractPermissioningConfiguration.setAccountSmartContractAddress(
Address.fromHexString(smartContractAddress));
smartContractPermissioningConfiguration.setSmartContractAccountAllowlistEnabled(true);
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
final PermissioningConfiguration permissioningConfiguration =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(permissioningConfiguration.getSmartContractConfig()).isPresent();
final SmartContractPermissioningConfiguration effectiveSmartContractConfig =
permissioningConfiguration.getSmartContractConfig().get();
assertThat(effectiveSmartContractConfig.isSmartContractAccountAllowlistEnabled()).isTrue();
assertThat(effectiveSmartContractConfig.getAccountSmartContractAddress())
.isEqualTo(Address.fromHexString(smartContractAddress));
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningTomlPathWithoutOptionMustDisplayUsage() {
parseCommand("--permissions-nodes-config-file");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith("Missing required parameter for option '--permissions-nodes-config-file'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningTomlPathWithoutOptionMustDisplayUsage() {
parseCommand("--permissions-accounts-config-file");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8))
.startsWith("Missing required parameter for option '--permissions-accounts-config-file'");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningEnabledWithNonexistentConfigFileMustError() {
parseCommand(
"--permissions-nodes-config-file-enabled",
"--permissions-nodes-config-file",
"file-does-not-exist");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Configuration file does not exist");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningEnabledWithNonexistentConfigFileMustError() {
parseCommand(
"--permissions-accounts-config-file-enabled",
"--permissions-accounts-config-file",
"file-does-not-exist");
Mockito.verifyNoInteractions(mockRunnerBuilder);
assertThat(commandErrorOutput.toString(UTF_8)).contains("Configuration file does not exist");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningTomlFileWithNoPermissionsEnabledMustNotError() throws IOException {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
parseCommand("--permissions-nodes-config-file", permToml.toString());
verify(mockRunnerBuilder).build();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningTomlFileWithNoPermissionsEnabledMustNotError()
throws IOException {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
parseCommand("--permissions-accounts-config-file", permToml.toString());
verify(mockRunnerBuilder).build();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void defaultPermissionsTomlFileWithNoPermissionsEnabledMustNotError() {
parseCommand("--p2p-enabled", "false");
verify(mockRunnerBuilder).build();
assertThat(commandErrorOutput.toString(UTF_8)).doesNotContain("no permissions enabled");
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void nodePermissioningTomlPathMustUseOption() throws IOException {
final List<EnodeURL> allowedNodes =
Lists.newArrayList(
EnodeURLImpl.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.9:4567"),
EnodeURLImpl.fromString(
"enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.169.0.9:4568"));
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
final String allowedNodesString =
allowedNodes.stream().map(Object::toString).collect(Collectors.joining(","));
parseCommand(
"--permissions-nodes-config-file-enabled",
"--permissions-nodes-config-file",
permToml.toString(),
"--bootnodes",
allowedNodesString);
final LocalPermissioningConfiguration localPermissioningConfiguration =
LocalPermissioningConfiguration.createDefault();
localPermissioningConfiguration.setNodePermissioningConfigFilePath(permToml.toString());
localPermissioningConfiguration.setNodeAllowlist(allowedNodes);
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
final PermissioningConfiguration config =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(config.getLocalConfig().get())
.usingRecursiveComparison()
.isEqualTo(localPermissioningConfiguration);
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
@Test
public void accountPermissioningTomlPathMustUseOption() throws IOException {
final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_TOML);
final Path permToml = createTempFile("toml", Resources.toByteArray(configFile));
parseCommand(
"--permissions-accounts-config-file-enabled",
"--permissions-accounts-config-file",
permToml.toString());
final LocalPermissioningConfiguration localPermissioningConfiguration =
LocalPermissioningConfiguration.createDefault();
localPermissioningConfiguration.setAccountPermissioningConfigFilePath(permToml.toString());
localPermissioningConfiguration.setAccountAllowlist(
Collections.singletonList("0x0000000000000000000000000000000000000009"));
verify(mockRunnerBuilder)
.permissioningConfiguration(permissioningConfigurationArgumentCaptor.capture());
final PermissioningConfiguration permissioningConfiguration =
permissioningConfigurationArgumentCaptor.getValue().get();
assertThat(permissioningConfiguration.getLocalConfig()).isPresent();
final LocalPermissioningConfiguration effectiveLocalPermissioningConfig =
permissioningConfiguration.getLocalConfig().get();
assertThat(effectiveLocalPermissioningConfig.isAccountAllowlistEnabled()).isTrue();
assertThat(effectiveLocalPermissioningConfig.getAccountPermissioningConfigFilePath())
.isEqualTo(permToml.toString());
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
assertThat(commandOutput.toString(UTF_8)).isEmpty();
}
}
Loading…
Cancel
Save