From 43c8a6a89bd88dae6b4a0c8b41eabdad3b8df967 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri <59369753+pullurib@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:45:01 -0500 Subject: [PATCH 1/3] Add RPC HTTP options to specify custom truststore and password (#7978) * Add RPC HTTP options to specify custom truststore and it's password * Update error logs to indicate options to use Signed-off-by: Bhanu Pulluri --------- Signed-off-by: Bhanu Pulluri Signed-off-by: Bhanu Pulluri <59369753+pullurib@users.noreply.github.com> Co-authored-by: Bhanu Pulluri Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 2 + .../besu/cli/options/JsonRpcHttpOptions.java | 74 ++++++++++++--- .../cli/options/JsonRpcHttpOptionsTest.java | 90 ++++++++++++++++++- .../src/test/resources/everything_config.toml | 2 + .../api/jsonrpc/JsonRpcHttpService.java | 10 ++- .../api/tls/TlsClientAuthConfiguration.java | 41 ++++++++- .../JsonRpcHttpServiceTlsClientAuthTest.java | 50 +++++++++++ 7 files changed, 252 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 795147ccb34..f906084db59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,10 @@ - Fast Sync ### Additions and Improvements +- Add RPC HTTP options to specify custom truststore and its password [#7978](https://github.com/hyperledger/besu/pull/7978) - Retrieve all transaction receipts for a block in one request [#6646](https://github.com/hyperledger/besu/pull/6646) + ### Bug fixes - Fix serialization of state overrides when `movePrecompileToAddress` is present [#8204](https://github.com/hyperledger/besu/pull/8024) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptions.java b/besu/src/main/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptions.java index c8c2c733440..371f855b7a0 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptions.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptions.java @@ -176,6 +176,20 @@ public class JsonRpcHttpOptions { "Enable to accept clients certificate signed by a valid CA for client authentication (default: ${DEFAULT-VALUE})") private final Boolean isRpcHttpTlsCAClientsEnabled = false; + @CommandLine.Option( + names = {"--rpc-http-tls-truststore-file"}, + paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP, + description = "Path to the truststore file for the JSON-RPC HTTP service.", + arity = "1") + private final Path rpcHttpTlsTruststoreFile = null; + + @CommandLine.Option( + names = {"--rpc-http-tls-truststore-password-file"}, + paramLabel = DefaultCommandValues.MANDATORY_FILE_FORMAT_HELP, + description = "Path to the file containing the password for the truststore.", + arity = "1") + private final Path rpcHttpTlsTruststorePasswordFile = null; + @CommandLine.Option( names = {"--rpc-http-tls-protocol", "--rpc-http-tls-protocols"}, description = "Comma separated list of TLS protocols to support (default: ${DEFAULT-VALUE})", @@ -306,7 +320,6 @@ public JsonRpcConfiguration jsonRpcConfiguration( jsonRpcConfiguration.setHost( Strings.isNullOrEmpty(rpcHttpHost) ? defaultHostAddress : rpcHttpHost); jsonRpcConfiguration.setHostsAllowlist(hostsAllowlist); - ; jsonRpcConfiguration.setHttpTimeoutSec(timoutSec); return jsonRpcConfiguration; } @@ -330,7 +343,18 @@ private void checkRpcTlsClientAuthOptionsDependencies( commandLine, "--rpc-http-tls-client-auth-enabled", !isRpcHttpTlsClientAuthEnabled, - asList("--rpc-http-tls-known-clients-file", "--rpc-http-tls-ca-clients-enabled")); + asList( + "--rpc-http-tls-known-clients-file", + "--rpc-http-tls-ca-clients-enabled", + "--rpc-http-tls-truststore-file", + "--rpc-http-tls-truststore-password-file")); + + CommandLineUtils.checkOptionDependencies( + logger, + commandLine, + "--rpc-http-tls-truststore-file", + rpcHttpTlsTruststoreFile == null, + asList("--rpc-http-tls-truststore-password-file")); } private void checkRpcTlsOptionsDependencies(final Logger logger, final CommandLine commandLine) { @@ -392,12 +416,31 @@ private void validateTls(final CommandLine commandLine) { "File containing password to unlock keystore is required when TLS is enabled for JSON-RPC HTTP endpoint"); } - if (isRpcHttpTlsClientAuthEnabled - && !isRpcHttpTlsCAClientsEnabled - && rpcHttpTlsKnownClientsFile == null) { - throw new CommandLine.ParameterException( - commandLine, - "Known-clients file must be specified or CA clients must be enabled when TLS client authentication is enabled for JSON-RPC HTTP endpoint"); + if (isRpcHttpTlsClientAuthEnabled) { + if (!isRpcHttpTlsCAClientsEnabled + && rpcHttpTlsKnownClientsFile == null + && rpcHttpTlsTruststoreFile == null) { + throw new CommandLine.ParameterException( + commandLine, + "Configuration error: TLS client authentication is enabled, but none of the following options are provided: " + + "1. Specify a known-clients file (--rpc-http-tls-known-clients-file) and/or Enable CA clients (--rpc-http-tls-ca-clients-enabled). " + + "2. Specify a truststore file and its password file (--rpc-http-tls-truststore-file and --rpc-http-tls-truststore-password-file). " + + "Only one of these options must be configured"); + } + + if (rpcHttpTlsTruststoreFile != null && rpcHttpTlsTruststorePasswordFile == null) { + throw new CommandLine.ParameterException( + commandLine, + "Configuration error: A truststore file is specified for JSON RPC HTTP endpoint, but the corresponding truststore password file (--rpc-http-tls-truststore-password-file) is missing"); + } + + if ((isRpcHttpTlsCAClientsEnabled || rpcHttpTlsKnownClientsFile != null) + && rpcHttpTlsTruststoreFile != null) { + throw new CommandLine.ParameterException( + commandLine, + "Configuration error: Truststore file (--rpc-http-tls-truststore-file) cannot be used together with CA clients (--rpc-http-tls-ca-clients-enabled) or a known-clients (--rpc-http-tls-known-clients-file) option. " + + "These options are mutually exclusive. Choose either truststore-based authentication or known-clients/CA clients configuration."); + } } rpcHttpTlsProtocols.retainAll(getJDKEnabledProtocols()); @@ -441,10 +484,17 @@ private boolean isRpcTlsConfigurationRequired() { private TlsClientAuthConfiguration rpcHttpTlsClientAuthConfiguration() { if (isRpcHttpTlsClientAuthEnabled) { - return TlsClientAuthConfiguration.Builder.aTlsClientAuthConfiguration() - .withKnownClientsFile(rpcHttpTlsKnownClientsFile) - .withCaClientsEnabled(isRpcHttpTlsCAClientsEnabled) - .build(); + TlsClientAuthConfiguration.Builder tlsClientAuthConfigurationBuilder = + TlsClientAuthConfiguration.Builder.aTlsClientAuthConfiguration() + .withKnownClientsFile(rpcHttpTlsKnownClientsFile) + .withCaClientsEnabled(isRpcHttpTlsCAClientsEnabled) + .withTruststorePath(rpcHttpTlsTruststoreFile); + + if (rpcHttpTlsTruststorePasswordFile != null) { + tlsClientAuthConfigurationBuilder.withTruststorePasswordSupplier( + new FileBasedPasswordProvider(rpcHttpTlsTruststorePasswordFile)); + } + return tlsClientAuthConfigurationBuilder.build(); } return null; diff --git a/besu/src/test/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptionsTest.java b/besu/src/test/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptionsTest.java index afb53bac934..e29b16c573e 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptionsTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/options/JsonRpcHttpOptionsTest.java @@ -332,7 +332,10 @@ public void rpcHttpTlsClientAuthWithoutKnownFileReportsError() { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)) .contains( - "Known-clients file must be specified or CA clients must be enabled when TLS client authentication is enabled for JSON-RPC HTTP endpoint"); + "Configuration error: TLS client authentication is enabled, but none of the following options are provided: " + + "1. Specify a known-clients file (--rpc-http-tls-known-clients-file) and/or Enable CA clients (--rpc-http-tls-ca-clients-enabled). " + + "2. Specify a truststore file and its password file (--rpc-http-tls-truststore-file and --rpc-http-tls-truststore-password-file). " + + "Only one of these options must be configured"); } @Test @@ -342,6 +345,7 @@ public void rpcHttpTlsClientAuthWithKnownClientFile() { final String keystoreFile = "/tmp/test.p12"; final String keystorePasswordFile = "/tmp/test.txt"; final String knownClientFile = "/tmp/knownClientFile"; + parseCommand( "--rpc-http-enabled", "--rpc-http-host", @@ -422,6 +426,90 @@ public void rpcHttpTlsClientAuthWithCAClient() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void rpcHttpTlsClientAuthWithTrustStore() throws IOException { + final String host = "1.2.3.4"; + final int port = 1234; + final String keystoreFile = "/tmp/test.p12"; + final String keystorePasswordFile = "/tmp/test.txt"; + final String truststoreFile = "/tmp/truststore.p12"; + final String truststorePasswordFile = "/tmp/truststore.txt"; + + Files.writeString(Path.of(truststorePasswordFile), "password"); + parseCommand( + "--rpc-http-enabled", + "--rpc-http-host", + host, + "--rpc-http-port", + String.valueOf(port), + "--rpc-http-tls-enabled", + "--rpc-http-tls-keystore-file", + keystoreFile, + "--rpc-http-tls-keystore-password-file", + keystorePasswordFile, + "--rpc-http-tls-client-auth-enabled", + "--rpc-http-tls-truststore-file", + truststoreFile, + "--rpc-http-tls-truststore-password-file", + truststorePasswordFile); + + verify(mockRunnerBuilder).jsonRpcConfiguration(jsonRpcConfigArgumentCaptor.capture()); + verify(mockRunnerBuilder).build(); + + assertThat(jsonRpcConfigArgumentCaptor.getValue().getHost()).isEqualTo(host); + assertThat(jsonRpcConfigArgumentCaptor.getValue().getPort()).isEqualTo(port); + final Optional tlsConfiguration = + jsonRpcConfigArgumentCaptor.getValue().getTlsConfiguration(); + assertThat(tlsConfiguration.isPresent()).isTrue(); + assertThat(tlsConfiguration.get().getKeyStorePath()).isEqualTo(Path.of(keystoreFile)); + assertThat(tlsConfiguration.get().getClientAuthConfiguration().isPresent()).isTrue(); + assertThat(tlsConfiguration.get().getClientAuthConfiguration().get().getTruststorePath()) + .isEqualTo(Optional.of(Path.of(truststoreFile))); + assertThat(tlsConfiguration.get().getClientAuthConfiguration().get().getTrustStorePassword()) + .isEqualTo(Files.readString(Path.of(truststorePasswordFile))); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + + @Test + public void rpcHttpTlsClientAuthWithTrustStoreAndKnownClientsFileReportsError() + throws IOException { + final String host = "1.2.3.4"; + final int port = 1234; + final String keystoreFile = "/tmp/test.p12"; + final String keystorePasswordFile = "/tmp/test.txt"; + final String truststoreFile = "/tmp/truststore.p12"; + final String truststorePasswordFile = "/tmp/truststore.txt"; + final String knownClientFile = "/tmp/knownClientFile"; + + Files.writeString(Path.of(truststorePasswordFile), "password"); + parseCommand( + "--rpc-http-enabled", + "--rpc-http-host", + host, + "--rpc-http-port", + String.valueOf(port), + "--rpc-http-tls-enabled", + "--rpc-http-tls-keystore-file", + keystoreFile, + "--rpc-http-tls-keystore-password-file", + keystorePasswordFile, + "--rpc-http-tls-client-auth-enabled", + "--rpc-http-tls-truststore-file", + truststoreFile, + "--rpc-http-tls-truststore-password-file", + truststorePasswordFile, + "--rpc-http-tls-known-clients-file", + knownClientFile); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)) + .contains( + "Configuration error: Truststore file (--rpc-http-tls-truststore-file) cannot be used together with CA clients (--rpc-http-tls-ca-clients-enabled) or a known-clients (--rpc-http-tls-known-clients-file) option. " + + "These options are mutually exclusive. Choose either truststore-based authentication or known-clients/CA clients configuration."); + } + @Test public void rpcHttpTlsClientAuthWithCAClientAndKnownClientFile() { final String host = "1.2.3.4"; diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index 402d5962765..0e944e7f0cf 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -84,6 +84,8 @@ rpc-http-tls-keystore-password-file="none.passwd" rpc-http-tls-client-auth-enabled=false rpc-http-tls-known-clients-file="rpc_tls_clients.txt" rpc-http-tls-ca-clients-enabled=false +rpc-http-tls-truststore-file="none.pfx" +rpc-http-tls-truststore-password-file="none.passwd" rpc-http-authentication-jwt-algorithm="RS256" rpc-ws-authentication-jwt-algorithm="RS256" rpc-http-tls-protocols=["TLSv1.2,TlSv1.1"] diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index af50b53bb1c..5f746304c97 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -429,7 +429,7 @@ private void applyTlsConfig(final HttpServerOptions httpServerOptions) { try { httpServerOptions .setSsl(true) - .setPfxKeyCertOptions( + .setKeyCertOptions( new PfxOptions() .setPath(tlsConfiguration.getKeyStorePath().toString()) .setPassword(tlsConfiguration.getKeyStorePassword())) @@ -472,6 +472,14 @@ private void applyTlsClientAuth( httpServerOptions.setTrustOptions( allowlistClients( knownClientsFile, clientAuthConfiguration.isCaClientsEnabled()))); + clientAuthConfiguration + .getTruststorePath() + .ifPresent( + truststorePath -> + httpServerOptions.setTrustOptions( + new PfxOptions() + .setPath(truststorePath.toString()) + .setPassword(clientAuthConfiguration.getTrustStorePassword()))); } private String tlsLogMessage() { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/tls/TlsClientAuthConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/tls/TlsClientAuthConfiguration.java index f765405bcaf..885bc22e3da 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/tls/TlsClientAuthConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/tls/TlsClientAuthConfiguration.java @@ -17,15 +17,23 @@ import java.nio.file.Path; import java.util.Objects; import java.util.Optional; +import java.util.function.Supplier; public class TlsClientAuthConfiguration { private final Optional knownClientsFile; private final boolean caClientsEnabled; + private final Optional truststorePath; + private final Supplier trustStorePasswordSupplier; private TlsClientAuthConfiguration( - final Optional knownClientsFile, final boolean caClientsEnabled) { + final Optional knownClientsFile, + final boolean caClientsEnabled, + final Optional truststorePath, + final Supplier trustStorePasswordSupplier) { this.knownClientsFile = knownClientsFile; this.caClientsEnabled = caClientsEnabled; + this.truststorePath = truststorePath; + this.trustStorePasswordSupplier = trustStorePasswordSupplier; } public Optional getKnownClientsFile() { @@ -36,9 +44,19 @@ public boolean isCaClientsEnabled() { return caClientsEnabled; } + public Optional getTruststorePath() { + return truststorePath; + } + + public String getTrustStorePassword() { + return trustStorePasswordSupplier.get(); + } + public static final class Builder { private Path knownClientsFile; private boolean caClientsEnabled; + private Path truststorePath; + private Supplier trustStorePasswordSupplier; private Builder() {} @@ -56,12 +74,29 @@ public Builder withCaClientsEnabled(final boolean caClientsEnabled) { return this; } + public Builder withTruststorePath(final Path truststorePath) { + this.truststorePath = truststorePath; + return this; + } + + public Builder withTruststorePasswordSupplier(final Supplier keyStorePasswordSupplier) { + this.trustStorePasswordSupplier = keyStorePasswordSupplier; + return this; + } + public TlsClientAuthConfiguration build() { - if (!caClientsEnabled) { + if (!caClientsEnabled && truststorePath == null) { Objects.requireNonNull(knownClientsFile, "Known Clients File is required"); } + if (!caClientsEnabled && knownClientsFile == null) { + Objects.requireNonNull(truststorePath, "Truststore File is required"); + } + return new TlsClientAuthConfiguration( - Optional.ofNullable(knownClientsFile), caClientsEnabled); + Optional.ofNullable(knownClientsFile), + caClientsEnabled, + Optional.ofNullable(truststorePath), + trustStorePasswordSupplier); } } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java index d1348e5327e..c2b1f4e3285 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java @@ -53,11 +53,13 @@ import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; import org.hyperledger.besu.nat.NatService; +import java.io.FileOutputStream; import java.io.IOException; import java.io.UncheckedIOException; import java.math.BigInteger; import java.nio.file.Files; import java.nio.file.Path; +import java.security.KeyStore; import java.util.Collections; import java.util.HashSet; import java.util.Map; @@ -187,6 +189,37 @@ private JsonRpcConfiguration createJsonRpcConfig( return config; } + private Optional getRpcHttpTlsConfigurationOnlyWithTruststore() { + final Path truststorePath = createTempFile(); + + // Create a new truststore and add the okHttpClientCertificate to it + try (FileOutputStream truststoreOutputStream = new FileOutputStream(truststorePath.toFile())) { + KeyStore truststore = KeyStore.getInstance("PKCS12"); + truststore.load(null, null); + truststore.setCertificateEntry( + "okHttpClientCertificate", okHttpClientCertificate.getCertificate()); + truststore.store(truststoreOutputStream, okHttpClientCertificate.getPassword()); + } catch (Exception e) { + throw new RuntimeException("Failed to create truststore", e); + } + + final FileBasedPasswordProvider trustStorePasswordProvider = + new FileBasedPasswordProvider(createPasswordFile(okHttpClientCertificate)); + + final TlsConfiguration tlsConfiguration = + aTlsConfiguration() + .withKeyStorePath(besuCertificate.getKeyStoreFile()) + .withKeyStorePasswordSupplier(fileBasedPasswordProvider) + .withClientAuthConfiguration( + aTlsClientAuthConfiguration() + .withTruststorePath(truststorePath) + .withTruststorePasswordSupplier(trustStorePasswordProvider) + .build()) + .build(); + + return Optional.of(tlsConfiguration); + } + private Optional getRpcHttpTlsConfiguration() { final Path knownClientsFile = createTempFile(); writeToKnownClientsFile( @@ -260,6 +293,23 @@ public void netVersionSuccessfulOnTlsWithClientCertInKnownClientsFile() throws E netVersionSuccessful(this::getTlsHttpClient, baseUrl); } + @Test + public void netVersionSuccessfulOnTlsWithClientCertInTruststore() throws Exception { + + JsonRpcHttpService jsonRpcHttpService = null; + try { + jsonRpcHttpService = + createJsonRpcHttpService( + createJsonRpcConfig(this::getRpcHttpTlsConfigurationOnlyWithTruststore)); + jsonRpcHttpService.start().join(); + netVersionSuccessful(this::getTlsHttpClient, jsonRpcHttpService.url()); + } finally { + if (jsonRpcHttpService != null) { + jsonRpcHttpService.stop().join(); + } + } + } + @Test public void netVersionSuccessfulOnTlsWithClientCertAddedAsCA() throws Exception { netVersionSuccessful(this::getTlsHttpClientAddedAsCA, baseUrl); From 8c451c109ac7ba6c334d56939a2e17ccc5392bc9 Mon Sep 17 00:00:00 2001 From: ahamlat Date: Wed, 18 Dec 2024 13:44:49 +0100 Subject: [PATCH 2/3] Revise the approach for setting level_compaction_dynamic_level_bytes (#8037) * Create a RocksDB opener that display a warning if it takes too much time to open the database * Change the strategy levelCompactionDynamicLevelBytes is set Signed-off-by: Ameziane H. --- CHANGELOG.md | 1 + ...imisticRocksDBColumnarKeyValueStorage.java | 2 +- .../RocksDBColumnarKeyValueStorage.java | 43 ++++- .../rocksdb/segmented/RocksDBOpener.java | 172 ++++++++++++++++++ ...ctionDBRocksDBColumnarKeyValueStorage.java | 2 +- 5 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBOpener.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f906084db59..9f0f3d40763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ ### Bug fixes - Fix serialization of state overrides when `movePrecompileToAddress` is present [#8204](https://github.com/hyperledger/besu/pull/8024) +- Revise the approach for setting level_compaction_dynamic_level_bytes RocksDB configuration option [#8037](https://github.com/hyperledger/besu/pull/8037) ## 24.12.2 Hotfix diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java index d2eaa350239..1e877c1738a 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/OptimisticRocksDBColumnarKeyValueStorage.java @@ -57,7 +57,7 @@ public OptimisticRocksDBColumnarKeyValueStorage( try { db = - OptimisticTransactionDB.open( + RocksDBOpener.openOptimisticTransactionDBWithWarning( options, configuration.getDatabaseDir().toString(), columnDescriptors, columnHandles); initMetrics(); initColumnHandles(); diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java index 0bf107ddb0e..aa508f085c1 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBColumnarKeyValueStorage.java @@ -51,10 +51,12 @@ import org.rocksdb.ColumnFamilyHandle; import org.rocksdb.ColumnFamilyOptions; import org.rocksdb.CompressionType; +import org.rocksdb.ConfigOptions; import org.rocksdb.DBOptions; import org.rocksdb.Env; import org.rocksdb.LRUCache; import org.rocksdb.Options; +import org.rocksdb.OptionsUtil; import org.rocksdb.ReadOptions; import org.rocksdb.RocksDB; import org.rocksdb.RocksDBException; @@ -76,9 +78,6 @@ public abstract class RocksDBColumnarKeyValueStorage implements SegmentedKeyValu /** RocksDb blockcache size when using the high spec option */ protected static final long ROCKSDB_BLOCKCACHE_SIZE_HIGH_SPEC = 1_073_741_824L; - /** RocksDb memtable size when using the high spec option */ - protected static final long ROCKSDB_MEMTABLE_SIZE_HIGH_SPEC = 536_870_912L; - /** Max total size of all WAL file, after which a flush is triggered */ protected static final long WAL_MAX_TOTAL_SIZE = 1_073_741_824L; @@ -186,15 +185,47 @@ public RocksDBColumnarKeyValueStorage( */ private ColumnFamilyDescriptor createColumnDescriptor( final SegmentIdentifier segment, final RocksDBConfiguration configuration) { - + boolean dynamicLevelBytes = true; + try { + ConfigOptions configOptions = new ConfigOptions(); + DBOptions dbOptions = new DBOptions(); + List cfDescriptors = new ArrayList<>(); + + String latestOptionsFileName = + OptionsUtil.getLatestOptionsFileName( + configuration.getDatabaseDir().toString(), Env.getDefault()); + LOG.trace("Latest OPTIONS file detected: " + latestOptionsFileName); + + String optionsFilePath = + configuration.getDatabaseDir().toString() + "/" + latestOptionsFileName; + OptionsUtil.loadOptionsFromFile(configOptions, optionsFilePath, dbOptions, cfDescriptors); + + LOG.trace("RocksDB options loaded successfully from: " + optionsFilePath); + + if (!cfDescriptors.isEmpty()) { + Optional matchedCfOptions = Optional.empty(); + for (ColumnFamilyDescriptor descriptor : cfDescriptors) { + if (Arrays.equals(descriptor.getName(), segment.getId())) { + matchedCfOptions = Optional.of(descriptor.getOptions()); + break; + } + } + if (matchedCfOptions.isPresent()) { + dynamicLevelBytes = matchedCfOptions.get().levelCompactionDynamicLevelBytes(); + LOG.trace("dynamicLevelBytes is set to an existing value : " + dynamicLevelBytes); + } + } + } catch (RocksDBException ex) { + // Options file is not found in the database + } BlockBasedTableConfig basedTableConfig = createBlockBasedTableConfig(segment, configuration); final var options = new ColumnFamilyOptions() .setTtl(0) .setCompressionType(CompressionType.LZ4_COMPRESSION) - .setTableFormatConfig(basedTableConfig); - + .setTableFormatConfig(basedTableConfig) + .setLevelCompactionDynamicLevelBytes(dynamicLevelBytes); if (segment.containsStaticData()) { options .setEnableBlobFiles(true) diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBOpener.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBOpener.java new file mode 100644 index 00000000000..b8c59d638d7 --- /dev/null +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/RocksDBOpener.java @@ -0,0 +1,172 @@ +/* + * 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.plugin.services.storage.rocksdb.segmented; + +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.rocksdb.ColumnFamilyDescriptor; +import org.rocksdb.ColumnFamilyHandle; +import org.rocksdb.DBOptions; +import org.rocksdb.OptimisticTransactionDB; +import org.rocksdb.RocksDBException; +import org.rocksdb.TransactionDB; +import org.rocksdb.TransactionDBOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for opening RocksDB instances with a warning mechanism. + * + *

This class provides methods to open RocksDB databases ({@link OptimisticTransactionDB} and + * {@link TransactionDB}) while monitoring the operation's duration. If the database takes longer + * than a predefined delay (default: 60 seconds) to open, a warning message is logged. This warning + * helps identify potential delays caused by factors such as RocksDB compaction. + */ +public class RocksDBOpener { + + /** + * Default delay (in seconds) after which a warning is logged if the database opening operation + * has not completed. + */ + public static final int DEFAULT_DELAY = 60; + + /** + * Warning message logged when the database opening operation takes longer than the predefined + * delay. + */ + public static final String WARN_MESSAGE = + "Opening RocksDB database is taking longer than 60 seconds... " + + "This may be due to prolonged RocksDB compaction. Please wait until the end of the compaction. " + + "No action is needed from the user."; + + private static final Logger LOG = LoggerFactory.getLogger(RocksDBOpener.class); + + /** + * Default constructor. + * + *

This is a utility class and is not meant to be instantiated directly. + */ + private RocksDBOpener() { + // Default constructor for RocksDBOpener + } + + /** + * Opens an {@link OptimisticTransactionDB} instance with a warning mechanism. + * + *

If the database opening operation takes longer than {@link #DEFAULT_DELAY} seconds, a + * warning message is logged indicating a possible delay caused by compaction. + * + * @param options the {@link DBOptions} instance used to configure the database. + * @param dbPath the file path to the RocksDB database directory. + * @param columnDescriptors a list of {@link ColumnFamilyDescriptor} objects for the column + * families to open. + * @param columnHandles a list of {@link ColumnFamilyHandle} objects to be populated with the + * opened column families. + * @return an instance of {@link OptimisticTransactionDB}. + * @throws RocksDBException if the database cannot be opened. + */ + public static OptimisticTransactionDB openOptimisticTransactionDBWithWarning( + final DBOptions options, + final String dbPath, + final List columnDescriptors, + final List columnHandles) + throws RocksDBException { + return openDBWithWarning( + () -> OptimisticTransactionDB.open(options, dbPath, columnDescriptors, columnHandles)); + } + + /** + * Opens a {@link TransactionDB} instance with a warning mechanism. + * + *

If the database opening operation takes longer than {@link #DEFAULT_DELAY} seconds, a + * warning message is logged indicating a possible delay caused by compaction. + * + * @param options the {@link DBOptions} instance used to configure the database. + * @param transactionDBOptions the {@link TransactionDBOptions} for transaction-specific + * configuration. + * @param dbPath the file path to the RocksDB database directory. + * @param columnDescriptors a list of {@link ColumnFamilyDescriptor} objects for the column + * families to open. + * @param columnHandles a list of {@link ColumnFamilyHandle} objects to be populated with the + * opened column families. + * @return an instance of {@link TransactionDB}. + * @throws RocksDBException if the database cannot be opened. + */ + public static TransactionDB openTransactionDBWithWarning( + final DBOptions options, + final TransactionDBOptions transactionDBOptions, + final String dbPath, + final List columnDescriptors, + final List columnHandles) + throws RocksDBException { + return openDBWithWarning( + () -> + TransactionDB.open( + options, transactionDBOptions, dbPath, columnDescriptors, columnHandles)); + } + + /** + * A generic method to open a RocksDB database with a warning mechanism. + * + *

If the operation takes longer than {@link #DEFAULT_DELAY} seconds, a warning message is + * logged. + * + * @param dbOperation a lambda or method reference representing the database opening logic. + * @param the type of the database being opened (e.g., {@link OptimisticTransactionDB} or + * {@link TransactionDB}). + * @return an instance of the database being opened. + * @throws RocksDBException if the database cannot be opened. + */ + private static T openDBWithWarning(final DBOperation dbOperation) throws RocksDBException { + AtomicBoolean operationCompleted = new AtomicBoolean(false); + ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + scheduler.schedule( + () -> { + if (!operationCompleted.get()) { + LOG.warn(WARN_MESSAGE); + } + }, + DEFAULT_DELAY, + TimeUnit.SECONDS); + + try { + T db = dbOperation.open(); + operationCompleted.set(true); + return db; + } finally { + scheduler.shutdown(); + } + } + + /** + * Functional interface representing a database opening operation. + * + * @param the type of the database being opened. + */ + @FunctionalInterface + private interface DBOperation { + /** + * Opens the database. + * + * @return the opened database instance. + * @throws RocksDBException if an error occurs while opening the database. + */ + T open() throws RocksDBException; + } +} diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java index 60879b658e6..035adbfa589 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/segmented/TransactionDBRocksDBColumnarKeyValueStorage.java @@ -56,7 +56,7 @@ public TransactionDBRocksDBColumnarKeyValueStorage( try { db = - TransactionDB.open( + RocksDBOpener.openTransactionDBWithWarning( options, txOptions, configuration.getDatabaseDir().toString(), From d3773d9e336cc7a0af7f1290301e7481f97a9c58 Mon Sep 17 00:00:00 2001 From: daniellehrner Date: Wed, 18 Dec 2024 18:28:08 +0100 Subject: [PATCH 3/3] Pectra Devnet-5: 7702 & 7251: address & code changes (#8029) * update 7251 address, update 7251 & 7702 code Signed-off-by: Daniel Lehrner * spotless Signed-off-by: Daniel Lehrner * Update EIP-7251: Set MAX_CONSOLIDATIONS=2 Signed-off-by: Daniel Lehrner --------- Signed-off-by: Daniel Lehrner --- .../requests/RequestContractAddresses.java | 2 +- .../t8n/prague-withdrawal-request.json | 41 ++++++++++--------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestContractAddresses.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestContractAddresses.java index ef76961ba2b..ebc48a10fb9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestContractAddresses.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/requests/RequestContractAddresses.java @@ -25,7 +25,7 @@ public class RequestContractAddresses { public static final Address DEFAULT_WITHDRAWAL_REQUEST_CONTRACT_ADDRESS = Address.fromHexString("0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA"); public static final Address DEFAULT_CONSOLIDATION_REQUEST_CONTRACT_ADDRESS = - Address.fromHexString("0x01ABEA29659E5E97C95107F20BB753CD3E09BBBB"); + Address.fromHexString("0x00431F263cE400f4455c2dCf564e53007Ca4bbBb"); public static final Address DEFAULT_DEPOSIT_CONTRACT_ADDRESS = Address.fromHexString("0x00000000219ab540356cbb839cbe05303d7705fa"); diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json index 91588037fd2..615161c88d8 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/prague-withdrawal-request.json @@ -55,13 +55,14 @@ "comment": "This is the runtime bytecode for the Withdrawal Request Smart Contract.", "nonce": "0x01", "balance": "0x00", - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460c7573615156028575f545f5260205ff35b36603814156101f05760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f057600182026001905f5b5f821115608057810190830284830290049160010191906065565b9093900434106101f057600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160db575060105b5f5b81811461017f5780604c02838201600302600401805490600101805490600101549160601b83528260140152807fffffffffffffffffffffffffffffffff0000000000000000000000000000000016826034015260401c906044018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160dd565b9101809214610191579060025561019c565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101c957505f5b6001546002828201116101de5750505f6101e4565b01600290035b5f555f600155604c025ff35b5f5ffd", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "storage": {} }, - "0x01abea29659e5e97c95107f20bb753cd3e09bbbb": { + "0x00431f263ce400f4455c2dcf564e53007ca4bbbb": { + "comment": "Increase the MAX_EFFECTIVE_BALANCE", "nonce": "0x01", "balance": "0x00", - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "storage": {} }, "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { @@ -183,13 +184,21 @@ "balance": "0x0", "nonce": "0x1" }, - "0x01abea29659e5e97c95107f20bb753cd3e09bbbb": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cf573615156028575f545f5260205ff35b366060141561019a5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f821115608057810190830284830290049160010191906065565b90939004341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060011160e3575060015b5f5b8181146101295780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160e5565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", + "0x00431f263ce400f4455c2dcf564e53007ca4bbbb": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "balance": "0x0", "nonce": "0x1" }, + "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e":{ + "code":"0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", + "storage":{ + "0x0000000000000000000000000000000000000000000000000000000000000000":"0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb" + }, + "balance":"0x0", + "nonce":"0x1" + }, "0x0c15f14308530b7cdb8460094bbb9cc28b9aaaaa": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460c7573615156028575f545f5260205ff35b36603814156101f05760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f057600182026001905f5b5f821115608057810190830284830290049160010191906065565b9093900434106101f057600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160db575060105b5f5b81811461017f5780604c02838201600302600401805490600101805490600101549160601b83528260140152807fffffffffffffffffffffffffffffffff0000000000000000000000000000000016826034015260401c906044018160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160dd565b9101809214610191579060025561019c565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101c957505f5b6001546002828201116101de5750505f6101e4565b01600290035b5f555f600155604c025ff35b5f5ffd", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000004": "0x0000000000000000000000000000000000000000000000000000000000001000", "0x0000000000000000000000000000000000000000000000000000000000000006": "0x0000000000000000000000000000000100000000000000000000000000000000" @@ -197,16 +206,8 @@ "balance": "0x1", "nonce": "0x1" }, - "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000000": "0x10715cfbefdb8a0cb2f7d7ca5ee6d1ea65515ecb41cff0a22d1e11716a9d27fb" - }, - "balance": "0x0", - "nonce": "0x1" - }, "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { - "balance": "0xad78ebc5ac61f2afcb", + "balance": "0xad78ebc5ac61f2b034", "nonce": "0x1" } }, @@ -218,16 +219,16 @@ "0x00000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000", "0x" ], - "stateRoot": "0x85f165ac5a1420cd8931904750ffa7d8e271a53590776045731a7a31bd28fb35", + "stateRoot": "0x575019750f84d65daf5469b26d05ad8e4335c63011dbca71ca97420cbd80d579", "txRoot": "0x0d36638e52999b7beafa00eb94f7ca23139774cd14229c011d0edc1fc66125c9", - "receiptsRoot": "0x74c42177b19a4db67c4bf4eb40d7e0a31102f8e918db6b60276994d95834b8f9", + "receiptsRoot": "0x2af83312a6aa55bd8f169e65eec48f92d6d6dc3398bc038d7ccfab5d9aa26b3f", "logsHash": "0xac344ad50aad544ec284bf76ac9b939f93e00f8fe16097a151df14bde2065f83", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000", "receipts": [ { "root": "0x", "status": "0x1", - "cumulativeGasUsed": "0x1e6e3", + "cumulativeGasUsed": "0x1e6d4", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000", "logs": [ { @@ -244,13 +245,13 @@ ], "transactionHash": "0xa888ec4587b7ba70d0127004a96fbb0a83ccb611e61405094e6514b970bf37f6", "contractAddress": "0x0000000000000000000000000000000000000000", - "gasUsed": "0x1e6e3", + "gasUsed": "0x1e6d4", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0" } ], "currentDifficulty": null, - "gasUsed": "0x1e6e3", + "gasUsed": "0x1e6d4", "currentBaseFee": "0x7", "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "currentExcessBlobGas": "0x0",