Merge branch 'main' into GetBodiesPeerTask

pull/7828/head
Matilda-Clerke 3 weeks ago committed by GitHub
commit b2e1069f31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 2
      CONTRIBUTING.md
  3. 2
      DCO.md
  4. 2
      MAINTAINERS.md
  5. 4
      README.md
  6. 2
      SUPPORT.md
  7. 29
      acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java
  8. 76
      acceptance-tests/test-plugins/src/main/java/org/hyperledger/besu/tests/acceptance/plugins/TestMetricsPlugin.java
  9. 4
      acceptance-tests/tests/build.gradle
  10. 73
      acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/plugins/MetricsPluginTest.java
  11. 24
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  12. 73
      besu/src/main/java/org/hyperledger/besu/cli/converter/MetricCategoryConverter.java
  13. 47
      besu/src/main/java/org/hyperledger/besu/cli/options/stable/MetricsOptions.java
  14. 149
      besu/src/main/java/org/hyperledger/besu/cli/subcommands/RetestethSubCommand.java
  15. 1
      besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java
  16. 10
      besu/src/main/java/org/hyperledger/besu/controller/MainnetBesuControllerBuilder.java
  17. 2
      besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java
  18. 34
      besu/src/test/java/org/hyperledger/besu/chainimport/JsonBlockImporterTest.java
  19. 41
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  20. 63
      besu/src/test/java/org/hyperledger/besu/cli/converter/MetricCategoryConverterTest.java
  21. 21
      besu/src/test/java/org/hyperledger/besu/cli/options/MetricsOptionsTest.java
  22. 2
      config/build.gradle
  23. 2
      consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java
  24. 3
      consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BaseBftProtocolScheduleBuilder.java
  25. 2
      consensus/common/src/test/java/org/hyperledger/besu/consensus/common/CombinedProtocolScheduleFactoryTest.java
  26. 2
      consensus/ibft/build.gradle
  27. 130
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftProtocolScheduleTest.java
  28. 2
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java
  29. 2
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/MergeProtocolSchedule.java
  30. 2
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java
  31. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/AbstractJsonRpcExecutor.java
  32. 44
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandler.java
  33. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2.java
  34. 110
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcExecutorHandlerTest.java
  35. 88
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayloadTest.java
  36. 20
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV2Test.java
  37. 36
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java
  38. 121
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV4Test.java
  39. 2
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreatorTest.java
  40. 3
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LegacyFeeMarketBlockTransactionSelectorTest.java
  41. 3
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java
  42. 9
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java
  43. 2
      ethereum/core/build.gradle
  44. 100
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolScheduleModule.java
  45. 51
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/components/ProtocolSpecModule.java
  46. 23
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/CoinbaseModule.java
  47. 32
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/EthereumCoreComponent.java
  48. 64
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/components/MiningParametersModule.java
  49. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/difficulty/fixed/FixedDifficultyProtocolSchedule.java
  50. 39
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSchedule.java
  51. 57
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java
  52. 2
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ExecutionContextTestFixture.java
  53. 8
      ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java
  54. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolScheduleTest.java
  55. 4
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilderTest.java
  56. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java
  57. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPoolFactoryTest.java
  58. 2
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java
  59. 2
      ethereum/referencetests/build.gradle
  60. 3
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java
  61. 28
      ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/mainnet/DifficultyCalculatorTests.java
  62. 58
      ethereum/retesteth/build.gradle
  63. 145
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java
  64. 60
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethClock.java
  65. 370
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethContext.java
  66. 122
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/RetestethService.java
  67. 73
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestGetLogHash.java
  68. 107
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlock.java
  69. 97
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java
  70. 51
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestModifyTimestamp.java
  71. 53
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestRewindToBlock.java
  72. 159
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParams.java
  73. 129
      ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestImportRawBlockTest.java
  74. 115
      ethereum/retesteth/src/test/java/org/hyperledger/besu/ethereum/retesteth/methods/TestSetChainParamsTest.java
  75. 21
      ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/1559ChainParams.json
  76. 102
      ethereum/retesteth/src/test/resources/org/hyperledger/besu/ethereum/retesteth/methods/multimpleBalanceInstructionChainParams.json
  77. 69
      metrics/core/src/main/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImpl.java
  78. 66
      metrics/core/src/test/java/org/hyperledger/besu/metrics/MetricCategoryRegistryImplTest.java
  79. 2
      plugin-api/build.gradle
  80. 10
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/metrics/MetricCategoryRegistry.java

@ -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
@ -12,8 +13,10 @@
- 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)
## 24.10.0

@ -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

@ -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).

@ -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

@ -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 <a href="https://www.yourkit.com/youmonitor/">YourKit YouMonitor</a>.
[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

@ -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

@ -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();
}
}

@ -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<String> getApplicationPrefix() {
return Optional.of("plugin_test_");
}
}
}

@ -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')
}

@ -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");
}
}

@ -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;
@ -75,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;
@ -170,7 +168,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 +329,6 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
private final Map<String, String> environment;
private final MetricCategoryRegistryImpl metricCategoryRegistry =
new MetricCategoryRegistryImpl();
private final MetricCategoryConverter metricCategoryConverter = new MetricCategoryConverter();
private final PreSynchronizationTaskRunner preSynchronizationTaskRunner =
new PreSynchronizationTaskRunner();
@ -1108,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(
@ -1136,10 +1131,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 +1165,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 +1185,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 +1881,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
@ -1903,7 +1897,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() {

@ -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<MetricCategory> {
private final Map<String, MetricCategory> 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 <T> the type parameter
* @param categoryEnum the category enum
*/
public <T extends Enum<T> & MetricCategory> void addCategories(final Class<T> 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<String, MetricCategory> getMetricCategories() {
return metricCategories;
}
}

@ -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<MetricsConfiguration>
public class MetricsOptions implements CLIOptions<MetricsConfiguration.Builder> {
private MetricCategoryRegistryImpl metricCategoryRegistry;
/**
* Returns a MetricsConfiguration.Builder because fields are often overridden from other domains,
@ -77,7 +81,10 @@ public class MetricsOptions implements CLIOptions<MetricsConfiguration.Builder>
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<MetricsConfiguration.Builder>
arity = "1..*",
description =
"Comma separated list of categories to track metrics for (default: ${DEFAULT-VALUE})")
private Set<MetricCategory> metricCategories = DEFAULT_METRIC_CATEGORIES;
private Set<String> 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<MetricsConfiguration.Builder>
* @return the metric categories
*/
public Set<MetricCategory> 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<MetricsConfiguration.Builder>
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();

@ -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 <code>0xba5e</code> 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 = "<hostname>[,<hostname>...]... 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();
}
}
}

@ -132,7 +132,6 @@ public class CliqueBesuControllerBuilder extends BesuControllerBuilder {
genesisConfigOptions,
forksSchedule,
nodeKey,
privacyParameters,
isRevertReasonEnabled,
evmConfiguration,
miningParameters,

@ -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);

@ -31,7 +31,7 @@ public class BesuConfigurationImpl implements BesuConfiguration {
private DataStorageConfiguration dataStorageConfiguration;
// defaults
private MiningParameters miningParameters = MiningParameters.newDefault();
private MiningParameters miningParameters;
private Optional<String> rpcHttpHost = Optional.of("http://localhost");
private Optional<Integer> rpcHttpPort = Optional.of(8545);

@ -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 {}
}

@ -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");

@ -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");
}
}

@ -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<MetricsConfiguration.Builder, MetricsOptions> {
private MetricCategoryRegistryImpl categoryRegistry;
@BeforeEach
public void setUp() {
categoryRegistry = new MetricCategoryRegistryImpl();
categoryRegistry.addCategories(BesuMetricCategory.class);
categoryRegistry.addCategories(StandardMetricCategory.class);
}
@Override
protected MetricsConfiguration.Builder createDefaultDomainObject() {
@ -39,11 +51,18 @@ 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
protected MetricsOptions getOptionsFromBesuCommand(final TestBesuCommand besuCommand) {
return besuCommand.getMetricsOptions();
}
@Override
protected String[] getNonOptionFields() {
return new String[] {"metricCategoryRegistry"};
}
}

@ -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')

@ -110,7 +110,7 @@ public class CliqueProtocolSchedule {
return new ProtocolScheduleBuilder(
config,
DEFAULT_CHAIN_ID,
Optional.of(DEFAULT_CHAIN_ID),
specAdapters,
privacyParameters,
isRevertReasonEnabled,

@ -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,

@ -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,

@ -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'
}

@ -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<Address> validators = singletonList(proposerAddress);
private ProtocolContext protocolContext;
private List<Address> 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<ForkSpec<BftConfigOptions>> forks) {
final BftExtraDataCodec bftExtraDataCodec,
final MutableBftConfigOptions arbitraryTransition) {
var genesisConfig = JsonGenesisConfigOptions.fromJsonObject(JsonUtil.createEmptyObjectNode());
ForksSchedule<BftConfigOptions> 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,20 +133,41 @@ public class IbftProtocolScheduleTest {
new NoOpMetricsSystem());
}
private boolean validateHeader(
final BftProtocolSchedule schedule,
final List<Address> 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<Address> provideValidators(final Address proposerAddress) {
return singletonList(proposerAddress);
}
@Provides
public BftExtraData mockBftExtraData(final List<Address> 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;
}
private ProtocolContext protocolContext(final Collection<Address> validators) {
@Provides
ProtocolContext protocolContext(
final List<Address> validators, final BftExtraDataCodec bftExtraDataCodec) {
return new ProtocolContext(
null,
null,
@ -130,3 +175,24 @@ public class IbftProtocolScheduleTest {
new BadBlockManager());
}
}
@Singleton
@Component(modules = {NoMiningParamters.class, IbftProtocolScheduleModule.class})
interface TestEthCoreComponent extends EthereumCoreComponent {
ProtocolContext protocolContext();
List<Address> validators();
NodeKey nodeKey();
BftExtraDataCodec bftExtraDataCodec();
}
@Module
static class NoMiningParamters {
@Provides
MiningParameters provideMiningParameters() {
return MiningParameters.MINING_DISABLED;
}
}
}

@ -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,

@ -101,7 +101,7 @@ public class MergeProtocolSchedule {
return new ProtocolScheduleBuilder(
config,
DEFAULT_CHAIN_ID,
Optional.of(DEFAULT_CHAIN_ID),
new ProtocolSpecAdapters(postMergeModifications),
privacyParameters,
isRevertReasonEnabled,

@ -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,

@ -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;
};
}

@ -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<RoutingContext> 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<AbstractJsonRpcExecutor> createExecutor(
final JsonRpcExecutor jsonRpcExecutor,
final Tracer tracer,

@ -61,11 +61,11 @@ public class EngineNewPayloadV2 extends AbstractEngineNewPayload {
final Optional<List<String>> 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();
}

@ -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<RoutingContext> handler =
JsonRpcExecutorHandler.handler(mockExecutor, mockTracer, mockConfig);
ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
@SuppressWarnings("unchecked")
ArgumentCaptor<Handler<Long>> 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<RoutingContext> 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);
}
}

@ -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<List<Withdrawal>> maybeWithdrawals,
final Optional<List<Request>> maybeRequests) {
final BlockProcessingResult value, final Optional<List<Withdrawal>> 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<List<Withdrawal>> maybeWithdrawals,
final Optional<List<Request>> maybeRequests) {
return createBlockHeaderFixture(maybeWithdrawals, maybeRequests).buildHeader();
protected BlockHeader createBlockHeader(final Optional<List<Withdrawal>> maybeWithdrawals) {
return createBlockHeaderFixture(maybeWithdrawals).buildHeader();
}
protected BlockHeaderTestFixture createBlockHeaderFixture(
final Optional<List<Withdrawal>> maybeWithdrawals,
final Optional<List<Request>> maybeRequests) {
final Optional<List<Withdrawal>> 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) {

@ -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();

@ -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<RpcErrorType> 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<List<Withdrawal>> maybeWithdrawals,
final Optional<List<Request>> maybeRequests) {
protected BlockHeader createBlockHeader(final Optional<List<Withdrawal>> 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)));

@ -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<Request> 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<Request> 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<Request> 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<List<Withdrawal>> maybeWithdrawals,
final Optional<List<Request>> maybeRequests) {
private BlockHeader createValidBlockHeaderForV4(
final Optional<List<Withdrawal>> maybeWithdrawals) {
return createBlockHeaderFixtureForV3(maybeWithdrawals)
.requestsHash(BodyValidation.requestsHash(VALID_REQUESTS))
.buildHeader();
}
private BlockHeaderTestFixture createBlockHeaderFixtureForV3(
final Optional<List<Withdrawal>> maybeWithdrawals) {
BlockHeader parentBlockHeader =
new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE)
@ -172,8 +146,7 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.blobGasUsed(0L)
.buildHeader();
BlockHeader mockHeader =
new BlockHeaderTestFixture()
return new BlockHeaderTestFixture()
.baseFeePerGas(Wei.ONE)
.parentHash(parentBlockHeader.getParentHash())
.number(parentBlockHeader.getNumber() + 1)
@ -181,39 +154,41 @@ public class EngineNewPayloadV4Test extends EngineNewPayloadV3Test {
.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;
maybeParentBeaconBlockRoot.isPresent() ? maybeParentBeaconBlockRoot : null);
}
@Override
protected BlockHeader createBlockHeader(final Optional<List<Withdrawal>> maybeWithdrawals) {
return createValidBlockHeaderForV4(maybeWithdrawals);
}
@Override
protected JsonRpcResponse resp(final EnginePayloadParameter payload) {
final List<String> 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<Request> requests) {
final List<String> 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(

@ -304,7 +304,7 @@ abstract class AbstractBlockCreatorTest {
.protocolSchedule(
new ProtocolScheduleBuilder(
genesisConfigFile.getConfigOptions(),
BigInteger.valueOf(42),
Optional.of(BigInteger.valueOf(42)),
protocolSpecAdapters,
PrivacyParameters.DEFAULT,
false,

@ -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,

@ -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,

@ -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 ->

@ -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')

@ -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<BigInteger> chainId = config.getChainId().or(() -> builder.getDefaultChainId());
DefaultProtocolSchedule protocolSchedule = new DefaultProtocolSchedule(chainId);
builder.initSchedule(protocolSchedule, chainId);
return protocolSchedule;
}
}

@ -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);
}
}

@ -1,5 +1,5 @@
/*
* Copyright ConsenSys AG.
* 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
@ -12,19 +12,20 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.retesteth;
package org.hyperledger.besu.ethereum.core.components;
import java.nio.file.Path;
import org.hyperledger.besu.datatypes.Address;
public class RetestethConfiguration {
import javax.inject.Named;
private final Path dataPath;
import dagger.Module;
import dagger.Provides;
public RetestethConfiguration(final Path dataPath) {
this.dataPath = dataPath;
}
Path getDataPath() {
return dataPath;
@Module
public class CoinbaseModule {
@Provides
@Named("emptyCoinbase")
Address provideEmptyCoinbase() {
return Address.fromHexString(String.format("%020x", 1));
}
}

@ -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();
}

@ -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");
}
}

@ -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 ->

@ -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> privacyParameters,
final Optional<Boolean> isRevertReasonEnabled,
final Optional<EvmConfiguration> 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,

@ -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<BigInteger> 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<BigInteger> chainId) {
final MainnetProtocolSpecFactory specFactory =
@ -557,4 +510,8 @@ public class ProtocolScheduleBuilder {
TIMESTAMP
}
}
public Optional<BigInteger> getDefaultChainId() {
return defaultChainId;
}
}

@ -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,

@ -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,

@ -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,

@ -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,

@ -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,

@ -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,

@ -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,

@ -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')

@ -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,

@ -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())
));
}

@ -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'
}

@ -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<ScheduledProtocolSpec> predicate) {
return delegate.anyMatch(predicate);
}
@Override
public boolean isOnMilestoneBoundary(final BlockHeader blockHeader) {
return delegate.isOnMilestoneBoundary(blockHeader);
}
@Override
public Optional<BigInteger> 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<ScheduledProtocolSpec.Hardfork> hardforkFor(
final Predicate<ScheduledProtocolSpec> 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);
}
}

@ -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<Instant> 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));
}
}

@ -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<Bytes> terminalTotalDifficulty;
private Optional<Bytes32> mixHash;
public boolean resetContext(
final String genesisConfigString, final String sealEngine, final Optional<Long> 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<Long> 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<ProtocolSpec> 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<Bytes> getTerminalTotalDifficulty() {
return terminalTotalDifficulty;
}
public Optional<Bytes32> getMixHash() {
return mixHash;
}
public PoWSolver getEthHashSolver() {
return poWSolver;
}
}

@ -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<String, JsonRpcMethod> 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<String, JsonRpcMethod> mapOf(final JsonRpcMethod... rpcMethods) {
return Arrays.stream(rpcMethods)
.collect(Collectors.toMap(JsonRpcMethod::getName, rpcMethod -> rpcMethod));
}
}

@ -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<TransactionReceiptWithMetadata> 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)));
}
}

@ -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());
}
}

@ -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();
}
}

@ -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);
}
}

@ -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));
}
}

@ -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<String, Object>) 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<String> 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();
}
}

@ -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);
}
}

@ -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");
}
}

@ -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": {}
}

@ -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"
}

@ -14,31 +14,80 @@
*/
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;
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<MetricCategory> metricCategories = new ArrayList<>();
private final Map<String, MetricCategory> metricCategories = new HashMap<>();
private MetricsConfiguration metricsConfiguration;
/** Default constructor */
public MetricCategoryRegistryImpl() {}
/**
* Gets metric categories.
* Add Metrics categories.
*
* @param <T> the type parameter
* @param categoryEnum the category enum
*/
public <T extends Enum<T> & MetricCategory> void addCategories(final Class<T> categoryEnum) {
EnumSet.allOf(categoryEnum).forEach(this::addMetricCategory);
}
/**
* Add registry category.
*
* @return the metric categories
* @param metricCategory the metric category
*/
public List<MetricCategory> getMetricCategories() {
return metricCategories;
@Override
public void addMetricCategory(final MetricCategory metricCategory) {
metricCategories.put(metricCategory.getName().toUpperCase(Locale.ROOT), metricCategory);
}
@Override
public void addMetricCategory(final MetricCategory newMetricCategory) {
metricCategories.add(newMetricCategory);
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
*
* @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));
}
/**
* 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;
}
}

@ -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));
}
}

@ -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')

@ -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);
}

Loading…
Cancel
Save