From 89fd7aee97563eaaffdcc8ee915576d6b69bc4f1 Mon Sep 17 00:00:00 2001 From: matkt Date: Thu, 21 Jan 2021 15:38:41 +0100 Subject: [PATCH] Add mainnet launcher (#1522) Add a launcher to easily configure the Besu client on the mainnet. Signed-off-by: Karim TAAM --- CHANGELOG.md | 3 +- besu/build.gradle | 2 +- .../org/hyperledger/besu/cli/BesuCommand.java | 35 +++- .../cli/options/unstable/LauncherOptions.java | 54 +++++ .../org/hyperledger/besu/cli/launcher.json | 187 ++++++++++++++++++ .../hyperledger/besu/cli/BesuCommandTest.java | 16 ++ .../besu/cli/CommandTestAbstract.java | 5 + build.gradle | 1 + .../besu/ethereum/api/jsonrpc/RpcApis.java | 4 + gradle/versions.gradle | 1 + 10 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/unstable/LauncherOptions.java create mode 100644 besu/src/main/resources/org/hyperledger/besu/cli/launcher.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 28e1ff1b21c..332d17b630b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ ### Additions and Improvements * Removed unused flags in default genesis configs [\#1812](https://github.com/hyperledger/besu/pull/1812) * `--skip-pow-validation-enabled` is now an error with `block import --format JSON`. This is because the JSON format doesn't include the nonce so the proof of work must be calculated. [\#1815](https://github.com/hyperledger/besu/pull/1815) - +* Added a new CLI option `--Xlauncher` to start a mainnet launcher. It will help to configure Besu easily. + ### Bug Fixes ### Early Access Features diff --git a/besu/build.gradle b/besu/build.gradle index 21cf2998247..b8a5967dcc8 100644 --- a/besu/build.gradle +++ b/besu/build.gradle @@ -68,7 +68,7 @@ dependencies { implementation 'org.apache.tuweni:units' implementation 'org.springframework.security:spring-security-crypto' implementation 'org.xerial.snappy:snappy-java' - + implementation 'net.consensys.services:quorum-mainnet-launcher' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' runtimeOnly 'org.apache.logging.log4j:log4j-jul' diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 4baff94dfe0..004c20bad8f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -52,6 +52,7 @@ import org.hyperledger.besu.cli.options.unstable.DnsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.EthstatsOptions; +import org.hyperledger.besu.cli.options.unstable.LauncherOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; import org.hyperledger.besu.cli.options.unstable.MiningOptions; import org.hyperledger.besu.cli.options.unstable.NatOptions; @@ -190,6 +191,10 @@ import io.vertx.core.VertxOptions; import io.vertx.core.json.DecodeException; import io.vertx.core.metrics.MetricsOptions; +import net.consensys.quorum.mainnet.launcher.LauncherManager; +import net.consensys.quorum.mainnet.launcher.config.ImmutableLauncherConfig; +import net.consensys.quorum.mainnet.launcher.exception.LauncherException; +import net.consensys.quorum.mainnet.launcher.util.ParseArgsHelper; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -241,6 +246,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { private final NatOptions unstableNatOptions = NatOptions.create(); private final NativeLibraryOptions unstableNativeLibraryOptions = NativeLibraryOptions.create(); private final RPCOptions unstableRPCOptions = RPCOptions.create(); + final LauncherOptions unstableLauncherOptions = LauncherOptions.create(); private final RunnerBuilder runnerBuilder; private final BesuController.Builder controllerBuilderFactory; @@ -1131,6 +1137,7 @@ public void parse( final BesuExceptionHandler exceptionHandler, final InputStream in, final String... args) { + commandLine = new CommandLine(this, new BesuCommandCustomFactory(besuPluginContext)) .setCaseInsensitiveEnumValuesAllowed(true); @@ -1145,6 +1152,7 @@ public void parse( @Override public void run() { + try { configureLogging(true); configureNativeLibs(); @@ -1228,6 +1236,7 @@ private void handleUnstableOptions() { .put("Mining", unstableMiningOptions) .put("Native Library", unstableNativeLibraryOptions) .put("Data Storage Options", unstableDataStorageOptions) + .put("Launcher", unstableLauncherOptions) .build(); UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions); @@ -1270,10 +1279,34 @@ private void parse( // Create a handler that will search for a config file option and use it for // default values // and eventually it will run regular parsing of the remaining options. + final ConfigOptionSearchAndRunHandler configParsingHandler = new ConfigOptionSearchAndRunHandler( resultHandler, exceptionHandler, CONFIG_FILE_OPTION_NAME, environment); - commandLine.parseWithHandlers(configParsingHandler, exceptionHandler, args); + + ParseArgsHelper.getLauncherOptions(unstableLauncherOptions, args); + if (unstableLauncherOptions.isLauncherMode() + || unstableLauncherOptions.isLauncherModeForced()) { + try { + final ImmutableLauncherConfig launcherConfig = + ImmutableLauncherConfig.builder() + .launcherScript(BesuCommand.class.getResourceAsStream("launcher.json")) + .addCommandClasses( + this, unstableNatOptions, unstableEthstatsOptions, unstableMiningOptions) + .isLauncherForced(unstableLauncherOptions.isLauncherModeForced()) + .build(); + final File file = new LauncherManager(launcherConfig).run(); + logger.info("Config file location : {}", file.getAbsolutePath()); + commandLine.parseWithHandlers( + configParsingHandler, + exceptionHandler, + String.format("%s=%s", CONFIG_FILE_OPTION_NAME, file.getAbsolutePath())); + } catch (LauncherException e) { + logger.warn("Unable to run the launcher {}", e.getMessage()); + } + } else { + commandLine.parseWithHandlers(configParsingHandler, exceptionHandler, args); + } } private void startSynchronization() { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/LauncherOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/LauncherOptions.java new file mode 100644 index 00000000000..7c01c1a89ea --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/LauncherOptions.java @@ -0,0 +1,54 @@ +/* + * Copyright 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.cli.options.unstable; + +import net.consensys.quorum.mainnet.launcher.options.Options; +import picocli.CommandLine; + +public class LauncherOptions implements Options { + + private static final String LAUNCHER_OPTION_NAME = "--Xlauncher"; + private static final String LAUNCHER_OPTION_NAME_FORCE = "--Xlauncher-force"; + + @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) + @CommandLine.Option( + hidden = true, + names = {LAUNCHER_OPTION_NAME}, + description = + "Activate the launcher if no configuration file is present. (default: ${DEFAULT-VALUE})", + arity = "0..1") + private Boolean isLauncherMode = Boolean.FALSE; + + @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) + @CommandLine.Option( + hidden = true, + names = {LAUNCHER_OPTION_NAME_FORCE}, + description = + "Force to activate the launcher even if a configuration file is present. (default: ${DEFAULT-VALUE})", + arity = "0..1") + private Boolean isLauncherModeForced = Boolean.FALSE; + + public static LauncherOptions create() { + return new LauncherOptions(); + } + + public boolean isLauncherMode() { + return isLauncherMode; + } + + public boolean isLauncherModeForced() { + return isLauncherModeForced; + } +} diff --git a/besu/src/main/resources/org/hyperledger/besu/cli/launcher.json b/besu/src/main/resources/org/hyperledger/besu/cli/launcher.json new file mode 100644 index 00000000000..63fb8b0e8c6 --- /dev/null +++ b/besu/src/main/resources/org/hyperledger/besu/cli/launcher.json @@ -0,0 +1,187 @@ +{ + "config-file-name": "config.toml", + "steps": [ + { + "prompt-type": "LIST", + "question": "Which Ethereum network would you like to use ?", + "config-key": "network", + "available-options": "org.hyperledger.besu.cli.config.NetworkName", + "additional-flag": { + "yolo_v2": "Xberlin-enabled" + } + }, + { + "prompt-type": "LIST", + "question": "Which synchronization mode?", + "config-key": "sync-mode", + "available-options": "org.hyperledger.besu.ethereum.eth.sync.SyncMode" + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to enable pruning?", + "config-key": "pruning-enabled", + "default-option": "no" + }, + { + "prompt-type": "INPUT", + "question": "What is the data directory ?", + "config-key": "data-path" + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to enable the JSON-RPC HTTP service ?", + "config-key": "rpc-http-enabled", + "default-option": "yes", + "sub-questions": [ + { + "prompt-type": "CONFIRM", + "question": "Do you want to configure the JSON-RPC options now ?", + "default-option": "yes", + "sub-questions": [ + { + "prompt-type": "INPUT", + "question": "What is the JSON RPC HTTP host address ?", + "config-key": "rpc-http-host" + }, + { + "prompt-type": "INPUT", + "question": "What is the JSON RPC HTTP port ?", + "config-key": "rpc-http-port", + "regex": "[0-9]+" + }, + { + "prompt-type": "CHECKBOX", + "question": "Select the list of APIs to enable on JSON-RPC HTTP service", + "config-key": "rpc-http-apis", + "available-options": "org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis$ALL_JSON_RPC_APIS", + "default-option": "ETH, NET, WEB3" + } + ] + } + ] + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to enable the JSON-RPC Websocket service ?", + "config-key": "rpc-ws-enabled", + "default-option": "no", + "sub-questions": [ + { + "prompt-type": "CONFIRM", + "question": "Do you want to configure the JSON-RPC options now ?", + "default-option": "yes", + "sub-questions": [ + { + "prompt-type": "INPUT", + "question": "What is the JSON RPC Websocket host address ?", + "config-key": "rpc-ws-host" + }, + { + "prompt-type": "INPUT", + "question": "What is the JSON RPC Websocket port ?", + "config-key": "rpc-ws-port", + "regex": "[0-9]+" + }, + { + "prompt-type": "CHECKBOX", + "question": "Select the list of APIs to enable on JSON-RPC Websocket service", + "config-key": "rpc-ws-apis", + "available-options": "org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis$ALL_JSON_RPC_APIS", + "default-option": "ETH, NET, WEB3" + } + ] + } + ] + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to enable GraphQL functionality ?", + "config-key": "graphql-http-enabled", + "default-option": "no", + "sub-questions": [ + { + "prompt-type": "CONFIRM", + "question": "Do you want to configure the GraphQL options now ?", + "default-option": "yes", + "sub-questions": [ + { + "prompt-type": "INPUT", + "question": "What is the GraphQL host address ?", + "config-key": "graphql-http-host" + }, + { + "prompt-type": "INPUT", + "question": "What is the GraphQL port ?", + "config-key": "graphql-http-port", + "regex": "[0-9]+" + } + ] + } + ] + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to use Ethstats ?", + "default-option": "no", + "sub-questions": [ + { + "prompt-type": "INPUT", + "question": "What is the URL of Ethstats (nodename:secret@host:port) ?", + "config-key": "Xethstats", + "regex": "([-\\w]+):([\\w]+)?@([-.\\w]+):([\\d]+)" + }, + { + "prompt-type": "INPUT", + "question": "What is the contact address ?", + "config-key": "Xethstats-contact" + } + ] + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to enable NAT ?", + "default-option": "no", + "sub-questions": [ + { + "prompt-type": "LIST", + "question": "Which NAT method would you like to use ?", + "config-key": "nat-method", + "available-options": "org.hyperledger.besu.nat.NatMethod" + } + ] + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to enable mining ?", + "default-option": "no", + "config-key": "miner-enabled", + "sub-questions": [ + { + "prompt-type": "INPUT", + "question": "What is the account to which mining rewards are paid ?", + "config-key": "miner-coinbase", + "regex": "^0x[0-9a-fA-F]{40}$" + }, + { + "prompt-type": "CONFIRM", + "question": "Do you want to use Stratum ?", + "default-option": "no", + "config-key": "miner-stratum-enabled", + "sub-questions": [ + { + "prompt-type": "INPUT", + "question": "What is the Stratum host address ?", + "config-key": "miner-stratum-host" + }, + { + "prompt-type": "INPUT", + "question": "What is the Stratum port service ?", + "config-key": "miner-stratum-port", + "regex": "[0-9]+" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 832e6265dc9..72a8ce8156f 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1515,6 +1515,22 @@ public void ethStatsContactOptionCannotBeUsedWithoutEthStatsServerProvided() { "The `--Xethstats-contact` requires ethstats server URL to be provided. Either remove --Xethstats-contact or provide an url (via --Xethstats=nodename:secret@host:port)"); } + @Test + public void launcherDefaultOptionValue() { + TestBesuCommand besuCommand = parseCommand(); + + assertThat(besuCommand.getLauncherOptions().isLauncherMode()).isFalse(); + assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isFalse(); + } + + @Test + public void launcherOptionIsParsedCorrectly() { + TestBesuCommand besuCommand = parseCommand("--Xlauncher", "true", "--Xlauncher-force", "true"); + + assertThat(besuCommand.getLauncherOptions().isLauncherMode()).isTrue(); + assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isFalse(); + } + @Test public void dnsEnabledOptionIsParsedCorrectly() { final TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java index 3a9fcebf20f..f6c0d882451 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; +import org.hyperledger.besu.cli.options.unstable.LauncherOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; import org.hyperledger.besu.cli.options.unstable.NetworkingOptions; import org.hyperledger.besu.cli.options.unstable.SynchronizerOptions; @@ -407,6 +408,10 @@ public MetricsCLIOptions getMetricsCLIOptions() { return unstableMetricsCLIOptions; } + public LauncherOptions getLauncherOptions() { + return unstableLauncherOptions; + } + public void close() { if (vertx != null) { final AtomicBoolean closed = new AtomicBoolean(false); diff --git a/build.gradle b/build.gradle index 9d1e545946b..424ca19e4b7 100644 --- a/build.gradle +++ b/build.gradle @@ -125,6 +125,7 @@ allprojects { mavenLocal() maven { url "https://hyperledger-org.bintray.com/besu-repo" } maven { url "https://consensys.bintray.com/pegasys-repo" } + maven { url "https://consensys.bintray.com/consensys" } maven { url "https://repo.spring.io/libs-release" } maven { url "https://dl.bintray.com/open-telemetry/maven" } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcApis.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcApis.java index dcbebc653ad..c290aa0ddb9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcApis.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcApis.java @@ -35,6 +35,10 @@ public class RpcApis { public static final List DEFAULT_JSON_RPC_APIS = Arrays.asList(ETH, NET, WEB3); + @SuppressWarnings("unused") + public static final List ALL_JSON_RPC_APIS = + Arrays.asList(ETH, DEBUG, MINER, NET, PERM, WEB3, ADMIN, EEA, PRIV, TX_POOL, TRACE, PLUGINS); + public static Optional valueOf(final String name) { if (name.equals(ETH.getCliValue())) { return Optional.of(ETH); diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 3fdc2328bed..64bcbf0f342 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -113,6 +113,7 @@ dependencyManagement { dependency 'org.bouncycastle:bcprov-jdk15on:1.68' dependency 'org.fusesource.jansi:jansi:2.1.1' + dependency 'net.consensys.services:quorum-mainnet-launcher:1.0.1' dependency 'org.hyperledger.besu:bls12-381:0.3.0' dependency 'org.hyperledger.besu:secp256k1:0.3.0'