diff --git a/CHANGELOG.md b/CHANGELOG.md index e01d115b51a..970e5103e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 24.1.2-SNAPSHOT +## 24.2.0-SNAPSHOT ### Breaking Changes - Following the OpenMetrics convention, the updated Prometheus client adds the `_total` suffix to every metrics of type counter, with the effect that some existing metrics have been renamed to have this suffix. If you are using the official Besu Grafana dashboard [(available here)](https://grafana.com/grafana/dashboards/16455-besu-full/), just update it to the latest revision, that accepts the old and the new name of the affected metrics. If you have a custom dashboard or use the metrics in other ways, then you need to manually update it to support the new naming. @@ -8,7 +8,7 @@ - Requesting the Ethereum Node Record (ENR) to acquire the fork id from bonded peers is now enabled by default, so the following change has been made [#5628](https://github.com/hyperledger/besu/pull/5628): - `--Xfilter-on-enr-fork-id` has been removed. To disable the feature use `--filter-on-enr-fork-id=false`. - `--engine-jwt-enabled` has been removed. Use `--engine-jwt-disabled` instead. [#6491](https://github.com/hyperledger/besu/pull/6491) - +- SNAP sync is now the default for named networks [#6530](https://github.com/hyperledger/besu/pull/6530) ### Deprecations - X_SNAP and X_CHECKPOINT are marked for deprecation and will be removed in 24.4.0 in favor of SNAP and CHECKPOINT [#6405](https://github.com/hyperledger/besu/pull/6405) @@ -31,12 +31,29 @@ - Support for `shanghaiTime` fork and Shanghai EVM smart contracts in QBFT/IBFT chains [#6353](https://github.com/hyperledger/besu/pull/6353) - Change ExecutionHaltReason for contract creation collision case to return ILLEGAL_STATE_CHANGE [#6518](https://github.com/hyperledger/besu/pull/6518) - Experimental feature `--Xbonsai-code-using-code-hash-enabled` for storing Bonsai code storage by code hash [#6505](https://github.com/hyperledger/besu/pull/6505) +- More accurate column size `storage rocksdb usage` subcommand [#6540](https://github.com/hyperledger/besu/pull/6540) +- Adds `storage rocksdb x-stats` subcommand [#6540](https://github.com/hyperledger/besu/pull/6540) +- New `eth_blobBaseFee`JSON-RPC method [#6581](https://github.com/hyperledger/besu/pull/6581) ### Bug fixes - Fix the way an advertised host configured with `--p2p-host` is treated when communicating with the originator of a PING packet [#6225](https://github.com/hyperledger/besu/pull/6225) - Fix `poa-block-txs-selection-max-time` option that was inadvertently reset to its default after being configured [#6444](https://github.com/hyperledger/besu/pull/6444) +- Fix for tx incorrectly discarded when there is a timeout during block creation [#6563](https://github.com/hyperledger/besu/pull/6563) + +### Download Links + +## 24.1.2 + +### Bug fixes +- Fix ETC Spiral upgrade breach of consensus [#6524](https://github.com/hyperledger/besu/pull/6524) + +### Additions and Improvements +- Adds timestamp to enable Cancun upgrade on mainnet [#6545](https://github.com/hyperledger/besu/pull/6545) +- Github Actions based build.[#6427](https://github.com/hyperledger/besu/pull/6427) ### Download Links +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/24.1.2/besu-24.1.2.zip / sha256 9033f300edd81c770d3aff27a29f59dd4b6142a113936886a8f170718e412971 +https://hyperledger.jfrog.io/artifactory/besu-binaries/besu/24.1.2/besu-24.1.2.tar.gz / sha256 082db8cf4fb67527aa0dd757e5d254b3b497f5027c23287f9c0a74a6a743bf08 ## 24.1.1 diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index 7f481a54095..214e108e15d 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -513,7 +513,7 @@ private InetAddress autoDiscoverDefaultIP() { names = {"--sync-mode"}, paramLabel = MANDATORY_MODE_FORMAT_HELP, description = - "Synchronization mode, possible values are ${COMPLETION-CANDIDATES} (default: FAST if a --network is supplied and privacy isn't enabled. FULL otherwise.)") + "Synchronization mode, possible values are ${COMPLETION-CANDIDATES} (default: SNAP if a --network is supplied and privacy isn't enabled. FULL otherwise.)") private SyncMode syncMode = null; @Option( @@ -2667,8 +2667,8 @@ private SyncMode getDefaultSyncModeIfNotSet() { .orElse( genesisFile == null && !privacyOptionGroup.isPrivacyEnabled - && Optional.ofNullable(network).map(NetworkName::canFastSync).orElse(false) - ? SyncMode.FAST + && Optional.ofNullable(network).map(NetworkName::canSnapSync).orElse(false) + ? SyncMode.SNAP : SyncMode.FULL); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index 94ec812de95..554d0645a44 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -47,17 +47,17 @@ public enum NetworkName { private final String genesisFile; private final BigInteger networkId; - private final boolean canFastSync; + private final boolean canSnapSync; private final String deprecationDate; NetworkName(final String genesisFile, final BigInteger networkId) { this(genesisFile, networkId, true); } - NetworkName(final String genesisFile, final BigInteger networkId, final boolean canFastSync) { + NetworkName(final String genesisFile, final BigInteger networkId, final boolean canSnapSync) { this.genesisFile = genesisFile; this.networkId = networkId; - this.canFastSync = canFastSync; + this.canSnapSync = canSnapSync; // no deprecations planned this.deprecationDate = null; } @@ -81,12 +81,12 @@ public BigInteger getNetworkId() { } /** - * Can fast sync boolean. + * Can SNAP sync boolean. * * @return the boolean */ - public boolean canFastSync() { - return canFastSync; + public boolean canSnapSync() { + return canSnapSync; } /** diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbHelper.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbHelper.java index 7f2fc609a1b..2b122979830 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbHelper.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbHelper.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; +import java.util.stream.Stream; import org.bouncycastle.util.Arrays; import org.rocksdb.ColumnFamilyDescriptor; @@ -66,36 +67,210 @@ static void forEachColumnFamily( } } - static void printUsageForColumnFamily( + static void printStatsForColumnFamily( final RocksDB rocksdb, final ColumnFamilyHandle cfHandle, final PrintWriter out) - throws RocksDBException, NumberFormatException { + throws RocksDBException { final String size = rocksdb.getProperty(cfHandle, "rocksdb.estimate-live-data-size"); final String numberOfKeys = rocksdb.getProperty(cfHandle, "rocksdb.estimate-num-keys"); - boolean emptyColumnFamily = false; - if (!size.isBlank() && !numberOfKeys.isBlank()) { + final long sizeLong = Long.parseLong(size); + final long numberOfKeysLong = Long.parseLong(numberOfKeys); + if (!size.isBlank() + && !numberOfKeys.isBlank() + && isPopulatedColumnFamily(sizeLong, numberOfKeysLong)) { + out.println("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); + out.println("Column Family: " + getNameById(cfHandle.getName())); + + final String prefix = "rocksdb."; + final String cfstats = "cfstats"; + final String cfstats_no_file_histogram = "cfstats-no-file-histogram"; + final String cf_file_histogram = "cf-file-histogram"; + final String cf_write_stall_stats = "cf-write-stall-stats"; + final String dbstats = "dbstats"; + final String db_write_stall_stats = "db-write-stall-stats"; + final String levelstats = "levelstats"; + final String block_cache_entry_stats = "block-cache-entry-stats"; + final String fast_block_cache_entry_stats = "fast-block-cache-entry-stats"; + final String num_immutable_mem_table = "num-immutable-mem-table"; + final String num_immutable_mem_table_flushed = "num-immutable-mem-table-flushed"; + final String mem_table_flush_pending = "mem-table-flush-pending"; + final String compaction_pending = "compaction-pending"; + final String background_errors = "background-errors"; + final String cur_size_active_mem_table = "cur-size-active-mem-table"; + final String cur_size_all_mem_tables = "cur-size-all-mem-tables"; + final String size_all_mem_tables = "size-all-mem-tables"; + final String num_entries_active_mem_table = "num-entries-active-mem-table"; + final String num_entries_imm_mem_tables = "num-entries-imm-mem-tables"; + final String num_deletes_active_mem_table = "num-deletes-active-mem-table"; + final String num_deletes_imm_mem_tables = "num-deletes-imm-mem-tables"; + final String estimate_num_keys = "estimate-num-keys"; + final String estimate_table_readers_mem = "estimate-table-readers-mem"; + final String is_file_deletions_enabled = "is-file-deletions-enabled"; + final String num_snapshots = "num-snapshots"; + final String oldest_snapshot_time = "oldest-snapshot-time"; + final String oldest_snapshot_sequence = "oldest-snapshot-sequence"; + final String num_live_versions = "num-live-versions"; + final String current_version_number = "current-super-version-number"; + final String estimate_live_data_size = "estimate-live-data-size"; + final String min_log_number_to_keep_str = "min-log-number-to-keep"; + final String min_obsolete_sst_number_to_keep_str = "min-obsolete-sst-number-to-keep"; + final String base_level_str = "base-level"; + final String total_sst_files_size = "total-sst-files-size"; + final String live_sst_files_size = "live-sst-files-size"; + final String obsolete_sst_files_size = "obsolete-sst-files-size"; + final String live_sst_files_size_at_temperature = "live-sst-files-size-at-temperature"; + final String estimate_pending_comp_bytes = "estimate-pending-compaction-bytes"; + final String aggregated_table_properties = "aggregated-table-properties"; + final String num_running_compactions = "num-running-compactions"; + final String num_running_flushes = "num-running-flushes"; + final String actual_delayed_write_rate = "actual-delayed-write-rate"; + final String is_write_stopped = "is-write-stopped"; + final String estimate_oldest_key_time = "estimate-oldest-key-time"; + final String block_cache_capacity = "block-cache-capacity"; + final String block_cache_usage = "block-cache-usage"; + final String block_cache_pinned_usage = "block-cache-pinned-usage"; + final String options_statistics = "options-statistics"; + final String num_blob_files = "num-blob-files"; + final String blob_stats = "blob-stats"; + final String total_blob_file_size = "total-blob-file-size"; + final String live_blob_file_size = "live-blob-file-size"; + final String live_blob_file_garbage_size = "live-blob-file-garbage-size"; + final String blob_cache_capacity = "blob-cache-capacity"; + final String blob_cache_usage = "blob-cache-usage"; + final String blob_cache_pinned_usage = "blob-cache-pinned-usage"; + Stream.of( + cfstats, + cfstats_no_file_histogram, + cf_file_histogram, + cf_write_stall_stats, + dbstats, + db_write_stall_stats, + levelstats, + block_cache_entry_stats, + fast_block_cache_entry_stats, + num_immutable_mem_table, + num_immutable_mem_table_flushed, + mem_table_flush_pending, + compaction_pending, + background_errors, + cur_size_active_mem_table, + cur_size_all_mem_tables, + size_all_mem_tables, + num_entries_active_mem_table, + num_entries_imm_mem_tables, + num_deletes_active_mem_table, + num_deletes_imm_mem_tables, + estimate_num_keys, + estimate_table_readers_mem, + is_file_deletions_enabled, + num_snapshots, + oldest_snapshot_time, + oldest_snapshot_sequence, + num_live_versions, + current_version_number, + estimate_live_data_size, + min_log_number_to_keep_str, + min_obsolete_sst_number_to_keep_str, + base_level_str, + total_sst_files_size, + live_sst_files_size, + obsolete_sst_files_size, + live_sst_files_size_at_temperature, + estimate_pending_comp_bytes, + aggregated_table_properties, + num_running_compactions, + num_running_flushes, + actual_delayed_write_rate, + is_write_stopped, + estimate_oldest_key_time, + block_cache_capacity, + block_cache_usage, + block_cache_pinned_usage, + options_statistics, + num_blob_files, + blob_stats, + total_blob_file_size, + live_blob_file_size, + live_blob_file_garbage_size, + blob_cache_capacity, + blob_cache_usage, + blob_cache_pinned_usage) + .forEach( + prop -> { + try { + final String value = rocksdb.getProperty(cfHandle, prefix + prop); + if (!value.isBlank()) { + out.println(prop + ": " + value); + } + } catch (RocksDBException e) { + LOG.debug("couldn't get property {}", prop); + } + }); + out.println("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="); + } + } + + static ColumnFamilyUsage getAndPrintUsageForColumnFamily( + final RocksDB rocksdb, final ColumnFamilyHandle cfHandle, final PrintWriter out) + throws RocksDBException, NumberFormatException { + final String numberOfKeys = rocksdb.getProperty(cfHandle, "rocksdb.estimate-num-keys"); + if (!numberOfKeys.isBlank()) { try { - final long sizeLong = Long.parseLong(size); final long numberOfKeysLong = Long.parseLong(numberOfKeys); final String totalSstFilesSize = rocksdb.getProperty(cfHandle, "rocksdb.total-sst-files-size"); final long totalSstFilesSizeLong = !totalSstFilesSize.isBlank() ? Long.parseLong(totalSstFilesSize) : 0; - if (sizeLong == 0 && numberOfKeysLong == 0) { - emptyColumnFamily = true; - } - if (!emptyColumnFamily) { + final String totalBlobFilesSize = + rocksdb.getProperty(cfHandle, "rocksdb.total-blob-file-size"); + final long totalBlobFilesSizeLong = + !totalBlobFilesSize.isBlank() ? Long.parseLong(totalBlobFilesSize) : 0; + + final long totalFilesSize = totalSstFilesSizeLong + totalBlobFilesSizeLong; + if (isPopulatedColumnFamily(0, numberOfKeysLong)) { printLine( out, getNameById(cfHandle.getName()), rocksdb.getProperty(cfHandle, "rocksdb.estimate-num-keys"), - formatOutputSize(sizeLong), - formatOutputSize(totalSstFilesSizeLong)); + formatOutputSize(totalFilesSize), + formatOutputSize(totalSstFilesSizeLong), + formatOutputSize(totalBlobFilesSizeLong)); } + return new ColumnFamilyUsage( + getNameById(cfHandle.getName()), + numberOfKeysLong, + totalFilesSize, + totalSstFilesSizeLong, + totalBlobFilesSizeLong); } catch (NumberFormatException e) { LOG.error("Failed to parse string into long: " + e.getMessage()); } } + // return empty usage on error + return new ColumnFamilyUsage(getNameById(cfHandle.getName()), 0, 0, 0, 0); + } + + static void printTotals(final PrintWriter out, final List columnFamilyUsages) { + final long totalKeys = columnFamilyUsages.stream().mapToLong(ColumnFamilyUsage::keys).sum(); + final long totalSize = + columnFamilyUsages.stream().mapToLong(ColumnFamilyUsage::totalSize).sum(); + final long totalSsts = + columnFamilyUsages.stream().mapToLong(ColumnFamilyUsage::sstFilesSize).sum(); + final long totalBlobs = + columnFamilyUsages.stream().mapToLong(ColumnFamilyUsage::blobFilesSize).sum(); + printSeparator(out); + printLine( + out, + "ESTIMATED TOTAL", + String.valueOf(totalKeys), + formatOutputSize(totalSize), + formatOutputSize(totalSsts), + formatOutputSize(totalBlobs)); + printSeparator(out); + } + + private static boolean isPopulatedColumnFamily(final long size, final long numberOfKeys) { + return size != 0 || numberOfKeys != 0; } static String formatOutputSize(final long size) { @@ -123,19 +298,28 @@ private static String getNameById(final byte[] id) { } static void printTableHeader(final PrintWriter out) { + printSeparator(out); out.format( - "| Column Family | Keys | Column Size | SST Files Size |\n"); + "| Column Family | Keys | Total Size | SST Files Size | Blob Files Size | \n"); + printSeparator(out); + } + + private static void printSeparator(final PrintWriter out) { out.format( - "|--------------------------------|-----------------|--------------|-----------------|\n"); + "|--------------------------------|-----------------|-------------|-----------------|------------------|\n"); } static void printLine( final PrintWriter out, final String cfName, final String keys, - final String columnSize, - final String sstFilesSize) { - final String format = "| %-30s | %-15s | %-12s | %-15s |\n"; - out.format(format, cfName, keys, columnSize, sstFilesSize); + final String totalFilesSize, + final String sstFilesSize, + final String blobFilesSize) { + final String format = "| %-30s | %-15s | %-11s | %-15s | %-16s |\n"; + out.format(format, cfName, keys, totalFilesSize, sstFilesSize, blobFilesSize); } + + record ColumnFamilyUsage( + String name, long keys, long totalSize, long sstFilesSize, long blobFilesSize) {} } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbSubCommand.java index 0beddfdcbca..9ca55cbc38b 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/RocksDbSubCommand.java @@ -19,6 +19,8 @@ import org.hyperledger.besu.cli.util.VersionProvider; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import org.rocksdb.RocksDBException; import picocli.CommandLine; @@ -31,12 +33,12 @@ description = "Print RocksDB information", mixinStandardHelpOptions = true, versionProvider = VersionProvider.class, - subcommands = {RocksDbSubCommand.RocksDbUsage.class}) + subcommands = {RocksDbSubCommand.RocksDbUsage.class, RocksDbSubCommand.RocksDbStats.class}) public class RocksDbSubCommand implements Runnable { @SuppressWarnings("unused") @ParentCommand - private StorageSubCommand parentCommand; + private StorageSubCommand storageSubCommand; @SuppressWarnings("unused") @CommandLine.Spec @@ -60,7 +62,7 @@ static class RocksDbUsage implements Runnable { @SuppressWarnings("unused") @ParentCommand - private RocksDbSubCommand parentCommand; + private RocksDbSubCommand rocksDbSubCommand; @Override public void run() { @@ -68,21 +70,64 @@ public void run() { final PrintWriter out = spec.commandLine().getOut(); final String dbPath = - parentCommand - .parentCommand - .parentCommand + rocksDbSubCommand + .storageSubCommand + .besuCommand .dataDir() - .toString() - .concat("/") - .concat(DATABASE_PATH); + .resolve(DATABASE_PATH) + .toString(); RocksDbHelper.printTableHeader(out); + final List columnFamilyUsages = new ArrayList<>(); RocksDbHelper.forEachColumnFamily( dbPath, (rocksdb, cfHandle) -> { try { - RocksDbHelper.printUsageForColumnFamily(rocksdb, cfHandle, out); + columnFamilyUsages.add( + RocksDbHelper.getAndPrintUsageForColumnFamily(rocksdb, cfHandle, out)); + } catch (RocksDBException e) { + throw new RuntimeException(e); + } + }); + RocksDbHelper.printTotals(out, columnFamilyUsages); + } + } + + @Command( + name = "x-stats", + description = "Print rocksdb stats", + mixinStandardHelpOptions = true, + versionProvider = VersionProvider.class) + static class RocksDbStats implements Runnable { + + @SuppressWarnings("unused") + @CommandLine.Spec + private CommandLine.Model.CommandSpec spec; + + @SuppressWarnings("unused") + @ParentCommand + private RocksDbSubCommand rocksDbSubCommand; + + @Override + public void run() { + + final PrintWriter out = spec.commandLine().getOut(); + + final String dbPath = + rocksDbSubCommand + .storageSubCommand + .besuCommand + .dataDir() + .resolve(DATABASE_PATH) + .toString(); + + out.println("Column Family Stats..."); + RocksDbHelper.forEachColumnFamily( + dbPath, + (rocksdb, cfHandle) -> { + try { + RocksDbHelper.printStatsForColumnFamily(rocksdb, cfHandle, out); } catch (RocksDBException e) { throw new RuntimeException(e); } diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java index 0dbfa3d22c5..57eb50846d8 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/StorageSubCommand.java @@ -57,7 +57,7 @@ public class StorageSubCommand implements Runnable { @SuppressWarnings("unused") @ParentCommand - BesuCommand parentCommand; + BesuCommand besuCommand; @SuppressWarnings("unused") @Spec @@ -104,8 +104,8 @@ public void run() { private StorageProvider getStorageProvider() { // init collection of ignorable segments - parentCommand.parentCommand.setIgnorableStorageSegments(); - return parentCommand.parentCommand.getStorageProvider(); + parentCommand.besuCommand.setIgnorableStorageSegments(); + return parentCommand.besuCommand.getStorageProvider(); } private void revert(final StorageProvider storageProvider) { diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java index 9317dde1304..47bad2292e4 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/storage/TrieLogSubCommand.java @@ -78,7 +78,7 @@ public void run() { } private static BesuController createBesuController() { - return parentCommand.parentCommand.buildController(); + return parentCommand.besuCommand.buildController(); } @Command( @@ -132,7 +132,7 @@ public void run() { final TrieLogContext context = getTrieLogContext(); final Path dataDirectoryPath = Paths.get( - TrieLogSubCommand.parentCommand.parentCommand.dataDir().toAbsolutePath().toString()); + TrieLogSubCommand.parentCommand.besuCommand.dataDir().toAbsolutePath().toString()); LOG.info("Estimating trie logs size before pruning..."); long sizeBefore = estimatedSizeOfTrieLogs(); @@ -167,7 +167,7 @@ public void run() { private long estimatedSizeOfTrieLogs() { final String dbPath = TrieLogSubCommand.parentCommand - .parentCommand + .besuCommand .dataDir() .toString() .concat("/") @@ -180,9 +180,13 @@ private long estimatedSizeOfTrieLogs() { (rocksdb, cfHandle) -> { try { if (Arrays.equals(cfHandle.getName(), TRIE_LOG_STORAGE.getId())) { - estimatedSaving.set( - Long.parseLong( - rocksdb.getProperty(cfHandle, "rocksdb.estimate-live-data-size"))); + + final long sstSize = + Long.parseLong(rocksdb.getProperty(cfHandle, "rocksdb.total-sst-files-size")); + final long blobSize = + Long.parseLong(rocksdb.getProperty(cfHandle, "rocksdb.total-blob-file-size")); + + estimatedSaving.set(sstSize + blobSize); } } catch (RocksDBException | NumberFormatException e) { throw new RuntimeException(e); @@ -233,7 +237,7 @@ public void run() { trieLogFilePath = Paths.get( TrieLogSubCommand.parentCommand - .parentCommand + .besuCommand .dataDir() .resolve("trie-logs.bin") .toAbsolutePath() @@ -283,7 +287,7 @@ public void run() { trieLogFilePath = Paths.get( TrieLogSubCommand.parentCommand - .parentCommand + .besuCommand .dataDir() .resolve("trie-logs.bin") .toAbsolutePath() diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index 09b7c8a2cbf..63841f12a86 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -257,7 +257,7 @@ public void callingBesuCommandWithoutOptionsMustSyncWithDefaultValues() { verify(mockControllerBuilder).build(); assertThat(storageProviderArgumentCaptor.getValue()).isNotNull(); - assertThat(syncConfigurationCaptor.getValue().getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfigurationCaptor.getValue().getSyncMode()).isEqualTo(SyncMode.SNAP); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); assertThat(miningArg.getValue().getCoinbase()).isEqualTo(Optional.empty()); assertThat(miningArg.getValue().getMinTransactionGasPrice()).isEqualTo(Wei.of(1000)); @@ -1149,6 +1149,18 @@ public void syncMode_full_by_default_for_dev() { assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); } + @Test + public void syncMode_snap_by_default() { + parseCommand(); + verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); + + final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.SNAP); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + } + @Test public void helpShouldDisplayFastSyncOptions() { parseCommand("--help"); diff --git a/besu/src/test/java/org/hyperledger/besu/cli/CascadingDefaultProviderTest.java b/besu/src/test/java/org/hyperledger/besu/cli/CascadingDefaultProviderTest.java index fcba28bd61b..008ae6a89b1 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/CascadingDefaultProviderTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/CascadingDefaultProviderTest.java @@ -179,7 +179,7 @@ public void noOverrideDefaultValuesIfKeyIsNotPresentInConfigFile() { verify(mockControllerBuilder).synchronizerConfiguration(syncConfigurationCaptor.capture()); final SynchronizerConfiguration syncConfig = syncConfigurationCaptor.getValue(); - assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.FAST); + assertThat(syncConfig.getSyncMode()).isEqualTo(SyncMode.SNAP); assertThat(syncConfig.getFastSyncMinimumPeerCount()).isEqualTo(5); assertThat(commandOutput.toString(UTF_8)).isEmpty(); diff --git a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java index 2f1b18eab13..d0944b131a8 100644 --- a/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java +++ b/besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java @@ -140,7 +140,10 @@ public void setUp() { .thenReturn(mockTransactionValidatorFactory); lenient().when(mockProtocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0L)); lenient() - .when(mockTransactionValidatorFactory.get().validate(any(), any(Optional.class), any())) + .when( + mockTransactionValidatorFactory + .get() + .validate(any(), any(Optional.class), any(Optional.class), any())) .thenReturn(ValidationResult.valid()); lenient() .when(mockTransactionValidatorFactory.get().validateForSender(any(), any(), any())) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java index fad3bffce6c..2e0fd4064d3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java @@ -428,6 +428,7 @@ private Router buildRouter() { .handler( BodyHandler.create() .setUploadsDirectory(dataDir.resolve("uploads").toString()) + .setBodyLimit(128 * 1024 * 1024) .setDeleteUploadedFilesOnEnd(true)); router.route("/").method(HttpMethod.GET).handler(this::handleEmptyRequest); router diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index d719e5b48b5..eb18f1379c1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -98,6 +98,7 @@ public enum RpcMethod { ETH_CREATE_ACCESS_LIST("eth_createAccessList"), ETH_FEE_HISTORY("eth_feeHistory"), ETH_GAS_PRICE("eth_gasPrice"), + ETH_BLOB_BASE_FEE("eth_blobBaseFee"), ETH_GET_BALANCE("eth_getBalance"), ETH_GET_BLOCK_BY_HASH("eth_getBlockByHash"), ETH_GET_BLOCK_BY_NUMBER("eth_getBlockByNumber"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java new file mode 100644 index 00000000000..b1108e815a8 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java @@ -0,0 +1,57 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.jsonrpc.internal.methods; + +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +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.results.Quantity; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; + +public class EthBlobBaseFee implements JsonRpcMethod { + + final Blockchain blockchain; + + private final ProtocolSchedule protocolSchedule; + + public EthBlobBaseFee(final Blockchain blockchain, final ProtocolSchedule protocolSchedule) { + this.blockchain = blockchain; + this.protocolSchedule = protocolSchedule; + } + + @Override + public String getName() { + return RpcMethod.ETH_BLOB_BASE_FEE.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { + return new JsonRpcSuccessResponse( + requestContext.getRequest().getId(), Quantity.create(computeNextBlobBaseFee())); + } + + private Wei computeNextBlobBaseFee() { + final BlockHeader header = blockchain.getChainHeadHeader(); + ProtocolSpec spec = protocolSchedule.getForNextBlockHeader(header, header.getTimestamp()); + return spec.getFeeMarket().blobGasPricePerGas(calculateExcessBlobGasForParent(spec, header)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java index 88b9348edf0..827aa57c642 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthAccounts; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlobBaseFee; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlockNumber; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCall; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthChainId; @@ -181,6 +182,7 @@ protected Map create() { new EthSubmitHashRate(miningCoordinator), new EthChainId(protocolSchedule.getChainId()), new EthGetMinerDataByBlockHash(blockchainQueries, protocolSchedule), - new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule)); + new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule), + new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java new file mode 100644 index 00000000000..3e613cc9955 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java @@ -0,0 +1,87 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * 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.jsonrpc.internal.methods; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +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.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class EthBlobBaseFeeTest { + private final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); + private MutableBlockchain blockchain; + private EthBlobBaseFee method; + private ProtocolSchedule protocolSchedule; + + @BeforeEach + public void setUp() { + protocolSchedule = mock(ProtocolSchedule.class); + Block genesisBlock = blockDataGenerator.genesisBlock(); + blockchain = createInMemoryBlockchain(genesisBlock); + blockDataGenerator + .blockSequence(genesisBlock, 10) + .forEach(block -> blockchain.appendBlock(block, blockDataGenerator.receipts(block))); + method = new EthBlobBaseFee(blockchain, protocolSchedule); + } + + /** Tests that the method returns the expected blob base fee */ + @Test + public void shouldReturnBlobBaseFee() { + configureProtocolSpec(FeeMarket.cancun(5, Optional.empty()), new CancunGasCalculator()); + assertThat(requestBlobBaseFee().getResult()).isEqualTo("0x1"); + } + + /** Tests that the method returns zero for forks that do not support blob transactions */ + @Test + public void shouldReturnZeroForNonBlobForks() { + configureProtocolSpec(FeeMarket.london(5, Optional.empty()), new ShanghaiGasCalculator()); + assertThat(requestBlobBaseFee().getResult()).isEqualTo("0x0"); + } + + private void configureProtocolSpec( + final BaseFeeMarket feeMarket, final GasCalculator gasCalculator) { + ProtocolSpec spec = mock(ProtocolSpec.class); + when(spec.getFeeMarket()).thenReturn(feeMarket); + when(spec.getGasCalculator()).thenReturn(gasCalculator); + when(protocolSchedule.getForNextBlockHeader( + blockchain.getChainHeadHeader(), blockchain.getChainHeadHeader().getTimestamp())) + .thenReturn(spec); + } + + private JsonRpcSuccessResponse requestBlobBaseFee() { + return (JsonRpcSuccessResponse) + method.response( + new JsonRpcRequestContext(new JsonRpcRequest("2.0", "eth_blobBaseFee", null))); + } +} diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java index 26ac79ef384..b37cff7e43a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/BlockTransactionSelector.java @@ -383,33 +383,11 @@ private TransactionSelectionResult handleTransactionSelected( if (tooLate) { // even if this tx passed all the checks, it is too late to include it in this block, // so we need to treat it as not selected - final var evaluationTimer = evaluationContext.getEvaluationTimer(); - - // check if this tx took too much to evaluate, and in case remove it from the pool - final TransactionSelectionResult timeoutSelectionResult; - if (evaluationTimer.elapsed(TimeUnit.MILLISECONDS) > blockTxsSelectionMaxTime) { - LOG.atWarn() - .setMessage( - "Transaction {} is too late for inclusion, evaluated in {} that is over the max limit of {}ms" - + ", removing it from the pool") - .addArgument(transaction::toTraceLog) - .addArgument(evaluationTimer) - .addArgument(blockTxsSelectionMaxTime) - .log(); - timeoutSelectionResult = TX_EVALUATION_TOO_LONG; - } else { - LOG.atTrace() - .setMessage("Transaction {} is too late for inclusion") - .addArgument(transaction::toTraceLog) - .addArgument(evaluationTimer) - .log(); - timeoutSelectionResult = BLOCK_SELECTION_TIMEOUT; - } // do not rely on the presence of this result, since by the time it is added, the code // reading it could have been already executed by another thread return handleTransactionNotSelected( - evaluationContext, timeoutSelectionResult, txWorldStateUpdater); + evaluationContext, BLOCK_SELECTION_TIMEOUT, txWorldStateUpdater); } pluginTransactionSelector.onTransactionSelected(evaluationContext, processingResult); @@ -437,17 +415,47 @@ private TransactionSelectionResult handleTransactionNotSelected( final var pendingTransaction = evaluationContext.getPendingTransaction(); - transactionSelectionResults.updateNotSelected( - evaluationContext.getTransaction(), selectionResult); - pluginTransactionSelector.onTransactionNotSelected(evaluationContext, selectionResult); + // check if this tx took too much to evaluate, and in case remove it from the pool + final TransactionSelectionResult actualResult = + isTimeout.get() + ? transactionTookTooLong(evaluationContext) + ? TX_EVALUATION_TOO_LONG + : BLOCK_SELECTION_TIMEOUT + : selectionResult; + + transactionSelectionResults.updateNotSelected(evaluationContext.getTransaction(), actualResult); + pluginTransactionSelector.onTransactionNotSelected(evaluationContext, actualResult); LOG.atTrace() - .setMessage("Not selected {} for block creation with result {}, evaluated in {}") + .setMessage( + "Not selected {} for block creation with result {} (original result {}), evaluated in {}") .addArgument(pendingTransaction::toTraceLog) + .addArgument(actualResult) .addArgument(selectionResult) .addArgument(evaluationContext.getEvaluationTimer()) .log(); - return selectionResult; + return actualResult; + } + + private boolean transactionTookTooLong(final TransactionEvaluationContext evaluationContext) { + final var evaluationTimer = evaluationContext.getEvaluationTimer(); + if (evaluationTimer.elapsed(TimeUnit.MILLISECONDS) > blockTxsSelectionMaxTime) { + LOG.atWarn() + .setMessage( + "Transaction {} is too late for inclusion, evaluated in {} that is over the max limit of {}ms" + + ", removing it from the pool") + .addArgument(evaluationContext.getPendingTransaction()::getHash) + .addArgument(evaluationTimer) + .addArgument(blockTxsSelectionMaxTime) + .log(); + return true; + } + LOG.atTrace() + .setMessage("Transaction {} is too late for inclusion") + .addArgument(evaluationContext.getPendingTransaction()::toTraceLog) + .log(); + + return false; } private TransactionSelectionResult handleTransactionNotSelected( diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index 052ce330a5a..2702b625583 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.entry; import static org.awaitility.Awaitility.await; import static org.hyperledger.besu.ethereum.core.MiningParameters.DEFAULT_NON_POA_BLOCK_TXS_SELECTION_MAX_TIME; +import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN; import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED; @@ -90,6 +91,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -1030,6 +1032,152 @@ private void internalBlockSelectionTimeoutSimulation( .isEqualTo(isLongProcessingTxDropped ? true : false); } + @ParameterizedTest + @MethodSource("subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver") + public void subsetOfInvalidPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver( + final boolean isPoa, + final boolean preProcessingTooLate, + final boolean processingTooLate, + final boolean postProcessingTooLate) { + + internalBlockSelectionTimeoutSimulationInvalidTxs( + isPoa, + preProcessingTooLate, + processingTooLate, + postProcessingTooLate, + 500, + BLOCK_SELECTION_TIMEOUT, + false, + UPFRONT_COST_EXCEEDS_BALANCE); + } + + @ParameterizedTest + @MethodSource("subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver") + public void invalidPendingTransactionsThatTakesTooLongToEvaluateIsDroppedFromThePool( + final boolean isPoa, + final boolean preProcessingTooLate, + final boolean processingTooLate, + final boolean postProcessingTooLate) { + + internalBlockSelectionTimeoutSimulationInvalidTxs( + isPoa, + preProcessingTooLate, + processingTooLate, + postProcessingTooLate, + 900, + TX_EVALUATION_TOO_LONG, + true, + UPFRONT_COST_EXCEEDS_BALANCE); + } + + private void internalBlockSelectionTimeoutSimulationInvalidTxs( + final boolean isPoa, + final boolean preProcessingTooLate, + final boolean processingTooLate, + final boolean postProcessingTooLate, + final long longProcessingTxTime, + final TransactionSelectionResult longProcessingTxResult, + final boolean isLongProcessingTxDropped, + final TransactionInvalidReason txInvalidReason) { + + final int txCount = 3; + final long fastProcessingTxTime = 200; + final var invalidSelectionResult = TransactionSelectionResult.invalid(txInvalidReason.name()); + + final Supplier> inTime = () -> invocation -> SELECTED; + + final BiFunction> tooLate = + (p, t) -> + invocation -> { + final org.hyperledger.besu.ethereum.blockcreation.txselection + .TransactionEvaluationContext + ctx = invocation.getArgument(0); + if (ctx.getTransaction().equals(p)) { + Thread.sleep(t); + } else { + Thread.sleep(fastProcessingTxTime); + } + return invalidSelectionResult; + }; + + final ProcessableBlockHeader blockHeader = createBlock(301_000); + final Address miningBeneficiary = AddressHelpers.ofValue(1); + final int poaGenesisBlockPeriod = 1; + final int blockTxsSelectionMaxTime = 750; + + final List transactionsToInject = new ArrayList<>(txCount); + for (int i = 0; i < txCount - 1; i++) { + final Transaction tx = createTransaction(i, Wei.of(7), 100_000); + transactionsToInject.add(tx); + if (processingTooLate) { + ensureTransactionIsInvalid(tx, txInvalidReason, fastProcessingTxTime); + } else { + ensureTransactionIsValid(tx); + } + } + + final Transaction lateTx = createTransaction(2, Wei.of(7), 100_000); + transactionsToInject.add(lateTx); + if (processingTooLate) { + ensureTransactionIsInvalid(lateTx, txInvalidReason, longProcessingTxTime); + } else { + ensureTransactionIsValid(lateTx); + } + + PluginTransactionSelector transactionSelector = mock(PluginTransactionSelector.class); + when(transactionSelector.evaluateTransactionPreProcessing(any())) + .thenAnswer( + preProcessingTooLate ? tooLate.apply(lateTx, longProcessingTxTime) : inTime.get()); + + when(transactionSelector.evaluateTransactionPostProcessing(any(), any())) + .thenAnswer( + postProcessingTooLate ? tooLate.apply(lateTx, longProcessingTxTime) : inTime.get()); + + final PluginTransactionSelectorFactory transactionSelectorFactory = + mock(PluginTransactionSelectorFactory.class); + when(transactionSelectorFactory.create()).thenReturn(transactionSelector); + + final BlockTransactionSelector selector = + createBlockSelectorAndSetupTxPool( + isPoa + ? createMiningParameters( + Wei.ZERO, + MIN_OCCUPANCY_100_PERCENT, + poaGenesisBlockPeriod, + PositiveNumber.fromInt(75)) + : createMiningParameters( + Wei.ZERO, + MIN_OCCUPANCY_100_PERCENT, + PositiveNumber.fromInt(blockTxsSelectionMaxTime)), + transactionProcessor, + blockHeader, + miningBeneficiary, + Wei.ZERO, + transactionSelectorFactory); + + transactionPool.addRemoteTransactions(transactionsToInject); + + final TransactionSelectionResults results = selector.buildTransactionListForBlock(); + + // no tx is selected since all are invalid + assertThat(results.getSelectedTransactions()).isEmpty(); + + // all txs are not selected so wait until all are evaluated + // before checking the results + await().until(() -> results.getNotSelectedTransactions().size() == transactionsToInject.size()); + final var expectedEntries = new HashMap(); + for (int i = 0; i < txCount - 1; i++) { + expectedEntries.put( + transactionsToInject.get(i), TransactionSelectionResult.invalid(txInvalidReason.name())); + } + expectedEntries.put(lateTx, longProcessingTxResult); + assertThat(results.getNotSelectedTransactions()) + .containsExactlyInAnyOrderEntriesOf(expectedEntries); + + assertThat(transactionPool.getTransactionByHash(lateTx.getHash()).isEmpty()) + .isEqualTo(isLongProcessingTxDropped ? true : false); + } + private static Stream subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver() { @@ -1174,9 +1322,22 @@ protected void ensureTransactionIsValid( protected void ensureTransactionIsInvalid( final Transaction tx, final TransactionInvalidReason invalidReason) { + ensureTransactionIsInvalid(tx, invalidReason, 0); + } + + protected void ensureTransactionIsInvalid( + final Transaction tx, + final TransactionInvalidReason invalidReason, + final long processingTime) { when(transactionProcessor.processTransaction( any(), any(), any(), eq(tx), any(), any(), any(), anyBoolean(), any(), any())) - .thenReturn(TransactionProcessingResult.invalid(ValidationResult.invalid(invalidReason))); + .thenAnswer( + invocation -> { + if (processingTime > 0) { + Thread.sleep(processingTime); + } + return TransactionProcessingResult.invalid(ValidationResult.invalid(invalidReason)); + }); } private BlockHeader blockHeader(final long number) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 4ec3eea8605..1756501814c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -273,7 +273,10 @@ public TransactionProcessingResult processTransaction( LOG.trace("Starting execution of {}", transaction); ValidationResult validationResult = transactionValidator.validate( - transaction, blockHeader.getBaseFee(), transactionValidationParams); + transaction, + blockHeader.getBaseFee(), + Optional.ofNullable(blobGasPrice), + transactionValidationParams); // Make sure the transaction is intrinsically valid before trying to // compare against a sender account (because the transaction may not // be signed correctly to extract the sender). diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index 5fd841c1c39..1e8c620ad16 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -83,6 +83,7 @@ public MainnetTransactionValidator( public ValidationResult validate( final Transaction transaction, final Optional baseFee, + final Optional blobFee, final TransactionValidationParams transactionValidationParams) { final ValidationResult signatureResult = validateTransactionSignature(transaction); @@ -128,17 +129,18 @@ public ValidationResult validate( transaction.getPayload().size(), maxInitcodeSize)); } - return validateCostAndFee(transaction, baseFee, transactionValidationParams); + return validateCostAndFee(transaction, baseFee, blobFee, transactionValidationParams); } private ValidationResult validateCostAndFee( final Transaction transaction, final Optional maybeBaseFee, + final Optional maybeBlobFee, final TransactionValidationParams transactionValidationParams) { if (maybeBaseFee.isPresent()) { final Wei price = feeMarket.getTransactionPriceCalculator().price(transaction, maybeBaseFee); - if (!transactionValidationParams.isAllowMaxFeeGasBelowBaseFee() + if (!transactionValidationParams.allowUnderpriced() && price.compareTo(maybeBaseFee.orElseThrow()) < 0) { return ValidationResult.invalid( TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE, @@ -168,6 +170,19 @@ private ValidationResult validateCostAndFee( "total blob gas %d exceeds max blob gas per block %d", txTotalBlobGas, gasLimitCalculator.currentBlobGasLimit())); } + if (maybeBlobFee.isEmpty()) { + throw new IllegalArgumentException( + "blob fee must be provided from blocks containing blobs"); + } else if (!transactionValidationParams.allowUnderpriced() + && maybeBlobFee.get().compareTo(transaction.getMaxFeePerBlobGas().get()) > 0) { + return ValidationResult.invalid( + TransactionInvalidReason.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE, + String.format( + "max fee per blob gas less than block blob gas fee: address %s blobGasFeeCap: %s, blobBaseFee: %s", + transaction.getSender().toHexString(), + transaction.getMaxFeePerBlobGas().get().toHumanReadableString(), + maybeBlobFee.get().toHumanReadableString())); + } } final long intrinsicGasCost = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java index 5325567d0f9..43b3d8d2be1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PermissionTransactionValidator.java @@ -43,8 +43,9 @@ public PermissionTransactionValidator( public ValidationResult validate( final Transaction transaction, final Optional baseFee, + final Optional blobBaseFee, final TransactionValidationParams transactionValidationParams) { - return delegate.validate(transaction, baseFee, transactionValidationParams); + return delegate.validate(transaction, baseFee, blobBaseFee, transactionValidationParams); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java index c60f376907d..be2185b09a7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java @@ -46,7 +46,7 @@ default boolean isAllowExceedingBalance() { } @Value.Default - default boolean isAllowMaxFeeGasBelowBaseFee() { + default boolean allowUnderpriced() { return false; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java index a70de0bcd7f..dc96ac46fcd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidator.java @@ -35,6 +35,7 @@ public interface TransactionValidator { ValidationResult validate( Transaction transaction, Optional baseFee, + Optional blobBaseFee, TransactionValidationParams transactionValidationParams); /** diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java index d3348599c1e..4ae57f7844f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java @@ -44,6 +44,7 @@ public enum TransactionInvalidReason { TOTAL_BLOB_GAS_TOO_HIGH, GAS_PRICE_TOO_LOW, GAS_PRICE_BELOW_CURRENT_BASE_FEE, + BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE, MAX_FEE_PER_GAS_BELOW_CURRENT_BASE_FEE, TX_FEECAP_EXCEEDED, INTERNAL_ERROR, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java index 3e40784ad42..ae95014150a 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java @@ -103,7 +103,7 @@ void shouldWarmCoinbaseIfRequested() { when(transaction.getPayload()).thenReturn(Bytes.EMPTY); when(transaction.getSender()).thenReturn(senderAddress); when(transaction.getValue()).thenReturn(Wei.ZERO); - when(transactionValidatorFactory.get().validate(any(), any(), any())) + when(transactionValidatorFactory.get().validate(any(), any(), any(), any())) .thenReturn(ValidationResult.valid()); when(transactionValidatorFactory.get().validateForSender(any(), any(), any())) .thenReturn(ValidationResult.valid()); @@ -168,7 +168,7 @@ void shouldTraceEndTxOnFailingTransaction(final Exception exception) { when(transaction.getPayload()).thenReturn(Bytes.EMPTY); when(transaction.getSender()).thenReturn(senderAddress); when(transaction.getValue()).thenReturn(Wei.ZERO); - when(transactionValidatorFactory.get().validate(any(), any(), any())) + when(transactionValidatorFactory.get().validate(any(), any(), any(), any())) .thenReturn(ValidationResult.valid()); when(transactionValidatorFactory.get().validateForSender(any(), any(), any())) .thenReturn(ValidationResult.valid()); @@ -255,7 +255,7 @@ void shouldCallTransactionValidatorWithExpectedTransactionValidationParams() { private ArgumentCaptor transactionValidationParamCaptor() { final ArgumentCaptor txValidationParamCaptor = ArgumentCaptor.forClass(TransactionValidationParams.class); - when(transactionValidatorFactory.get().validate(any(), any(), any())) + when(transactionValidatorFactory.get().validate(any(), any(), any(), any())) .thenReturn(ValidationResult.valid()); // returning invalid transaction to halt method execution when(transactionValidatorFactory diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index 65e737609b5..b0e555c9dd0 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.processingBlockParams; import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionPoolParams; +import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.INVALID_TRANSACTION_FORMAT; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS; @@ -128,7 +129,9 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { .createTransaction(senderKeys); when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L); - assertThat(validator.validate(transaction, Optional.empty(), transactionValidationParams)) + assertThat( + validator.validate( + transaction, Optional.empty(), Optional.empty(), transactionValidationParams)) .isEqualTo( ValidationResult.invalid(TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT)); } @@ -138,7 +141,9 @@ public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot( final TransactionValidator validator = createTransactionValidator( gasCalculator, GasLimitCalculator.constant(), false, Optional.empty()); - assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) + assertThat( + validator.validate( + basicTransaction, Optional.empty(), Optional.empty(), transactionValidationParams)) .isEqualTo( ValidationResult.invalid( TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED)); @@ -152,7 +157,9 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { GasLimitCalculator.constant(), false, Optional.of(BigInteger.valueOf(2))); - assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) + assertThat( + validator.validate( + basicTransaction, Optional.empty(), Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.WRONG_CHAIN_ID)); } @@ -300,13 +307,60 @@ public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { .signAndBuild(new SECP256K1().generateKeyPair()); final ValidationResult validationResult = - validator.validate(transaction, Optional.of(Wei.ONE), transactionValidationParams); + validator.validate( + transaction, Optional.of(Wei.ONE), Optional.empty(), transactionValidationParams); assertThat(validationResult) .isEqualTo(ValidationResult.invalid(MAX_PRIORITY_FEE_PER_GAS_EXCEEDS_MAX_FEE_PER_GAS)); assertThat(validationResult.getErrorMessage()) .isEqualTo("max priority fee per gas cannot be greater than max fee per gas"); } + @Test + public void shouldRejectTransactionWithMaxBlobPriorityFeeSmallerThanBlobBaseFee() { + final TransactionValidator validator = + createTransactionValidator( + gasCalculator, + GasLimitCalculator.constant(), + FeeMarket.cancun(0L, Optional.empty()), + false, + Optional.of(BigInteger.ONE), + Set.of( + new TransactionType[] { + TransactionType.FRONTIER, + TransactionType.ACCESS_LIST, + TransactionType.EIP1559, + TransactionType.BLOB + }), + Integer.MAX_VALUE); + + BlobTestFixture blobTestFixture = new BlobTestFixture(); + BlobsWithCommitments bwc = blobTestFixture.createBlobsWithCommitments(1); + + final Transaction transaction = + new TransactionTestFixture() + .to(Optional.of(Address.fromHexString("0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"))) + .type(TransactionType.BLOB) + .chainId(Optional.of(BigInteger.ONE)) + .maxFeePerGas(Optional.of(Wei.of(15))) + .maxFeePerBlobGas(Optional.of(Wei.of(7))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1))) + .blobsWithCommitments(Optional.of(bwc)) + .versionedHashes(Optional.of(bwc.getVersionedHashes())) + .createTransaction(senderKeys); + + final ValidationResult validationResult = + validator.validate( + transaction, + Optional.of(Wei.ONE), + Optional.of(Wei.of(10)), + transactionValidationParams); + assertThat(validationResult) + .isEqualTo(ValidationResult.invalid(BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE)); + assertThat(validationResult.getErrorMessage()) + .matches( + "max fee per blob gas less than block blob gas fee: address 0x[0-9a-f]+ blobGasFeeCap: 7 wei, blobBaseFee: 10 wei"); + } + @Test public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { final TransactionValidator frontierValidator = @@ -339,14 +393,15 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { .createTransaction(senderKeys); assertThat( - frontierValidator.validate(transaction, Optional.empty(), transactionValidationParams)) + frontierValidator.validate( + transaction, Optional.empty(), Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.invalid(INVALID_TRANSACTION_FORMAT)); when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(0L); assertThat( eip1559Validator.validate( - transaction, Optional.of(Wei.ONE), transactionValidationParams)) + transaction, Optional.of(Wei.ONE), Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.valid()); } @@ -369,7 +424,8 @@ public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { .chainId(Optional.of(BigInteger.ONE)) .createTransaction(senderKeys); final Optional basefee = Optional.of(Wei.of(150000L)); - assertThat(validator.validate(transaction, basefee, transactionValidationParams)) + assertThat( + validator.validate(transaction, basefee, Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.invalid(GAS_PRICE_BELOW_CURRENT_BASE_FEE)); } @@ -393,7 +449,9 @@ public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { .chainId(Optional.of(BigInteger.ONE)) .createTransaction(senderKeys); - assertThat(validator.validate(transaction, zeroBaseFee, transactionValidationParams)) + assertThat( + validator.validate( + transaction, zeroBaseFee, Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.valid()); } @@ -418,7 +476,8 @@ public void shouldAcceptValidEIP1559() { final Optional basefee = Optional.of(Wei.of(150000L)); when(gasCalculator.transactionIntrinsicGasCost(any(), anyBoolean())).thenReturn(50L); - assertThat(validator.validate(transaction, basefee, transactionValidationParams)) + assertThat( + validator.validate(transaction, basefee, Optional.empty(), transactionValidationParams)) .isEqualTo(ValidationResult.valid()); } @@ -444,7 +503,10 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction assertThat( validator.validate( - transaction, Optional.of(Wei.ONE), TransactionValidationParams.transactionPool())) + transaction, + Optional.of(Wei.ONE), + Optional.empty(), + TransactionValidationParams.transactionPool())) .isEqualTo(ValidationResult.valid()); } @@ -466,7 +528,8 @@ public void shouldRejectTooLargeInitcode() { .chainId(Optional.of(BigInteger.ONE)) .createTransaction(senderKeys); var validationResult = - validator.validate(bigPayload, Optional.empty(), transactionValidationParams); + validator.validate( + bigPayload, Optional.empty(), Optional.empty(), transactionValidationParams); assertThat(validationResult.isValid()).isFalse(); assertThat(validationResult.getInvalidReason()) @@ -511,7 +574,8 @@ public void shouldRejectContractCreateWithBlob() { .versionedHashes(Optional.of(List.of(VersionedHash.DEFAULT_VERSIONED_HASH))) .createTransaction(senderKeys); var validationResult = - validator.validate(blobTx, Optional.empty(), transactionValidationParams); + validator.validate( + blobTx, Optional.empty(), Optional.of(Wei.of(15)), transactionValidationParams); if (!validationResult.isValid()) { System.out.println( validationResult.getInvalidReason() + " " + validationResult.getErrorMessage()); @@ -549,7 +613,8 @@ public void shouldAcceptTransactionWithAtLeastOneBlob() { .versionedHashes(Optional.of(bwc.getVersionedHashes())) .createTransaction(senderKeys); var validationResult = - validator.validate(blobTx, Optional.empty(), transactionValidationParams); + validator.validate( + blobTx, Optional.empty(), Optional.of(Wei.of(15)), transactionValidationParams); if (!validationResult.isValid()) { System.out.println( validationResult.getInvalidReason() + " " + validationResult.getErrorMessage()); diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java index a91a21c3f56..db54d1fca7f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionPool.java @@ -395,7 +395,6 @@ private ValidationResultAndAccount validateTransaction( final FeeMarket feeMarket = protocolSchedule.getByBlockHeader(chainHeadBlockHeader).getFeeMarket(); - final TransactionInvalidReason priceInvalidReason = validatePrice(transaction, isLocal, hasPriority, feeMarket); if (priceInvalidReason != null) { @@ -407,6 +406,9 @@ private ValidationResultAndAccount validateTransaction( .validate( transaction, chainHeadBlockHeader.getBaseFee(), + Optional.of( + Wei.ZERO), // TransactionValidationParams.transactionPool() allows underpriced + // txs TransactionValidationParams.transactionPool()); if (!basicValidationResult.isValid()) { return new ValidationResultAndAccount(basicValidationResult); diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java index cbc84646f97..2f2604086bb 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTest.java @@ -552,11 +552,11 @@ public void shouldNotAddRemoteTransactionsThatAreInvalidAccordingToStateDependen assertTransactionNotPending(transaction1); verify(transactionBroadcaster).onTransactionsAdded(singletonList(transaction0)); verify(transactionValidatorFactory.get()) - .validate(eq(transaction0), any(Optional.class), any()); + .validate(eq(transaction0), any(Optional.class), any(Optional.class), any()); verify(transactionValidatorFactory.get()) .validateForSender(eq(transaction0), eq(null), any(TransactionValidationParams.class)); verify(transactionValidatorFactory.get()) - .validate(eq(transaction1), any(Optional.class), any()); + .validate(eq(transaction1), any(Optional.class), any(Optional.class), any()); verify(transactionValidatorFactory.get()).validateForSender(eq(transaction1), any(), any()); verifyNoMoreInteractions(transactionValidatorFactory.get()); } @@ -727,7 +727,9 @@ public void shouldCallValidatorWithExpectedValidationParameters() { final ArgumentCaptor txValidationParamCaptor = ArgumentCaptor.forClass(TransactionValidationParams.class); - when(transactionValidatorFactory.get().validate(eq(transaction0), any(Optional.class), any())) + when(transactionValidatorFactory + .get() + .validate(eq(transaction0), any(Optional.class), any(Optional.class), any())) .thenReturn(valid()); when(transactionValidatorFactory .get() @@ -1355,7 +1357,9 @@ protected void addAndAssertTransactionViaApiInvalid( @SuppressWarnings("unchecked") protected void givenTransactionIsValid(final Transaction transaction) { - when(transactionValidatorFactory.get().validate(eq(transaction), any(Optional.class), any())) + when(transactionValidatorFactory + .get() + .validate(eq(transaction), any(Optional.class), any(Optional.class), any())) .thenReturn(valid()); when(transactionValidatorFactory .get() diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java index 45ba21c7e0c..bf17f2f96ec 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java @@ -178,7 +178,7 @@ public void milestone( final Transaction transaction = Transaction.readFrom(RLP.input(rlp)); final ValidationResult validation = transactionValidator(milestone) - .validate(transaction, baseFee, TransactionValidationParams.processingBlock()); + .validate(transaction, baseFee, Optional.empty(), TransactionValidationParams.processingBlock()); if (!validation.isValid()) { throw new RuntimeException( String.format( diff --git a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java index 2540648693f..f18473b0bf2 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/processor/ContractCreationProcessor.java @@ -127,7 +127,6 @@ public void start(final MessageFrame frame, final OperationTracer operationTrace contract.setNonce(initialContractNonce); contract.clearStorage(); frame.setState(MessageFrame.State.CODE_EXECUTING); - frame.addCreate(contractAddress); } } catch (final ModificationNotAllowedException ex) { LOG.trace("Contract creation error: attempt to mutate an immutable account"); diff --git a/gradle.properties b/gradle.properties index 40b4a08aba7..c92257fa5ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=24.1.2-SNAPSHOT +version=24.2.0-SNAPSHOT dockerOrgName=consensys dockerArtifactName=linea-besu dockerVariants=openjdk-17