mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 21:17:54 -05:00
Merge branch 'main' into zkbesu
This commit is contained in:
21
CHANGELOG.md
21
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,13 +31,30 @@
|
||||
- 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
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -513,7 +513,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
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 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
|
||||
.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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 enum NetworkName {
|
||||
}
|
||||
|
||||
/**
|
||||
* Can fast sync boolean.
|
||||
* Can SNAP sync boolean.
|
||||
*
|
||||
* @return the boolean
|
||||
*/
|
||||
public boolean canFastSync() {
|
||||
return canFastSync;
|
||||
public boolean canSnapSync() {
|
||||
return canSnapSync;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.io.PrintWriter;
|
||||
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 @@ public class RocksDbHelper {
|
||||
}
|
||||
}
|
||||
|
||||
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<ColumnFamilyUsage> 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 @@ public class RocksDbHelper {
|
||||
}
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import static org.hyperledger.besu.controller.BesuController.DATABASE_PATH;
|
||||
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 @@ import picocli.CommandLine.ParentCommand;
|
||||
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 @@ public class RocksDbSubCommand implements Runnable {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ParentCommand
|
||||
private RocksDbSubCommand parentCommand;
|
||||
private RocksDbSubCommand rocksDbSubCommand;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -68,21 +70,64 @@ public class RocksDbSubCommand implements Runnable {
|
||||
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<RocksDbHelper.ColumnFamilyUsage> 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);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class StorageSubCommand implements Runnable {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ParentCommand
|
||||
BesuCommand parentCommand;
|
||||
BesuCommand besuCommand;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Spec
|
||||
@@ -104,8 +104,8 @@ public class StorageSubCommand implements Runnable {
|
||||
|
||||
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) {
|
||||
|
||||
@@ -78,7 +78,7 @@ public class TrieLogSubCommand implements Runnable {
|
||||
}
|
||||
|
||||
private static BesuController createBesuController() {
|
||||
return parentCommand.parentCommand.buildController();
|
||||
return parentCommand.besuCommand.buildController();
|
||||
}
|
||||
|
||||
@Command(
|
||||
@@ -132,7 +132,7 @@ public class TrieLogSubCommand implements Runnable {
|
||||
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 class TrieLogSubCommand implements Runnable {
|
||||
private long estimatedSizeOfTrieLogs() {
|
||||
final String dbPath =
|
||||
TrieLogSubCommand.parentCommand
|
||||
.parentCommand
|
||||
.besuCommand
|
||||
.dataDir()
|
||||
.toString()
|
||||
.concat("/")
|
||||
@@ -180,9 +180,13 @@ public class TrieLogSubCommand implements Runnable {
|
||||
(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 class TrieLogSubCommand implements Runnable {
|
||||
trieLogFilePath =
|
||||
Paths.get(
|
||||
TrieLogSubCommand.parentCommand
|
||||
.parentCommand
|
||||
.besuCommand
|
||||
.dataDir()
|
||||
.resolve("trie-logs.bin")
|
||||
.toAbsolutePath()
|
||||
@@ -283,7 +287,7 @@ public class TrieLogSubCommand implements Runnable {
|
||||
trieLogFilePath =
|
||||
Paths.get(
|
||||
TrieLogSubCommand.parentCommand
|
||||
.parentCommand
|
||||
.besuCommand
|
||||
.dataDir()
|
||||
.resolve("trie-logs.bin")
|
||||
.toAbsolutePath()
|
||||
|
||||
@@ -257,7 +257,7 @@ public class BesuCommandTest extends CommandTestAbstract {
|
||||
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 class BesuCommandTest extends CommandTestAbstract {
|
||||
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");
|
||||
|
||||
@@ -179,7 +179,7 @@ public class CascadingDefaultProviderTest extends CommandTestAbstract {
|
||||
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();
|
||||
|
||||
@@ -140,7 +140,10 @@ public class BesuEventsImplTest {
|
||||
.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()))
|
||||
|
||||
@@ -428,6 +428,7 @@ public class EngineJsonRpcService {
|
||||
.handler(
|
||||
BodyHandler.create()
|
||||
.setUploadsDirectory(dataDir.resolve("uploads").toString())
|
||||
.setBodyLimit(128 * 1024 * 1024)
|
||||
.setDeleteUploadedFilesOnEnd(true));
|
||||
router.route("/").method(HttpMethod.GET).handler(this::handleEmptyRequest);
|
||||
router
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.api.ApiConfiguration;
|
||||
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 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
|
||||
new EthSubmitHashRate(miningCoordinator),
|
||||
new EthChainId(protocolSchedule.getChainId()),
|
||||
new EthGetMinerDataByBlockHash(blockchainQueries, protocolSchedule),
|
||||
new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule));
|
||||
new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule),
|
||||
new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
@@ -383,33 +383,11 @@ public class BlockTransactionSelector {
|
||||
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 @@ public class BlockTransactionSelector {
|
||||
|
||||
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(
|
||||
|
||||
@@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
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.math.BigInteger;
|
||||
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 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
.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<Answer<TransactionSelectionResult>> inTime = () -> invocation -> SELECTED;
|
||||
|
||||
final BiFunction<Transaction, Long, Answer<TransactionSelectionResult>> 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<Transaction> 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<Transaction, TransactionSelectionResult>();
|
||||
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<Arguments>
|
||||
subsetOfPendingTransactionsIncludedWhenTxSelectionMaxTimeIsOver() {
|
||||
|
||||
@@ -1174,9 +1322,22 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
|
||||
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) {
|
||||
|
||||
@@ -273,7 +273,10 @@ public class MainnetTransactionProcessor {
|
||||
LOG.trace("Starting execution of {}", transaction);
|
||||
ValidationResult<TransactionInvalidReason> 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).
|
||||
|
||||
@@ -83,6 +83,7 @@ public class MainnetTransactionValidator implements TransactionValidator {
|
||||
public ValidationResult<TransactionInvalidReason> validate(
|
||||
final Transaction transaction,
|
||||
final Optional<Wei> baseFee,
|
||||
final Optional<Wei> blobFee,
|
||||
final TransactionValidationParams transactionValidationParams) {
|
||||
final ValidationResult<TransactionInvalidReason> signatureResult =
|
||||
validateTransactionSignature(transaction);
|
||||
@@ -128,17 +129,18 @@ public class MainnetTransactionValidator implements TransactionValidator {
|
||||
transaction.getPayload().size(), maxInitcodeSize));
|
||||
}
|
||||
|
||||
return validateCostAndFee(transaction, baseFee, transactionValidationParams);
|
||||
return validateCostAndFee(transaction, baseFee, blobFee, transactionValidationParams);
|
||||
}
|
||||
|
||||
private ValidationResult<TransactionInvalidReason> validateCostAndFee(
|
||||
final Transaction transaction,
|
||||
final Optional<Wei> maybeBaseFee,
|
||||
final Optional<Wei> 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 @@ public class MainnetTransactionValidator implements TransactionValidator {
|
||||
"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 =
|
||||
|
||||
@@ -43,8 +43,9 @@ public class PermissionTransactionValidator implements TransactionValidator {
|
||||
public ValidationResult<TransactionInvalidReason> validate(
|
||||
final Transaction transaction,
|
||||
final Optional<Wei> baseFee,
|
||||
final Optional<Wei> blobBaseFee,
|
||||
final TransactionValidationParams transactionValidationParams) {
|
||||
return delegate.validate(transaction, baseFee, transactionValidationParams);
|
||||
return delegate.validate(transaction, baseFee, blobBaseFee, transactionValidationParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,7 +46,7 @@ public interface TransactionValidationParams {
|
||||
}
|
||||
|
||||
@Value.Default
|
||||
default boolean isAllowMaxFeeGasBelowBaseFee() {
|
||||
default boolean allowUnderpriced() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public interface TransactionValidator {
|
||||
ValidationResult<TransactionInvalidReason> validate(
|
||||
Transaction transaction,
|
||||
Optional<Wei> baseFee,
|
||||
Optional<Wei> blobBaseFee,
|
||||
TransactionValidationParams transactionValidationParams);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -103,7 +103,7 @@ class MainnetTransactionProcessorTest {
|
||||
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 @@ class MainnetTransactionProcessorTest {
|
||||
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 @@ class MainnetTransactionProcessorTest {
|
||||
private ArgumentCaptor<TransactionValidationParams> transactionValidationParamCaptor() {
|
||||
final ArgumentCaptor<TransactionValidationParams> 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
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.mainnet;
|
||||
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 class MainnetTransactionValidatorTest {
|
||||
.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 class MainnetTransactionValidatorTest {
|
||||
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 class MainnetTransactionValidatorTest {
|
||||
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 class MainnetTransactionValidatorTest {
|
||||
.signAndBuild(new SECP256K1().generateKeyPair());
|
||||
|
||||
final ValidationResult<TransactionInvalidReason> 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<TransactionInvalidReason> 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 class MainnetTransactionValidatorTest {
|
||||
.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 class MainnetTransactionValidatorTest {
|
||||
.chainId(Optional.of(BigInteger.ONE))
|
||||
.createTransaction(senderKeys);
|
||||
final Optional<Wei> 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 class MainnetTransactionValidatorTest {
|
||||
.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 class MainnetTransactionValidatorTest {
|
||||
final Optional<Wei> 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 class MainnetTransactionValidatorTest {
|
||||
|
||||
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 class MainnetTransactionValidatorTest {
|
||||
.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 class MainnetTransactionValidatorTest {
|
||||
.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 class MainnetTransactionValidatorTest {
|
||||
.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());
|
||||
|
||||
@@ -395,7 +395,6 @@ public class TransactionPool implements BlockAddedObserver {
|
||||
|
||||
final FeeMarket feeMarket =
|
||||
protocolSchedule.getByBlockHeader(chainHeadBlockHeader).getFeeMarket();
|
||||
|
||||
final TransactionInvalidReason priceInvalidReason =
|
||||
validatePrice(transaction, isLocal, hasPriority, feeMarket);
|
||||
if (priceInvalidReason != null) {
|
||||
@@ -407,6 +406,9 @@ public class TransactionPool implements BlockAddedObserver {
|
||||
.validate(
|
||||
transaction,
|
||||
chainHeadBlockHeader.getBaseFee(),
|
||||
Optional.of(
|
||||
Wei.ZERO), // TransactionValidationParams.transactionPool() allows underpriced
|
||||
// txs
|
||||
TransactionValidationParams.transactionPool());
|
||||
if (!basicValidationResult.isValid()) {
|
||||
return new ValidationResultAndAccount(basicValidationResult);
|
||||
|
||||
@@ -552,11 +552,11 @@ public abstract class AbstractTransactionPoolTest {
|
||||
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 abstract class AbstractTransactionPoolTest {
|
||||
final ArgumentCaptor<TransactionValidationParams> 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 @@ public abstract class AbstractTransactionPoolTest {
|
||||
|
||||
@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()
|
||||
|
||||
@@ -178,7 +178,7 @@ public class TransactionTest {
|
||||
final Transaction transaction = Transaction.readFrom(RLP.input(rlp));
|
||||
final ValidationResult<TransactionInvalidReason> validation =
|
||||
transactionValidator(milestone)
|
||||
.validate(transaction, baseFee, TransactionValidationParams.processingBlock());
|
||||
.validate(transaction, baseFee, Optional.empty(), TransactionValidationParams.processingBlock());
|
||||
if (!validation.isValid()) {
|
||||
throw new RuntimeException(
|
||||
String.format(
|
||||
|
||||
@@ -127,7 +127,6 @@ public class ContractCreationProcessor extends AbstractMessageProcessor {
|
||||
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");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version=24.1.2-SNAPSHOT
|
||||
version=24.2.0-SNAPSHOT
|
||||
dockerOrgName=consensys
|
||||
dockerArtifactName=linea-besu
|
||||
dockerVariants=openjdk-17
|
||||
|
||||
Reference in New Issue
Block a user