From 65cb5f6a9ccf4719255315708167fcaf8a29b59c Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 28 Oct 2021 12:13:59 -0700 Subject: [PATCH] iterative merge: Initial plumbing for merge subproject (#2968) Signed-off-by: garyschulte --- .../org/hyperledger/besu/cli/BesuCommand.java | 3 + .../cli/options/unstable/MergeOptions.java | 57 ++++++++++++++++++ .../options/unstable/MergeOptionsTest.java | 60 +++++++++++++++++++ config/build.gradle | 1 + .../besu/config/GenesisConfigOptions.java | 4 ++ .../besu/config/JsonGenesisConfigOptions.java | 6 ++ .../besu/config/StubGenesisConfigOptions.java | 14 +++++ .../config/experimental/MergeOptions.java | 40 +++++++++++++ .../besu/config/GenesisConfigFileTest.java | 18 ++++++ .../besu/config/GenesisConfigOptionsTest.java | 23 +++++++ consensus/merge/build.gradle | 48 +++++++++++++++ .../blockcreation/MergeMiningCoordinator.java | 19 ++++++ settings.gradle | 1 + 13 files changed, 294 insertions(+) create mode 100644 besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MergeOptions.java create mode 100644 besu/src/test/java/org/hyperledger/besu/cli/options/unstable/MergeOptionsTest.java create mode 100644 config/src/main/java/org/hyperledger/besu/config/experimental/MergeOptions.java create mode 100644 consensus/merge/build.gradle create mode 100644 consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java 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 c95d33e386..4369b81d77 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -55,6 +55,7 @@ import org.hyperledger.besu.cli.options.unstable.DnsOptions; import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions; import org.hyperledger.besu.cli.options.unstable.EvmOptions; import org.hyperledger.besu.cli.options.unstable.LauncherOptions; +import org.hyperledger.besu.cli.options.unstable.MergeOptions; import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions; import org.hyperledger.besu.cli.options.unstable.MiningOptions; import org.hyperledger.besu.cli.options.unstable.NatOptions; @@ -268,6 +269,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(); + private final MergeOptions mergeOptions = MergeOptions.create(); final LauncherOptions unstableLauncherOptions = LauncherOptions.create(); private final PrivacyPluginOptions unstablePrivacyPluginOptions = PrivacyPluginOptions.create(); private final EvmOptions unstableEvmOptions = EvmOptions.create(); @@ -1302,6 +1304,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { .put("Native Library", unstableNativeLibraryOptions) .put("Data Storage Options", unstableDataStorageOptions) .put("Launcher", unstableLauncherOptions) + .put("Merge", mergeOptions) .put("EVM Options", unstableEvmOptions) .build(); diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MergeOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MergeOptions.java new file mode 100644 index 0000000000..36f70448d6 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/unstable/MergeOptions.java @@ -0,0 +1,57 @@ +/* + * 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 static org.hyperledger.besu.config.experimental.MergeOptions.setMergeEnabled; + +import java.util.Stack; + +import net.consensys.quorum.mainnet.launcher.options.Options; +import picocli.CommandLine; +import picocli.CommandLine.Option; + +/** Unstable support for eth1/2 merge */ +public class MergeOptions implements Options { + // To make it easier for tests to reset the value to default + public static final boolean MERGE_ENABLED_DEFAULT_VALUE = false; + + @Option( + hidden = true, + names = {"--Xmerge-support"}, + description = "Enable experimental support for eth1/eth2 merge (default: ${DEFAULT-VALUE})", + arity = "1", + parameterConsumer = MergeConfigConsumer.class) + @SuppressWarnings({"FieldCanBeFinal"}) + private static boolean mergeEnabled = MERGE_ENABLED_DEFAULT_VALUE; + + public static MergeOptions create() { + return new MergeOptions(); + } + + public Boolean isMergeEnabled() { + return mergeEnabled; + } + + @SuppressWarnings({"JdkObsolete"}) + static class MergeConfigConsumer implements CommandLine.IParameterConsumer { + @Override + public void consumeParameters( + final Stack args, + final CommandLine.Model.ArgSpec argSpec, + final CommandLine.Model.CommandSpec commandSpec) { + setMergeEnabled(Boolean.parseBoolean(args.pop())); + } + } +} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/unstable/MergeOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/unstable/MergeOptionsTest.java new file mode 100644 index 0000000000..e1133e95d4 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/unstable/MergeOptionsTest.java @@ -0,0 +1,60 @@ +/* + * 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 static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import java.util.Stack; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +@SuppressWarnings({"JdkObsolete"}) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class MergeOptionsTest { + + @Test + public void shouldBeDisabledByDefault() { + // disabledByDefault + assertThat(MergeOptions.create().isMergeEnabled()).isFalse(); + } + + @Test + public void shouldBeEnabledFromCliConsumer() { + // enable + var mockStack = new Stack(); + mockStack.push("true"); + new MergeOptions.MergeConfigConsumer().consumeParameters(mockStack, null, null); + + assertThat(org.hyperledger.besu.config.experimental.MergeOptions.isMergeEnabled()).isTrue(); + } + + @Test + public void shouldDoWithMergeEnabled() { + final AtomicBoolean check = new AtomicBoolean(false); + org.hyperledger.besu.config.experimental.MergeOptions.doIfMergeEnabled((() -> check.set(true))); + assertThat(check.get()).isTrue(); + } + + @Test + public void shouldThrowOnReconfigure() { + assertThatThrownBy( + () -> org.hyperledger.besu.config.experimental.MergeOptions.setMergeEnabled(false)) + .isInstanceOf(RuntimeException.class); + } +} diff --git a/config/build.gradle b/config/build.gradle index a0e489be54..714abc5c2c 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation 'org.apache.logging.log4j:log4j-api' implementation 'info.picocli:picocli' implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'org.apache.tuweni:tuweni-units' runtimeOnly 'org.apache.logging.log4j:log4j-core' testImplementation project(':testutil') diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java index 7c7a054845..445a890fc5 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -21,6 +21,8 @@ import java.util.Optional; import java.util.OptionalInt; import java.util.OptionalLong; +import org.apache.tuweni.units.bigints.UInt256; + public interface GenesisConfigOptions { boolean isEthHash(); @@ -73,6 +75,8 @@ public interface GenesisConfigOptions { OptionalLong getBaseFeePerGas(); + Optional getTerminalTotalDifficulty(); + List getForks(); /** diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index c05a96b992..dc76e853db 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -31,6 +31,7 @@ import java.util.stream.Stream; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableMap; +import org.apache.tuweni.units.bigints.UInt256; public class JsonGenesisConfigOptions implements GenesisConfigOptions { @@ -263,6 +264,11 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { .orElse(OptionalLong.empty()); } + @Override + public Optional getTerminalTotalDifficulty() { + return getOptionalBigInteger("terminaltotaldifficulty").map(UInt256::valueOf); + } + @Override public OptionalLong getClassicForkBlock() { return getOptionalLong("classicforkblock"); diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index 08284ceee0..fdfc2d7cfc 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -23,6 +23,7 @@ import java.util.OptionalInt; import java.util.OptionalLong; import com.google.common.collect.ImmutableMap; +import org.apache.tuweni.units.bigints.UInt256; public class StubGenesisConfigOptions implements GenesisConfigOptions { @@ -37,6 +38,8 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { private OptionalLong muirGlacierBlockNumber = OptionalLong.empty(); private OptionalLong berlinBlockNumber = OptionalLong.empty(); private OptionalLong londonBlockNumber = OptionalLong.empty(); + private Optional terminalTotalDifficulty = Optional.empty(); + private OptionalLong baseFeePerGas = OptionalLong.empty(); private OptionalLong classicForkBlock = OptionalLong.empty(); private OptionalLong ecip1015BlockNumber = OptionalLong.empty(); @@ -183,6 +186,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { return baseFeePerGas; } + @Override + public Optional getTerminalTotalDifficulty() { + return terminalTotalDifficulty; + } + @Override public OptionalLong getClassicForkBlock() { return classicForkBlock; @@ -403,6 +411,12 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { return this; } + public StubGenesisConfigOptions terminalTotalDifficulty( + final UInt256 updatedTerminalTotalDifficulty) { + terminalTotalDifficulty = Optional.of(updatedTerminalTotalDifficulty); + return this; + } + public StubGenesisConfigOptions baseFeePerGas(final long baseFeeOverride) { baseFeePerGas = OptionalLong.of(baseFeeOverride); return this; diff --git a/config/src/main/java/org/hyperledger/besu/config/experimental/MergeOptions.java b/config/src/main/java/org/hyperledger/besu/config/experimental/MergeOptions.java new file mode 100644 index 0000000000..900a671e81 --- /dev/null +++ b/config/src/main/java/org/hyperledger/besu/config/experimental/MergeOptions.java @@ -0,0 +1,40 @@ +/* + * 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.config.experimental; + +import java.util.Optional; + +/** For now there is a static config that is driven by a command line option. */ +public class MergeOptions { + private static Optional mergeEnabled = Optional.empty(); + + public static void setMergeEnabled(final boolean bool) { + if (!mergeEnabled.isPresent()) { + mergeEnabled = Optional.of(bool); + } else if (mergeEnabled.get() != bool) { + throw new RuntimeException("Refusing to re-configure already configured merge feature"); + } + } + + public static boolean isMergeEnabled() { + return mergeEnabled.orElse(false); + } + + public static void doIfMergeEnabled(final Runnable mergeDo) { + if (isMergeEnabled()) { + mergeDo.run(); + } + } +} diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java index a85a9b4038..2d2e37e0ac 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigFileTest.java @@ -32,6 +32,7 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.io.Resources; +import org.apache.tuweni.units.bigints.UInt256; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.Test; @@ -178,6 +179,23 @@ public class GenesisConfigFileTest { assertThat(withOverrides.getBaseFeePerGas().getAsLong()).isEqualTo(8L); } + @Test + public void shouldGetTerminalTotalDifficultyAtGenesis() { + GenesisConfigFile withTerminalTotalDifficultyAtGenesis = + fromConfig("{\"config\":{\"terminalTotalDifficulty\":1000}}"); + assertThat( + withTerminalTotalDifficultyAtGenesis + .getConfigOptions() + .getTerminalTotalDifficulty() + .get()) + .isEqualTo(UInt256.valueOf(1000L)); + } + + @Test + public void shouldGetEmptyTerminalTotalDifficultyAtGenesis() { + assertThat(EMPTY_CONFIG.getConfigOptions().getTerminalTotalDifficulty()).isNotPresent(); + } + @Test public void shouldDefaultTimestampToZero() { assertThat(EMPTY_CONFIG.getTimestamp()).isZero(); diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java index e0e56d50d4..9c4d807ba0 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.Map; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.tuweni.units.bigints.UInt256; import org.junit.Test; public class GenesisConfigOptionsTest { @@ -224,6 +225,28 @@ public class GenesisConfigOptionsTest { assertThat(config.getHomesteadBlockNumber()).isEmpty(); } + @Test + public void shouldGetTerminalTotalDifficultyWhenSpecified() { + final GenesisConfigOptions config = + fromConfigOptions(singletonMap("terminalTotalDifficulty", BigInteger.valueOf(1000))); + assertThat(config.getTerminalTotalDifficulty()).isPresent(); + assertThat(config.getTerminalTotalDifficulty().get()).isEqualTo(UInt256.valueOf(1000)); + + // stubJsonGenesis + final GenesisConfigOptions stub = + new StubGenesisConfigOptions().terminalTotalDifficulty(UInt256.valueOf(500)); + assertThat(stub.getTerminalTotalDifficulty()).isPresent(); + assertThat(stub.getTerminalTotalDifficulty().get()).isEqualTo(UInt256.valueOf(500)); + } + + @Test + public void shouldNotReturnTerminalTotalDifficultyWhenNotSpecified() { + final GenesisConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getTerminalTotalDifficulty()).isNotPresent(); + // stubJsonGenesis + assertThat(new StubGenesisConfigOptions().getTerminalTotalDifficulty()).isNotPresent(); + } + @Test public void isQuorumShouldDefaultToFalse() { final GenesisConfigOptions config = GenesisConfigFile.fromConfig("{}").getConfigOptions(); diff --git a/consensus/merge/build.gradle b/consensus/merge/build.gradle new file mode 100644 index 0000000000..a05900da44 --- /dev/null +++ b/consensus/merge/build.gradle @@ -0,0 +1,48 @@ +/* + * 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 + */ + +apply plugin: 'java-library' + +jar { + archiveBaseName = 'besu-merge' + manifest { + attributes( + 'Specification-Title': archiveBaseName, + 'Specification-Version': project.version, + 'Implementation-Title': archiveBaseName, + 'Implementation-Version': calculateVersion() + ) + } +} + +repositories { mavenCentral() } + +dependencies { + implementation project(':config') + implementation project(':datatypes') + implementation project(':ethereum:blockcreation') + implementation project(':ethereum:core') + implementation project(':ethereum:eth') + implementation project(':evm') + implementation project(':util') + + implementation 'com.google.guava:guava' + implementation 'io.vertx:vertx-core' + implementation 'org.apache.tuweni:tuweni-bytes' + implementation 'org.apache.tuweni:tuweni-units' + + testImplementation 'junit:junit' + testImplementation 'org.assertj:assertj-core' +} diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java new file mode 100644 index 0000000000..ff1a09545c --- /dev/null +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeMiningCoordinator.java @@ -0,0 +1,19 @@ +/* + * 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.consensus.merge.blockcreation; + +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; + +public interface MergeMiningCoordinator extends MiningCoordinator {} diff --git a/settings.gradle b/settings.gradle index 0b3de9f218..2536f8ef6c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,6 +23,7 @@ include 'consensus:clique' include 'consensus:common' include 'consensus:ibft' include 'consensus:ibftlegacy' +include 'consensus:merge' include 'consensus:qbft' include 'container-tests:tests' include 'datatypes'