From 22a570eda42dd4bba917bcaac93bdf642fe765fd Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 30 Oct 2024 16:21:10 +0100 Subject: [PATCH 1/9] Fix registering new metric categories from plugins (#7825) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../acceptance/plugins/TestMetricsPlugin.java | 76 +++++++++++++++++++ .../acceptance/plugins/MetricsPluginTest.java | 73 ++++++++++++++++++ .../org/hyperledger/besu/cli/BesuCommand.java | 18 ++--- .../converter/MetricCategoryConverter.java | 73 ------------------ .../cli/options/stable/MetricsOptions.java | 47 +++++++++++- .../hyperledger/besu/cli/BesuCommandTest.java | 41 ++++++---- .../MetricCategoryConverterTest.java | 63 --------------- .../besu/cli/options/MetricsOptionsTest.java | 16 +++- .../metrics/MetricCategoryRegistryImpl.java | 47 +++++++++--- 10 files changed, 279 insertions(+), 176 deletions(-) create mode 100644 acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestMetricsPlugin.java create mode 100644 acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/MetricsPluginTest.java delete mode 100644 besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java delete mode 100644 besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bfb4ebd3e..4b20bc15ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813) ### Bug fixes +- Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825) ## 24.10.0 diff --git a/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestMetricsPlugin.java b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestMetricsPlugin.java new file mode 100644 index 0000000000..7e1ac2ccde --- /dev/null +++ b/acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestMetricsPlugin.java @@ -0,0 +1,76 @@ +/* + * Copyright contributors to Besu. + * + * 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.tests.acceptance.plugins; + +import org.hyperledger.besu.plugin.BesuContext; +import org.hyperledger.besu.plugin.BesuPlugin; +import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.metrics.MetricCategory; +import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; + +import java.util.Locale; +import java.util.Optional; + +import com.google.auto.service.AutoService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@AutoService(BesuPlugin.class) +public class TestMetricsPlugin implements BesuPlugin { + private static final Logger LOG = LoggerFactory.getLogger(TestMetricsPlugin.class); + private BesuContext besuContext; + + @Override + public void register(final BesuContext context) { + LOG.info("Registering TestMetricsPlugin"); + besuContext = context; + context + .getService(MetricCategoryRegistry.class) + .orElseThrow() + .addMetricCategory(TestMetricCategory.TEST_METRIC_CATEGORY); + } + + @Override + public void start() { + LOG.info("Starting TestMetricsPlugin"); + besuContext + .getService(MetricsSystem.class) + .orElseThrow() + .createGauge( + TestMetricCategory.TEST_METRIC_CATEGORY, + "test_metric", + "Returns 1 on succes", + () -> 1.0); + } + + @Override + public void stop() { + LOG.info("Stopping TestMetricsPlugin"); + } + + public enum TestMetricCategory implements MetricCategory { + TEST_METRIC_CATEGORY; + + @Override + public String getName() { + return name().toLowerCase(Locale.ROOT); + } + + @Override + public Optional getApplicationPrefix() { + return Optional.of("plugin_test_"); + } + } +} diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/MetricsPluginTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/MetricsPluginTest.java new file mode 100644 index 0000000000..7559200720 --- /dev/null +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/MetricsPluginTest.java @@ -0,0 +1,73 @@ +/* + * Copyright contributors to Besu. + * + * 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.tests.acceptance.plugins; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.tests.acceptance.plugins.TestMetricsPlugin.TestMetricCategory.TEST_METRIC_CATEGORY; + +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; +import org.hyperledger.besu.tests.acceptance.dsl.node.BesuNode; +import org.hyperledger.besu.tests.acceptance.dsl.node.configuration.BesuNodeConfigurationBuilder; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class MetricsPluginTest extends AcceptanceTestBase { + private BesuNode node; + private MetricsConfiguration metricsConfiguration; + + @BeforeEach + public void setUp() throws Exception { + metricsConfiguration = + MetricsConfiguration.builder() + .enabled(true) + .port(0) + .metricCategories(Set.of(TEST_METRIC_CATEGORY)) + .build(); + node = + besu.create( + new BesuNodeConfigurationBuilder() + .name("node1") + .plugins(List.of("testPlugins")) + .metricsConfiguration(metricsConfiguration) + .build()); + + cluster.start(node); + } + + @Test + public void metricCategoryAdded() throws IOException, InterruptedException { + final var httpClient = HttpClient.newHttpClient(); + final var req = HttpRequest.newBuilder(URI.create(node.metricsHttpUrl().get())).build(); + final var resp = httpClient.send(req, HttpResponse.BodyHandlers.ofLines()); + assertThat(resp.statusCode()).isEqualTo(200); + final var foundMetric = + resp.body() + .filter( + line -> line.startsWith(TEST_METRIC_CATEGORY.getApplicationPrefix().orElseThrow())) + .findFirst() + .orElseThrow(); + assertThat(foundMetric).endsWith("1.0"); + } +} 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 886e3d6838..45feaf1005 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -37,7 +37,6 @@ import org.hyperledger.besu.chainimport.RlpBlockImporter; import org.hyperledger.besu.cli.config.EthNetworkConfig; import org.hyperledger.besu.cli.config.NetworkName; import org.hyperledger.besu.cli.config.ProfilesCompletionCandidates; -import org.hyperledger.besu.cli.converter.MetricCategoryConverter; import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty; import org.hyperledger.besu.cli.error.BesuExecutionExceptionHandler; import org.hyperledger.besu.cli.error.BesuParameterExceptionHandler; @@ -170,7 +169,6 @@ import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService; import org.hyperledger.besu.plugin.services.TransactionSelectionService; import org.hyperledger.besu.plugin.services.TransactionSimulationService; import org.hyperledger.besu.plugin.services.exception.StorageException; -import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; import org.hyperledger.besu.plugin.services.p2p.P2PService; import org.hyperledger.besu.plugin.services.rlp.RlpConverterService; @@ -332,7 +330,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { private final Map environment; private final MetricCategoryRegistryImpl metricCategoryRegistry = new MetricCategoryRegistryImpl(); - private final MetricCategoryConverter metricCategoryConverter = new MetricCategoryConverter(); private final PreSynchronizationTaskRunner preSynchronizationTaskRunner = new PreSynchronizationTaskRunner(); @@ -1136,10 +1133,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { commandLine.registerConverter(Hash.class, Hash::fromHexString); commandLine.registerConverter(Optional.class, Optional::of); commandLine.registerConverter(Double.class, Double::parseDouble); - - metricCategoryConverter.addCategories(BesuMetricCategory.class); - metricCategoryConverter.addCategories(StandardMetricCategory.class); - commandLine.registerConverter(MetricCategory.class, metricCategoryConverter); } private void handleStableOptions() { @@ -1174,6 +1167,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable { besuPluginContext.addService(PicoCLIOptions.class, new PicoCLIOptionsImpl(commandLine)); besuPluginContext.addService(SecurityModuleService.class, securityModuleService); besuPluginContext.addService(StorageService.class, storageService); + + metricCategoryRegistry.addCategories(BesuMetricCategory.class); + metricCategoryRegistry.addCategories(StandardMetricCategory.class); besuPluginContext.addService(MetricCategoryRegistry.class, metricCategoryRegistry); besuPluginContext.addService(PermissioningService.class, permissioningService); besuPluginContext.addService(PrivacyPluginService.class, privacyPluginService); @@ -1191,10 +1187,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { rocksDBPlugin.register(besuPluginContext); new InMemoryStoragePlugin().register(besuPluginContext); - metricCategoryRegistry - .getMetricCategories() - .forEach(metricCategoryConverter::addRegistryCategory); - // register default security module securityModuleService.register( DEFAULT_SECURITY_MODULE, Suppliers.memoize(this::defaultSecurityModule)); @@ -1891,6 +1883,10 @@ public class BesuCommand implements DefaultCommandValues, Runnable { "--metrics-push-interval", "--metrics-push-prometheus-job")); + metricsOptions.setMetricCategoryRegistry(metricCategoryRegistry); + + metricsOptions.validate(commandLine); + final MetricsConfiguration.Builder metricsConfigurationBuilder = metricsOptions.toDomainObject(); metricsConfigurationBuilder diff --git a/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java b/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java deleted file mode 100644 index 339da86b2d..0000000000 --- a/besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.converter; - -import org.hyperledger.besu.plugin.services.metrics.MetricCategory; - -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import com.google.common.annotations.VisibleForTesting; -import picocli.CommandLine; - -/** The Metric category converter for CLI options. */ -public class MetricCategoryConverter implements CommandLine.ITypeConverter { - - private final Map metricCategories = new HashMap<>(); - - /** Default Constructor. */ - public MetricCategoryConverter() {} - - @Override - public MetricCategory convert(final String value) { - final MetricCategory category = metricCategories.get(value); - if (category == null) { - throw new IllegalArgumentException("Unknown category: " + value); - } - return category; - } - - /** - * Add Metrics categories. - * - * @param the type parameter - * @param categoryEnum the category enum - */ - public & MetricCategory> void addCategories(final Class categoryEnum) { - EnumSet.allOf(categoryEnum) - .forEach(category -> metricCategories.put(category.name(), category)); - } - - /** - * Add registry category. - * - * @param metricCategory the metric category - */ - public void addRegistryCategory(final MetricCategory metricCategory) { - metricCategories.put(metricCategory.getName().toUpperCase(Locale.ROOT), metricCategory); - } - - /** - * Gets metric categories. - * - * @return the metric categories - */ - @VisibleForTesting - Map getMetricCategories() { - return metricCategories; - } -} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java index 4906cf538e..beba20e29b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.cli.options.stable; +import static com.google.common.base.Preconditions.checkState; +import static java.util.stream.Collectors.toUnmodifiableSet; import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP; import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_INTEGER_FORMAT_HELP; import static org.hyperledger.besu.cli.DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP; @@ -24,6 +26,7 @@ import static org.hyperledger.besu.metrics.prometheus.MetricsConfiguration.DEFAU import org.hyperledger.besu.cli.options.CLIOptions; import org.hyperledger.besu.cli.util.CommandLineUtils; +import org.hyperledger.besu.metrics.MetricCategoryRegistryImpl; import org.hyperledger.besu.metrics.MetricsProtocol; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; @@ -36,6 +39,7 @@ import picocli.CommandLine; /** Command line options for configuring metrics. */ // TODO: implement CLIOption public class MetricsOptions implements CLIOptions { + private MetricCategoryRegistryImpl metricCategoryRegistry; /** * Returns a MetricsConfiguration.Builder because fields are often overridden from other domains, @@ -77,7 +81,10 @@ public class MetricsOptions implements CLIOptions metricsOptions.metricsHost = config.getHost(); metricsOptions.metricsPort = config.getPort(); metricsOptions.metricsProtocol = config.getProtocol(); - metricsOptions.metricCategories = config.getMetricCategories(); + metricsOptions.metricCategories = + config.getMetricCategories().stream() + .map(MetricCategory::getName) + .collect(toUnmodifiableSet()); metricsOptions.metricsPrometheusJob = config.getPrometheusJob(); metricsOptions.isMetricsPushEnabled = config.isPushEnabled(); metricsOptions.metricsPushHost = config.getPushHost(); @@ -126,7 +133,8 @@ public class MetricsOptions implements CLIOptions arity = "1..*", description = "Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})") - private Set metricCategories = DEFAULT_METRIC_CATEGORIES; + private Set metricCategories = + DEFAULT_METRIC_CATEGORIES.stream().map(MetricCategory::getName).collect(toUnmodifiableSet()); @CommandLine.Option( names = {"--metrics-push-enabled"}, @@ -216,7 +224,13 @@ public class MetricsOptions implements CLIOptions * @return the metric categories */ public Set getMetricCategories() { - return metricCategories; + checkState( + metricCategoryRegistry != null, "Set metricCategoryRegistry before calling this method"); + + final var list = + metricCategories.stream().map(metricCategoryRegistry::getMetricCategory).toList(); + + return Set.copyOf(list); } /** @@ -264,6 +278,33 @@ public class MetricsOptions implements CLIOptions return metricsPrometheusJob; } + /** + * Perform final validation after all the options, and the metric category registry, have been set + * + * @param commandLine the command line + */ + public void validate(final CommandLine commandLine) { + checkState( + metricCategoryRegistry != null, "Set metricCategoryRegistry before calling this method"); + final var unknownCategories = + metricCategories.stream() + .filter(category -> !metricCategoryRegistry.containsMetricCategory(category)) + .toList(); + if (!unknownCategories.isEmpty()) { + throw new CommandLine.ParameterException( + commandLine, "--metrics-categories contains unknown categories: " + unknownCategories); + } + } + + /** + * Set the metric category registry in order to support verification and conversion + * + * @param metricCategoryRegistry the metric category registry + */ + public void setMetricCategoryRegistry(final MetricCategoryRegistryImpl metricCategoryRegistry) { + this.metricCategoryRegistry = metricCategoryRegistry; + } + @CommandLine.ArgGroup(validate = false) private final MetricsOptions.Unstable unstableOptions = new MetricsOptions.Unstable(); 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 019e8d83cd..cf3c40860d 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -40,6 +40,7 @@ import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import org.hyperledger.besu.BesuInfo; import org.hyperledger.besu.cli.config.EthNetworkConfig; @@ -99,7 +100,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import picocli.CommandLine; @@ -566,7 +566,7 @@ public class BesuCommandTest extends CommandTestAbstract { parseCommand("--genesis-file", genesisFile.toString(), "--network", "mainnet"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) @@ -578,7 +578,7 @@ public class BesuCommandTest extends CommandTestAbstract { final String nonExistentGenesis = "non-existent-genesis.json"; parseCommand("--genesis-file", nonExistentGenesis); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).startsWith("Unable to load genesis file"); @@ -1177,7 +1177,7 @@ public class BesuCommandTest extends CommandTestAbstract { parseCommand( "--remote-connections-limit-enabled", "--remote-connections-max-percentage", "invalid"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( @@ -1190,7 +1190,7 @@ public class BesuCommandTest extends CommandTestAbstract { parseCommand( "--remote-connections-limit-enabled", "--remote-connections-max-percentage", "150"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( @@ -1225,7 +1225,7 @@ public class BesuCommandTest extends CommandTestAbstract { @Test public void syncMode_invalid() { parseCommand("--sync-mode", "bogus"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) @@ -1275,7 +1275,7 @@ public class BesuCommandTest extends CommandTestAbstract { public void helpShouldDisplayFastSyncOptions() { parseCommand("--help"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).contains("--fast-sync-min-peers"); // whitelist is now a hidden option @@ -1335,7 +1335,7 @@ public class BesuCommandTest extends CommandTestAbstract { public void parsesInvalidFastSyncMinPeersOptionWrongFormatShouldFail() { parseCommand("--sync-mode", "FAST", "--fast-sync-min-peers", "ten"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains("Invalid value for option '--fast-sync-min-peers': 'ten' is not an int"); @@ -1358,7 +1358,7 @@ public class BesuCommandTest extends CommandTestAbstract { public void netRestrictInvalidShouldFail() { final String subnet = "127.0.0.1/abc"; parseCommand("--net-restrict", subnet); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandErrorOutput.toString(UTF_8)) .contains("Invalid value for option '--net-restrict'"); } @@ -1382,7 +1382,7 @@ public class BesuCommandTest extends CommandTestAbstract { @Test public void ethStatsContactOptionCannotBeUsedWithoutEthStatsServerProvided() { parseCommand("--ethstats-contact", "besu-updated"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( @@ -1435,7 +1435,7 @@ public class BesuCommandTest extends CommandTestAbstract { public void parsesInvalidWhenFullSyncAndBonsaiLimitTrieLogsExplicitlyTrue() { parseCommand("--sync-mode=FULL", "--bonsai-limit-trie-logs-enabled=true"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( @@ -1467,7 +1467,7 @@ public class BesuCommandTest extends CommandTestAbstract { parseCommand("--data-storage-format", "BONSAI", "--bonsai-maximum-back-layers-to-load", "ten"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( @@ -1501,7 +1501,7 @@ public class BesuCommandTest extends CommandTestAbstract { @Test public void dnsUpdateEnabledOptionCannotBeUsedWithoutDnsEnabled() { parseCommand("--Xdns-update-enabled", "true"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( @@ -1720,6 +1720,17 @@ public class BesuCommandTest extends CommandTestAbstract { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void metricsUnknownCategoryRaiseError() { + parseCommand("--metrics-enabled", "--metrics-category", "UNKNOWN_CATEGORY"); + + verifyNoInteractions(mockRunnerBuilder); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)) + .startsWith("--metrics-categories contains unknown categories: [UNKNOWN_CATEGORY]"); + } + @Test public void metricsPushEnabledPropertyMustBeUsed() { parseCommand("--metrics-push-enabled"); @@ -1799,7 +1810,7 @@ public class BesuCommandTest extends CommandTestAbstract { public void metricsAndMetricsPushMustNotBeUsedTogether() { parseCommand("--metrics-enabled", "--metrics-push-enabled"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) @@ -2023,7 +2034,7 @@ public class BesuCommandTest extends CommandTestAbstract { public void fullCLIOptionsShown() { parseCommand("--help"); - Mockito.verifyNoInteractions(mockRunnerBuilder); + verifyNoInteractions(mockRunnerBuilder); assertThat(commandOutput.toString(UTF_8)).contains("--config-file"); assertThat(commandOutput.toString(UTF_8)).contains("--data-path"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java b/besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java deleted file mode 100644 index 8c78b7fecc..0000000000 --- a/besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.converter; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.mockito.Mockito.when; - -import org.hyperledger.besu.plugin.services.metrics.MetricCategory; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -public class MetricCategoryConverterTest { - - private MetricCategoryConverter metricCategoryConverter; - - @Mock MetricCategory metricCategory; - - @BeforeEach - public void setUp() { - metricCategoryConverter = new MetricCategoryConverter(); - } - - @Test - public void convertShouldFailIfValueNotRegistered() { - assertThatExceptionOfType(IllegalArgumentException.class) - .isThrownBy(() -> metricCategoryConverter.convert("notRegistered")); - } - - @Test - public void addRegistryCategoryShouldUppercaseInputValues() { - when(metricCategory.getName()).thenReturn("testcat"); - metricCategoryConverter.addRegistryCategory(metricCategory); - when(metricCategory.getName()).thenReturn("tesTCat2"); - metricCategoryConverter.addRegistryCategory(metricCategory); - - final boolean containsLowercase = - metricCategoryConverter.getMetricCategories().keySet().stream() - .anyMatch(testString -> testString.chars().anyMatch(Character::isLowerCase)); - - assertThat(containsLowercase).isFalse(); - assertThat(metricCategoryConverter.getMetricCategories().size()).isEqualTo(2); - assertThat(metricCategoryConverter.getMetricCategories().keySet()) - .containsExactlyInAnyOrder("TESTCAT", "TESTCAT2"); - } -} diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java index 992dcc437d..7f35effb7d 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java @@ -15,14 +15,26 @@ package org.hyperledger.besu.cli.options; import org.hyperledger.besu.cli.options.stable.MetricsOptions; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.metrics.MetricCategoryRegistryImpl; +import org.hyperledger.besu.metrics.StandardMetricCategory; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) public class MetricsOptionsTest extends AbstractCLIOptionsTest { + private MetricCategoryRegistryImpl categoryRegistry; + + @BeforeEach + public void setUp() { + categoryRegistry = new MetricCategoryRegistryImpl(); + categoryRegistry.addCategories(BesuMetricCategory.class); + categoryRegistry.addCategories(StandardMetricCategory.class); + } @Override protected MetricsConfiguration.Builder createDefaultDomainObject() { @@ -39,7 +51,9 @@ public class MetricsOptionsTest @Override protected MetricsOptions optionsFromDomainObject( final MetricsConfiguration.Builder domainObject) { - return MetricsOptions.fromConfiguration(domainObject.build()); + final var options = MetricsOptions.fromConfiguration(domainObject.build()); + options.setMetricCategoryRegistry(categoryRegistry); + return options; } @Override diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java index b0a31793bc..b78bcf18a8 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java @@ -17,28 +17,55 @@ package org.hyperledger.besu.metrics; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; -import java.util.ArrayList; -import java.util.List; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; /** The Metric category registry implementation. */ public class MetricCategoryRegistryImpl implements MetricCategoryRegistry { - - private final List metricCategories = new ArrayList<>(); + private final Map metricCategories = new HashMap<>(); /** Default constructor */ public MetricCategoryRegistryImpl() {} /** - * Gets metric categories. + * Add Metrics categories. * - * @return the metric categories + * @param the type parameter + * @param categoryEnum the category enum */ - public List getMetricCategories() { - return metricCategories; + public & MetricCategory> void addCategories(final Class categoryEnum) { + EnumSet.allOf(categoryEnum).forEach(this::addMetricCategory); } + /** + * Add registry category. + * + * @param metricCategory the metric category + */ @Override - public void addMetricCategory(final MetricCategory newMetricCategory) { - metricCategories.add(newMetricCategory); + public void addMetricCategory(final MetricCategory metricCategory) { + metricCategories.put(metricCategory.getName().toUpperCase(Locale.ROOT), metricCategory); + } + + /** + * Return true if a category with that name is already registered + * + * @param name the category name + * @return true if a category with that name is already registered + */ + public boolean containsMetricCategory(final String name) { + return metricCategories.containsKey(name.toUpperCase(Locale.ROOT)); + } + + /** + * Return a metric category by name + * + * @param name the category name + * @return the metric category or null if not registered + */ + public MetricCategory getMetricCategory(final String name) { + return metricCategories.get(name.toUpperCase(Locale.ROOT)); } } From ba86ce1181a923a2ea04f18b61f488df4ebef5f5 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 30 Oct 2024 18:12:10 +0100 Subject: [PATCH 2/9] Add a method to check if a metric category is enabled to the plugin API (#7832) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 4 +- .../besu/cli/options/MetricsOptionsTest.java | 5 ++ .../metrics/MetricCategoryRegistryImpl.java | 22 +++++++ .../MetricCategoryRegistryImplTest.java | 66 +++++++++++++++++++ plugin-api/build.gradle | 2 +- .../metrics/MetricCategoryRegistry.java | 10 ++- 7 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 metrics/core/src/test/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImplTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b20bc15ae..26342cf7be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Create and publish Besu BOM (Bill of Materials) [#7615](https://github.com/hyperledger/besu/pull/7615) - Update Java dependencies [#7786](https://github.com/hyperledger/besu/pull/7786) - Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813) +- Add a method to check if a metric category is enabled to the plugin API [#7832](https://github.com/hyperledger/besu/pull/7832) ### Bug fixes - Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825) 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 45feaf1005..bf79da288d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1899,7 +1899,9 @@ public class BesuCommand implements DefaultCommandValues, Runnable { ? p2PDiscoveryOptions.autoDiscoverDefaultIP().getHostAddress() : metricsOptions.getMetricsPushHost()) .hostsAllowlist(hostsAllowlist); - return metricsConfigurationBuilder.build(); + final var metricsConfiguration = metricsConfigurationBuilder.build(); + metricCategoryRegistry.setMetricsConfiguration(metricsConfiguration); + return metricsConfiguration; } private PrivacyParameters privacyParameters() { diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java index 7f35effb7d..cd541759ad 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java @@ -60,4 +60,9 @@ public class MetricsOptionsTest protected MetricsOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) { return besuCommand.getMetricsOptions(); } + + @Override + protected String[] getNonOptionFields() { + return new String[] {"metricCategoryRegistry"}; + } } diff --git a/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java b/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java index b78bcf18a8..6596268acb 100644 --- a/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java +++ b/metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java @@ -14,6 +14,9 @@ */ package org.hyperledger.besu.metrics; +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.plugin.services.metrics.MetricCategory; import org.hyperledger.besu.plugin.services.metrics.MetricCategoryRegistry; @@ -25,6 +28,7 @@ import java.util.Map; /** The Metric category registry implementation. */ public class MetricCategoryRegistryImpl implements MetricCategoryRegistry { private final Map metricCategories = new HashMap<>(); + private MetricsConfiguration metricsConfiguration; /** Default constructor */ public MetricCategoryRegistryImpl() {} @@ -49,6 +53,14 @@ public class MetricCategoryRegistryImpl implements MetricCategoryRegistry { metricCategories.put(metricCategory.getName().toUpperCase(Locale.ROOT), metricCategory); } + @Override + public boolean isMetricCategoryEnabled(final MetricCategory metricCategory) { + checkNotNull( + metricsConfiguration, "Metrics configuration must be set before calling this method"); + return (metricsConfiguration.isEnabled() || metricsConfiguration.isPushEnabled()) + && metricsConfiguration.getMetricCategories().contains(metricCategory); + } + /** * Return true if a category with that name is already registered * @@ -68,4 +80,14 @@ public class MetricCategoryRegistryImpl implements MetricCategoryRegistry { public MetricCategory getMetricCategory(final String name) { return metricCategories.get(name.toUpperCase(Locale.ROOT)); } + + /** + * Set the metric configuration via a method since it is still not available when creating this + * object + * + * @param metricsConfiguration the metrics configuration + */ + public void setMetricsConfiguration(final MetricsConfiguration metricsConfiguration) { + this.metricsConfiguration = metricsConfiguration; + } } diff --git a/metrics/core/src/test/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImplTest.java b/metrics/core/src/test/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImplTest.java new file mode 100644 index 0000000000..b2da02f480 --- /dev/null +++ b/metrics/core/src/test/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImplTest.java @@ -0,0 +1,66 @@ +/* + * Copyright contributors to Besu. + * + * 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.metrics; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; + +import java.util.Set; + +import org.junit.jupiter.api.Test; + +class MetricCategoryRegistryImplTest { + + @Test + void metricCategoryIsEnabledAndMetricsAreEnabled() { + final var registry = new MetricCategoryRegistryImpl(); + registry.addMetricCategory(BesuMetricCategory.BLOCKCHAIN); + final var metricsConfiguration = + MetricsConfiguration.builder() + .enabled(true) + .metricCategories(Set.of(BesuMetricCategory.BLOCKCHAIN)) + .build(); + registry.setMetricsConfiguration(metricsConfiguration); + assertTrue(registry.isMetricCategoryEnabled(BesuMetricCategory.BLOCKCHAIN)); + } + + @Test + void metricCategoryIsDisabledAndMetricsAreEnabled() { + final var registry = new MetricCategoryRegistryImpl(); + registry.addMetricCategory(BesuMetricCategory.ETHEREUM); + final var metricsConfiguration = + MetricsConfiguration.builder() + .enabled(true) + .metricCategories(Set.of(BesuMetricCategory.ETHEREUM)) + .build(); + registry.setMetricsConfiguration(metricsConfiguration); + assertFalse(registry.isMetricCategoryEnabled(BesuMetricCategory.BLOCKCHAIN)); + } + + @Test + void metricCategoryNotEnabledWhenMetricsAreDisabled() { + final var registry = new MetricCategoryRegistryImpl(); + registry.addMetricCategory(BesuMetricCategory.BLOCKCHAIN); + final var metricsConfiguration = + MetricsConfiguration.builder() + .enabled(false) + .metricCategories(Set.of(BesuMetricCategory.BLOCKCHAIN)) + .build(); + registry.setMetricsConfiguration(metricsConfiguration); + assertFalse(registry.isMetricCategoryEnabled(BesuMetricCategory.BLOCKCHAIN)); + } +} diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 3632bb5ae1..c7ec672867 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'uNQzVjMa7m1fw3d10NuVOjmzGxmCkgZd88yGFgP3qoY=' + knownHash = '8rPIE3fYl48RPRQXxYhMk559e/r+wHSKU9bGSJmruKQ=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/MetricCategoryRegistry.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/MetricCategoryRegistry.java index d6e460aa2f..1f84953460 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/MetricCategoryRegistry.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/MetricCategoryRegistry.java @@ -29,5 +29,13 @@ public interface MetricCategoryRegistry extends BesuService { * * @param newMetricCategory The {@link MetricCategory} that is being registered. */ - public void addMetricCategory(final MetricCategory newMetricCategory); + void addMetricCategory(final MetricCategory newMetricCategory); + + /** + * Return true if the metrics are enabled and the metric category is enabled + * + * @param metricCategory the metric category + * @return true if the metrics are enabled and the metric category is enabled + */ + boolean isMetricCategoryEnabled(final MetricCategory metricCategory); } From f9f721c10e839c0e6e72dedfc2295074a0c052a9 Mon Sep 17 00:00:00 2001 From: Ade Lucas <37906710+cloudspores@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:26:54 -0400 Subject: [PATCH 3/9] Issue 5589 trigger a timeout (#7469) * Make timeout feature use vertx timer. * Handle all errors resulting from timeout. * Ensure that after the timeout occurs, we properly handle the response and don't allow the execution to continue. --------- Signed-off-by: Ade Lucas Signed-off-by: cloudspores Co-authored-by: Ade Lucas Co-authored-by: Ade Lucas Co-authored-by: Justin Florentine --- .../api/handlers/AbstractJsonRpcExecutor.java | 1 + .../api/handlers/JsonRpcExecutorHandler.java | 44 ++++++- .../handlers/JsonRpcExecutorHandlerTest.java | 110 ++++++++++++++++++ 3 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandlerTest.java diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java index 95dc88f6a5..f73d162fa1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java @@ -106,6 +106,7 @@ public abstract class AbstractJsonRpcExecutor { private static HttpResponseStatus statusCodeFromError(final RpcErrorType error) { return switch (error) { case INVALID_REQUEST, PARSE_ERROR -> HttpResponseStatus.BAD_REQUEST; + case TIMEOUT_ERROR -> HttpResponseStatus.REQUEST_TIMEOUT; default -> HttpResponseStatus.OK; }; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java index 278a38c557..8386631695 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java @@ -34,6 +34,9 @@ import org.slf4j.LoggerFactory; public class JsonRpcExecutorHandler { private static final Logger LOG = LoggerFactory.getLogger(JsonRpcExecutorHandler.class); + // Default timeout for RPC calls in seconds + private static final long DEFAULT_TIMEOUT_MILLISECONDS = 30_000L; + private JsonRpcExecutorHandler() {} public static Handler handler( @@ -49,6 +52,19 @@ public class JsonRpcExecutorHandler { final Tracer tracer, final JsonRpcConfiguration jsonRpcConfiguration) { return ctx -> { + final long timerId = + ctx.vertx() + .setTimer( + DEFAULT_TIMEOUT_MILLISECONDS, + id -> { + final String method = + ctx.get(ContextKey.REQUEST_BODY_AS_JSON_OBJECT.name()).toString(); + LOG.error("Timeout occurred in JSON-RPC executor for method {}", method); + handleErrorAndEndResponse(ctx, null, RpcErrorType.TIMEOUT_ERROR); + }); + + ctx.put("timerId", timerId); + try { createExecutor(jsonRpcExecutor, tracer, ctx, jsonRpcConfiguration) .ifPresentOrElse( @@ -58,18 +74,38 @@ public class JsonRpcExecutorHandler { } catch (IOException e) { final String method = executor.getRpcMethodName(ctx); LOG.error("{} - Error streaming JSON-RPC response", method, e); - handleJsonRpcError(ctx, null, RpcErrorType.INTERNAL_ERROR); + handleErrorAndEndResponse(ctx, null, RpcErrorType.INTERNAL_ERROR); + } finally { + cancelTimer(ctx); } }, - () -> handleJsonRpcError(ctx, null, RpcErrorType.PARSE_ERROR)); + () -> { + handleErrorAndEndResponse(ctx, null, RpcErrorType.PARSE_ERROR); + cancelTimer(ctx); + }); } catch (final RuntimeException e) { - final String method = ctx.get(ContextKey.REQUEST_BODY_AS_JSON_OBJECT.name()); + final String method = ctx.get(ContextKey.REQUEST_BODY_AS_JSON_OBJECT.name()).toString(); LOG.error("Unhandled exception in JSON-RPC executor for method {}", method, e); - handleJsonRpcError(ctx, null, RpcErrorType.INTERNAL_ERROR); + handleErrorAndEndResponse(ctx, null, RpcErrorType.INTERNAL_ERROR); + cancelTimer(ctx); } }; } + private static void cancelTimer(final RoutingContext ctx) { + Long timerId = ctx.get("timerId"); + if (timerId != null) { + ctx.vertx().cancelTimer(timerId); + } + } + + private static void handleErrorAndEndResponse( + final RoutingContext ctx, final Object id, final RpcErrorType errorType) { + if (!ctx.response().ended()) { + handleJsonRpcError(ctx, id, errorType); + } + } + private static Optional createExecutor( final JsonRpcExecutor jsonRpcExecutor, final Tracer tracer, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandlerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandlerTest.java new file mode 100644 index 0000000000..ee00e433b2 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandlerTest.java @@ -0,0 +1,110 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.api.handlers; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; +import org.hyperledger.besu.ethereum.api.jsonrpc.context.ContextKey; +import org.hyperledger.besu.ethereum.api.jsonrpc.execution.JsonRpcExecutor; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.opentelemetry.api.trace.Tracer; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +class JsonRpcExecutorHandlerTest { + + private JsonRpcExecutor mockExecutor; + private Tracer mockTracer; + private JsonRpcConfiguration mockConfig; + private RoutingContext mockContext; + private Vertx mockVertx; + private HttpServerResponse mockResponse; + + @BeforeEach + void setUp() { + mockExecutor = mock(JsonRpcExecutor.class); + mockTracer = mock(Tracer.class); + mockConfig = mock(JsonRpcConfiguration.class); + mockContext = mock(RoutingContext.class); + mockVertx = mock(Vertx.class); + mockResponse = mock(HttpServerResponse.class); + + when(mockContext.vertx()).thenReturn(mockVertx); + when(mockContext.response()).thenReturn(mockResponse); + when(mockResponse.ended()).thenReturn(false); + when(mockResponse.setStatusCode(anyInt())).thenReturn(mockResponse); + } + + @Test + void testTimeoutHandling() { + // Arrange + Handler handler = + JsonRpcExecutorHandler.handler(mockExecutor, mockTracer, mockConfig); + ArgumentCaptor delayCaptor = ArgumentCaptor.forClass(Long.class); + @SuppressWarnings("unchecked") + ArgumentCaptor> timerHandlerCaptor = ArgumentCaptor.forClass(Handler.class); + + when(mockContext.get(eq(ContextKey.REQUEST_BODY_AS_JSON_OBJECT.name()))).thenReturn("{}"); + when(mockVertx.setTimer(delayCaptor.capture(), timerHandlerCaptor.capture())).thenReturn(1L); + when(mockContext.get("timerId")).thenReturn(1L); + + // Act + handler.handle(mockContext); + + // Assert + verify(mockVertx).setTimer(eq(30000L), any()); + + // Simulate timeout + timerHandlerCaptor.getValue().handle(1L); + + // Verify timeout handling + verify(mockResponse, times(1)) + .setStatusCode(eq(HttpResponseStatus.REQUEST_TIMEOUT.code())); // Expect 408 Request Timeout + verify(mockResponse, times(1)).end(contains("Timeout expired")); + verify(mockVertx, times(1)).cancelTimer(1L); + } + + @Test + void testCancelTimerOnSuccessfulExecution() { + // Arrange + Handler handler = + JsonRpcExecutorHandler.handler(mockExecutor, mockTracer, mockConfig); + when(mockContext.get(eq(ContextKey.REQUEST_BODY_AS_JSON_OBJECT.name()))).thenReturn("{}"); + when(mockVertx.setTimer(anyLong(), any())).thenReturn(1L); + when(mockContext.get("timerId")).thenReturn(1L); + + // Act + handler.handle(mockContext); + + // Assert + verify(mockVertx).setTimer(anyLong(), any()); + verify(mockVertx).cancelTimer(1L); + } +} From db29df7c8d686a3bcb13b16dc21a218cea87b247 Mon Sep 17 00:00:00 2001 From: Matilda-Clerke Date: Thu, 31 Oct 2024 09:29:46 +1100 Subject: [PATCH 4/9] 7311: add GetReceiptsFromPeerTask (#7638) Signed-off-by: Matilda Clerke --- .../controller/BesuControllerBuilder.java | 8 + .../TransitionBesuControllerBuilder.java | 3 + .../java/org/hyperledger/besu/RunnerTest.java | 30 +- .../jsonrpc/execution/JsonRpcExecutor.java | 4 +- .../eth/manager/EthProtocolManager.java | 1 - .../ethereum/eth/manager/EthScheduler.java | 15 +- .../eth/manager/peertask/PeerTask.java | 4 +- .../manager/peertask/PeerTaskExecutor.java | 2 +- .../task/GetReceiptsFromPeerTask.java | 135 +++++++++ .../eth/sync/DefaultSynchronizer.java | 5 + .../CheckpointDownloadBlockStep.java | 73 ++++- .../CheckpointDownloaderFactory.java | 4 + .../checkpointsync/CheckpointSyncActions.java | 4 + .../CheckpointSyncChainDownloader.java | 10 +- ...CheckpointSyncDownloadPipelineFactory.java | 14 +- .../sync/fastsync/DownloadReceiptsStep.java | 80 +++++- .../eth/sync/fastsync/FastSyncActions.java | 5 + .../fastsync/FastSyncChainDownloader.java | 10 +- .../FastSyncDownloadPipelineFactory.java | 7 +- .../worldstate/FastDownloaderFactory.java | 3 + .../sync/snapsync/SnapDownloaderFactory.java | 3 + .../peertask/PeerTaskExecutorTest.java | 12 +- .../task/GetReceiptsFromPeerTaskTest.java | 264 ++++++++++++++++++ .../CheckPointSyncChainDownloaderTest.java | 137 ++++++++- .../fastsync/DownloadReceiptsStepTest.java | 73 ++++- .../fastsync/FastDownloaderFactoryTest.java | 7 + .../sync/fastsync/FastSyncActionsTest.java | 2 + .../fastsync/FastSyncChainDownloaderTest.java | 2 + 28 files changed, 864 insertions(+), 53 deletions(-) create mode 100644 ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTask.java create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTaskTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java index a26bcb9811..6a4cc203a3 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/BesuControllerBuilder.java @@ -55,6 +55,8 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; import org.hyperledger.besu.ethereum.eth.manager.MonitoredExecutors; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskRequestSender; import org.hyperledger.besu.ethereum.eth.manager.snap.SnapProtocolManager; import org.hyperledger.besu.ethereum.eth.peervalidation.CheckpointBlocksPeerValidator; import org.hyperledger.besu.ethereum.eth.peervalidation.ClassicForkPeerValidator; @@ -653,6 +655,8 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides } final EthContext ethContext = new EthContext(ethPeers, ethMessages, snapMessages, scheduler); + final PeerTaskExecutor peerTaskExecutor = + new PeerTaskExecutor(ethPeers, new PeerTaskRequestSender(), metricsSystem); final boolean fullSyncDisabled = !SyncMode.isFullSync(syncConfig.getSyncMode()); final SyncState syncState = new SyncState(blockchain, ethPeers, fullSyncDisabled, checkpoint); @@ -704,6 +708,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides worldStateStorageCoordinator, protocolContext, ethContext, + peerTaskExecutor, syncState, ethProtocolManager, pivotBlockSelector); @@ -830,6 +835,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides * @param worldStateStorageCoordinator the world state storage * @param protocolContext the protocol context * @param ethContext the eth context + * @param peerTaskExecutor the PeerTaskExecutor * @param syncState the sync state * @param ethProtocolManager the eth protocol manager * @param pivotBlockSelector the pivot block selector @@ -840,6 +846,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final EthProtocolManager ethProtocolManager, final PivotBlockSelector pivotBlockSelector) { @@ -851,6 +858,7 @@ public abstract class BesuControllerBuilder implements MiningParameterOverrides worldStateStorageCoordinator, ethProtocolManager.getBlockBroadcaster(), ethContext, + peerTaskExecutor, syncState, dataDirectory, storageProvider, diff --git a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java index ee2611d9c8..703592f90a 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/TransitionBesuControllerBuilder.java @@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.MergePeerFilter; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.DefaultSynchronizer; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; @@ -225,6 +226,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { final WorldStateStorageCoordinator worldStateStorageCoordinator, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final EthProtocolManager ethProtocolManager, final PivotBlockSelector pivotBlockSelector) { @@ -235,6 +237,7 @@ public class TransitionBesuControllerBuilder extends BesuControllerBuilder { worldStateStorageCoordinator, protocolContext, ethContext, + peerTaskExecutor, syncState, ethProtocolManager, pivotBlockSelector); diff --git a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java index cbbf980408..6324fabb74 100644 --- a/besu/src/test/java/org/hyperledger/besu/RunnerTest.java +++ b/besu/src/test/java/org/hyperledger/besu/RunnerTest.java @@ -153,7 +153,15 @@ public final class RunnerTest { // set merge flag to false, otherwise this test can fail if a merge test runs first MergeConfiguration.setMergeEnabled(false); - syncFromGenesis(SyncMode.FULL, getFastSyncGenesis()); + syncFromGenesis(SyncMode.FULL, getFastSyncGenesis(), false); + } + + @Test + public void fullSyncFromGenesisUsingPeerTaskSystem() throws Exception { + // set merge flag to false, otherwise this test can fail if a merge test runs first + MergeConfiguration.setMergeEnabled(false); + + syncFromGenesis(SyncMode.FULL, getFastSyncGenesis(), true); } @Test @@ -161,10 +169,21 @@ public final class RunnerTest { // set merge flag to false, otherwise this test can fail if a merge test runs first MergeConfiguration.setMergeEnabled(false); - syncFromGenesis(SyncMode.FAST, getFastSyncGenesis()); + syncFromGenesis(SyncMode.FAST, getFastSyncGenesis(), false); + } + + @Test + public void fastSyncFromGenesisUsingPeerTaskSystem() throws Exception { + // set merge flag to false, otherwise this test can fail if a merge test runs first + MergeConfiguration.setMergeEnabled(false); + + syncFromGenesis(SyncMode.FAST, getFastSyncGenesis(), true); } - private void syncFromGenesis(final SyncMode mode, final GenesisConfigFile genesisConfig) + private void syncFromGenesis( + final SyncMode mode, + final GenesisConfigFile genesisConfig, + final boolean isPeerTaskSystemEnabled) throws Exception { final Path dataDirAhead = Files.createTempDirectory(temp, "db-ahead"); final Path dbAhead = dataDirAhead.resolve("database"); @@ -172,7 +191,10 @@ public final class RunnerTest { final NodeKey aheadDbNodeKey = NodeKeyUtils.createFrom(KeyPairUtil.loadKeyPair(dataDirAhead)); final NodeKey behindDbNodeKey = NodeKeyUtils.generate(); final SynchronizerConfiguration syncConfigAhead = - SynchronizerConfiguration.builder().syncMode(SyncMode.FULL).build(); + SynchronizerConfiguration.builder() + .syncMode(SyncMode.FULL) + .isPeerTaskSystemEnabled(isPeerTaskSystemEnabled) + .build(); final ObservableMetricsSystem noOpMetricsSystem = new NoOpMetricsSystem(); final var miningParameters = MiningParameters.newDefault(); final var dataStorageConfiguration = DataStorageConfiguration.DEFAULT_FOREST_CONFIG; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java index 6fedcc70ca..b8786eb7a5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/JsonRpcExecutor.java @@ -104,9 +104,9 @@ public class JsonRpcExecutor { private Optional validateMethodAvailability(final JsonRpcRequest request) { final String name = request.getMethod(); - if (LOG.isDebugEnabled()) { + if (LOG.isTraceEnabled()) { final JsonArray params = JsonObject.mapFrom(request).getJsonArray("params"); - LOG.debug("JSON-RPC request -> {} {}", name, params); + LOG.trace("JSON-RPC request -> {} {}", name, params); } final JsonRpcMethod method = rpcMethods.get(name); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java index 58318f9611..30cd03c15c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthProtocolManager.java @@ -337,7 +337,6 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { public void handleNewConnection(final PeerConnection connection) { ethPeers.registerNewConnection(connection, peerValidators); final EthPeer peer = ethPeers.peer(connection); - final Capability cap = connection.capability(getSupportedProtocol()); final ForkId latestForkId = cap.getVersion() >= 64 ? forkIdManager.getForkIdForChainHead() : null; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java index 1e2f3eb6ab..8c90993c68 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthScheduler.java @@ -145,7 +145,7 @@ public class EthScheduler { servicesExecutor.execute(command); } - public CompletableFuture scheduleServiceTask(final Runnable task) { + public CompletableFuture scheduleServiceTask(final Runnable task) { return CompletableFuture.runAsync(task, servicesExecutor); } @@ -156,6 +156,19 @@ public class EthScheduler { return serviceFuture; } + public CompletableFuture scheduleServiceTask(final Supplier> future) { + final CompletableFuture promise = new CompletableFuture<>(); + final Future workerFuture = servicesExecutor.submit(() -> propagateResult(future, promise)); + // If returned promise is cancelled, cancel the worker future + promise.whenComplete( + (r, t) -> { + if (t instanceof CancellationException) { + workerFuture.cancel(false); + } + }); + return promise; + } + public CompletableFuture startPipeline(final Pipeline pipeline) { final CompletableFuture pipelineFuture = pipeline.start(servicesExecutor); pendingFutures.add(pipelineFuture); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTask.java index 1243846ac3..fed671d38d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTask.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTask.java @@ -41,13 +41,13 @@ public interface PeerTask { MessageData getRequestMessage(); /** - * Parses the MessageData response from the EthPeer + * Parses and processes the MessageData response from the EthPeer * * @param messageData the response MessageData to be parsed * @return a T built from the response MessageData * @throws InvalidPeerTaskResponseException if the response messageData is invalid */ - T parseResponse(MessageData messageData) throws InvalidPeerTaskResponseException; + T processResponse(MessageData messageData) throws InvalidPeerTaskResponseException; /** * Gets the number of times this task may be attempted against other peers diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java index 984cedccec..a2ae045526 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutor.java @@ -133,7 +133,7 @@ public class PeerTaskExecutor { MessageData responseMessageData = requestSender.sendRequest(peerTask.getSubProtocol(), requestMessageData, peer); - result = peerTask.parseResponse(responseMessageData); + result = peerTask.processResponse(responseMessageData); } finally { inflightRequestCountForThisTaskClass.decrementAndGet(); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTask.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTask.java new file mode 100644 index 0000000000..7d4b5d585e --- /dev/null +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTask.java @@ -0,0 +1,135 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.eth.manager.peertask.task; + +import static java.util.Collections.emptyList; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.eth.EthProtocol; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.InvalidPeerTaskResponseException; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTask; +import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage; +import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class GetReceiptsFromPeerTask + implements PeerTask>> { + + private final Collection blockHeaders; + private final ProtocolSchedule protocolSchedule; + private final Map> receiptsByBlockHeader = new HashMap<>(); + private final Map> headersByReceiptsRoot = new HashMap<>(); + private final long requiredBlockchainHeight; + + public GetReceiptsFromPeerTask( + final Collection blockHeaders, final ProtocolSchedule protocolSchedule) { + this.blockHeaders = new ArrayList<>(blockHeaders); + this.protocolSchedule = protocolSchedule; + + // pre-fill any headers with an empty receipts root into the result map + this.blockHeaders.stream() + .filter(header -> header.getReceiptsRoot().equals(Hash.EMPTY_TRIE_HASH)) + .forEach(header -> receiptsByBlockHeader.put(header, emptyList())); + this.blockHeaders.removeAll(receiptsByBlockHeader.keySet()); + + // group headers by their receipts root hash to reduce total number of receipts hashes requested + // for + this.blockHeaders.forEach( + header -> + headersByReceiptsRoot + .computeIfAbsent(header.getReceiptsRoot(), key -> new ArrayList<>()) + .add(header)); + + // calculate the minimum required blockchain height a peer will need to be able to fulfil this + // request + requiredBlockchainHeight = + this.blockHeaders.stream() + .mapToLong(BlockHeader::getNumber) + .max() + .orElse(BlockHeader.GENESIS_BLOCK_NUMBER); + } + + @Override + public SubProtocol getSubProtocol() { + return EthProtocol.get(); + } + + @Override + public MessageData getRequestMessage() { + // Since we have to match up the data by receipt root, we only need to request receipts + // for one of the headers with each unique receipt root. + final List blockHashes = + headersByReceiptsRoot.values().stream() + .map(headers -> headers.getFirst().getHash()) + .toList(); + return GetReceiptsMessage.create(blockHashes); + } + + @Override + public Map> processResponse(final MessageData messageData) + throws InvalidPeerTaskResponseException { + if (messageData == null) { + throw new InvalidPeerTaskResponseException(); + } + final ReceiptsMessage receiptsMessage = ReceiptsMessage.readFrom(messageData); + final List> receiptsByBlock = receiptsMessage.receipts(); + // take a copy of the pre-filled receiptsByBlockHeader, to ensure idempotency of subsequent + // calls to processResponse + final Map> receiptsByHeader = + new HashMap<>(receiptsByBlockHeader); + if (!blockHeaders.isEmpty()) { + if (receiptsByBlock.isEmpty() || receiptsByBlock.size() > blockHeaders.size()) { + throw new InvalidPeerTaskResponseException(); + } + + for (final List receiptsInBlock : receiptsByBlock) { + final List blockHeaders = + headersByReceiptsRoot.get(BodyValidation.receiptsRoot(receiptsInBlock)); + if (blockHeaders == null) { + // Contains receipts that we didn't request, so mustn't be the response we're looking for. + throw new InvalidPeerTaskResponseException(); + } + blockHeaders.forEach(header -> receiptsByHeader.put(header, receiptsInBlock)); + } + } + return receiptsByHeader; + } + + @Override + public Predicate getPeerRequirementFilter() { + return (ethPeer) -> + ethPeer.getProtocolName().equals(getSubProtocol().getName()) + && (protocolSchedule.anyMatch((ps) -> ps.spec().isPoS()) + || ethPeer.chainState().getEstimatedHeight() >= requiredBlockchainHeight); + } + + @Override + public boolean isSuccess(final Map> result) { + return !result.isEmpty(); + } +} diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java index 2384437299..66684ab787 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/DefaultSynchronizer.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.checkpointsync.CheckpointDownloaderFactory; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncDownloader; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; @@ -82,6 +83,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi final WorldStateStorageCoordinator worldStateStorageCoordinator, final BlockBroadcaster blockBroadcaster, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final Path dataDirectory, final StorageProvider storageProvider, @@ -147,6 +149,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, @@ -163,6 +166,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, @@ -179,6 +183,7 @@ public class DefaultSynchronizer implements Synchronizer, UnverifiedForkchoiceLi protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloadBlockStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloadBlockStep.java index b4bdf58541..72f1fae764 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloadBlockStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloadBlockStep.java @@ -16,17 +16,23 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask; import org.hyperledger.besu.ethereum.eth.manager.task.AbstractPeerTask.PeerTaskResult; import org.hyperledger.besu.ethereum.eth.manager.task.GetBlockFromPeerTask; -import org.hyperledger.besu.ethereum.eth.manager.task.GetReceiptsFromPeerTask; +import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.fastsync.checkpoint.Checkpoint; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.plugin.services.MetricsSystem; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -34,17 +40,23 @@ public class CheckpointDownloadBlockStep { private final ProtocolSchedule protocolSchedule; private final EthContext ethContext; + private final PeerTaskExecutor peerTaskExecutor; private final Checkpoint checkpoint; + private final SynchronizerConfiguration synchronizerConfiguration; private final MetricsSystem metricsSystem; public CheckpointDownloadBlockStep( final ProtocolSchedule protocolSchedule, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final Checkpoint checkpoint, + final SynchronizerConfiguration synchronizerConfiguration, final MetricsSystem metricsSystem) { this.protocolSchedule = protocolSchedule; this.ethContext = ethContext; + this.peerTaskExecutor = peerTaskExecutor; this.checkpoint = checkpoint; + this.synchronizerConfiguration = synchronizerConfiguration; this.metricsSystem = metricsSystem; } @@ -65,17 +77,52 @@ public class CheckpointDownloadBlockStep { private CompletableFuture> downloadReceipts( final PeerTaskResult peerTaskResult) { final Block block = peerTaskResult.getResult(); - final GetReceiptsFromPeerTask getReceiptsFromPeerTask = - GetReceiptsFromPeerTask.forHeaders(ethContext, List.of(block.getHeader()), metricsSystem); - return getReceiptsFromPeerTask - .run() - .thenCompose( - receiptTaskResult -> { - final Optional> transactionReceipts = - Optional.ofNullable(receiptTaskResult.getResult().get(block.getHeader())); - return CompletableFuture.completedFuture( - transactionReceipts.map(receipts -> new BlockWithReceipts(block, receipts))); - }) - .exceptionally(throwable -> Optional.empty()); + if (synchronizerConfiguration.isPeerTaskSystemEnabled()) { + return ethContext + .getScheduler() + .scheduleServiceTask( + () -> { + GetReceiptsFromPeerTask task = + new GetReceiptsFromPeerTask(List.of(block.getHeader()), protocolSchedule); + PeerTaskExecutorResult>> executorResult = + peerTaskExecutor.execute(task); + + if (executorResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS) { + List transactionReceipts = + executorResult + .result() + .map((map) -> map.get(block.getHeader())) + .orElseThrow( + () -> + new IllegalStateException( + "PeerTask response code was success, but empty")); + if (block.getBody().getTransactions().size() != transactionReceipts.size()) { + throw new IllegalStateException( + "PeerTask response code was success, but incorrect number of receipts returned"); + } + BlockWithReceipts blockWithReceipts = + new BlockWithReceipts(block, transactionReceipts); + return CompletableFuture.completedFuture(Optional.of(blockWithReceipts)); + } else { + return CompletableFuture.completedFuture(Optional.empty()); + } + }); + + } else { + final org.hyperledger.besu.ethereum.eth.manager.task.GetReceiptsFromPeerTask + getReceiptsFromPeerTask = + org.hyperledger.besu.ethereum.eth.manager.task.GetReceiptsFromPeerTask.forHeaders( + ethContext, List.of(block.getHeader()), metricsSystem); + return getReceiptsFromPeerTask + .run() + .thenCompose( + receiptTaskResult -> { + final Optional> transactionReceipts = + Optional.ofNullable(receiptTaskResult.getResult().get(block.getHeader())); + return CompletableFuture.completedFuture( + transactionReceipts.map(receipts -> new BlockWithReceipts(block, receipts))); + }) + .exceptionally(throwable -> Optional.empty()); + } } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java index 03df47e440..30134d9f6c 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointDownloaderFactory.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -61,6 +62,7 @@ public class CheckpointDownloaderFactory extends SnapDownloaderFactory { final ProtocolContext protocolContext, final MetricsSystem metricsSystem, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final WorldStateStorageCoordinator worldStateStorageCoordinator, final SyncState syncState, final Clock clock, @@ -110,6 +112,7 @@ public class CheckpointDownloaderFactory extends SnapDownloaderFactory { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, pivotBlockSelector, metricsSystem); @@ -127,6 +130,7 @@ public class CheckpointDownloaderFactory extends SnapDownloaderFactory { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, pivotBlockSelector, metricsSystem); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java index 5096b74e24..61b997e6c5 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncActions.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -34,6 +35,7 @@ public class CheckpointSyncActions extends FastSyncActions { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final PivotBlockSelector pivotBlockSelector, final MetricsSystem metricsSystem) { @@ -43,6 +45,7 @@ public class CheckpointSyncActions extends FastSyncActions { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, pivotBlockSelector, metricsSystem); @@ -57,6 +60,7 @@ public class CheckpointSyncActions extends FastSyncActions { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, metricsSystem, currentState, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java index 5450b9e5a4..2590e4736a 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncChainDownloader.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.checkpointsync; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -36,6 +37,7 @@ public class CheckpointSyncChainDownloader extends FastSyncChainDownloader { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final MetricsSystem metricsSystem, final FastSyncState fastSyncState, @@ -55,7 +57,13 @@ public class CheckpointSyncChainDownloader extends FastSyncChainDownloader { syncState, syncTargetManager, new CheckpointSyncDownloadPipelineFactory( - config, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem), + config, + protocolSchedule, + protocolContext, + ethContext, + peerTaskExecutor, + fastSyncState, + metricsSystem), ethContext.getScheduler(), metricsSystem, syncDurationMetrics); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncDownloadPipelineFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncDownloadPipelineFactory.java index 45f3f243d8..0be1086986 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncDownloadPipelineFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckpointSyncDownloadPipelineFactory.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncDownloadPipelineFactory; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; @@ -40,9 +41,17 @@ public class CheckpointSyncDownloadPipelineFactory extends FastSyncDownloadPipel final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final FastSyncState fastSyncState, final MetricsSystem metricsSystem) { - super(syncConfig, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem); + super( + syncConfig, + protocolSchedule, + protocolContext, + ethContext, + peerTaskExecutor, + fastSyncState, + metricsSystem); } @Override @@ -76,7 +85,8 @@ public class CheckpointSyncDownloadPipelineFactory extends FastSyncDownloadPipel checkPointSource, checkpoint, protocolContext.getBlockchain()); final CheckpointDownloadBlockStep checkPointDownloadBlockStep = - new CheckpointDownloadBlockStep(protocolSchedule, ethContext, checkpoint, metricsSystem); + new CheckpointDownloadBlockStep( + protocolSchedule, ethContext, peerTaskExecutor, checkpoint, syncConfig, metricsSystem); return PipelineBuilder.createPipelineFrom( "fetchCheckpoints", diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java index cd57de371d..876e96d107 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java @@ -22,10 +22,16 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask; +import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.tasks.GetReceiptsForHeadersTask; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.util.FutureUtils; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -33,24 +39,69 @@ import java.util.function.Function; public class DownloadReceiptsStep implements Function, CompletableFuture>> { + + private final ProtocolSchedule protocolSchedule; private final EthContext ethContext; + private final PeerTaskExecutor peerTaskExecutor; + private final SynchronizerConfiguration synchronizerConfiguration; private final MetricsSystem metricsSystem; - public DownloadReceiptsStep(final EthContext ethContext, final MetricsSystem metricsSystem) { + public DownloadReceiptsStep( + final ProtocolSchedule protocolSchedule, + final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, + final SynchronizerConfiguration synchronizerConfiguration, + final MetricsSystem metricsSystem) { + this.protocolSchedule = protocolSchedule; this.ethContext = ethContext; + this.peerTaskExecutor = peerTaskExecutor; + this.synchronizerConfiguration = synchronizerConfiguration; this.metricsSystem = metricsSystem; } @Override public CompletableFuture> apply(final List blocks) { final List headers = blocks.stream().map(Block::getHeader).collect(toList()); - final CompletableFuture>> getReceipts = - GetReceiptsForHeadersTask.forHeaders(ethContext, headers, metricsSystem).run(); - final CompletableFuture> combineWithBlocks = - getReceipts.thenApply( - receiptsByHeader -> combineBlocksAndReceipts(blocks, receiptsByHeader)); - FutureUtils.propagateCancellation(combineWithBlocks, getReceipts); - return combineWithBlocks; + if (synchronizerConfiguration.isPeerTaskSystemEnabled()) { + return ethContext + .getScheduler() + .scheduleServiceTask(() -> getReceiptsWithPeerTaskSystem(headers)) + .thenApply((receipts) -> combineBlocksAndReceipts(blocks, receipts)); + + } else { + return GetReceiptsForHeadersTask.forHeaders(ethContext, headers, metricsSystem) + .run() + .thenApply((receipts) -> combineBlocksAndReceipts(blocks, receipts)); + } + } + + private CompletableFuture>> + getReceiptsWithPeerTaskSystem(final List headers) { + Map> getReceipts = new HashMap<>(); + do { + GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(headers, protocolSchedule); + PeerTaskExecutorResult>> getReceiptsResult = + peerTaskExecutor.execute(task); + if (getReceiptsResult.responseCode() == PeerTaskExecutorResponseCode.SUCCESS + && getReceiptsResult.result().isPresent()) { + Map> taskResult = getReceiptsResult.result().get(); + taskResult + .keySet() + .forEach( + (blockHeader) -> + getReceipts.merge( + blockHeader, + taskResult.get(blockHeader), + (initialReceipts, newReceipts) -> { + throw new IllegalStateException( + "Unexpectedly got receipts for block header already populated!"); + })); + // remove all the headers we found receipts for + headers.removeAll(getReceipts.keySet()); + } + // repeat until all headers have receipts + } while (!headers.isEmpty()); + return CompletableFuture.completedFuture(getReceipts); } private List combineBlocksAndReceipts( @@ -60,8 +111,17 @@ public class DownloadReceiptsStep block -> { final List receipts = receiptsByHeader.getOrDefault(block.getHeader(), emptyList()); + if (block.getBody().getTransactions().size() != receipts.size()) { + throw new IllegalStateException( + "PeerTask response code was success, but incorrect number of receipts returned. Header hash: " + + block.getHeader().getHash() + + ", Transactions: " + + block.getBody().getTransactions().size() + + ", receipts: " + + receipts.size()); + } return new BlockWithReceipts(block, receipts); }) - .collect(toList()); + .toList(); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java index 7f6bbae3f3..58a64bd562 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActions.java @@ -19,6 +19,7 @@ import static java.util.concurrent.CompletableFuture.completedFuture; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.manager.task.WaitForPeersTask; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; @@ -48,6 +49,7 @@ public class FastSyncActions { protected final ProtocolSchedule protocolSchedule; protected final ProtocolContext protocolContext; protected final EthContext ethContext; + protected final PeerTaskExecutor peerTaskExecutor; protected final SyncState syncState; protected final PivotBlockSelector pivotBlockSelector; protected final MetricsSystem metricsSystem; @@ -60,6 +62,7 @@ public class FastSyncActions { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final PivotBlockSelector pivotBlockSelector, final MetricsSystem metricsSystem) { @@ -68,6 +71,7 @@ public class FastSyncActions { this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; this.ethContext = ethContext; + this.peerTaskExecutor = peerTaskExecutor; this.syncState = syncState; this.pivotBlockSelector = pivotBlockSelector; this.metricsSystem = metricsSystem; @@ -164,6 +168,7 @@ public class FastSyncActions { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, metricsSystem, currentState, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java index c36ff7cb48..1bf55a3811 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloader.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.PipelineChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -35,6 +36,7 @@ public class FastSyncChainDownloader { final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final SyncState syncState, final MetricsSystem metricsSystem, final FastSyncState fastSyncState, @@ -53,7 +55,13 @@ public class FastSyncChainDownloader { syncState, syncTargetManager, new FastSyncDownloadPipelineFactory( - config, protocolSchedule, protocolContext, ethContext, fastSyncState, metricsSystem), + config, + protocolSchedule, + protocolContext, + ethContext, + peerTaskExecutor, + fastSyncState, + metricsSystem), ethContext.getScheduler(), metricsSystem, syncDurationMetrics); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java index 87032b76e5..ac56260887 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncDownloadPipelineFactory.java @@ -26,6 +26,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.DownloadBodiesStep; import org.hyperledger.besu.ethereum.eth.sync.DownloadHeadersStep; import org.hyperledger.besu.ethereum.eth.sync.DownloadPipelineFactory; @@ -58,6 +59,7 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory protected final ProtocolSchedule protocolSchedule; protected final ProtocolContext protocolContext; protected final EthContext ethContext; + protected final PeerTaskExecutor peerTaskExecutor; protected final FastSyncState fastSyncState; protected final MetricsSystem metricsSystem; protected final FastSyncValidationPolicy attachedValidationPolicy; @@ -69,12 +71,14 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final FastSyncState fastSyncState, final MetricsSystem metricsSystem) { this.syncConfig = syncConfig; this.protocolSchedule = protocolSchedule; this.protocolContext = protocolContext; this.ethContext = ethContext; + this.peerTaskExecutor = peerTaskExecutor; this.fastSyncState = fastSyncState; this.metricsSystem = metricsSystem; final LabelledMetric fastSyncValidationCounter = @@ -145,7 +149,8 @@ public class FastSyncDownloadPipelineFactory implements DownloadPipelineFactory final DownloadBodiesStep downloadBodiesStep = new DownloadBodiesStep(protocolSchedule, ethContext, metricsSystem); final DownloadReceiptsStep downloadReceiptsStep = - new DownloadReceiptsStep(ethContext, metricsSystem); + new DownloadReceiptsStep( + protocolSchedule, ethContext, peerTaskExecutor, syncConfig, metricsSystem); final ImportBlocksStep importBlockStep = new ImportBlocksStep( protocolSchedule, diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java index 8b71a57885..1d775cc80f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/worldstate/FastDownloaderFactory.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.fastsync.worldstate; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -59,6 +60,7 @@ public class FastDownloaderFactory { final ProtocolContext protocolContext, final MetricsSystem metricsSystem, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final WorldStateStorageCoordinator worldStateStorageCoordinator, final SyncState syncState, final Clock clock, @@ -126,6 +128,7 @@ public class FastDownloaderFactory { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, pivotBlockSelector, metricsSystem), diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java index 5de8ceb984..6c5ce0b04e 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/SnapDownloaderFactory.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -57,6 +58,7 @@ public class SnapDownloaderFactory extends FastDownloaderFactory { final ProtocolContext protocolContext, final MetricsSystem metricsSystem, final EthContext ethContext, + final PeerTaskExecutor peerTaskExecutor, final WorldStateStorageCoordinator worldStateStorageCoordinator, final SyncState syncState, final Clock clock, @@ -121,6 +123,7 @@ public class SnapDownloaderFactory extends FastDownloaderFactory { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, pivotBlockSelector, metricsSystem), diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutorTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutorTest.java index 0262e276da..9639de154d 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutorTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/PeerTaskExecutorTest.java @@ -72,7 +72,7 @@ public class PeerTaskExecutorTest { Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) .thenReturn(responseMessageData); - Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); + Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); PeerTaskExecutorResult result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); @@ -101,7 +101,7 @@ public class PeerTaskExecutorTest { Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) .thenReturn(responseMessageData); - Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); + Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(false); PeerTaskExecutorResult result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); @@ -130,7 +130,7 @@ public class PeerTaskExecutorTest { .thenThrow(new TimeoutException()) .thenReturn(responseMessageData); Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode); - Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); + Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); PeerTaskExecutorResult result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); @@ -204,7 +204,7 @@ public class PeerTaskExecutorTest { Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) .thenReturn(responseMessageData); - Mockito.when(peerTask.parseResponse(responseMessageData)) + Mockito.when(peerTask.processResponse(responseMessageData)) .thenThrow(new InvalidPeerTaskResponseException()); PeerTaskExecutorResult result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); @@ -236,7 +236,7 @@ public class PeerTaskExecutorTest { Mockito.when(subprotocol.getName()).thenReturn("subprotocol"); Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, ethPeer)) .thenReturn(responseMessageData); - Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); + Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); PeerTaskExecutorResult result = peerTaskExecutor.executeAgainstPeer(peerTask, ethPeer); @@ -274,7 +274,7 @@ public class PeerTaskExecutorTest { Mockito.when(requestMessageData.getCode()).thenReturn(requestMessageDataCode); Mockito.when(requestSender.sendRequest(subprotocol, requestMessageData, peer2)) .thenReturn(responseMessageData); - Mockito.when(peerTask.parseResponse(responseMessageData)).thenReturn(responseObject); + Mockito.when(peerTask.processResponse(responseMessageData)).thenReturn(responseObject); Mockito.when(peerTask.isSuccess(responseObject)).thenReturn(true); PeerTaskExecutorResult result = peerTaskExecutor.execute(peerTask); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTaskTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTaskTest.java new file mode 100644 index 0000000000..90e6f738fc --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/manager/peertask/task/GetReceiptsFromPeerTaskTest.java @@ -0,0 +1,264 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.eth.manager.peertask.task; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.eth.EthProtocol; +import org.hyperledger.besu.ethereum.eth.manager.ChainState; +import org.hyperledger.besu.ethereum.eth.manager.EthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.InvalidPeerTaskResponseException; +import org.hyperledger.besu.ethereum.eth.messages.EthPV63; +import org.hyperledger.besu.ethereum.eth.messages.GetReceiptsMessage; +import org.hyperledger.besu.ethereum.eth.messages.ReceiptsMessage; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +public class GetReceiptsFromPeerTaskTest { + + @Test + public void testGetSubProtocol() { + GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null); + Assertions.assertEquals(EthProtocol.get(), task.getSubProtocol()); + } + + @Test + public void testGetRequestMessage() { + BlockHeader blockHeader1 = mockBlockHeader(1); + TransactionReceipt receiptForBlock1 = + new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader1.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1))); + + BlockHeader blockHeader2 = mockBlockHeader(2); + TransactionReceipt receiptForBlock2 = + new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader2.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2))); + + BlockHeader blockHeader3 = mockBlockHeader(3); + TransactionReceipt receiptForBlock3 = + new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader3.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3))); + + GetReceiptsFromPeerTask task = + new GetReceiptsFromPeerTask(List.of(blockHeader1, blockHeader2, blockHeader3), null); + + MessageData messageData = task.getRequestMessage(); + GetReceiptsMessage getReceiptsMessage = GetReceiptsMessage.readFrom(messageData); + + Assertions.assertEquals(EthPV63.GET_RECEIPTS, getReceiptsMessage.getCode()); + Iterable hashesInMessage = getReceiptsMessage.hashes(); + List expectedHashes = + List.of( + Hash.fromHexString(StringUtils.repeat("00", 31) + "11"), + Hash.fromHexString(StringUtils.repeat("00", 31) + "21"), + Hash.fromHexString(StringUtils.repeat("00", 31) + "31")); + List actualHashes = new ArrayList<>(); + hashesInMessage.forEach(actualHashes::add); + + Assertions.assertEquals(3, actualHashes.size()); + Assertions.assertEquals( + expectedHashes.stream().sorted().toList(), actualHashes.stream().sorted().toList()); + } + + @Test + public void testParseResponseWithNullResponseMessage() { + GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null); + Assertions.assertThrows( + InvalidPeerTaskResponseException.class, () -> task.processResponse(null)); + } + + @Test + public void testParseResponseForInvalidResponse() { + BlockHeader blockHeader1 = mockBlockHeader(1); + TransactionReceipt receiptForBlock1 = + new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader1.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1))); + + BlockHeader blockHeader2 = mockBlockHeader(2); + TransactionReceipt receiptForBlock2 = + new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader2.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2))); + + BlockHeader blockHeader3 = mockBlockHeader(3); + TransactionReceipt receiptForBlock3 = + new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader3.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3))); + GetReceiptsFromPeerTask task = + new GetReceiptsFromPeerTask(List.of(blockHeader1, blockHeader2, blockHeader3), null); + ReceiptsMessage receiptsMessage = + ReceiptsMessage.create( + List.of( + List.of(receiptForBlock1), + List.of(receiptForBlock2), + List.of(receiptForBlock3), + List.of( + new TransactionReceipt(1, 101112, Collections.emptyList(), Optional.empty())))); + + Assertions.assertThrows( + InvalidPeerTaskResponseException.class, () -> task.processResponse(receiptsMessage)); + } + + @Test + public void testParseResponse() throws InvalidPeerTaskResponseException { + BlockHeader blockHeader1 = mockBlockHeader(1); + TransactionReceipt receiptForBlock1 = + new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader1.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1))); + + BlockHeader blockHeader2 = mockBlockHeader(2); + TransactionReceipt receiptForBlock2 = + new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader2.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2))); + + BlockHeader blockHeader3 = mockBlockHeader(3); + TransactionReceipt receiptForBlock3 = + new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader3.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3))); + + BlockHeader blockHeader4 = mockBlockHeader(4); + Mockito.when(blockHeader4.getReceiptsRoot()).thenReturn(Hash.EMPTY_TRIE_HASH); + + GetReceiptsFromPeerTask task = + new GetReceiptsFromPeerTask( + List.of(blockHeader1, blockHeader2, blockHeader3, blockHeader4), null); + + ReceiptsMessage receiptsMessage = + ReceiptsMessage.create( + List.of( + List.of(receiptForBlock1), List.of(receiptForBlock2), List.of(receiptForBlock3))); + + Map> resultMap = task.processResponse(receiptsMessage); + + Assertions.assertEquals(4, resultMap.size()); + Assertions.assertEquals(Collections.emptyList(), resultMap.get(blockHeader4)); + Assertions.assertEquals(List.of(receiptForBlock1), resultMap.get(blockHeader1)); + Assertions.assertEquals(List.of(receiptForBlock2), resultMap.get(blockHeader2)); + Assertions.assertEquals(List.of(receiptForBlock3), resultMap.get(blockHeader3)); + } + + @Test + public void testParseResponseForOnlyPrefilledEmptyTrieReceiptsRoots() + throws InvalidPeerTaskResponseException { + BlockHeader blockHeader1 = mockBlockHeader(1); + Mockito.when(blockHeader1.getReceiptsRoot()).thenReturn(Hash.EMPTY_TRIE_HASH); + + GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(List.of(blockHeader1), null); + + ReceiptsMessage receiptsMessage = ReceiptsMessage.create(Collections.emptyList()); + + Map> resultMap = task.processResponse(receiptsMessage); + + Assertions.assertEquals(1, resultMap.size()); + Assertions.assertEquals(Collections.emptyList(), resultMap.get(blockHeader1)); + } + + @Test + public void testGetPeerRequirementFilter() { + BlockHeader blockHeader1 = mockBlockHeader(1); + TransactionReceipt receiptForBlock1 = + new TransactionReceipt(1, 123, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader1.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock1))); + + BlockHeader blockHeader2 = mockBlockHeader(2); + TransactionReceipt receiptForBlock2 = + new TransactionReceipt(1, 456, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader2.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock2))); + + BlockHeader blockHeader3 = mockBlockHeader(3); + TransactionReceipt receiptForBlock3 = + new TransactionReceipt(1, 789, Collections.emptyList(), Optional.empty()); + Mockito.when(blockHeader3.getReceiptsRoot()) + .thenReturn(BodyValidation.receiptsRoot(List.of(receiptForBlock3))); + + ProtocolSchedule protocolSchedule = Mockito.mock(ProtocolSchedule.class); + Mockito.when(protocolSchedule.anyMatch(Mockito.any())).thenReturn(false); + + GetReceiptsFromPeerTask task = + new GetReceiptsFromPeerTask( + List.of(blockHeader1, blockHeader2, blockHeader3), protocolSchedule); + + EthPeer failForIncorrectProtocol = mockPeer("incorrectProtocol", 5); + EthPeer failForShortChainHeight = mockPeer("incorrectProtocol", 1); + EthPeer successfulCandidate = mockPeer(EthProtocol.NAME, 5); + + Assertions.assertFalse(task.getPeerRequirementFilter().test(failForIncorrectProtocol)); + Assertions.assertFalse(task.getPeerRequirementFilter().test(failForShortChainHeight)); + Assertions.assertTrue(task.getPeerRequirementFilter().test(successfulCandidate)); + } + + @Test + public void testIsSuccessForPartialSuccess() { + GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null); + + Assertions.assertFalse(task.isSuccess(Collections.emptyMap())); + } + + @Test + public void testIsSuccessForFullSuccess() { + GetReceiptsFromPeerTask task = new GetReceiptsFromPeerTask(Collections.emptyList(), null); + + Map> map = new HashMap<>(); + map.put(mockBlockHeader(1), null); + + Assertions.assertTrue(task.isSuccess(map)); + } + + private BlockHeader mockBlockHeader(final long blockNumber) { + BlockHeader blockHeader = Mockito.mock(BlockHeader.class); + Mockito.when(blockHeader.getNumber()).thenReturn(blockNumber); + // second to last hex digit indicates the blockNumber, last hex digit indicates the usage of the + // hash + Mockito.when(blockHeader.getHash()) + .thenReturn(Hash.fromHexString(StringUtils.repeat("00", 31) + blockNumber + "1")); + + return blockHeader; + } + + private EthPeer mockPeer(final String protocol, final long chainHeight) { + EthPeer ethPeer = Mockito.mock(EthPeer.class); + ChainState chainState = Mockito.mock(ChainState.class); + + Mockito.when(ethPeer.getProtocolName()).thenReturn(protocol); + Mockito.when(ethPeer.chainState()).thenReturn(chainState); + Mockito.when(chainState.getEstimatedHeight()).thenReturn(chainHeight); + + return ethPeer; + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java index 43f03100a7..56e0461f70 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/checkpointsync/CheckPointSyncChainDownloaderTest.java @@ -22,13 +22,19 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.sync.fastsync.FastSyncState; @@ -44,8 +50,15 @@ import org.hyperledger.besu.metrics.SyncDurationMetrics; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; import java.util.stream.Stream; import org.junit.jupiter.api.AfterEach; @@ -55,12 +68,16 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.platform.commons.util.ReflectionUtils; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; public class CheckPointSyncChainDownloaderTest { protected ProtocolSchedule protocolSchedule; protected EthProtocolManager ethProtocolManager; protected EthContext ethContext; + private PeerTaskExecutor peerTaskExecutor; protected ProtocolContext protocolContext; private SyncState syncState; @@ -100,6 +117,7 @@ public class CheckPointSyncChainDownloaderTest { localBlockchain = localBlockchainSetup.getBlockchain(); otherBlockchainSetup = BlockchainSetupUtil.forTesting(dataStorageFormat); otherBlockchain = otherBlockchainSetup.getBlockchain(); + otherBlockchainSetup.importFirstBlocks(30); protocolSchedule = localBlockchainSetup.getProtocolSchedule(); protocolContext = localBlockchainSetup.getProtocolContext(); ethProtocolManager = @@ -123,6 +141,41 @@ public class CheckPointSyncChainDownloaderTest { ethContext.getEthPeers(), true, Optional.of(checkpoint)); + + peerTaskExecutor = mock(PeerTaskExecutor.class); + + when(peerTaskExecutor.execute(any(GetReceiptsFromPeerTask.class))) + .thenAnswer( + new Answer>>>() { + @Override + public PeerTaskExecutorResult>> answer( + final InvocationOnMock invocationOnMock) throws Throwable { + GetReceiptsFromPeerTask task = + invocationOnMock.getArgument(0, GetReceiptsFromPeerTask.class); + + return processTask(task); + } + }); + } + + @SuppressWarnings("unchecked") + private PeerTaskExecutorResult>> processTask( + final GetReceiptsFromPeerTask task) throws IllegalAccessException { + Map> getReceiptsFromPeerTaskResult = new HashMap<>(); + List fields = + ReflectionUtils.findFields( + task.getClass(), + (field) -> field.getName().equals("blockHeaders"), + ReflectionUtils.HierarchyTraversalMode.TOP_DOWN); + fields.forEach((f) -> f.setAccessible(true)); + Collection blockHeaders = (Collection) fields.getFirst().get(task); + blockHeaders.forEach( + (bh) -> + getReceiptsFromPeerTaskResult.put( + bh, otherBlockchain.getTxReceipts(bh.getHash()).get())); + + return new PeerTaskExecutorResult<>( + Optional.of(getReceiptsFromPeerTaskResult), PeerTaskExecutorResponseCode.SUCCESS); } @AfterEach @@ -140,6 +193,7 @@ public class CheckPointSyncChainDownloaderTest { protocolSchedule, protocolContext, ethContext, + peerTaskExecutor, syncState, new NoOpMetricsSystem(), new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get()), @@ -148,9 +202,9 @@ public class CheckPointSyncChainDownloaderTest { @ParameterizedTest @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) - public void shouldSyncToPivotBlockInMultipleSegments(final DataStorageFormat storageFormat) { + public void shouldSyncToPivotBlockInMultipleSegments(final DataStorageFormat storageFormat) + throws IllegalAccessException { setup(storageFormat); - otherBlockchainSetup.importFirstBlocks(30); final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); @@ -161,6 +215,7 @@ public class CheckPointSyncChainDownloaderTest { SynchronizerConfiguration.builder() .downloaderChainSegmentSize(5) .downloaderHeadersRequestSize(3) + .isPeerTaskSystemEnabled(false) .build(); final long pivotBlockNumber = 25; ethContext @@ -184,9 +239,9 @@ public class CheckPointSyncChainDownloaderTest { @ParameterizedTest @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) - public void shouldSyncToPivotBlockInSingleSegment(final DataStorageFormat storageFormat) { + public void shouldSyncToPivotBlockInSingleSegment(final DataStorageFormat storageFormat) + throws IllegalAccessException { setup(storageFormat); - otherBlockchainSetup.importFirstBlocks(30); final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); @@ -194,7 +249,79 @@ public class CheckPointSyncChainDownloaderTest { RespondingEthPeer.blockchainResponder(otherBlockchain); final long pivotBlockNumber = 10; - final SynchronizerConfiguration syncConfig = SynchronizerConfiguration.builder().build(); + final SynchronizerConfiguration syncConfig = + SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(); + ethContext + .getEthPeers() + .streamAvailablePeers() + .forEach( + ethPeer -> { + ethPeer.setCheckpointHeader( + otherBlockchainSetup.getBlocks().get((int) checkpoint.blockNumber()).getHeader()); + }); + final ChainDownloader downloader = downloader(syncConfig, pivotBlockNumber); + final CompletableFuture result = downloader.start(); + + peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone()); + + assertThat(result).isCompleted(); + assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(pivotBlockNumber); + assertThat(localBlockchain.getChainHeadHeader()) + .isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get()); + } + + @ParameterizedTest + @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) + public void shouldSyncToPivotBlockInMultipleSegmentsWithPeerTaskSystem( + final DataStorageFormat storageFormat) + throws IllegalAccessException, ExecutionException, InterruptedException, TimeoutException { + setup(storageFormat); + + final RespondingEthPeer peer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); + final RespondingEthPeer.Responder responder = + RespondingEthPeer.blockchainResponder(otherBlockchain); + + final SynchronizerConfiguration syncConfig = + SynchronizerConfiguration.builder() + .downloaderChainSegmentSize(5) + .downloaderHeadersRequestSize(3) + .isPeerTaskSystemEnabled(true) + .build(); + final long pivotBlockNumber = 25; + ethContext + .getEthPeers() + .streamAvailablePeers() + .forEach( + ethPeer -> { + ethPeer.setCheckpointHeader( + otherBlockchainSetup.getBlocks().get((int) checkpoint.blockNumber()).getHeader()); + }); + final ChainDownloader downloader = downloader(syncConfig, pivotBlockNumber); + final CompletableFuture result = downloader.start(); + + peer.respondWhileOtherThreadsWork(responder, () -> !result.isDone()); + + assertThat(result).isCompleted(); + assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(pivotBlockNumber); + assertThat(localBlockchain.getChainHeadHeader()) + .isEqualTo(otherBlockchain.getBlockHeader(pivotBlockNumber).get()); + } + + @ParameterizedTest + @ArgumentsSource(CheckPointSyncChainDownloaderTestArguments.class) + public void shouldSyncToPivotBlockInSingleSegmentWithPeerTaskSystem( + final DataStorageFormat storageFormat) throws IllegalAccessException { + setup(storageFormat); + + final RespondingEthPeer peer = + EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); + final RespondingEthPeer.Responder responder = + RespondingEthPeer.blockchainResponder(otherBlockchain); + + final long pivotBlockNumber = 10; + final SynchronizerConfiguration syncConfig = + SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(true).build(); ethContext .getEthPeers() .streamAvailablePeers() diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java index c9cfeda119..4559b211e6 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java @@ -18,47 +18,64 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResponseCode; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutorResult; +import org.hyperledger.besu.ethereum.eth.manager.peertask.task.GetReceiptsFromPeerTask; +import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; public class DownloadReceiptsStepTest { private static ProtocolContext protocolContext; + private static ProtocolSchedule protocolSchedule; private static MutableBlockchain blockchain; + private PeerTaskExecutor peerTaskExecutor; private EthProtocolManager ethProtocolManager; - private DownloadReceiptsStep downloadReceiptsStep; @BeforeAll public static void setUpClass() { final BlockchainSetupUtil setupUtil = BlockchainSetupUtil.forTesting(DataStorageFormat.FOREST); setupUtil.importFirstBlocks(20); protocolContext = setupUtil.getProtocolContext(); + protocolSchedule = setupUtil.getProtocolSchedule(); blockchain = setupUtil.getBlockchain(); } @BeforeEach public void setUp() { + peerTaskExecutor = mock(PeerTaskExecutor.class); TransactionPool transactionPool = mock(TransactionPool.class); ethProtocolManager = EthProtocolManagerTestUtil.create( @@ -68,12 +85,17 @@ public class DownloadReceiptsStepTest { protocolContext.getWorldStateArchive(), transactionPool, EthProtocolConfiguration.defaultConfig()); - downloadReceiptsStep = - new DownloadReceiptsStep(ethProtocolManager.ethContext(), new NoOpMetricsSystem()); } @Test public void shouldDownloadReceiptsForBlocks() { + DownloadReceiptsStep downloadReceiptsStep = + new DownloadReceiptsStep( + protocolSchedule, + ethProtocolManager.ethContext(), + peerTaskExecutor, + SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(false).build(), + new NoOpMetricsSystem()); final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 1000); final List blocks = asList(block(1), block(2), block(3), block(4)); @@ -90,6 +112,39 @@ public class DownloadReceiptsStepTest { blockWithReceipts(4))); } + @Test + public void shouldDownloadReceiptsForBlocksUsingPeerTaskSystem() + throws ExecutionException, InterruptedException { + DownloadReceiptsStep downloadReceiptsStep = + new DownloadReceiptsStep( + protocolSchedule, + ethProtocolManager.ethContext(), + peerTaskExecutor, + SynchronizerConfiguration.builder().isPeerTaskSystemEnabled(true).build(), + new NoOpMetricsSystem()); + + final List blocks = asList(mockBlock(), mockBlock(), mockBlock(), mockBlock()); + Map> receiptsMap = new HashMap<>(); + blocks.forEach( + (b) -> receiptsMap.put(b.getHeader(), List.of(Mockito.mock(TransactionReceipt.class)))); + PeerTaskExecutorResult>> peerTaskResult = + new PeerTaskExecutorResult<>( + Optional.of(receiptsMap), PeerTaskExecutorResponseCode.SUCCESS); + Mockito.when(peerTaskExecutor.execute(Mockito.any(GetReceiptsFromPeerTask.class))) + .thenReturn(peerTaskResult); + + final CompletableFuture> result = downloadReceiptsStep.apply(blocks); + + assertThat(result.get().get(0).getBlock()).isEqualTo(blocks.get(0)); + assertThat(result.get().get(0).getReceipts().size()).isEqualTo(1); + assertThat(result.get().get(1).getBlock()).isEqualTo(blocks.get(1)); + assertThat(result.get().get(1).getReceipts().size()).isEqualTo(1); + assertThat(result.get().get(2).getBlock()).isEqualTo(blocks.get(2)); + assertThat(result.get().get(2).getReceipts().size()).isEqualTo(1); + assertThat(result.get().get(3).getBlock()).isEqualTo(blocks.get(3)); + assertThat(result.get().get(3).getReceipts().size()).isEqualTo(1); + } + private Block block(final long number) { final BlockHeader header = blockchain.getBlockHeader(number).get(); return new Block(header, blockchain.getBlockBody(header.getHash()).get()); @@ -100,4 +155,16 @@ public class DownloadReceiptsStepTest { final List receipts = blockchain.getTxReceipts(block.getHash()).get(); return new BlockWithReceipts(block, receipts); } + + private Block mockBlock() { + final Block block = Mockito.mock(Block.class); + final BlockHeader blockHeader = Mockito.mock(BlockHeader.class); + Mockito.when(block.getHeader()).thenAnswer((invocationOnMock) -> blockHeader); + Mockito.when(blockHeader.getReceiptsRoot()).thenReturn(Hash.fromHexStringLenient("DEADBEEF")); + final BlockBody blockBody = Mockito.mock(BlockBody.class); + Mockito.when(block.getBody()).thenAnswer((invocationOnMock) -> blockBody); + Mockito.when(blockBody.getTransactions()) + .thenAnswer((invocationOnMock) -> List.of(Mockito.mock(Transaction.class))); + return block; + } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java index 37ca5be2e9..bc493ebd03 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastDownloaderFactoryTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; @@ -71,6 +72,7 @@ public class FastDownloaderFactoryTest { @Mock private ProtocolContext protocolContext; @Mock private MetricsSystem metricsSystem; @Mock private EthContext ethContext; + @Mock private PeerTaskExecutor peerTaskExecutor; @Mock private SyncState syncState; @Mock private Clock clock; @Mock private Path dataDirectory; @@ -114,6 +116,7 @@ public class FastDownloaderFactoryTest { protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, @@ -139,6 +142,7 @@ public class FastDownloaderFactoryTest { protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, @@ -167,6 +171,7 @@ public class FastDownloaderFactoryTest { protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, @@ -202,6 +207,7 @@ public class FastDownloaderFactoryTest { protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, @@ -239,6 +245,7 @@ public class FastDownloaderFactoryTest { protocolContext, metricsSystem, ethContext, + peerTaskExecutor, worldStateStorageCoordinator, syncState, clock, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java index 68caf2182c..7af807c1c7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncActionsTest.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.peervalidation.PeerValidator; import org.hyperledger.besu.ethereum.eth.sync.PivotBlockSelector; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; @@ -536,6 +537,7 @@ public class FastSyncActionsTest { protocolSchedule, protocolContext, ethContext, + new PeerTaskExecutor(null, null, new NoOpMetricsSystem()), new SyncState(blockchain, ethContext.getEthPeers(), true, Optional.empty()), pivotBlockSelector, new NoOpMetricsSystem()); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java index 34014246d2..0e5b5ec2c7 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastSyncChainDownloaderTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; +import org.hyperledger.besu.ethereum.eth.manager.peertask.PeerTaskExecutor; import org.hyperledger.besu.ethereum.eth.messages.EthPV62; import org.hyperledger.besu.ethereum.eth.messages.GetBlockHeadersMessage; import org.hyperledger.besu.ethereum.eth.sync.ChainDownloader; @@ -110,6 +111,7 @@ public class FastSyncChainDownloaderTest { protocolSchedule, protocolContext, ethContext, + new PeerTaskExecutor(null, null, new NoOpMetricsSystem()), syncState, new NoOpMetricsSystem(), new FastSyncState(otherBlockchain.getBlockHeader(pivotBlockNumber).get()), From c5020be1d673f4f6e2d9d0a14d6aaa8b8281ebd1 Mon Sep 17 00:00:00 2001 From: monem <119044801+pucedoteth@users.noreply.github.com> Date: Thu, 31 Oct 2024 04:54:11 +0200 Subject: [PATCH 5/9] Update DCO.md (#7827) Signed-off-by: monem <119044801+pucedoteth@users.noreply.github.com> Co-authored-by: Sally MacFarlane --- DCO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DCO.md b/DCO.md index 4bf56cb80a..48227cadcd 100644 --- a/DCO.md +++ b/DCO.md @@ -5,4 +5,4 @@ As per section 13.a of the [Hyperledger Charter](https://www.hyperledger.org/abo The sign off needs to be using your legal name, not a pseudonym. Git has a built-in mechanism to allow this with the `-s` or `--signoff` argument to `git commit` command, providing your `user.name` and `user.email` have been setup correctly. -If you have any questions, you can reach us on Besu chat; first, [join the Discord server](https://discord.gg/hyperledger/) then [join the Besu channel](https://discord.com/channels/905194001349627914/938504958909747250). +If you have any questions, you can reach us on Besu chat; first, [join the Discord server](https://discord.com/invite/hyperledger) then [join the Besu channel](https://discord.com/channels/905194001349627914/938504958909747250). From ec46074ca656a1f4869b69dfe9b5921e94740f68 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Thu, 31 Oct 2024 15:54:32 +1000 Subject: [PATCH 6/9] Test against EngineNewPayloadV4 in EngineNewPayloadV4Test (#7837) Also change "Missing" -> "Unexpected" message when V3 blob params sent to V2 Signed-off-by: Simon Dudley --- .../methods/engine/EngineNewPayloadV2.java | 4 +- .../engine/AbstractEngineNewPayloadTest.java | 88 +++++------ .../engine/EngineNewPayloadV2Test.java | 20 +-- .../engine/EngineNewPayloadV3Test.java | 36 +++-- .../engine/EngineNewPayloadV4Test.java | 137 +++++++----------- 5 files changed, 126 insertions(+), 159 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java index 00b0f83054..8d6bd7e433 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java @@ -61,11 +61,11 @@ public class EngineNewPayloadV2 extends AbstractEngineNewPayload { final Optional> maybeRequestsParam) { if (payloadParameter.getBlobGasUsed() != null) { return ValidationResult.invalid( - RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Missing blob gas used field"); + RpcErrorType.INVALID_BLOB_GAS_USED_PARAMS, "Unexpected blob gas used field present"); } if (payloadParameter.getExcessBlobGas() != null) { return ValidationResult.invalid( - RpcErrorType.INVALID_EXCESS_BLOB_GAS_PARAMS, "Missing excess blob gas field"); + RpcErrorType.INVALID_EXCESS_BLOB_GAS_PARAMS, "Unexpected excess blob gas field present"); } return ValidationResult.valid(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java index e793ee8b57..0b81ac111a 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.ACCEPTED; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; @@ -51,7 +52,6 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Withdrawal; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; @@ -62,7 +62,6 @@ import org.hyperledger.besu.ethereum.trie.MerkleTrieException; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.rpc.RpcResponseType; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -123,12 +122,11 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), Optional.empty()); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); assertValidResponse(mockHeader, resp); } @@ -136,12 +134,11 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldReturnInvalidOnBlockExecutionError() { BlockHeader mockHeader = - setupValidPayload( - new BlockProcessingResult("error 42"), Optional.empty(), Optional.empty()); + setupValidPayload(new BlockProcessingResult("error 42"), Optional.empty()); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash().get()).isEqualTo(mockHash); @@ -152,14 +149,14 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldReturnAcceptedOnLatestValidAncestorEmpty() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class))) .thenReturn(Optional.empty()); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).isEmpty(); @@ -170,20 +167,19 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldReturnSuccessOnAlreadyPresent() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); - Block mockBlock = - new Block(mockHeader, new BlockBody(Collections.emptyList(), Collections.emptyList())); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); + Block mockBlock = new Block(mockHeader, new BlockBody(emptyList(), emptyList())); when(blockchain.getBlockByHash(any())).thenReturn(Optional.of(mockBlock)); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); assertValidResponse(mockHeader, resp); } @Test public void shouldReturnInvalidWithLatestValidHashIsABadBlock() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); Hash latestValidHash = Hash.hash(Bytes32.fromHexStringLenient("0xcafebabe")); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); @@ -191,7 +187,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT when(mergeCoordinator.getLatestValidHashOfBadBlock(mockHeader.getHash())) .thenReturn(Optional.of(latestValidHash)); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).isEqualTo(Optional.of(latestValidHash)); @@ -204,12 +200,11 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.empty(), new StorageException("database bedlam")), - Optional.empty(), Optional.empty()); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); fromErrorResp(resp); verify(engineCallListener, times(1)).executionEngineCalled(); @@ -220,13 +215,12 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.empty(), new MerkleTrieException("missing leaf")), - Optional.empty(), Optional.empty()); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); verify(engineCallListener, times(1)).executionEngineCalled(); @@ -235,7 +229,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldNotReturnInvalidOnThrownMerkleTrieException() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); @@ -243,7 +237,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT .thenReturn(Optional.of(mockHash)); when(mergeCoordinator.rememberBlock(any())).thenThrow(new MerkleTrieException("missing leaf")); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); verify(engineCallListener, times(1)).executionEngineCalled(); @@ -252,7 +246,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldReturnInvalidBlockHashOnBadHashParameter() { - BlockHeader mockHeader = spy(createBlockHeader(Optional.empty(), Optional.empty())); + BlockHeader mockHeader = spy(createBlockHeader(Optional.empty())); lenient() .when(mergeCoordinator.getLatestValidAncestor(mockHeader.getBlockHash())) .thenReturn(Optional.empty()); @@ -260,7 +254,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); lenient().when(mockHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getStatusAsString()).isEqualTo(getExpectedInvalidBlockHashStatus().name()); @@ -269,11 +263,11 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldCheckBlockValidityBeforeCheckingByHashForExisting() { - BlockHeader realHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader realHeader = createBlockHeader(Optional.empty()); BlockHeader paramHeader = spy(realHeader); when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); - var resp = resp(mockEnginePayload(paramHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(paramHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).isEmpty(); @@ -283,7 +277,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldReturnInvalidOnMalformedTransactions() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); when(mergeCoordinator.getLatestValidAncestor(any(Hash.class))) .thenReturn(Optional.of(mockHash)); @@ -298,9 +292,9 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldRespondWithSyncingDuringForwardSync() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); when(mergeContext.isSyncing()).thenReturn(Boolean.TRUE); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getError()).isNull(); @@ -311,10 +305,10 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldRespondWithSyncingDuringBackwardsSync() { - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); when(mergeCoordinator.appendNewPayloadToSync(any())) .thenReturn(CompletableFuture.completedFuture(null)); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).isEmpty(); @@ -325,12 +319,12 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldRespondWithInvalidIfExtraDataIsNull() { - BlockHeader realHeader = createBlockHeader(Optional.empty(), Optional.empty()); + BlockHeader realHeader = createBlockHeader(Optional.empty()); BlockHeader paramHeader = spy(realHeader); when(paramHeader.getHash()).thenReturn(Hash.fromHexStringLenient("0x1337")); when(paramHeader.getExtraData().toHexString()).thenReturn(null); - var resp = resp(mockEnginePayload(paramHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(paramHeader, emptyList())); EnginePayloadStatusResult res = fromSuccessResp(resp); assertThat(res.getLatestValidHash()).isEmpty(); @@ -342,8 +336,8 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT @Test public void shouldReturnInvalidWhenBadBlock() { when(mergeCoordinator.isBadBlock(any(Hash.class))).thenReturn(true); - BlockHeader mockHeader = createBlockHeader(Optional.empty(), Optional.empty()); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + BlockHeader mockHeader = createBlockHeader(Optional.empty()); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); when(protocolSpec.getWithdrawalsValidator()) .thenReturn(new WithdrawalsValidator.AllowedWithdrawals()); EnginePayloadStatusResult res = fromSuccessResp(resp); @@ -359,12 +353,11 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), Optional.empty()); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); assertValidResponse(mockHeader, resp); } @@ -408,11 +401,9 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT } protected BlockHeader setupValidPayload( - final BlockProcessingResult value, - final Optional> maybeWithdrawals, - final Optional> maybeRequests) { + final BlockProcessingResult value, final Optional> maybeWithdrawals) { - BlockHeader mockHeader = createBlockHeader(maybeWithdrawals, maybeRequests); + BlockHeader mockHeader = createBlockHeader(maybeWithdrawals); when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty()); when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class))) .thenReturn(Optional.of(mockHash)); @@ -425,6 +416,11 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT } protected EnginePayloadStatusResult fromSuccessResp(final JsonRpcResponse resp) { + if (resp.getType().equals(RpcResponseType.ERROR)) { + final JsonRpcError jsonRpcError = fromErrorResp(resp); + throw new AssertionError( + "Expected success but was error with message: " + jsonRpcError.getMessage()); + } assertThat(resp.getType()).isEqualTo(RpcResponseType.SUCCESS); return Optional.of(resp) .map(JsonRpcSuccessResponse.class::cast) @@ -441,15 +437,12 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT .get(); } - protected BlockHeader createBlockHeader( - final Optional> maybeWithdrawals, - final Optional> maybeRequests) { - return createBlockHeaderFixture(maybeWithdrawals, maybeRequests).buildHeader(); + protected BlockHeader createBlockHeader(final Optional> maybeWithdrawals) { + return createBlockHeaderFixture(maybeWithdrawals).buildHeader(); } protected BlockHeaderTestFixture createBlockHeaderFixture( - final Optional> maybeWithdrawals, - final Optional> maybeRequests) { + final Optional> maybeWithdrawals) { BlockHeader parentBlockHeader = new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader(); return new BlockHeaderTestFixture() @@ -458,8 +451,7 @@ public abstract class AbstractEngineNewPayloadTest extends AbstractScheduledApiT .number(parentBlockHeader.getNumber() + 1) .timestamp(parentBlockHeader.getTimestamp() + 1) .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) - .parentBeaconBlockRoot(maybeParentBeaconBlockRoot) - .requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null)); + .parentBeaconBlockRoot(maybeParentBeaconBlockRoot); } protected void assertValidResponse(final BlockHeader mockHeader, final JsonRpcResponse resp) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java index abf2c29767..171ee0499f 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java @@ -82,8 +82,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.of(withdrawals), - Optional.empty()); + Optional.of(withdrawals)); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); @@ -100,7 +99,6 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), Optional.empty()); lenient() .when(blockchain.getBlockHeader(mockHeader.getParentHash())) @@ -120,7 +118,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { var resp = resp( mockEnginePayload( - createBlockHeader(Optional.of(Collections.emptyList()), Optional.empty()), + createBlockHeader(Optional.of(Collections.emptyList())), Collections.emptyList(), withdrawals)); @@ -133,14 +131,14 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { public void shouldValidateBlobGasUsedCorrectly() { // V2 should return error if non-null blobGasUsed BlockHeader blockHeader = - createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty()) + createBlockHeaderFixture(Optional.of(Collections.emptyList())) .blobGasUsed(100L) .buildHeader(); var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of())); final JsonRpcError jsonRpcError = fromErrorResp(resp); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_BLOB_GAS_USED_PARAMS.getCode()); - assertThat(jsonRpcError.getData()).isEqualTo("Missing blob gas used field"); + assertThat(jsonRpcError.getData()).isEqualTo("Unexpected blob gas used field present"); verify(engineCallListener, times(1)).executionEngineCalled(); } @@ -148,7 +146,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { public void shouldValidateExcessBlobGasCorrectly() { // V2 should return error if non-null ExcessBlobGas BlockHeader blockHeader = - createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty()) + createBlockHeaderFixture(Optional.of(Collections.emptyList())) .excessBlobGas(BlobGas.MAX_BLOB_GAS) .buildHeader(); @@ -156,7 +154,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { final JsonRpcError jsonRpcError = fromErrorResp(resp); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); - assertThat(jsonRpcError.getData()).isEqualTo("Missing excess blob gas field"); + assertThat(jsonRpcError.getData()).isEqualTo("Unexpected excess blob gas field present"); verify(engineCallListener, times(1)).executionEngineCalled(); } @@ -169,9 +167,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { var resp = resp( mockEnginePayload( - createBlockHeader(Optional.empty(), Optional.empty()), - Collections.emptyList(), - withdrawals)); + createBlockHeader(Optional.empty()), Collections.emptyList(), withdrawals)); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); verify(engineCallListener, times(1)).executionEngineCalled(); @@ -182,7 +178,7 @@ public class EngineNewPayloadV2Test extends AbstractEngineNewPayloadTest { // Cancun starte at timestamp 30 final long blockTimestamp = 31L; BlockHeader blockHeader = - createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty()) + createBlockHeaderFixture(Optional.of(Collections.emptyList())) .timestamp(blockTimestamp) .buildHeader(); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java index b79cb587eb..1810ce9450 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID; import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_PARAMS; @@ -44,7 +45,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadS import org.hyperledger.besu.ethereum.core.BlobTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.Withdrawal; @@ -56,7 +56,6 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import java.math.BigInteger; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Supplier; @@ -112,8 +111,18 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { when(payload.getExcessBlobGas()).thenReturn("99"); when(payload.getBlobGasUsed()).thenReturn(9l); + // TODO locking this as V3 otherwise this breaks the EngineNewPayloadV4Test subclass when method + // field is V4 + final EngineNewPayloadV3 methodV3 = + new EngineNewPayloadV3( + vertx, + protocolSchedule, + protocolContext, + mergeCoordinator, + ethPeers, + engineCallListener); final JsonRpcResponse badParam = - method.response( + methodV3.response( new JsonRpcRequestContext( new JsonRpcRequest( "2.0", @@ -133,24 +142,20 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { final BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), Optional.empty()); - final EnginePayloadParameter payload = - mockEnginePayload(mockHeader, Collections.emptyList(), null); + final EnginePayloadParameter payload = mockEnginePayload(mockHeader, emptyList(), null); ValidationResult res = method.validateParameters( payload, Optional.of(List.of()), Optional.of("0x0000000000000000000000000000000000000000000000000000000000000000"), - Optional.empty()); + Optional.of(emptyList())); assertThat(res.isValid()).isTrue(); } @Override - protected BlockHeader createBlockHeader( - final Optional> maybeWithdrawals, - final Optional> maybeRequests) { + protected BlockHeader createBlockHeader(final Optional> maybeWithdrawals) { BlockHeader parentBlockHeader = new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) @@ -186,12 +191,12 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { public void shouldValidateBlobGasUsedCorrectly() { // V3 must return error if null blobGasUsed BlockHeader blockHeader = - createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty()) + createBlockHeaderFixture(Optional.of(emptyList())) .excessBlobGas(BlobGas.MAX_BLOB_GAS) .blobGasUsed(null) .buildHeader(); - var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of())); + var resp = resp(mockEnginePayload(blockHeader, emptyList(), List.of())); final JsonRpcError jsonRpcError = fromErrorResp(resp); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); @@ -204,12 +209,12 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { public void shouldValidateExcessBlobGasCorrectly() { // V3 must return error if null excessBlobGas BlockHeader blockHeader = - createBlockHeaderFixture(Optional.of(Collections.emptyList()), Optional.empty()) + createBlockHeaderFixture(Optional.of(emptyList())) .excessBlobGas(null) .blobGasUsed(100L) .buildHeader(); - var resp = resp(mockEnginePayload(blockHeader, Collections.emptyList(), List.of())); + var resp = resp(mockEnginePayload(blockHeader, emptyList(), List.of())); final JsonRpcError jsonRpcError = fromErrorResp(resp); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); @@ -229,7 +234,6 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult(Optional.of(new BlockProcessingOutputs(null, List.of()))), - Optional.empty(), Optional.empty()); var resp = resp(mockEnginePayload(mockHeader, transactions)); @@ -265,7 +269,7 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { protected JsonRpcResponse resp(final EnginePayloadParameter payload) { Object[] params = maybeParentBeaconBlockRoot - .map(bytes32 -> new Object[] {payload, Collections.emptyList(), bytes32.toHexString()}) + .map(bytes32 -> new Object[] {payload, emptyList(), bytes32.toHexString()}) .orElseGet(() -> new Object[] {payload}); return method.response( new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params))); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java index c8504e7451..fe7c38917c 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java @@ -14,8 +14,10 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine; +import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.api.graphql.internal.response.GraphQLError.INVALID_PARAMS; +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INVALID_EXECUTION_REQUESTS_PARAMS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -42,7 +44,6 @@ import org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsValidator; import org.hyperledger.besu.ethereum.mainnet.requests.ProhibitedRequestValidator; import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Optional; @@ -59,14 +60,19 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { public EngineNewPayloadV4Test() {} + private static final List VALID_REQUESTS = + List.of( + new Request(RequestType.DEPOSIT, Bytes.of(1)), + new Request(RequestType.WITHDRAWAL, Bytes.of(1)), + new Request(RequestType.CONSOLIDATION, Bytes.of(1))); + @BeforeEach @Override public void before() { super.before(); maybeParentBeaconBlockRoot = Optional.of(Bytes32.ZERO); - // TODO this should be using NewPayloadV4 this.method = - new EngineNewPayloadV3( + new EngineNewPayloadV4( vertx, protocolSchedule, protocolContext, @@ -75,95 +81,63 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { engineCallListener); lenient().when(protocolSchedule.hardforkFor(any())).thenReturn(Optional.of(pragueHardfork)); lenient().when(protocolSpec.getGasCalculator()).thenReturn(new PragueGasCalculator()); + mockAllowedRequestsValidator(); } @Override public void shouldReturnExpectedMethodName() { - assertThat(method.getName()).isEqualTo("engine_newPayloadV3"); - } - - @Test - public void shouldReturnValidIfRequestsIsNull_WhenRequestsProhibited() { - mockProhibitedRequestsValidator(); - - BlockHeader mockHeader = - setupValidPayload( - new BlockProcessingResult( - Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.empty()))), - Optional.empty(), - Optional.empty()); - when(blockchain.getBlockHeader(mockHeader.getParentHash())) - .thenReturn(Optional.of(mock(BlockHeader.class))); - when(mergeCoordinator.getLatestValidAncestor(mockHeader)) - .thenReturn(Optional.of(mockHeader.getHash())); - - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList())); - - assertValidResponse(mockHeader, resp); + assertThat(method.getName()).isEqualTo("engine_newPayloadV4"); } @Test public void shouldReturnInvalidIfRequestsIsNull_WhenRequestsAllowed() { - mockAllowedRequestsValidator(); var resp = - resp( - mockEnginePayload( - createBlockHeader(Optional.empty(), Optional.empty()), Collections.emptyList())); + respWithInvalidRequests( + mockEnginePayload(createValidBlockHeaderForV4(Optional.empty()), emptyList())); assertThat(fromErrorResp(resp).getCode()).isEqualTo(INVALID_PARAMS.getCode()); + assertThat(fromErrorResp(resp).getMessage()) + .isEqualTo(INVALID_EXECUTION_REQUESTS_PARAMS.getMessage()); verify(engineCallListener, times(1)).executionEngineCalled(); } @Test public void shouldReturnValidIfRequestsIsNotNull_WhenRequestsAllowed() { - final List requests = - List.of( - new Request(RequestType.DEPOSIT, Bytes.of(1)), - new Request(RequestType.WITHDRAWAL, Bytes.of(1)), - new Request(RequestType.CONSOLIDATION, Bytes.of(1))); - - mockAllowedRequestsValidator(); BlockHeader mockHeader = setupValidPayload( new BlockProcessingResult( - Optional.of(new BlockProcessingOutputs(null, List.of(), Optional.of(requests)))), - Optional.empty(), + Optional.of( + new BlockProcessingOutputs(null, List.of(), Optional.of(VALID_REQUESTS)))), Optional.empty()); when(blockchain.getBlockHeader(mockHeader.getParentHash())) .thenReturn(Optional.of(mock(BlockHeader.class))); when(mergeCoordinator.getLatestValidAncestor(mockHeader)) .thenReturn(Optional.of(mockHeader.getHash())); - var resp = resp(mockEnginePayload(mockHeader, Collections.emptyList()), requests); + var resp = resp(mockEnginePayload(mockHeader, emptyList())); assertValidResponse(mockHeader, resp); } @Test public void shouldReturnInvalidIfRequestsIsNotNull_WhenRequestsProhibited() { - final List requests = - List.of( - new Request(RequestType.DEPOSIT, Bytes.of(1)), - new Request(RequestType.WITHDRAWAL, Bytes.of(1)), - new Request(RequestType.CONSOLIDATION, Bytes.of(1))); - mockProhibitedRequestsValidator(); - var resp = - resp( - mockEnginePayload( - createBlockHeader(Optional.empty(), Optional.of(Collections.emptyList())), - Collections.emptyList()), - requests); + var resp = resp(mockEnginePayload(createValidBlockHeaderForV4(Optional.empty()), emptyList())); final JsonRpcError jsonRpcError = fromErrorResp(resp); assertThat(jsonRpcError.getCode()).isEqualTo(INVALID_PARAMS.getCode()); verify(engineCallListener, times(1)).executionEngineCalled(); } - @Override - protected BlockHeader createBlockHeader( - final Optional> maybeWithdrawals, - final Optional> maybeRequests) { + private BlockHeader createValidBlockHeaderForV4( + final Optional> maybeWithdrawals) { + return createBlockHeaderFixtureForV3(maybeWithdrawals) + .requestsHash(BodyValidation.requestsHash(VALID_REQUESTS)) + .buildHeader(); + } + + private BlockHeaderTestFixture createBlockHeaderFixtureForV3( + final Optional> maybeWithdrawals) { BlockHeader parentBlockHeader = new BlockHeaderTestFixture() .baseFeePerGas(Wei.ONE) @@ -172,48 +146,49 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test { .blobGasUsed(0L) .buildHeader(); - BlockHeader mockHeader = - new BlockHeaderTestFixture() - .baseFeePerGas(Wei.ONE) - .parentHash(parentBlockHeader.getParentHash()) - .number(parentBlockHeader.getNumber() + 1) - .timestamp(parentBlockHeader.getTimestamp() + 1) - .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) - .excessBlobGas(BlobGas.ZERO) - .blobGasUsed(0L) - .requestsHash(maybeRequests.map(BodyValidation::requestsHash).orElse(null)) - .parentBeaconBlockRoot( - maybeParentBeaconBlockRoot.isPresent() ? maybeParentBeaconBlockRoot : null) - .buildHeader(); - return mockHeader; + return new BlockHeaderTestFixture() + .baseFeePerGas(Wei.ONE) + .parentHash(parentBlockHeader.getParentHash()) + .number(parentBlockHeader.getNumber() + 1) + .timestamp(parentBlockHeader.getTimestamp() + 1) + .withdrawalsRoot(maybeWithdrawals.map(BodyValidation::withdrawalsRoot).orElse(null)) + .excessBlobGas(BlobGas.ZERO) + .blobGasUsed(0L) + .parentBeaconBlockRoot( + maybeParentBeaconBlockRoot.isPresent() ? maybeParentBeaconBlockRoot : null); + } + + @Override + protected BlockHeader createBlockHeader(final Optional> maybeWithdrawals) { + return createValidBlockHeaderForV4(maybeWithdrawals); } @Override protected JsonRpcResponse resp(final EnginePayloadParameter payload) { + final List requestsWithoutRequestId = + VALID_REQUESTS.stream() + .sorted(Comparator.comparing(Request::getType)) + .map(r -> r.getData().toHexString()) + .toList(); Object[] params = maybeParentBeaconBlockRoot - .map(bytes32 -> new Object[] {payload, Collections.emptyList(), bytes32.toHexString()}) + .map( + bytes32 -> + new Object[] { + payload, emptyList(), bytes32.toHexString(), requestsWithoutRequestId + }) .orElseGet(() -> new Object[] {payload}); return method.response( new JsonRpcRequestContext(new JsonRpcRequest("2.0", this.method.getName(), params))); } - protected JsonRpcResponse resp( - final EnginePayloadParameter payload, final List requests) { - final List requestsWithoutRequestId = - requests.stream() - .sorted(Comparator.comparing(Request::getType)) - .map(r -> r.getData().toHexString()) - .toList(); + protected JsonRpcResponse respWithInvalidRequests(final EnginePayloadParameter payload) { Object[] params = maybeParentBeaconBlockRoot .map( bytes32 -> - new Object[] { - payload, - Collections.emptyList(), - bytes32.toHexString(), - requestsWithoutRequestId + new Object[] {payload, emptyList(), bytes32.toHexString() + // empty requests param is invalid }) .orElseGet(() -> new Object[] {payload}); return method.response( From 24ed2d0b21633cea067d64bdf37c1a0c671801cf Mon Sep 17 00:00:00 2001 From: Sally MacFarlane Date: Thu, 31 Oct 2024 18:09:22 +1000 Subject: [PATCH 7/9] update discord invite link (#7836) Signed-off-by: Sally MacFarlane --- CONTRIBUTING.md | 2 +- MAINTAINERS.md | 2 +- README.md | 4 ++-- SUPPORT.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2d6c57d25..c13ea67852 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ Welcome to the Besu repository! The following links are a set of guidelines for Having the following accounts is necessary for contributing code/issues to Besu. * If you want to contribute code, you can make a [github account here](https://github.com). * If you want to raise an issue, do so [in the issues tab](https://github.com/hyperledger/besu/issues). -* To ask questions or chat with us, join our [Discord](https://discord.gg/hyperledger) +* To ask questions or chat with us, join our [Discord](https://discord.com/invite/hyperledger) * To edit pages in our wiki, you'll need a [Linux Foundation (LF) account]. ### Useful contributing links diff --git a/MAINTAINERS.md b/MAINTAINERS.md index ae6720632a..afb82b6fc5 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -84,7 +84,7 @@ The following steps must occur for a contributor to be "upgraded" as a maintaine - The proposed maintainer accepts the nomination and expresses a willingness to be a long-term (more than 6 month) committer by adding a comment in the proposal PR. - The PR will be communicated in all appropriate communication channels - including at least [besu-contributors channel on Discord](https://discord.gg/hyperledger), + including at least [besu-contributors channel on Discord](https://discord.com/invite/hyperledger), the [mailing list](https://lists.hyperledger.org/g/besu) and any maintainer/community call. - Approval by at least 3 current maintainers within two weeks of the proposal or diff --git a/README.md b/README.md index 7139df8580..8f5f51a726 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Documentation](https://img.shields.io/github/actions/workflow/status/hyperledger/besu-docs/publish-main-docs.yml?branch=main&label=docs)](https://github.com/hyperledger/besu-docs/actions/workflows/publish-main-docs.yml) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3174/badge)](https://bestpractices.coreinfrastructure.org/projects/3174) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/hyperledger/besu/blob/main/LICENSE) - [![Discord](https://img.shields.io/discord/905194001349627914?logo=Hyperledger&style=plastic)](https://discord.gg/hyperledger) + [![Discord](https://img.shields.io/discord/905194001349627914?logo=Hyperledger&style=plastic)](https://discord.com/invite/hyperledger) [![Twitter Follow](https://img.shields.io/twitter/follow/HyperledgerBesu)](https://twitter.com/HyperledgerBesu) [Download](https://github.com/hyperledger/besu/releases) @@ -67,5 +67,5 @@ and YourKit YouMonitor. [Besu Issues]: https://github.com/hyperledger/besu/issues [Besu User Documentation]: https://besu.hyperledger.org -[Besu channel on Discord]: https://discord.gg/hyperledger +[Besu channel on Discord]: https://discord.com/invite/hyperledger [Contributing Guidelines]: CONTRIBUTING.md diff --git a/SUPPORT.md b/SUPPORT.md index 9e4a7b7b42..97715857cb 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -20,5 +20,5 @@ Having Github, Discord, and Linux Foundation accounts is necessary for obtaining [Besu User Documentation]: https://besu.hyperledger.org -[Besu channel on Discord]: https://discord.gg/hyperledger +[Besu channel on Discord]: https://discord.com/invite/hyperledger [Contributing Guidelines]: CONTRIBUTING.md From d846e3749bed4d1d665d2a20435d4421efbefefe Mon Sep 17 00:00:00 2001 From: garyschulte Date: Thu, 31 Oct 2024 12:18:27 -0700 Subject: [PATCH 8/9] Remove retesteth rpc service and commands (#7833) * remove retesteth rpc service and commands Signed-off-by: garyschulte --- CHANGELOG.md | 1 + .../org/hyperledger/besu/cli/BesuCommand.java | 2 - .../cli/subcommands/RetestethSubCommand.java | 149 ------- ethereum/retesteth/build.gradle | 58 --- .../NoRewardProtocolScheduleWrapper.java | 145 ------- .../ethereum/retesteth/RetestethClock.java | 60 --- .../retesteth/RetestethConfiguration.java | 30 -- .../ethereum/retesteth/RetestethContext.java | 370 ------------------ .../ethereum/retesteth/RetestethService.java | 122 ------ .../retesteth/methods/TestGetLogHash.java | 73 ---- .../retesteth/methods/TestImportRawBlock.java | 107 ----- .../retesteth/methods/TestMineBlocks.java | 97 ----- .../methods/TestModifyTimestamp.java | 51 --- .../retesteth/methods/TestRewindToBlock.java | 53 --- .../retesteth/methods/TestSetChainParams.java | 159 -------- .../methods/TestImportRawBlockTest.java | 129 ------ .../methods/TestSetChainParamsTest.java | 115 ------ .../retesteth/methods/1559ChainParams.json | 21 - ...ultimpleBalanceInstructionChainParams.json | 102 ----- 19 files changed, 1 insertion(+), 1843 deletions(-) delete mode 100644 besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java delete mode 100644 ethereum/retesteth/build.gradle delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethClock.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethConfiguration.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestModifyTimestamp.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestRewindToBlock.java delete mode 100644 ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java delete mode 100644 ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java delete mode 100644 ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java delete mode 100644 ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/1559ChainParams.json delete mode 100644 ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/multimpleBalanceInstructionChainParams.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 26342cf7be..41aea176de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Added isLabelsObserved to LabelledGauge in plugin-api. Default implementation returns false. ### Breaking Changes +- Removed Retesteth rpc service and commands [#7833](https://github.com/hyperledger/besu/pull/7783) ### Upcoming Breaking Changes 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 bf79da288d..8a01236725 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -74,7 +74,6 @@ import org.hyperledger.besu.cli.presynctasks.PreSynchronizationTaskRunner; import org.hyperledger.besu.cli.presynctasks.PrivateDatabaseMigrationPreSyncTask; import org.hyperledger.besu.cli.subcommands.PasswordSubCommand; import org.hyperledger.besu.cli.subcommands.PublicKeySubCommand; -import org.hyperledger.besu.cli.subcommands.RetestethSubCommand; import org.hyperledger.besu.cli.subcommands.TxParseSubCommand; import org.hyperledger.besu.cli.subcommands.ValidateConfigSubCommand; import org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand; @@ -1105,7 +1104,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable { PublicKeySubCommand.COMMAND_NAME, new PublicKeySubCommand(commandLine.getOut())); commandLine.addSubcommand( PasswordSubCommand.COMMAND_NAME, new PasswordSubCommand(commandLine.getOut())); - commandLine.addSubcommand(RetestethSubCommand.COMMAND_NAME, new RetestethSubCommand()); commandLine.addSubcommand( RLPSubCommand.COMMAND_NAME, new RLPSubCommand(commandLine.getOut(), in)); commandLine.addSubcommand( diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java deleted file mode 100644 index 67af49c400..0000000000 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.subcommands; - -import static org.hyperledger.besu.cli.subcommands.RetestethSubCommand.COMMAND_NAME; - -import org.hyperledger.besu.BesuInfo; -import org.hyperledger.besu.cli.DefaultCommandValues; -import org.hyperledger.besu.cli.custom.JsonRPCAllowlistHostsProperty; -import org.hyperledger.besu.cli.options.stable.LoggingLevelOption; -import org.hyperledger.besu.cli.util.VersionProvider; -import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; -import org.hyperledger.besu.ethereum.retesteth.RetestethConfiguration; -import org.hyperledger.besu.ethereum.retesteth.RetestethService; -import org.hyperledger.besu.util.LogConfigurator; - -import java.net.InetAddress; -import java.nio.file.Path; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import picocli.CommandLine.Command; -import picocli.CommandLine.Mixin; -import picocli.CommandLine.Option; - -/** Subcommand to run a Retesteth compatible server for reference tests. */ -@Command( - name = COMMAND_NAME, - description = "Run a Retesteth compatible server for reference tests.", - mixinStandardHelpOptions = true, - versionProvider = VersionProvider.class) -@SuppressWarnings("unused") -public class RetestethSubCommand implements Runnable { - - private static final Logger LOG = LoggerFactory.getLogger(RetestethSubCommand.class); - - /** The constant COMMAND_NAME. */ - public static final String COMMAND_NAME = "retesteth"; - - /** - * Using a distinct port for retesteth will result in less testing collisions and accidental RPC - * calls. This is 0xba5e in hex, a hex speak play on the english translation of - * "Besu." - */ - public static final int RETESTETH_PORT = 47710; - - @Option( - names = {"--data-path"}, - paramLabel = DefaultCommandValues.MANDATORY_PATH_FORMAT_HELP, - description = "The path to Besu data directory (default: ${DEFAULT-VALUE})") - private final Path dataPath = DefaultCommandValues.getDefaultBesuDataPath(this); - - @Mixin private LoggingLevelOption loggingLevelOption; - - @SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"}) // PicoCLI requires non-final Strings. - @Option( - names = {"--rpc-http-host"}, - paramLabel = DefaultCommandValues.MANDATORY_HOST_FORMAT_HELP, - description = "Host for Retesteth JSON-RPC HTTP to listen on (default: ${DEFAULT-VALUE})", - arity = "1") - private String rpcHttpHost = autoDiscoverDefaultIP().getHostAddress(); - - @Option( - names = {"--rpc-http-port"}, - paramLabel = DefaultCommandValues.MANDATORY_PORT_FORMAT_HELP, - description = "Port for Retesteth JSON-RPC HTTP to listen on (default: ${DEFAULT-VALUE})", - arity = "1") - private final Integer rpcHttpPort = RETESTETH_PORT; - - @Option( - names = {"--host-allowlist", "--host-whitelist"}, - paramLabel = "[,...]... or * or all", - description = - "Comma separated list of hostnames to allow for RPC access, or * to accept any host (default: ${DEFAULT-VALUE})", - defaultValue = "localhost,127.0.0.1") - private final JsonRPCAllowlistHostsProperty hostsAllowlist = new JsonRPCAllowlistHostsProperty(); - - private InetAddress autoDiscoveredDefaultIP; - - /** Default Constructor. */ - public RetestethSubCommand() {} - - // Used to discover the default IP of the client. - // Loopback IP is used by default as this is how smokeTests require it to be - // and it's probably a good security behaviour to default only on the localhost. - private InetAddress autoDiscoverDefaultIP() { - - if (autoDiscoveredDefaultIP != null) { - return autoDiscoveredDefaultIP; - } - - autoDiscoveredDefaultIP = InetAddress.getLoopbackAddress(); - - return autoDiscoveredDefaultIP; - } - - private void prepareLogging() { - // set log level per CLI flags - final String logLevel = loggingLevelOption.getLogLevel(); - if (logLevel != null) { - System.out.println("Setting logging level to " + logLevel); - LogConfigurator.setLevel("", logLevel); - } - } - - @Override - public void run() { - prepareLogging(); - - final RetestethConfiguration retestethConfiguration = new RetestethConfiguration(dataPath); - final JsonRpcConfiguration jsonRpcConfiguration = JsonRpcConfiguration.createDefault(); - jsonRpcConfiguration.setHost(rpcHttpHost); - jsonRpcConfiguration.setPort(rpcHttpPort); - jsonRpcConfiguration.setHostsAllowlist(hostsAllowlist); - - final RetestethService retestethService = - new RetestethService(BesuInfo.version(), retestethConfiguration, jsonRpcConfiguration); - - Runtime.getRuntime() - .addShutdownHook( - new Thread( - () -> { - try { - retestethService.close(); - LogConfigurator.shutdown(); - } catch (final Exception e) { - LOG.error("Failed to stop Besu Retesteth"); - } - })); - retestethService.start(); - try { - Thread.sleep(Long.MAX_VALUE); // Is there a better way? - } catch (final InterruptedException e) { - // e.printStackTrace(); - } - } -} diff --git a/ethereum/retesteth/build.gradle b/ethereum/retesteth/build.gradle deleted file mode 100644 index 484953a391..0000000000 --- a/ethereum/retesteth/build.gradle +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2019 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 { - archiveBaseName = 'besu-retesteth' - manifest { - attributes( - 'Specification-Title': archiveBaseName, - 'Specification-Version': project.version, - 'Implementation-Title': archiveBaseName, - 'Implementation-Version': calculateVersion(), - 'Commit-Hash': getGitCommitDetails(40).hash - ) - } -} - -dependencies { - api 'org.slf4j:slf4j-api' - - implementation project(':config') - implementation project(':datatypes') - implementation project(':ethereum:api') - implementation project(':ethereum:api') - implementation project(':ethereum:blockcreation') - implementation project(':ethereum:core') - implementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') - implementation project(':ethereum:eth') - implementation project(':ethereum:p2p') - implementation project(':ethereum:rlp') - implementation project(':evm') - implementation project(':metrics:core') - implementation project(':nat') - implementation project(':services:kvstore') - implementation project(':util') - - implementation 'com.google.guava:guava' - implementation 'io.vertx:vertx-core' - implementation 'io.vertx:vertx-web' - implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'io.tmio:tuweni-bytes' - implementation 'io.tmio:tuweni-units' - - testImplementation 'org.assertj:assertj-core' - testImplementation 'org.junit.jupiter:junit-jupiter' - testImplementation 'org.mockito:mockito-core' -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java deleted file mode 100644 index db1ac943f0..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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.ethereum.retesteth; - -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.BlockValidator; -import org.hyperledger.besu.ethereum.MainnetBlockValidator; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockImporter; -import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter; -import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; -import org.hyperledger.besu.ethereum.mainnet.BlockProcessor; -import org.hyperledger.besu.ethereum.mainnet.MainnetBlockImporter; -import org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; - -import java.math.BigInteger; -import java.util.Optional; -import java.util.function.Predicate; - -public class NoRewardProtocolScheduleWrapper implements ProtocolSchedule { - - private final ProtocolSchedule delegate; - private final BadBlockManager badBlockManager; - - NoRewardProtocolScheduleWrapper( - final ProtocolSchedule delegate, final BadBlockManager badBlockManager) { - this.delegate = delegate; - this.badBlockManager = badBlockManager; - } - - @Override - public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { - final ProtocolSpec original = delegate.getByBlockHeader(blockHeader); - final BlockProcessor noRewardBlockProcessor = - new MainnetBlockProcessor( - original.getTransactionProcessor(), - original.getTransactionReceiptFactory(), - Wei.ZERO, - original.getMiningBeneficiaryCalculator(), - original.isSkipZeroBlockRewards(), - delegate); - final BlockValidator noRewardBlockValidator = - new MainnetBlockValidator( - original.getBlockHeaderValidator(), - original.getBlockBodyValidator(), - noRewardBlockProcessor, - badBlockManager); - final BlockImporter noRewardBlockImporter = new MainnetBlockImporter(noRewardBlockValidator); - return new ProtocolSpec( - original.getName(), - original.getEvm(), - original.getTransactionValidatorFactory(), - original.getTransactionProcessor(), - original.getPrivateTransactionProcessor(), - original.getBlockHeaderValidator(), - original.getOmmerHeaderValidator(), - original.getBlockBodyValidator(), - noRewardBlockProcessor, - noRewardBlockImporter, - noRewardBlockValidator, - original.getBlockHeaderFunctions(), - original.getTransactionReceiptFactory(), - original.getDifficultyCalculator(), - Wei.ZERO, // block reward - original.getMiningBeneficiaryCalculator(), - original.getPrecompileContractRegistry(), - original.isSkipZeroBlockRewards(), - original.getGasCalculator(), - original.getGasLimitCalculator(), - original.getFeeMarket(), - Optional.empty(), - original.getWithdrawalsValidator(), - original.getWithdrawalsProcessor(), - original.getRequestsValidator(), - original.getRequestProcessorCoordinator(), - original.getBlockHashProcessor(), - original.isPoS(), - original.isReplayProtectionSupported()); - } - - @Override - public boolean anyMatch(final Predicate predicate) { - return delegate.anyMatch(predicate); - } - - @Override - public boolean isOnMilestoneBoundary(final BlockHeader blockHeader) { - return delegate.isOnMilestoneBoundary(blockHeader); - } - - @Override - public Optional getChainId() { - return delegate.getChainId(); - } - - @Override - public void putBlockNumberMilestone(final long blockNumber, final ProtocolSpec protocolSpec) { - delegate.putBlockNumberMilestone(blockNumber, protocolSpec); - } - - @Override - public void putTimestampMilestone(final long timestamp, final ProtocolSpec protocolSpec) { - delegate.putTimestampMilestone(timestamp, protocolSpec); - } - - @Override - public Optional hardforkFor( - final Predicate predicate) { - return delegate.hardforkFor(predicate); - } - - @Override - public String listMilestones() { - return delegate.listMilestones(); - } - - @Override - public void setPermissionTransactionFilter( - final PermissionTransactionFilter permissionTransactionFilter) { - delegate.setPermissionTransactionFilter(permissionTransactionFilter); - } - - @Override - public void setPublicWorldStateArchiveForPrivacyBlockProcessor( - final WorldStateArchive publicWorldStateArchive) { - delegate.setPublicWorldStateArchiveForPrivacyBlockProcessor(publicWorldStateArchive); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethClock.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethClock.java deleted file mode 100644 index fdd22f42b0..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethClock.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.ethereum.retesteth; - -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; -import java.util.Optional; - -public class RetestethClock extends Clock { - - private Optional fixedInstant; - private final Clock delegateClock; - - RetestethClock() { - this(Clock.systemUTC()); - } - - private RetestethClock(final Clock delegateClock) { - fixedInstant = Optional.empty(); - this.delegateClock = delegateClock; - } - - @Override - public ZoneId getZone() { - return delegateClock.getZone(); - } - - @Override - public Clock withZone(final ZoneId zone) { - final RetestethClock zonedClock = new RetestethClock(delegateClock.withZone(zone)); - zonedClock.fixedInstant = fixedInstant; - return zonedClock; - } - - @Override - public Instant instant() { - return fixedInstant.orElseGet(delegateClock::instant); - } - - public void resetTime(final long time) { - fixedInstant = Optional.of(Instant.ofEpochSecond(time)); - } - - public void advanceSeconds(final long seconds) { - fixedInstant = Optional.of(Instant.ofEpochSecond(instant().getEpochSecond() + seconds)); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethConfiguration.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethConfiguration.java deleted file mode 100644 index bb4fa31a55..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethConfiguration.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.ethereum.retesteth; - -import java.nio.file.Path; - -public class RetestethConfiguration { - - private final Path dataPath; - - public RetestethConfiguration(final Path dataPath) { - this.dataPath = dataPath; - } - - Path getDataPath() { - return dataPath; - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java deleted file mode 100644 index 32d4e0bab1..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * 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.ethereum.retesteth; - -import static org.hyperledger.besu.config.JsonUtil.normalizeKeys; - -import org.hyperledger.besu.config.JsonGenesisConfigOptions; -import org.hyperledger.besu.config.JsonUtil; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; -import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; -import org.hyperledger.besu.ethereum.chain.DefaultBlockchain; -import org.hyperledger.besu.ethereum.chain.GenesisState; -import org.hyperledger.besu.ethereum.chain.MutableBlockchain; -import org.hyperledger.besu.ethereum.chain.VariablesStorage; -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; -import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; -import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitValues; -import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.Unstable; -import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.core.MutableWorldState; -import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; -import org.hyperledger.besu.ethereum.eth.manager.EthContext; -import org.hyperledger.besu.ethereum.eth.manager.EthMessages; -import org.hyperledger.besu.ethereum.eth.manager.EthPeers; -import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; -import org.hyperledger.besu.ethereum.eth.sync.SyncMode; -import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; -import org.hyperledger.besu.ethereum.eth.transactions.BlobCache; -import org.hyperledger.besu.ethereum.eth.transactions.ImmutableTransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; -import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolFactory; -import org.hyperledger.besu.ethereum.forkid.ForkIdManager; -import org.hyperledger.besu.ethereum.mainnet.EpochCalculator; -import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; -import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; -import org.hyperledger.besu.ethereum.mainnet.PoWHasher; -import org.hyperledger.besu.ethereum.mainnet.PoWSolution; -import org.hyperledger.besu.ethereum.mainnet.PoWSolver; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; -import org.hyperledger.besu.ethereum.storage.keyvalue.VariablesKeyValueStorage; -import org.hyperledger.besu.ethereum.storage.keyvalue.WorldStatePreimageKeyValueStorage; -import org.hyperledger.besu.ethereum.trie.forest.ForestWorldStateArchive; -import org.hyperledger.besu.ethereum.trie.forest.storage.ForestWorldStateKeyValueStorage; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; -import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.services.kvstore.InMemoryKeyValueStorage; -import org.hyperledger.besu.util.Subscribers; -import org.hyperledger.besu.util.number.Fraction; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Supplier; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.units.bigints.UInt256; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class RetestethContext { - - private static final Logger LOG = LoggerFactory.getLogger(RetestethContext.class); - private static final PoWHasher NO_WORK_HASHER = - (final long nonce, final long number, EpochCalculator epochCalc, final Bytes headerHash) -> - new PoWSolution(nonce, Hash.ZERO, UInt256.ZERO, Hash.ZERO); - public static final int MAX_PEERS = 25; - - private final ReentrantLock contextLock = new ReentrantLock(); - private final BadBlockManager badBlockManager = new BadBlockManager(); - private Address coinbase; - private Bytes extraData; - private MutableBlockchain blockchain; - private ProtocolContext protocolContext; - private BlockchainQueries blockchainQueries; - private ProtocolSchedule protocolSchedule; - private BlockHeaderFunctions blockHeaderFunctions; - private HeaderValidationMode headerValidationMode; - private BlockReplay blockReplay; - private RetestethClock retestethClock; - private MiningParameters miningParameters; - private TransactionPool transactionPool; - private EthScheduler ethScheduler; - private PoWSolver poWSolver; - - private Optional terminalTotalDifficulty; - private Optional mixHash; - - public boolean resetContext( - final String genesisConfigString, final String sealEngine, final Optional clockTime) { - contextLock.lock(); - try { - tearDownContext(); - return buildContext(genesisConfigString, sealEngine, clockTime); - } catch (final Exception e) { - LOG.error("Error shutting down existing runner", e); - return false; - } finally { - contextLock.unlock(); - } - } - - private void tearDownContext() { - try { - if (ethScheduler != null) { - ethScheduler.stop(); - ethScheduler.awaitStop(); - } - } catch (final InterruptedException e) { - throw new RuntimeException(e); - } - } - - private boolean buildContext( - final String genesisConfigString, final String sealEngine, final Optional clockTime) { - final ObjectNode genesisConfig = - normalizeKeys(JsonUtil.objectNodeFromString(genesisConfigString)); - - retestethClock = new RetestethClock(); - clockTime.ifPresent(retestethClock::resetTime); - final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - - terminalTotalDifficulty = - Optional.ofNullable(genesisConfig.get("params")) - .map(n -> n.get("terminaltotaldifficulty")) - .map(JsonNode::asText) - .map(Bytes::fromHexString); - - final JsonGenesisConfigOptions jsonGenesisConfigOptions = - JsonGenesisConfigOptions.fromJsonObject( - JsonUtil.getObjectNode(genesisConfig, "config").get()); - protocolSchedule = - MainnetProtocolSchedule.fromConfig( - jsonGenesisConfigOptions, - EvmConfiguration.DEFAULT, - miningParameters, - badBlockManager, - false, - new NoOpMetricsSystem()); - if ("NoReward".equalsIgnoreCase(sealEngine)) { - protocolSchedule = new NoRewardProtocolScheduleWrapper(protocolSchedule, badBlockManager); - } - blockHeaderFunctions = ScheduleBasedBlockHeaderFunctions.create(protocolSchedule); - - final GenesisState genesisState = GenesisState.fromJson(genesisConfigString, protocolSchedule); - coinbase = genesisState.getBlock().getHeader().getCoinbase(); - extraData = genesisState.getBlock().getHeader().getExtraData(); - mixHash = Optional.ofNullable(genesisState.getBlock().getHeader().getMixHashOrPrevRandao()); - - final WorldStateArchive worldStateArchive = - new ForestWorldStateArchive( - new WorldStateStorageCoordinator( - new ForestWorldStateKeyValueStorage(new InMemoryKeyValueStorage())), - new WorldStatePreimageKeyValueStorage(new InMemoryKeyValueStorage()), - EvmConfiguration.DEFAULT); - final MutableWorldState worldState = worldStateArchive.getMutable(); - genesisState.writeStateTo(worldState); - - blockchain = createInMemoryBlockchain(genesisState.getBlock()); - protocolContext = new ProtocolContext(blockchain, worldStateArchive, null, badBlockManager); - - blockchainQueries = - new BlockchainQueries( - protocolSchedule, blockchain, worldStateArchive, ethScheduler, miningParameters); - - final String sealengine = JsonUtil.getString(genesisConfig, "sealengine", ""); - headerValidationMode = - "NoProof".equals(sealengine) || "NoReward".equals(sealEngine) - ? HeaderValidationMode.LIGHT - : HeaderValidationMode.FULL; - - miningParameters = - ImmutableMiningParameters.builder() - .mutableInitValues( - MutableInitValues.builder() - .coinbase(coinbase) - .extraData(extraData) - .targetGasLimit(blockchain.getChainHeadHeader().getGasLimit()) - .minBlockOccupancyRatio(0.0) - .minTransactionGasPrice(Wei.ZERO) - .build()) - .unstable(Unstable.builder().powJobTimeToLive(1000).maxOmmerDepth(8).build()) - .build(); - miningParameters.setMinTransactionGasPrice(Wei.ZERO); - poWSolver = - ("NoProof".equals(sealengine) || "NoReward".equals(sealEngine)) - ? new PoWSolver( - miningParameters, - NO_WORK_HASHER, - false, - Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator()) - : new PoWSolver( - miningParameters, - PoWHasher.ETHASH_LIGHT, - false, - Subscribers.none(), - new EpochCalculator.DefaultEpochCalculator()); - - blockReplay = - new BlockReplay(protocolSchedule, protocolContext, blockchainQueries.getBlockchain()); - - final Bytes localNodeKey = Bytes.wrap(new byte[64]); - - // mining support - - final Supplier currentProtocolSpecSupplier = - () -> protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()); - final EthPeers ethPeers = - new EthPeers( - "reteseth", - currentProtocolSpecSupplier, - retestethClock, - metricsSystem, - EthProtocolConfiguration.DEFAULT_MAX_MESSAGE_SIZE, - Collections.emptyList(), - localNodeKey, - MAX_PEERS, - MAX_PEERS, - false, - SyncMode.FAST, - new ForkIdManager(blockchain, List.of(), List.of(), false)); - final SyncState syncState = new SyncState(blockchain, ethPeers); - - ethScheduler = new EthScheduler(1, 1, 1, 1, metricsSystem); - final EthContext ethContext = new EthContext(ethPeers, new EthMessages(), ethScheduler); - - final TransactionPoolConfiguration transactionPoolConfiguration = - ImmutableTransactionPoolConfiguration.builder() - .txPoolLimitByAccountPercentage(Fraction.fromFloat(0.004f)) - .build(); - - transactionPool = - TransactionPoolFactory.createTransactionPool( - protocolSchedule, - protocolContext, - ethContext, - retestethClock, - metricsSystem, - syncState, - transactionPoolConfiguration, - new BlobCache(), - MiningParameters.newDefault()); - - if (LOG.isTraceEnabled()) { - LOG.trace("Genesis Block {} ", genesisState.getBlock()); - } - - return true; - } - - private static MutableBlockchain createInMemoryBlockchain(final Block genesisBlock) { - return createInMemoryBlockchain(genesisBlock, new MainnetBlockHeaderFunctions()); - } - - private static MutableBlockchain createInMemoryBlockchain( - final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) { - final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); - final VariablesStorage variablesStorage = - new VariablesKeyValueStorage(new InMemoryKeyValueStorage()); - return DefaultBlockchain.createMutable( - genesisBlock, - new KeyValueStoragePrefixedKeyBlockchainStorage( - keyValueStorage, variablesStorage, blockHeaderFunctions, false), - new NoOpMetricsSystem(), - 100); - } - - public ProtocolSchedule getProtocolSchedule() { - return protocolSchedule; - } - - public BlockHeaderFunctions getBlockHeaderFunctions() { - return blockHeaderFunctions; - } - - public ProtocolContext getProtocolContext() { - return protocolContext; - } - - public EthScheduler getEthScheduler() { - return ethScheduler; - } - - public void setEthScheduler(final EthScheduler ethScheduler) { - this.ethScheduler = ethScheduler; - } - - public long getBlockHeight() { - return blockchain.getChainHeadBlockNumber(); - } - - public ProtocolSpec getProtocolSpec(final BlockHeader blockHeader) { - return getProtocolSchedule().getByBlockHeader(blockHeader); - } - - public BlockHeader getBlockHeader(final long blockNumber) { - return blockchain.getBlockHeader(blockNumber).get(); - } - - public BlockchainQueries getBlockchainQueries() { - return blockchainQueries; - } - - public HeaderValidationMode getHeaderValidationMode() { - return headerValidationMode; - } - - BlockReplay getBlockReplay() { - return blockReplay; - } - - public TransactionPool getTransactionPool() { - return transactionPool; - } - - public MiningParameters getMiningParameters() { - return miningParameters; - } - - public MutableBlockchain getBlockchain() { - return blockchain; - } - - public RetestethClock getRetestethClock() { - return retestethClock; - } - - public Optional getTerminalTotalDifficulty() { - return terminalTotalDifficulty; - } - - public Optional getMixHash() { - return mixHash; - } - - public PoWSolver getEthHashSolver() { - return poWSolver; - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java deleted file mode 100644 index 877c597686..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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.ethereum.retesteth; - -import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; -import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcHttpService; -import org.hyperledger.besu.ethereum.api.jsonrpc.health.HealthService; -import org.hyperledger.besu.ethereum.api.jsonrpc.health.LivenessCheck; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugAccountRange; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.DebugStorageRangeAt; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlockNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBalance; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetBlockByNumber; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetCode; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetTransactionCount; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendRawTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.Web3ClientVersion; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; -import org.hyperledger.besu.ethereum.core.DummySynchronizer; -import org.hyperledger.besu.ethereum.core.Synchronizer; -import org.hyperledger.besu.ethereum.retesteth.methods.TestGetLogHash; -import org.hyperledger.besu.ethereum.retesteth.methods.TestImportRawBlock; -import org.hyperledger.besu.ethereum.retesteth.methods.TestMineBlocks; -import org.hyperledger.besu.ethereum.retesteth.methods.TestModifyTimestamp; -import org.hyperledger.besu.ethereum.retesteth.methods.TestRewindToBlock; -import org.hyperledger.besu.ethereum.retesteth.methods.TestSetChainParams; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.nat.NatService; - -import java.util.Arrays; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import io.vertx.core.Vertx; - -public class RetestethService { - - private final JsonRpcHttpService jsonRpcHttpService; - private final Vertx vertx; - - private final RetestethContext retestethContext; - - public RetestethService( - final String clientVersion, - final RetestethConfiguration retestethConfiguration, - final JsonRpcConfiguration jsonRpcConfiguration) { - vertx = Vertx.vertx(); - retestethContext = new RetestethContext(); - - final BlockResultFactory blockResult = new BlockResultFactory(); - final NatService natService = new NatService(Optional.empty()); - - // Synchronizer needed by RPC methods. Didn't wanna mock it, since this isn't the test module. - Synchronizer sync = new DummySynchronizer(); - - final Map jsonRpcMethods = - mapOf( - new Web3ClientVersion(clientVersion), - new TestSetChainParams(retestethContext), - new TestImportRawBlock(retestethContext), - new EthBlockNumber(retestethContext::getBlockchainQueries, true), - new EthGetBlockByNumber( - retestethContext::getBlockchainQueries, blockResult, sync, true), - new DebugAccountRange(retestethContext::getBlockchainQueries), - new EthGetBalance(retestethContext::getBlockchainQueries), - new EthGetBlockByHash(retestethContext::getBlockchainQueries, blockResult, true), - new EthGetCode(retestethContext::getBlockchainQueries), - new EthGetTransactionCount( - retestethContext::getBlockchainQueries, retestethContext::getTransactionPool), - new DebugStorageRangeAt( - retestethContext::getBlockchainQueries, retestethContext::getBlockReplay, true), - new TestModifyTimestamp(retestethContext), - new EthSendRawTransaction(retestethContext::getTransactionPool, true), - new TestMineBlocks(retestethContext), - new TestGetLogHash(retestethContext), - new TestRewindToBlock(retestethContext)); - - jsonRpcHttpService = - new JsonRpcHttpService( - vertx, - retestethConfiguration.getDataPath(), - jsonRpcConfiguration, - new NoOpMetricsSystem(), - natService, - jsonRpcMethods, - new HealthService(new LivenessCheck()), - HealthService.ALWAYS_HEALTHY); - } - - public void start() { - jsonRpcHttpService.start(); - } - - public void close() { - stop(); - } - - public void stop() { - jsonRpcHttpService.stop(); - vertx.close(); - } - - private static Map mapOf(final JsonRpcMethod... rpcMethods) { - return Arrays.stream(rpcMethods) - .collect(Collectors.toMap(JsonRpcMethod::getName, rpcMethod -> rpcMethod)); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java deleted file mode 100644 index 398d72d665..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; -import org.hyperledger.besu.ethereum.rlp.RLP; -import org.hyperledger.besu.evm.log.Log; - -import java.util.Optional; - -public class TestGetLogHash implements JsonRpcMethod { - private final RetestethContext context; - - public TestGetLogHash(final RetestethContext context) { - this.context = context; - } - - @Override - public String getName() { - return "test_getLogHash"; - } - - @Override - public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { - final Hash txHash; - try { - txHash = requestContext.getRequiredParameter(0, Hash.class); - } catch (JsonRpcParameterException e) { - throw new InvalidJsonRpcParameters( - "Invalid transaction hash parameter (index 0)", - RpcErrorType.INVALID_TRANSACTION_HASH_PARAMS, - e); - } - - final Optional receipt = - context - .getBlockchainQueries() - .transactionReceiptByTransactionHash(txHash, context.getProtocolSchedule()); - return new JsonRpcSuccessResponse( - requestContext.getRequest().getId(), - receipt.map(this::calculateLogHash).orElse(Hash.EMPTY_LIST_HASH).toString()); - } - - private Hash calculateLogHash( - final TransactionReceiptWithMetadata transactionReceiptWithMetadata) { - return Hash.hash( - RLP.encode( - out -> - out.writeList( - transactionReceiptWithMetadata.getReceipt().getLogsList(), Log::writeTo))); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java deleted file mode 100644 index 580b107a8b..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockImporter; -import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; -import org.hyperledger.besu.ethereum.rlp.RLP; -import org.hyperledger.besu.ethereum.rlp.RLPException; - -import java.util.Collections; - -import org.apache.tuweni.bytes.Bytes; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TestImportRawBlock implements JsonRpcMethod { - private static final Logger LOG = LoggerFactory.getLogger(TestImportRawBlock.class); - - public static final String METHOD_NAME = "test_importRawBlock"; - - private final RetestethContext context; - - public TestImportRawBlock(final RetestethContext context) { - this.context = context; - } - - @Override - public String getName() { - return METHOD_NAME; - } - - @Override - public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { - final String input; - try { - input = requestContext.getRequiredParameter(0, String.class); - } catch (JsonRpcParameterException e) { - throw new InvalidJsonRpcParameters( - "Invalid block parameter (index 0)", RpcErrorType.INVALID_BLOCK_PARAMS, e); - } - final ProtocolContext protocolContext = this.context.getProtocolContext(); - - final Block block; - try { - block = - Block.readFrom(RLP.input(Bytes.fromHexString(input)), context.getBlockHeaderFunctions()); - } catch (final RLPException | IllegalArgumentException e) { - LOG.debug("Failed to parse block RLP", e); - return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), RpcErrorType.BLOCK_RLP_IMPORT_ERROR); - } - - // retesteth expects test_rawImportBlock to not only import the block, but append it to head - if (context.getBlockchain().contains(block.getHash())) { - // if we already have the block but it is not head, append it: - context - .getBlockchain() - .appendBlock( - block, - context - .getBlockchain() - .getTxReceipts(block.getHash()) - .orElse(Collections.emptyList())); - } else { - // otherwise attempt to import the block - final BlockImporter blockImporter = - context.getProtocolSpec(block.getHeader()).getBlockImporter(); - final BlockImportResult result = - blockImporter.importBlock( - protocolContext, - block, - context.getHeaderValidationMode(), - context.getHeaderValidationMode()); - if (!result.isImported()) { - LOG.debug("Failed to import block."); - return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), RpcErrorType.BLOCK_IMPORT_ERROR); - } - } - // return success on append or import - return new JsonRpcSuccessResponse( - requestContext.getRequest().getId(), block.getHash().toString()); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java deleted file mode 100644 index 00a27bb7a8..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.blockcreation.PoWBlockCreator; -import org.hyperledger.besu.ethereum.chain.MutableBlockchain; -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockImporter; -import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.mainnet.BlockImportResult; -import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.retesteth.RetestethClock; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; - -public class TestMineBlocks implements JsonRpcMethod { - private final RetestethContext context; - - public TestMineBlocks(final RetestethContext context) { - this.context = context; - } - - @Override - public String getName() { - return "test_mineBlocks"; - } - - @Override - public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { - long blocksToMine = 0; - try { - blocksToMine = requestContext.getRequiredParameter(0, Long.class); - } catch (JsonRpcParameterException e) { - throw new InvalidJsonRpcParameters( - "Invalid blocks to mine (index 0)", RpcErrorType.INVALID_BLOCK_COUNT_PARAMS, e); - } - while (blocksToMine-- > 0) { - if (!mineNewBlock()) { - return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), false); - } - } - - return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); - } - - private boolean mineNewBlock() { - final RetestethClock retesethClock = context.getRetestethClock(); - final ProtocolSchedule protocolSchedule = context.getProtocolSchedule(); - final ProtocolContext protocolContext = context.getProtocolContext(); - final MutableBlockchain blockchain = context.getBlockchain(); - final HeaderValidationMode headerValidationMode = context.getHeaderValidationMode(); - final MiningParameters miningParameters = context.getMiningParameters(); - final PoWBlockCreator blockCreator = - new PoWBlockCreator( - miningParameters, - header -> miningParameters.getExtraData(), - context.getTransactionPool(), - protocolContext, - protocolSchedule, - context.getEthHashSolver(), - context.getEthScheduler()); - final Block block = - blockCreator - .createBlock(retesethClock.instant().getEpochSecond(), blockchain.getChainHeadHeader()) - .getBlock(); - - // advance clock so next mine won't hit the same timestamp - retesethClock.advanceSeconds(1); - - final BlockImporter blockImporter = - protocolSchedule.getByBlockHeader(blockchain.getChainHeadHeader()).getBlockImporter(); - final BlockImportResult result = - blockImporter.importBlock( - protocolContext, block, headerValidationMode, headerValidationMode); - return result.isImported(); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestModifyTimestamp.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestModifyTimestamp.java deleted file mode 100644 index 717cf41b45..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestModifyTimestamp.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; - -public class TestModifyTimestamp implements JsonRpcMethod { - - private final RetestethContext context; - - public TestModifyTimestamp(final RetestethContext context) { - this.context = context; - } - - @Override - public String getName() { - return "test_modifyTimestamp"; - } - - @Override - public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { - final long epochSeconds; - try { - epochSeconds = requestContext.getRequiredParameter(0, Long.class); - } catch (JsonRpcParameterException e) { - throw new InvalidJsonRpcParameters( - "Invalid timestamp parameter (index 0)", RpcErrorType.INVALID_TIMESTAMP_PARAMS, e); - } - context.getRetestethClock().resetTime(epochSeconds); - return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestRewindToBlock.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestRewindToBlock.java deleted file mode 100644 index d9b847af42..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestRewindToBlock.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; - -public class TestRewindToBlock implements JsonRpcMethod { - private final RetestethContext context; - - public static final String METHOD_NAME = "test_rewindToBlock"; - - public TestRewindToBlock(final RetestethContext context) { - this.context = context; - } - - @Override - public String getName() { - return METHOD_NAME; - } - - @Override - public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { - final long blockNumber; - try { - blockNumber = requestContext.getRequiredParameter(0, Long.TYPE); - } catch (JsonRpcParameterException e) { - throw new InvalidJsonRpcParameters( - "Invalid block number parameter (index 0)", RpcErrorType.INVALID_BLOCK_NUMBER_PARAMS, e); - } - - return new JsonRpcSuccessResponse( - requestContext.getRequest().getId(), context.getBlockchain().rewindToBlock(blockNumber)); - } -} diff --git a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java b/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java deleted file mode 100644 index 1446fd939f..0000000000 --- a/ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; - -import java.util.Iterator; -import java.util.Map; -import java.util.Optional; - -import io.vertx.core.json.JsonObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TestSetChainParams implements JsonRpcMethod { - - private static final Logger LOG = LoggerFactory.getLogger(TestSetChainParams.class); - - public static final String METHOD_NAME = "test_setChainParams"; - private final RetestethContext context; - - public TestSetChainParams(final RetestethContext context) { - this.context = context; - } - - @Override - public String getName() { - return METHOD_NAME; - } - - @SuppressWarnings("unchecked") - @Override - public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { - - try { - final JsonObject chainParamsAsJson = - new JsonObject((Map) requestContext.getRequest().getParams()[0]); - final String chainParamsAsString = chainParamsAsJson.encodePrettily(); - LOG.trace("ChainParams {}", chainParamsAsString); - final String genesisFileAsString = modifyGenesisFile(chainParamsAsString); - LOG.trace("Genesis {}", genesisFileAsString); - final boolean result = - context.resetContext( - genesisFileAsString, - chainParamsAsJson.getString("sealEngine", "NoProof"), - Optional.empty()); - - return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result); - } catch (final Exception e) { - LOG.error("Unhandled error", e); - return new JsonRpcErrorResponse( - requestContext.getRequest().getId(), RpcErrorType.INVALID_PARAMS); - } - } - - private static void maybeMove( - final JsonObject src, final String srcName, final JsonObject dest, final String destName) { - if (src.containsKey(srcName)) { - dest.put(destName, src.getValue(srcName)); - src.remove(srcName); - } - } - - private static void maybeMoveToNumber( - final JsonObject src, final String srcName, final JsonObject dest, final String destName) { - if (src.containsKey(srcName)) { - dest.put(destName, Long.decode(src.getString(srcName))); - src.remove(srcName); - } - } - - private static void maybeMoveToNumber( - final JsonObject src, - final String srcName, - final JsonObject dest, - final String destName, - final long defaultValue) { - if (src.containsKey(srcName)) { - dest.put(destName, Long.decode(src.getString(srcName))); - src.remove(srcName); - } else { - dest.put(destName, defaultValue); - } - } - - private static String modifyGenesisFile(final String initialGenesis) { - final JsonObject chainParamsJson = new JsonObject(initialGenesis); - final JsonObject config = new JsonObject(); - chainParamsJson.put("config", config); - final JsonObject params = chainParamsJson.getJsonObject("params"); - final JsonObject genesis = chainParamsJson.getJsonObject("genesis"); - - // Whether sealEngine is NoProof, Ethash, or NoReward the genesis file is the same - final JsonObject ethash = new JsonObject(); - config.put("ethash", ethash); - - maybeMoveToNumber(params, "homesteadForkBlock", config, "homesteadBlock"); - maybeMoveToNumber(params, "daoHardforkBlock", config, "daoForkBlock"); - maybeMoveToNumber(params, "EIP150ForkBlock", config, "eip150Block"); - maybeMoveToNumber(params, "EIP158ForkBlock", config, "eip158Block"); - maybeMoveToNumber(params, "byzantiumForkBlock", config, "byzantiumBlock"); - maybeMoveToNumber(params, "constantinopleForkBlock", config, "constantinopleBlock"); - maybeMoveToNumber(params, "constantinopleFixForkBlock", config, "petersburgBlock"); - maybeMoveToNumber(params, "istanbulForkBlock", config, "istanbulBlock"); - maybeMoveToNumber(params, "muirGlacierForkBlock", config, "muirGlacierBlock"); - maybeMoveToNumber(params, "berlinForkBlock", config, "berlinBlock"); - maybeMoveToNumber(params, "londonForkBlock", config, "londonBlock"); - maybeMoveToNumber(params, "arrowGlacierForkBlock", config, "arrowGlacierBlock"); - maybeMoveToNumber(params, "grayGlacierForkBlock", config, "grayGlacierBlock"); - maybeMoveToNumber(params, "mergeNetSplitForkBlock", config, "mergeNetSplitBlock"); - maybeMoveToNumber(params, "shanghaiForkTime", config, "shanghaiTime"); - maybeMoveToNumber(params, "cancunForkTime", config, "cancunTime"); - maybeMoveToNumber(params, "pragueForkTime", config, "pragueTime"); - maybeMoveToNumber(params, "futureEipsForkTime", config, "futureEipsTime"); - maybeMoveToNumber(params, "experimentalEipsForkTime", config, "experimentalEipsTime"); - maybeMoveToNumber(params, "chainID", config, "chainId", 1); - - maybeMove(genesis, "author", chainParamsJson, "coinbase"); - maybeMove(genesis, "difficulty", chainParamsJson, "difficulty"); - maybeMove(genesis, "extraData", chainParamsJson, "extraData"); - maybeMove(genesis, "gasLimit", chainParamsJson, "gasLimit"); - maybeMove(genesis, "mixHash", chainParamsJson, "mixHash"); - maybeMove(genesis, "nonce", chainParamsJson, "nonce"); - maybeMove(genesis, "timestamp", chainParamsJson, "timestamp"); - maybeMove(chainParamsJson, "accounts", chainParamsJson, "alloc"); - maybeMove(genesis, "baseFeePerGas", chainParamsJson, "baseFeePerGas"); - - // strip out precompiles with zero balance - final JsonObject alloc = chainParamsJson.getJsonObject("alloc"); - final Iterator fieldNamesIter = alloc.fieldNames().iterator(); - while (fieldNamesIter.hasNext()) { - final String address = fieldNamesIter.next(); - final JsonObject account = alloc.getJsonObject(address); - if (account.containsKey("precompiled") && !account.containsKey("balance")) { - fieldNamesIter.remove(); - } - } - - return chainParamsJson.encodePrettily(); - } -} diff --git a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java b/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java deleted file mode 100644 index b156f2294d..0000000000 --- a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; -import org.hyperledger.besu.plugin.services.rpc.RpcResponseType; - -import java.io.IOException; - -import com.google.common.base.Charsets; -import com.google.common.io.Resources; -import io.vertx.core.json.JsonObject; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class TestImportRawBlockTest { - private TestImportRawBlock test_importRawBlock; - private TestRewindToBlock test_rewindToBlock; - private RetestethContext context; - - @BeforeEach - public void setupClass() throws IOException { - context = new RetestethContext(); - test_importRawBlock = new TestImportRawBlock(context); - test_rewindToBlock = new TestRewindToBlock(context); - final TestSetChainParams test_setChainParams = new TestSetChainParams(context); - final String chainParamsJsonString = - Resources.toString( - TestSetChainParamsTest.class.getResource("multimpleBalanceInstructionChainParams.json"), - Charsets.UTF_8); - final JsonObject chainParamsJson = new JsonObject(chainParamsJsonString); - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestSetChainParams.METHOD_NAME, new Object[] {chainParamsJson.getMap()})); - - assertThat(test_setChainParams.response(request)) - .isEqualTo(new JsonRpcSuccessResponse(null, true)); - } - - @Test - public void testMissingParent() { - final String rawBlockRLPString = - "0xf9045df901f9a0e38bef3dadb98e856ea82c7e9813b76a6ec8d9cf60694dd65d800a1669c1a1fda03770bba814f8cc5534ab5e40bdb3fe51866b537805c5577888091766e621fc13948888f1f195afa192cfee860698584c030f4c9db1a019ce64082807650d3d01ac60cd16a583e9472dcc0ccb8f39dd867e317cf025dda09735e49acaddb4d8338ed33df8dd006449b20b85e89e47224ac8ec8f7ea26071a0056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200000483301fd28252088454c99c2142a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f86003018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0a7b7f2fa93025fc1e6aa18c1aa07c32a456439754e196cb74f2f7d12cf3e840da02078cf840fb25fc3d858b2a85b622f21be0588b5c5d81d433427f6470e06a4a7f901faf901f7a0f88512d9e022357594866c44ecaa2fc9cb48f34d1987e401109400761aeb898da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794bcde5374fce5edbc8e2a8697c15331677e6ebf0ba0fe87abb0d3ab38d4eb64405de03db5245b0d40c4b85d8a1b5028ada8643de2dba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000002833007cf808454c9945142a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"; - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestImportRawBlock.METHOD_NAME, new Object[] {rawBlockRLPString})); - - final var response = test_importRawBlock.response(request); - assertThat(response.getType()).isEqualTo(RpcResponseType.ERROR); - assertThat(((JsonRpcErrorResponse) response).getErrorType()) - .isEqualTo(RpcErrorType.BLOCK_IMPORT_ERROR); - } - - @Test - public void testBadBlock() { - final String rawBlockRLPString = "0xf9045df901f9a08"; - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestImportRawBlock.METHOD_NAME, new Object[] {rawBlockRLPString})); - - final var response = test_importRawBlock.response(request); - assertThat(response.getType()).isEqualTo(RpcResponseType.ERROR); - assertThat(((JsonRpcErrorResponse) response).getErrorType()) - .isEqualTo(RpcErrorType.BLOCK_RLP_IMPORT_ERROR); - } - - @Test - public void testGoodBlock() { - final String rawBlockRLPString = - "0xf90262f901faa0e38bef3dadb98e856ea82c7e9813b76a6ec8d9cf60694dd65d800a1669c1a1fda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a06e6be3f633fe0399cb17a9d8238b988a39bd9ab3e0ac0820f4df705a1ee37536a06fb77a9ddaa64a8e161b643d05533a4093f2be900ad06279b1b56b3bcee3b979a04b33fa3c9c50b7b9a4500f5c0b1e71ab43362abc81c2cf31fd2b54acf7d750d8b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefba83016b66845db7320980a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f860800a830249f094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0d42a045ac77a6d4676dd5fbc5104ed7471b6cef2465cfefaa52919b340f942a9a06e4d319aea79e45cde79d337e6edf849ceac505cab65dd41a572cab132d4dccac0"; - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestImportRawBlock.METHOD_NAME, new Object[] {rawBlockRLPString})); - - final var response = test_importRawBlock.response(request); - assertThat(response.getType()).isEqualTo(RpcResponseType.SUCCESS); - } - - @Test - public void testReimportExistingBlock() { - final String rawBlockRLPString = - "0xf90262f901faa0e38bef3dadb98e856ea82c7e9813b76a6ec8d9cf60694dd65d800a1669c1a1fda01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a06e6be3f633fe0399cb17a9d8238b988a39bd9ab3e0ac0820f4df705a1ee37536a06fb77a9ddaa64a8e161b643d05533a4093f2be900ad06279b1b56b3bcee3b979a04b33fa3c9c50b7b9a4500f5c0b1e71ab43362abc81c2cf31fd2b54acf7d750d8b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefba83016b66845db7320980a00000000000000000000000000000000000000000000000000000000000000000880000000000000000f862f860800a830249f094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0d42a045ac77a6d4676dd5fbc5104ed7471b6cef2465cfefaa52919b340f942a9a06e4d319aea79e45cde79d337e6edf849ceac505cab65dd41a572cab132d4dccac0"; - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestImportRawBlock.METHOD_NAME, new Object[] {rawBlockRLPString})); - - final JsonRpcRequestContext requestRewind = - new JsonRpcRequestContext( - new JsonRpcRequest("2.0", TestRewindToBlock.METHOD_NAME, new Object[] {0L})); - - final var response = test_importRawBlock.response(request); - assertThat(response.getType()).isEqualTo(RpcResponseType.SUCCESS); - final var rewindResponse = test_rewindToBlock.response(requestRewind); - assertThat(rewindResponse.getType()).isEqualTo(RpcResponseType.SUCCESS); - final var reimportResponse = test_importRawBlock.response(request); - assertThat(reimportResponse.getType()).isEqualTo(RpcResponseType.SUCCESS); - - assertThat(context.getBlockchain().getChainHead().getHeight()).isEqualTo(1L); - } -} diff --git a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java b/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java deleted file mode 100644 index f376fa0c25..0000000000 --- a/ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.ethereum.retesteth.methods; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.retesteth.RetestethContext; - -import java.io.IOException; - -import com.google.common.base.Charsets; -import com.google.common.io.Resources; -import io.vertx.core.json.JsonObject; -import org.apache.tuweni.units.bigints.UInt256; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -public class TestSetChainParamsTest { - - private static RetestethContext context; - private static TestSetChainParams test_setChainParams; - - @BeforeAll - public static void setupClass() { - context = new RetestethContext(); - test_setChainParams = new TestSetChainParams(context); - } - - @Test - public void testValidateGenesisImport() throws IOException { - final String chainParamsJsonString = - Resources.toString( - TestSetChainParamsTest.class.getResource("multimpleBalanceInstructionChainParams.json"), - Charsets.UTF_8); - final JsonObject chainParamsJson = new JsonObject(chainParamsJsonString); - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestSetChainParams.METHOD_NAME, new Object[] {chainParamsJson.getMap()})); - - assertThat(test_setChainParams.response(request)) - .isEqualTo(new JsonRpcSuccessResponse(null, true)); - - final BlockHeader blockHeader = context.getBlockHeader(0); - - assertThat(blockHeader.getLogsBloom().toString()) - .isEqualTo( - "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); - assertThat(blockHeader.getCoinbase().toString()) - .isEqualTo("0x8888f1f195afa192cfee860698584c030f4c9db1"); - assertThat(blockHeader.getDifficulty()).isEqualTo(UInt256.fromHexString("0x20000")); - assertThat(blockHeader.getExtraData().toHexString()).isEqualTo("0x42"); - assertThat(blockHeader.getGasLimit()).isEqualTo(3141592); - assertThat(blockHeader.getGasUsed()).isEqualTo(0); - assertThat(blockHeader.getMixHash().toString()) - .isEqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - assertThat(blockHeader.getNonce()).isEqualTo(0x0102030405060708L); - assertThat(blockHeader.getNumber()).isEqualTo(0); - assertThat(blockHeader.getParentHash().toString()) - .isEqualTo("0x0000000000000000000000000000000000000000000000000000000000000000"); - assertThat(blockHeader.getReceiptsRoot().toString()) - .isEqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - assertThat(blockHeader.getStateRoot().toString()) - .isEqualTo("0xf403922bfd555a9223f68fc755564004e20d78bb42aae647e867e3b23c48beba"); - assertThat(blockHeader.getTimestamp()).isEqualTo(0x54c98c81); - assertThat(blockHeader.getTransactionsRoot().toString()) - .isEqualTo("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - assertThat(blockHeader.getOmmersHash().toString()) - .isEqualTo("0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - } - - @Test - public void testValidate1559GenesisImport() throws IOException { - final String chainParamsJsonString = - Resources.toString( - TestSetChainParamsTest.class.getResource("1559ChainParams.json"), Charsets.UTF_8); - final JsonObject chainParamsJson = new JsonObject(chainParamsJsonString); - - final JsonRpcRequestContext request = - new JsonRpcRequestContext( - new JsonRpcRequest( - "2.0", TestSetChainParams.METHOD_NAME, new Object[] {chainParamsJson.getMap()})); - - assertThat(test_setChainParams.response(request)) - .isEqualTo(new JsonRpcSuccessResponse(null, true)); - - final BlockHeader blockHeader = context.getBlockHeader(0); - assertThat(blockHeader.getDifficulty()).isEqualTo(UInt256.fromHexString("0x20000")); - assertThat(blockHeader.getGasLimit()).isEqualTo(1234L); - assertThat(blockHeader.getBaseFee()).hasValue(Wei.of(12345L)); - assertThat(blockHeader.getExtraData().toHexString()).isEqualTo("0x00"); - assertThat(blockHeader.getTimestamp()).isEqualTo(0l); - assertThat(blockHeader.getNonce()).isEqualTo(0L); - assertThat(blockHeader.getMixHash().toHexString()) - .isEqualTo("0x0000000000000000000000000000000000000000000000000000000000000000"); - } -} diff --git a/ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/1559ChainParams.json b/ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/1559ChainParams.json deleted file mode 100644 index 95535e269f..0000000000 --- a/ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/1559ChainParams.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "genesis" : { - "author" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "difficulty" : "0x020000", - "gasLimit" : "0x04d2", - "baseFeePerGas" : "0x3039", - "extraData" : "0x00", - "timestamp" : "0x00", - "nonce" : "0x0000000000000000", - "mixHash" : "0x0000000000000000000000000000000000000000000000000000000000000000" - }, - "params": { - "EIP150ForkBlock": "0x00", - "EIP158ForkBlock": "0x00", - "byzantiumForkBlock": "0x00", - "homesteadForkBlock": "0x00", - "londonForkBlock": "0x00" - }, - "sealEngine": "NoProof", - "accounts": {} -} \ No newline at end of file diff --git a/ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/multimpleBalanceInstructionChainParams.json b/ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/multimpleBalanceInstructionChainParams.json deleted file mode 100644 index 0cb0cfc960..0000000000 --- a/ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/multimpleBalanceInstructionChainParams.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "accounts": { - "0x0000000000000000000000000000000000000001": { - "precompiled": { - "linear": { - "base": 3000, - "word": 0 - }, - "name": "ecrecover" - } - }, - "0x0000000000000000000000000000000000000002": { - "precompiled": { - "linear": { - "base": 60, - "word": 12 - }, - "name": "sha256" - } - }, - "0x0000000000000000000000000000000000000003": { - "precompiled": { - "linear": { - "base": 600, - "word": 120 - }, - "name": "sha256" - } - }, - "0x0000000000000000000000000000000000000004": { - "precompiled": { - "linear": { - "base": 15, - "word": 3 - }, - "name": "identity" - } - }, - "0x0000000000000000000000000000000000000005": { - "precompiled": { - "name": "modexp" - } - }, - "0x0000000000000000000000000000000000000006": { - "precompiled": { - "linear": { - "base": 500, - "word": 0 - }, - "name": "alt_bn128_G1_add" - } - }, - "0x0000000000000000000000000000000000000007": { - "precompiled": { - "linear": { - "base": 40000, - "word": 0 - }, - "name": "alt_bn128_G1_mul" - } - }, - "0x0000000000000000000000000000000000000008": { - "precompiled": { - "name": "alt_bn128_pairing_product" - } - }, - "0x095e7baea6a6c7c4c2dfeb977efac326af552d87": { - "balance": "0x0186a0", - "code": "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0b31600055738888f1f195afa192cfee860698584c030f4c9db13160015573a94f5374fce5edbc8e2a8697c15331677e6ebf0b31600255738888f1f195afa192cfee860698584c030f4c9db13160035573095e7baea6a6c7c4c2dfeb977efac326af552d8731600555", - "nonce": "0x00", - "storage": {} - }, - "0x195e7baea6a6c7c4c2dfeb977efac326af552d87": { - "balance": "0x0186a0", - "code": "0x73a94f5374fce5edbc8e2a8697c15331677e6ebf0b31600055738888f1f195afa192cfee860698584c030f4c9db13160015573a94f5374fce5edbc8e2a8697c15331677e6ebf0b31600255738888f1f195afa192cfee860698584c030f4c9db13160035573095e7baea6a6c7c4c2dfeb977efac326af552d873160045573195e7baea6a6c7c4c2dfeb977efac326af552d8731600555", - "nonce": "0x00", - "storage": {} - }, - "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0x1748721582", - "code": "0x", - "nonce": "0x00", - "storage": {} - } - }, - "genesis": { - "author": "0x8888f1f195afa192cfee860698584c030f4c9db1", - "difficulty": "0x020000", - "extraData": "0x42", - "gasLimit": "0x2fefd8", - "mixHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "nonce": "0x0102030405060708", - "timestamp": "0x54c98c81" - }, - "params": { - "EIP150ForkBlock": "0x00", - "EIP158ForkBlock": "0x00", - "byzantiumForkBlock": "0x00", - "homesteadForkBlock": "0x00" - }, - "sealEngine": "NoProof" -} \ No newline at end of file From 7eb7b870c34be8801673ae1aee627661183bce4f Mon Sep 17 00:00:00 2001 From: Justin Florentine Date: Thu, 31 Oct 2024 19:26:41 -0400 Subject: [PATCH 9/9] Refactoring around MiningParameters (#7798) decoupled parent block header from block creators optionalized some fields of ProtocolSchedule constructor, which will allow us to reduce number of constructors later. Refactored JsonBlockImporterTest so it can provide a BesuComponent ProtocolScheduleBuilder optionalizes the default chainid Blocks SubCommand is now Dagger aware Creates but rarely uses ProtocolSpec and ProtocolSchedule modules. Deeper adoption pending. Adds a Coinbase module with fixed values for use in testing. Introduces an EthereumCoreComponent, to be used as a subcomponent of BesuComponent in the future. Introduces a MiningParameters module with common static values used by tests. Removes MiningParameters static constructor. --------- Signed-off-by: Justin Florentine Signed-off-by: jflo --- .../dsl/node/ThreadBesuNodeRunner.java | 29 +++- acceptance-tests/tests/build.gradle | 4 + .../CliqueBesuControllerBuilder.java | 1 - .../MainnetBesuControllerBuilder.java | 10 +- .../besu/services/BesuConfigurationImpl.java | 2 +- .../chainimport/JsonBlockImporterTest.java | 34 ++++- config/build.gradle | 2 + .../clique/CliqueProtocolSchedule.java | 2 +- .../bft/BaseBftProtocolScheduleBuilder.java | 3 +- .../CombinedProtocolScheduleFactoryTest.java | 2 +- consensus/ibft/build.gradle | 2 + .../ibft/IbftProtocolScheduleTest.java | 140 +++++++++++++----- .../IbftBlockHeightManagerTest.java | 2 +- .../merge/MergeProtocolSchedule.java | 2 +- .../QbftBlockHeightManagerTest.java | 2 +- .../AbstractBlockCreatorTest.java | 2 +- ...FeeMarketBlockTransactionSelectorTest.java | 3 +- ...FeeMarketBlockTransactionSelectorTest.java | 3 +- .../blockcreation/PoWBlockCreatorTest.java | 9 +- ethereum/core/build.gradle | 2 + .../components/ProtocolScheduleModule.java | 100 +++++++++++++ .../components/ProtocolSpecModule.java | 51 +++++++ .../core/components/CoinbaseModule.java | 31 ++++ .../components/EthereumCoreComponent.java | 32 ++++ .../components/MiningParametersModule.java | 64 ++++++++ .../FixedDifficultyProtocolSchedule.java | 8 +- .../mainnet/MainnetProtocolSchedule.java | 39 ++--- .../mainnet/ProtocolScheduleBuilder.java | 57 +------ .../core/ExecutionContextTestFixture.java | 2 +- .../core/ProtocolScheduleFixture.java | 8 +- .../mainnet/DefaultProtocolScheduleTest.java | 2 +- .../mainnet/ProtocolScheduleBuilderTest.java | 4 +- .../AbstractTransactionPoolTestBase.java | 2 +- .../TransactionPoolFactoryTest.java | 2 +- .../evmtool/MainnetGenesisFileModule.java | 2 +- ethereum/referencetests/build.gradle | 2 + .../ReferenceTestProtocolSchedules.java | 3 +- .../mainnet/DifficultyCalculatorTests.java | 28 ++-- 38 files changed, 537 insertions(+), 156 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolScheduleModule.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolSpecModule.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/CoinbaseModule.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/EthereumCoreComponent.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/MiningParametersModule.java diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java index 42c0df73c7..036a1e0019 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java @@ -57,6 +57,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.MetricCategoryRegistryImpl; import org.hyperledger.besu.metrics.MetricsSystemModule; import org.hyperledger.besu.metrics.ObservableMetricsSystem; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.plugin.data.EnodeURL; import org.hyperledger.besu.plugin.services.BesuConfiguration; @@ -406,9 +407,18 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { } } + @Module + public static class ThreadBesuNodeRunnerModule { + @Provides + @Singleton + public ThreadBesuNodeRunner provideThreadBesuNodeRunner() { + return new ThreadBesuNodeRunner(); + } + } + @Module @SuppressWarnings("CloseableProvides") - static class BesuControllerModule { + public static class BesuControllerModule { @Provides @Singleton public SynchronizerConfiguration provideSynchronizationConfiguration() { @@ -579,7 +589,16 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { } @Module - static class MockBesuCommandModule { + public static class ObservableMetricsSystemModule { + @Provides + @Singleton + public ObservableMetricsSystem provideObservableMetricsSystem() { + return new NoOpMetricsSystem(); + } + } + + @Module + public static class MockBesuCommandModule { @Provides BesuCommand provideBesuCommand(final BesuPluginContextImpl pluginContext) { @@ -610,6 +629,8 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { modules = { ThreadBesuNodeRunner.BesuControllerModule.class, ThreadBesuNodeRunner.MockBesuCommandModule.class, + ThreadBesuNodeRunner.ObservableMetricsSystemModule.class, + ThreadBesuNodeRunnerModule.class, BonsaiCachedMerkleTrieLoaderModule.class, MetricsSystemModule.class, ThreadBesuNodeRunner.BesuNodeProviderModule.class, @@ -625,5 +646,9 @@ public class ThreadBesuNodeRunner implements BesuNodeRunner { RpcEndpointServiceImpl rpcEndpointService(); BlockchainServiceImpl blockchainService(); + + ObservableMetricsSystem getObservableMetricsSystem(); + + ThreadBesuNodeRunner getThreadBesuNodeRunner(); } } diff --git a/acceptance-tests/tests/build.gradle b/acceptance-tests/tests/build.gradle index fdc7735452..b6c388172e 100644 --- a/acceptance-tests/tests/build.gradle +++ b/acceptance-tests/tests/build.gradle @@ -31,6 +31,7 @@ dependencies { api 'org.slf4j:slf4j-api' implementation project(':crypto:algorithms') + implementation project(':ethereum:eth') testImplementation project(':acceptance-tests:dsl') testImplementation project(':acceptance-tests:test-plugins') @@ -42,6 +43,7 @@ dependencies { testImplementation project(':ethereum:api') testImplementation project(':ethereum:core') testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') + testImplementation project(':ethereum:eth') testImplementation project(':ethereum:p2p') testImplementation project(':ethereum:permissioning') testImplementation project(':ethereum:rlp') @@ -78,6 +80,8 @@ dependencies { testImplementation 'org.web3j:besu' testImplementation 'org.web3j:core' testImplementation 'org.wiremock:wiremock' + testImplementation 'com.google.dagger:dagger' + testAnnotationProcessor 'com.google.dagger:dagger-compiler' testImplementation project(path: ':acceptance-tests:tests:shanghai') } diff --git a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java index b4ada60549..77bf60b034 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java @@ -132,7 +132,6 @@ public class CliqueBesuControllerBuilder extends BesuControllerBuilder { genesisConfigOptions, forksSchedule, nodeKey, - privacyParameters, isRevertReasonEnabled, evmConfiguration, miningParameters, diff --git a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java index e0fbed608a..dbd2c5904a 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java @@ -31,6 +31,8 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import java.util.Optional; + /** The Mainnet besu controller builder. */ public class MainnetBesuControllerBuilder extends BesuControllerBuilder { @@ -95,10 +97,10 @@ public class MainnetBesuControllerBuilder extends BesuControllerBuilder { protected ProtocolSchedule createProtocolSchedule() { return MainnetProtocolSchedule.fromConfig( genesisConfigOptions, - privacyParameters, - isRevertReasonEnabled, - evmConfiguration, - miningParameters, + Optional.of(privacyParameters), + Optional.of(isRevertReasonEnabled), + Optional.of(evmConfiguration), + super.miningParameters, badBlockManager, isParallelTxProcessingEnabled, metricsSystem); diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java index 0adbda23b7..6d9a5410c4 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java @@ -31,7 +31,7 @@ public class BesuConfigurationImpl implements BesuConfiguration { private DataStorageConfiguration dataStorageConfiguration; // defaults - private MiningParameters miningParameters = MiningParameters.newDefault(); + private MiningParameters miningParameters; private Optional rpcHttpHost = Optional.of("http://localhost"); private Optional rpcHttpPort = Optional.of(8545); diff --git a/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java b/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java index 7b1a4bc7d2..bc52cb60be 100644 --- a/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java +++ b/besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java @@ -17,9 +17,10 @@ package org.hyperledger.besu.chainimport; import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; +import org.hyperledger.besu.components.BesuCommandModule; import org.hyperledger.besu.components.BesuComponent; +import org.hyperledger.besu.components.BesuPluginContextModule; import org.hyperledger.besu.config.GenesisConfigFile; import org.hyperledger.besu.config.JsonUtil; import org.hyperledger.besu.controller.BesuController; @@ -36,12 +37,16 @@ import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters.MutableInitV import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.components.MiningParametersModule; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.sync.SyncMode; import org.hyperledger.besu.ethereum.eth.sync.SynchronizerConfiguration; +import org.hyperledger.besu.ethereum.eth.transactions.BlobCacheModule; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.p2p.config.NetworkingConfiguration; +import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.cache.BonsaiCachedMerkleTrieLoader; import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.MetricsSystemModule; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.testutil.TestClock; @@ -52,9 +57,13 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import javax.inject.Singleton; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.io.Resources; +import dagger.Component; +import dagger.Module; +import dagger.Provides; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -465,7 +474,28 @@ public abstract class JsonBlockImporterTest { .gasLimitCalculator(GasLimitCalculator.constant()) .evmConfiguration(EvmConfiguration.DEFAULT) .networkConfiguration(NetworkingConfiguration.create()) - .besuComponent(mock(BesuComponent.class)) + .besuComponent(DaggerJsonBlockImporterTest_JsonBlockImportComponent.builder().build()) .build(); } + + @Module + public static class JsonBlockImporterModule { + + @Provides + BonsaiCachedMerkleTrieLoader provideCachedMerkleTrieLoaderModule() { + return new BonsaiCachedMerkleTrieLoader(new NoOpMetricsSystem()); + } + } + + @Singleton + @Component( + modules = { + BesuCommandModule.class, + MiningParametersModule.class, + MetricsSystemModule.class, + JsonBlockImporterModule.class, + BesuPluginContextModule.class, + BlobCacheModule.class + }) + interface JsonBlockImportComponent extends BesuComponent {} } diff --git a/config/build.gradle b/config/build.gradle index a78b9a7105..e269ce51fc 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -36,11 +36,13 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' + implementation 'com.google.dagger:dagger' implementation 'info.picocli:picocli' implementation 'io.tmio:tuweni-bytes' implementation 'io.tmio:tuweni-units' implementation "org.immutables:value-annotations" annotationProcessor "org.immutables:value" + annotationProcessor 'com.google.dagger:dagger-compiler' testImplementation project(':testutil') diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java index cd19755638..551a8c3f44 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java @@ -110,7 +110,7 @@ public class CliqueProtocolSchedule { return new ProtocolScheduleBuilder( config, - DEFAULT_CHAIN_ID, + Optional.of(DEFAULT_CHAIN_ID), specAdapters, privacyParameters, isRevertReasonEnabled, diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java index 311bf30fae..0df63452b3 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java @@ -38,6 +38,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.function.Function; /** Defines the protocol behaviours for a blockchain using a BFT consensus mechanism. */ @@ -90,7 +91,7 @@ public abstract class BaseBftProtocolScheduleBuilder { final ProtocolSchedule protocolSchedule = new ProtocolScheduleBuilder( config, - DEFAULT_CHAIN_ID, + Optional.of(DEFAULT_CHAIN_ID), specAdapters, privacyParameters, isRevertReasonEnabled, diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java index 02689d52af..659337bdd2 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java @@ -172,7 +172,7 @@ public class CombinedProtocolScheduleFactoryTest { final ProtocolScheduleBuilder protocolScheduleBuilder = new ProtocolScheduleBuilder( genesisConfigOptions, - BigInteger.ONE, + Optional.of(BigInteger.ONE), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/consensus/ibft/build.gradle b/consensus/ibft/build.gradle index da6304c4e5..e95c866143 100644 --- a/consensus/ibft/build.gradle +++ b/consensus/ibft/build.gradle @@ -76,4 +76,6 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' testImplementation 'org.mockito:mockito-junit-jupiter' + testImplementation 'com.google.dagger:dagger' + testAnnotationProcessor 'com.google.dagger:dagger-compiler' } diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java index e5551ff3f3..a5510ea80a 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java @@ -22,7 +22,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import org.hyperledger.besu.config.BftConfigOptions; -import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.JsonGenesisConfigOptions; import org.hyperledger.besu.config.JsonQbftConfigOptions; import org.hyperledger.besu.config.JsonUtil; @@ -43,28 +42,36 @@ import org.hyperledger.besu.ethereum.core.MilestoneStreamingProtocolSchedule; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Util; +import org.hyperledger.besu.ethereum.core.components.EthereumCoreComponent; import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.math.BigInteger; -import java.util.Collection; import java.util.List; +import javax.inject.Singleton; +import dagger.Component; +import dagger.Module; +import dagger.Provides; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class IbftProtocolScheduleTest { - private final BftExtraDataCodec bftExtraDataCodec = mock(BftExtraDataCodec.class); - private final BftExtraData bftExtraData = mock(BftExtraData.class); - private final NodeKey proposerNodeKey = NodeKeyUtils.generate(); - private final Address proposerAddress = Util.publicKeyToAddress(proposerNodeKey.getPublicKey()); - private final List
validators = singletonList(proposerAddress); + + private ProtocolContext protocolContext; + private List
validators; + private NodeKey proposerNodeKey; + private TestEthCoreComponent component; @BeforeEach public void setup() { - when(bftExtraDataCodec.decode(any())).thenReturn(bftExtraData); - when(bftExtraData.getValidators()).thenReturn(validators); + TestEthCoreComponent component = + DaggerIbftProtocolScheduleTest_TestEthCoreComponent.builder().build(); + this.component = component; + this.protocolContext = component.protocolContext(); + this.validators = component.validators(); + this.proposerNodeKey = component.nodeKey(); } @Test @@ -81,24 +88,41 @@ public class IbftProtocolScheduleTest { .buildHeader(); final BftProtocolSchedule schedule = - createProtocolSchedule( - JsonGenesisConfigOptions.fromJsonObject(JsonUtil.createEmptyObjectNode()), - List.of( - new ForkSpec<>(0, JsonQbftConfigOptions.DEFAULT), - new ForkSpec<>(1, arbitraryTransition), - new ForkSpec<>(2, JsonQbftConfigOptions.DEFAULT))); + createProtocolSchedule(component.bftExtraDataCodec(), arbitraryTransition); assertThat(new MilestoneStreamingProtocolSchedule(schedule).streamMilestoneBlocks().count()) .isEqualTo(3); - assertThat(validateHeader(schedule, validators, parentHeader, blockHeader, 0)).isTrue(); - assertThat(validateHeader(schedule, validators, parentHeader, blockHeader, 1)).isTrue(); - assertThat(validateHeader(schedule, validators, parentHeader, blockHeader, 2)).isTrue(); + assertThat(validateHeader(schedule, parentHeader, blockHeader, 0)).isTrue(); + assertThat(validateHeader(schedule, parentHeader, blockHeader, 1)).isTrue(); + assertThat(validateHeader(schedule, parentHeader, blockHeader, 2)).isTrue(); + } + + private boolean validateHeader( + final BftProtocolSchedule schedule, + final BlockHeader parentHeader, + final BlockHeader blockHeader, + final int block) { + return schedule + .getByBlockNumberOrTimestamp(block, blockHeader.getTimestamp()) + .getBlockHeaderValidator() + .validateHeader( + blockHeader, parentHeader, this.protocolContext, HeaderValidationMode.LIGHT); } private BftProtocolSchedule createProtocolSchedule( - final GenesisConfigOptions genesisConfig, final List> forks) { + final BftExtraDataCodec bftExtraDataCodec, + final MutableBftConfigOptions arbitraryTransition) { + + var genesisConfig = JsonGenesisConfigOptions.fromJsonObject(JsonUtil.createEmptyObjectNode()); + ForksSchedule forkSched = + new ForksSchedule<>( + List.of( + new ForkSpec<>(0, JsonQbftConfigOptions.DEFAULT), + new ForkSpec<>(1, arbitraryTransition), + new ForkSpec<>(2, JsonQbftConfigOptions.DEFAULT))); + return IbftProtocolScheduleBuilder.create( genesisConfig, - new ForksSchedule<>(forks), + forkSched, PrivacyParameters.DEFAULT, false, bftExtraDataCodec, @@ -109,24 +133,66 @@ public class IbftProtocolScheduleTest { new NoOpMetricsSystem()); } - private boolean validateHeader( - final BftProtocolSchedule schedule, - final List
validators, - final BlockHeader parentHeader, - final BlockHeader blockHeader, - final int block) { - return schedule - .getByBlockNumberOrTimestamp(block, blockHeader.getTimestamp()) - .getBlockHeaderValidator() - .validateHeader( - blockHeader, parentHeader, protocolContext(validators), HeaderValidationMode.LIGHT); + @Module + static class IbftProtocolScheduleModule { + @Provides + @Singleton + NodeKey nodeKey() { + return NodeKeyUtils.generate(); + } + + @Provides + Address provideProposerAddress(final NodeKey proposerNodeKey) { + return Util.publicKeyToAddress(proposerNodeKey.getPublicKey()); + } + + @Provides + List
provideValidators(final Address proposerAddress) { + return singletonList(proposerAddress); + } + + @Provides + public BftExtraData mockBftExtraData(final List
validators) { + BftExtraData bftExtraData = mock(BftExtraData.class); + when(bftExtraData.getValidators()).thenReturn(validators); + return bftExtraData; + } + + @Provides + public BftExtraDataCodec mockBftExtraDataCodec(final BftExtraData bftExtraData) { + BftExtraDataCodec bftExtraDataCodec = mock(BftExtraDataCodec.class); + when(bftExtraDataCodec.decode(any())).thenReturn(bftExtraData); + return bftExtraDataCodec; + } + + @Provides + ProtocolContext protocolContext( + final List
validators, final BftExtraDataCodec bftExtraDataCodec) { + return new ProtocolContext( + null, + null, + setupContextWithBftExtraDataEncoder(BftContext.class, validators, bftExtraDataCodec), + new BadBlockManager()); + } + } + + @Singleton + @Component(modules = {NoMiningParamters.class, IbftProtocolScheduleModule.class}) + interface TestEthCoreComponent extends EthereumCoreComponent { + ProtocolContext protocolContext(); + + List
validators(); + + NodeKey nodeKey(); + + BftExtraDataCodec bftExtraDataCodec(); } - private ProtocolContext protocolContext(final Collection
validators) { - return new ProtocolContext( - null, - null, - setupContextWithBftExtraDataEncoder(BftContext.class, validators, bftExtraDataCodec), - new BadBlockManager()); + @Module + static class NoMiningParamters { + @Provides + MiningParameters provideMiningParameters() { + return MiningParameters.MINING_DISABLED; + } } } diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java index b9f57debb6..9ca5b0b8e1 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java @@ -180,7 +180,7 @@ public class IbftBlockHeightManagerTest { final ProtocolScheduleBuilder protocolScheduleBuilder = new ProtocolScheduleBuilder( new StubGenesisConfigOptions(), - BigInteger.ONE, + Optional.empty(), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java index abbc3b130a..f794152a78 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java @@ -101,7 +101,7 @@ public class MergeProtocolSchedule { return new ProtocolScheduleBuilder( config, - DEFAULT_CHAIN_ID, + Optional.of(DEFAULT_CHAIN_ID), new ProtocolSpecAdapters(postMergeModifications), privacyParameters, isRevertReasonEnabled, diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java index 190c87e020..23321f23cc 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java @@ -182,7 +182,7 @@ public class QbftBlockHeightManagerTest { final ProtocolScheduleBuilder protocolScheduleBuilder = new ProtocolScheduleBuilder( new StubGenesisConfigOptions(), - BigInteger.ONE, + Optional.of(BigInteger.ONE), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java index d30349e3d0..727cfd440f 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java @@ -304,7 +304,7 @@ abstract class AbstractBlockCreatorTest { .protocolSchedule( new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(42), + Optional.of(BigInteger.valueOf(42)), protocolSpecAdapters, PrivacyParameters.DEFAULT, false, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java index 940d076bbc..731b8b3854 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java @@ -42,6 +42,7 @@ import org.hyperledger.besu.testutil.TestClock; import org.hyperledger.besu.util.number.Fraction; import java.time.ZoneId; +import java.util.Optional; import java.util.function.Function; public class LegacyFeeMarketBlockTransactionSelectorTest @@ -56,7 +57,7 @@ public class LegacyFeeMarketBlockTransactionSelectorTest protected ProtocolSchedule createProtocolSchedule() { return new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - CHAIN_ID, + Optional.of(CHAIN_ID), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index 68d9a71de6..3bb559550b 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java @@ -51,6 +51,7 @@ import org.hyperledger.besu.util.number.Fraction; import java.time.ZoneId; import java.util.List; +import java.util.Optional; import java.util.function.Function; import org.junit.jupiter.api.Test; @@ -67,7 +68,7 @@ public class LondonFeeMarketBlockTransactionSelectorTest protected ProtocolSchedule createProtocolSchedule() { return new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - CHAIN_ID, + Optional.of(CHAIN_ID), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java index 509efd7b19..8e7f992ad5 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java @@ -62,6 +62,7 @@ import org.hyperledger.besu.util.Subscribers; import java.io.IOException; import java.math.BigInteger; import java.util.Collections; +import java.util.Optional; import java.util.function.Function; import com.google.common.collect.Lists; @@ -93,7 +94,7 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { .protocolSchedule( new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(42), + Optional.of(BigInteger.valueOf(42)), ProtocolSpecAdapters.create(0, Function.identity()), PrivacyParameters.DEFAULT, false, @@ -152,7 +153,7 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { .protocolSchedule( new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(42), + Optional.of(BigInteger.valueOf(42)), ProtocolSpecAdapters.create( 0, specBuilder -> @@ -208,7 +209,7 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { ProtocolSchedule protocolSchedule = new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(42), + Optional.of(BigInteger.valueOf(42)), ProtocolSpecAdapters.create( 0, specBuilder -> @@ -285,7 +286,7 @@ class PoWBlockCreatorTest extends AbstractBlockCreatorTest { ProtocolSchedule protocolSchedule = new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(42), + Optional.of(BigInteger.valueOf(42)), ProtocolSpecAdapters.create( 0, specBuilder -> diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 912d8673a5..c5ab446266 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -107,6 +107,8 @@ dependencies { testSupportImplementation 'org.junit.jupiter:junit-jupiter' testSupportImplementation 'org.assertj:assertj-core' testSupportImplementation 'org.mockito:mockito-core' + testSupportImplementation 'com.google.dagger:dagger' + testSupportAnnotationProcessor 'com.google.dagger:dagger-compiler' jmhImplementation project(path: ':config', configuration: 'testSupportArtifacts') jmhImplementation project(':crypto:algorithms') diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolScheduleModule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolScheduleModule.java new file mode 100644 index 0000000000..039747db0b --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolScheduleModule.java @@ -0,0 +1,100 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.components; + +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.ethereum.chain.BadBlockManager; +import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; + +import java.math.BigInteger; +import java.util.Optional; +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +/** Provides the protocol schedule for the network. */ +@Module +public class ProtocolScheduleModule { + + /** Default constructor. */ + public ProtocolScheduleModule() {} + + /** + * Provides the protocol schedule builder. + * + * @param config the genesis config options + * @param protocolSpecAdapters the protocol spec adapters + * @param privacyParameters the privacy parameters + * @param isRevertReasonEnabled whether revert reason is enabled + * @param evmConfiguration the EVM configuration + * @param badBlockManager the bad block manager + * @param isParallelTxProcessingEnabled whether parallel tx processing is enabled + * @param metricsSystem the metrics system + * @param miningParameters the mining parameters + * @return the protocol schedule builder + */ + @Singleton + @Provides + public ProtocolScheduleBuilder provideProtocolScheduleBuilder( + final GenesisConfigOptions config, + final ProtocolSpecAdapters protocolSpecAdapters, + final PrivacyParameters privacyParameters, + final boolean isRevertReasonEnabled, + final EvmConfiguration evmConfiguration, + final BadBlockManager badBlockManager, + final boolean isParallelTxProcessingEnabled, + final MetricsSystem metricsSystem, + final MiningParameters miningParameters) { + + ProtocolScheduleBuilder builder = + new ProtocolScheduleBuilder( + config, + config.getChainId(), + protocolSpecAdapters, + privacyParameters, + isRevertReasonEnabled, + evmConfiguration, + miningParameters, + badBlockManager, + isParallelTxProcessingEnabled, + metricsSystem); + + return builder; + } + + /** + * Provides the protocol schedule. + * + * @param builder the protocol schedule builder + * @param config the genesis config options + * @return the protocol schedule + */ + @Provides + public ProtocolSchedule createProtocolSchedule( + final ProtocolScheduleBuilder builder, final GenesisConfigOptions config) { + final Optional chainId = config.getChainId().or(() -> builder.getDefaultChainId()); + DefaultProtocolSchedule protocolSchedule = new DefaultProtocolSchedule(chainId); + builder.initSchedule(protocolSchedule, chainId); + return protocolSchedule; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolSpecModule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolSpecModule.java new file mode 100644 index 0000000000..fe9b0f3fab --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolSpecModule.java @@ -0,0 +1,51 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.components; + +import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSpecs; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.plugin.services.MetricsSystem; + +import javax.inject.Named; + +import dagger.Module; +import dagger.Provides; + +/** Provides protocol specs for network forks. */ +@Module +public class ProtocolSpecModule { + + /** Default constructor. */ + public ProtocolSpecModule() {} + + /** + * Provides the protocol spec for the frontier network fork. + * + * @param evmConfiguration the EVM configuration + * @param isParalleltxEnabled whether parallel tx processing is enabled + * @param metricsSystem the metrics system + * @return the protocol spec for the frontier network fork + */ + @Provides + @Named("frontier") + public ProtocolSpecBuilder frontierProtocolSpec( + final EvmConfiguration evmConfiguration, + final boolean isParalleltxEnabled, + final MetricsSystem metricsSystem) { + return MainnetProtocolSpecs.frontierDefinition( + evmConfiguration, isParalleltxEnabled, metricsSystem); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/CoinbaseModule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/CoinbaseModule.java new file mode 100644 index 0000000000..bb613b4e17 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/CoinbaseModule.java @@ -0,0 +1,31 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.core.components; + +import org.hyperledger.besu.datatypes.Address; + +import javax.inject.Named; + +import dagger.Module; +import dagger.Provides; + +@Module +public class CoinbaseModule { + @Provides + @Named("emptyCoinbase") + Address provideEmptyCoinbase() { + return Address.fromHexString(String.format("%020x", 1)); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/EthereumCoreComponent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/EthereumCoreComponent.java new file mode 100644 index 0000000000..2b081399a9 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/EthereumCoreComponent.java @@ -0,0 +1,32 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.core.components; + +import org.hyperledger.besu.ethereum.components.ProtocolScheduleModule; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import javax.inject.Singleton; + +import dagger.Subcomponent; + +@Singleton +@Subcomponent( + modules = { + MiningParametersModule.class, + ProtocolScheduleModule.class, + }) +public interface EthereumCoreComponent { + MiningParameters getMiningParameters(); +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/MiningParametersModule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/MiningParametersModule.java new file mode 100644 index 0000000000..8551d0e946 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/MiningParametersModule.java @@ -0,0 +1,64 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * 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.ethereum.core.components; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters; +import org.hyperledger.besu.ethereum.core.MiningParameters; + +import javax.inject.Named; + +import dagger.Module; +import dagger.Provides; + +@Module +public class MiningParametersModule { + + @Provides + @Named("defaultMiningParameters") + protected MiningParameters createImmutableMiningParams() { + return ImmutableMiningParameters.builder().build(); + } + + @Provides + @Named("noMining") + protected MiningParameters createNoMining() { + return ImmutableMiningParameters.builder() + .mutableInitValues( + ImmutableMiningParameters.MutableInitValues.builder().isMiningEnabled(false).build()) + .build(); + } + + @Provides + @Named("zeroGas") + MiningParameters createZeroGasMining(final @Named("emptyCoinbase") Address coinbase) { + final MiningParameters miningParameters = + ImmutableMiningParameters.builder() + .mutableInitValues( + ImmutableMiningParameters.MutableInitValues.builder() + .isMiningEnabled(true) + .minTransactionGasPrice(Wei.ZERO) + .coinbase(coinbase) + .build()) + .build(); + return miningParameters; + } + + @Provides + MiningParameters provideMiningParameters() { + throw new IllegalStateException("unimplemented"); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java index b86b2b0de2..4290679bae 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java @@ -24,7 +24,12 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; -/** A ProtocolSchedule which behaves similarly to MainNet, but with a much reduced difficulty. */ +import java.util.Optional; + +/** + * A ProtocolSchedule which behaves similarly to pre-merge MainNet, but with a much reduced + * difficulty. + */ public class FixedDifficultyProtocolSchedule { public static ProtocolSchedule create( @@ -38,6 +43,7 @@ public class FixedDifficultyProtocolSchedule { final MetricsSystem metricsSystem) { return new ProtocolScheduleBuilder( config, + Optional.empty(), ProtocolSpecAdapters.create( 0, builder -> diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java index 88b6a5ae1b..e6c372a682 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.plugin.services.MetricsSystem; import java.math.BigInteger; +import java.util.Optional; import java.util.function.Function; /** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */ @@ -47,9 +48,9 @@ public class MainnetProtocolSchedule { */ public static ProtocolSchedule fromConfig( final GenesisConfigOptions config, - final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled, - final EvmConfiguration evmConfiguration, + final Optional privacyParameters, + final Optional isRevertReasonEnabled, + final Optional evmConfiguration, final MiningParameters miningParameters, final BadBlockManager badBlockManager, final boolean isParallelTxProcessingEnabled, @@ -57,9 +58,9 @@ public class MainnetProtocolSchedule { if (FixedDifficultyCalculators.isFixedDifficultyInConfig(config)) { return FixedDifficultyProtocolSchedule.create( config, - privacyParameters, - isRevertReasonEnabled, - evmConfiguration, + privacyParameters.orElse(PrivacyParameters.DEFAULT), + isRevertReasonEnabled.orElse(false), + evmConfiguration.orElse(EvmConfiguration.DEFAULT), miningParameters, badBlockManager, isParallelTxProcessingEnabled, @@ -67,11 +68,11 @@ public class MainnetProtocolSchedule { } return new ProtocolScheduleBuilder( config, - DEFAULT_CHAIN_ID, + Optional.of(DEFAULT_CHAIN_ID), ProtocolSpecAdapters.create(0, Function.identity()), - privacyParameters, - isRevertReasonEnabled, - evmConfiguration, + privacyParameters.orElse(PrivacyParameters.DEFAULT), + isRevertReasonEnabled.orElse(false), + evmConfiguration.orElse(EvmConfiguration.DEFAULT), miningParameters, badBlockManager, isParallelTxProcessingEnabled, @@ -101,9 +102,9 @@ public class MainnetProtocolSchedule { final MetricsSystem metricsSystem) { return fromConfig( config, - PrivacyParameters.DEFAULT, - isRevertReasonEnabled, - evmConfiguration, + Optional.empty(), + Optional.of(isRevertReasonEnabled), + Optional.of(evmConfiguration), miningParameters, badBlockManager, isParallelTxProcessingEnabled, @@ -130,9 +131,9 @@ public class MainnetProtocolSchedule { final MetricsSystem metricsSystem) { return fromConfig( config, - PrivacyParameters.DEFAULT, - false, - evmConfiguration, + Optional.empty(), + Optional.empty(), + Optional.of(evmConfiguration), miningParameters, badBlockManager, isParallelTxProcessingEnabled, @@ -157,9 +158,9 @@ public class MainnetProtocolSchedule { final MetricsSystem metricsSystem) { return fromConfig( config, - PrivacyParameters.DEFAULT, - false, - EvmConfiguration.DEFAULT, + Optional.empty(), + Optional.empty(), + Optional.empty(), miningParameters, badBlockManager, isParallelTxProcessingEnabled, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index 52003bc96c..fd27ca0574 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -48,59 +48,12 @@ public class ProtocolScheduleBuilder { private final PrivacyParameters privacyParameters; private final boolean isRevertReasonEnabled; private final EvmConfiguration evmConfiguration; - private final MiningParameters miningParameters; private final BadBlockManager badBlockManager; private final boolean isParallelTxProcessingEnabled; private final MetricsSystem metricsSystem; + private final MiningParameters miningParameters; public ProtocolScheduleBuilder( - final GenesisConfigOptions config, - final BigInteger defaultChainId, - final ProtocolSpecAdapters protocolSpecAdapters, - final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled, - final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters, - final BadBlockManager badBlockManager, - final boolean isParallelTxProcessingEnabled, - final MetricsSystem metricsSystem) { - this( - config, - Optional.of(defaultChainId), - protocolSpecAdapters, - privacyParameters, - isRevertReasonEnabled, - evmConfiguration, - miningParameters, - badBlockManager, - isParallelTxProcessingEnabled, - metricsSystem); - } - - public ProtocolScheduleBuilder( - final GenesisConfigOptions config, - final ProtocolSpecAdapters protocolSpecAdapters, - final PrivacyParameters privacyParameters, - final boolean isRevertReasonEnabled, - final EvmConfiguration evmConfiguration, - final MiningParameters miningParameters, - final BadBlockManager badBlockManager, - final boolean isParallelTxProcessingEnabled, - final MetricsSystem metricsSystem) { - this( - config, - Optional.empty(), - protocolSpecAdapters, - privacyParameters, - isRevertReasonEnabled, - evmConfiguration, - miningParameters, - badBlockManager, - isParallelTxProcessingEnabled, - metricsSystem); - } - - private ProtocolScheduleBuilder( final GenesisConfigOptions config, final Optional defaultChainId, final ProtocolSpecAdapters protocolSpecAdapters, @@ -117,10 +70,10 @@ public class ProtocolScheduleBuilder { this.isRevertReasonEnabled = isRevertReasonEnabled; this.evmConfiguration = evmConfiguration; this.defaultChainId = defaultChainId; - this.miningParameters = miningParameters; this.badBlockManager = badBlockManager; this.isParallelTxProcessingEnabled = isParallelTxProcessingEnabled; this.metricsSystem = metricsSystem; + this.miningParameters = miningParameters; } public ProtocolSchedule createProtocolSchedule() { @@ -130,7 +83,7 @@ public class ProtocolScheduleBuilder { return protocolSchedule; } - private void initSchedule( + public void initSchedule( final ProtocolSchedule protocolSchedule, final Optional chainId) { final MainnetProtocolSpecFactory specFactory = @@ -557,4 +510,8 @@ public class ProtocolScheduleBuilder { TIMESTAMP } } + + public Optional getDefaultChainId() { + return defaultChainId; + } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java index 511b94d3ae..e05ba21268 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java @@ -152,7 +152,7 @@ public class ExecutionContextTestFixture { protocolSchedule = new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(42), + Optional.of(BigInteger.valueOf(42)), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java index e94c6b49fd..5eec6d61e5 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java @@ -22,10 +22,10 @@ import org.hyperledger.besu.config.JsonGenesisConfigOptions; import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import java.io.IOException; +import java.util.Optional; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonParser; @@ -36,9 +36,9 @@ public class ProtocolScheduleFixture { public static final ProtocolSchedule MAINNET = MainnetProtocolSchedule.fromConfig( getMainnetConfigOptions(), - PrivacyParameters.DEFAULT, - false, - EvmConfiguration.DEFAULT, + Optional.empty(), + Optional.empty(), + Optional.empty(), MiningParameters.newDefault(), new BadBlockManager(), false, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java index 2d5dd2cee3..e48cd67302 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java @@ -56,7 +56,7 @@ public class DefaultProtocolScheduleTest { builder = new ProtocolScheduleBuilder( config, - DEFAULT_CHAIN_ID, + Optional.of(DEFAULT_CHAIN_ID), ProtocolSpecAdapters.create(FIRST_TIMESTAMP_FORK, modifier), privacyParameters, isRevertReasonEnabled, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java index ad261abf47..cade5bd601 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java @@ -62,7 +62,7 @@ class ProtocolScheduleBuilderTest { builder = new ProtocolScheduleBuilder( configOptions, - CHAIN_ID, + Optional.of(CHAIN_ID), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, @@ -257,7 +257,7 @@ class ProtocolScheduleBuilderTest { final ProtocolScheduleBuilder builder = new ProtocolScheduleBuilder( configOptions, - CHAIN_ID, + Optional.of(CHAIN_ID), ProtocolSpecAdapters.create(blockNumber, modifier), new PrivacyParameters(), false, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java index c3ca24a4e1..07d4e6ab4b 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java @@ -178,7 +178,7 @@ public abstract class AbstractTransactionPoolTestBase { final ProtocolSchedule protocolSchedule = new ProtocolScheduleBuilder( genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(1), + Optional.of(BigInteger.valueOf(1)), ProtocolSpecAdapters.create(0, Function.identity()), new PrivacyParameters(), false, diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java index 5742637c3e..d1bafc3969 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java @@ -373,7 +373,7 @@ public class TransactionPoolFactoryTest { schedule = new ProtocolScheduleBuilder( config, - DEFAULT_CHAIN_ID, + Optional.of(DEFAULT_CHAIN_ID), ProtocolSpecAdapters.create(0, Function.identity()), PrivacyParameters.DEFAULT, false, diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java index 8dc8a74c1f..8490312d81 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java @@ -187,7 +187,7 @@ class MainnetGenesisFileModule extends GenesisFileModule { return () -> new ProtocolScheduleBuilder( options, - options.getChainId().orElse(BigInteger.ONE), + options.getChainId(), ProtocolSpecAdapters.create(0, Function.identity()), PrivacyParameters.DEFAULT, false, diff --git a/ethereum/referencetests/build.gradle b/ethereum/referencetests/build.gradle index 48f556a5b9..5fbab994cf 100644 --- a/ethereum/referencetests/build.gradle +++ b/ethereum/referencetests/build.gradle @@ -191,6 +191,8 @@ dependencies { implementation 'io.tmio:tuweni-rlp' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.google.guava:guava' + implementation 'com.google.dagger:dagger' + annotationProcessor 'com.google.dagger:dagger-compiler' referenceTestImplementation project(path: ':config') referenceTestImplementation project(path: ':datatypes') diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index 976c8e70d2..b9af680fe3 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -34,6 +34,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -151,7 +152,7 @@ public class ReferenceTestProtocolSchedules { private static ProtocolSchedule createSchedule(final GenesisConfigOptions options) { return new ProtocolScheduleBuilder( options, - CHAIN_ID, + Optional.of(CHAIN_ID), ProtocolSpecAdapters.create(0, Function.identity()), PrivacyParameters.DEFAULT, false, diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java index cfb56d1ebc..3a61967044 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java @@ -61,64 +61,64 @@ public class DifficultyCalculatorTests { MainnetProtocolSchedule.fromConfig( GenesisConfigFile.mainnet() .withOverrides(postMergeOverrides).getConfigOptions(), - EvmConfiguration.DEFAULT, MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem())), + EvmConfiguration.DEFAULT, MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem())), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierForkBlock.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierTimeDiff1.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfGrayGlacier/difficultyGrayGlacierTimeDiff2.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + new StubGenesisConfigOptions().grayGlacierBlock(15050000), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierForkBlock.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierTimeDiff1.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfArrowGlacier/difficultyArrowGlacierTimeDiff2.json", MainnetProtocolSchedule.fromConfig( - new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + new StubGenesisConfigOptions().arrowGlacierBlock(13773000), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfByzantium/difficultyByzantium.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().byzantiumBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().byzantiumBlock(0), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfConstantinople/difficultyConstantinople.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384_random.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfEIP2384/difficultyEIP2384_random_to20M.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().muirGlacierBlock(0), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfFrontier/difficultyFrontier.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions(), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions(), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) ), Arguments.of( "/DifficultyTests/dfHomestead/difficultyHomestead.json", - MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().homesteadBlock(0), MiningParameters.newDefault(), new BadBlockManager(), false, new NoOpMetricsSystem()) + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().homesteadBlock(0), MiningParameters.MINING_DISABLED, new BadBlockManager(), false, new NoOpMetricsSystem()) )); }