mirror of https://github.com/hyperledger/besu
commit
b2e1069f31
@ -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_"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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"); |
||||||
|
} |
||||||
|
} |
@ -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; |
|
||||||
} |
|
||||||
} |
|
@ -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();
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -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"); |
|
||||||
} |
|
||||||
} |
|
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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"); |
||||||
|
} |
||||||
|
} |
@ -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" |
|
||||||
} |
|
@ -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)); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue