From 11a62a072050270b76ef01fec77504f3099f275c Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 9 Oct 2024 13:36:51 +1000 Subject: [PATCH 01/10] Fix unhandled exception (#7743) * clean up and use thread safe cache Signed-off-by: stefan.pingel@consensys.net --- CHANGELOG.md | 1 + .../p2p/discovery/internal/PeerTable.java | 48 +++++-------------- .../p2p/discovery/internal/PeerTableTest.java | 15 ++---- 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bcbfa51b..592b445bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - Corrects a regression where custom plugin services are not initialized correctly. [#7625](https://github.com/hyperledger/besu/pull/7625) - Fix for IBFT2 chains using the BONSAI DB format [#7631](https://github.com/hyperledger/besu/pull/7631) - Fix reading `tx-pool-min-score` option from configuration file [#7623](https://github.com/hyperledger/besu/pull/7623) +- Fix an undhandled exception. [#7733](https://github.com/hyperledger/besu/issues/7733) ## 24.9.1 diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java index 9f58ab1af..33bbed0f0 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTable.java @@ -26,16 +26,17 @@ import org.hyperledger.besu.ethereum.p2p.peers.Peer; import org.hyperledger.besu.ethereum.p2p.peers.PeerId; import java.util.Arrays; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.common.hash.BloomFilter; -import org.apache.commons.collections4.queue.CircularFifoQueue; import org.apache.tuweni.bytes.Bytes; /** @@ -54,10 +55,7 @@ public class PeerTable { private final Map distanceCache; private BloomFilter idBloom; private int evictionCnt = 0; - private final LinkedHashMapWithMaximumSize ipAddressCheckMap = - new LinkedHashMapWithMaximumSize<>(DEFAULT_BUCKET_SIZE * N_BUCKETS); - private final CircularFifoQueue invalidIPs = - new CircularFifoQueue<>(DEFAULT_BUCKET_SIZE * N_BUCKETS); + private final Cache unresponsiveIPs; /** * Builds a new peer table, where distance is calculated using the provided nodeId as a baseline. @@ -72,6 +70,11 @@ public class PeerTable { .toArray(Bucket[]::new); this.distanceCache = new ConcurrentHashMap<>(); this.maxEntriesCnt = N_BUCKETS * DEFAULT_BUCKET_SIZE; + this.unresponsiveIPs = + CacheBuilder.newBuilder() + .maximumSize(maxEntriesCnt) + .expireAfterWrite(15L, TimeUnit.MINUTES) + .build(); // A bloom filter with 4096 expected insertions of 64-byte keys with a 0.1% false positive // probability yields a memory footprint of ~7.5kb. @@ -140,7 +143,6 @@ public class PeerTable { if (!res.isPresent()) { idBloom.put(id); distanceCache.put(id, distance); - ipAddressCheckMap.put(getKey(peer.getEndpoint()), peer.getEndpoint().getUdpPort()); return AddResult.added(); } @@ -214,26 +216,12 @@ public class PeerTable { public boolean isIpAddressInvalid(final Endpoint endpoint) { final String key = getKey(endpoint); - if (invalidIPs.contains(key)) { - return true; - } - if (ipAddressCheckMap.containsKey(key) && ipAddressCheckMap.get(key) != endpoint.getUdpPort()) { - // This peer has multiple discovery services on the same IP address + TCP port. - invalidIPs.add(key); - for (final Bucket bucket : table) { - bucket.getPeers().stream() - .filter(p -> p.getEndpoint().getHost().equals(endpoint.getHost())) - .forEach(bucket::evict); - } - return true; - } else { - return false; - } + return unresponsiveIPs.getIfPresent(key) != null; } public void invalidateIP(final Endpoint endpoint) { final String key = getKey(endpoint); - invalidIPs.add(key); + unresponsiveIPs.put(key, Integer.MAX_VALUE); } private static String getKey(final Endpoint endpoint) { @@ -313,20 +301,6 @@ public class PeerTable { } } - private static class LinkedHashMapWithMaximumSize extends LinkedHashMap { - private final int maxSize; - - public LinkedHashMapWithMaximumSize(final int maxSize) { - super(maxSize, 0.75f, false); - this.maxSize = maxSize; - } - - @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { - return size() > maxSize; - } - } - static class EvictResult { public enum EvictOutcome { EVICTED, diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java index 331711a07..5d2fc4a43 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/discovery/internal/PeerTableTest.java @@ -188,15 +188,12 @@ public class PeerTableTest { @Test public void ipAddressIsInvalidReturnsTrue() { final Endpoint endpoint1 = new Endpoint("1.1.1.1", 2, Optional.of(Integer.valueOf(1))); - final Endpoint endpoint2 = new Endpoint("1.1.1.1", 3, Optional.of(Integer.valueOf(1))); final DiscoveryPeer peer1 = DiscoveryPeer.fromIdAndEndpoint(Peer.randomId(), endpoint1); - final DiscoveryPeer peer2 = DiscoveryPeer.fromIdAndEndpoint(Peer.randomId(), endpoint2); final PeerTable table = new PeerTable(Bytes.random(64)); - final PeerTable.AddResult addResult1 = table.tryAdd(peer1); - assertThat(addResult1.getOutcome()).isEqualTo(PeerTable.AddResult.added().getOutcome()); + table.invalidateIP(endpoint1); - assertThat(table.isIpAddressInvalid(peer2.getEndpoint())).isEqualTo(true); + assertThat(table.isIpAddressInvalid(peer1.getEndpoint())).isEqualTo(true); } @Test @@ -216,16 +213,12 @@ public class PeerTableTest { @Test public void invalidIPAddressNotAdded() { final Endpoint endpoint1 = new Endpoint("1.1.1.1", 2, Optional.of(Integer.valueOf(1))); - final Endpoint endpoint2 = new Endpoint("1.1.1.1", 3, Optional.of(Integer.valueOf(1))); final DiscoveryPeer peer1 = DiscoveryPeer.fromIdAndEndpoint(Peer.randomId(), endpoint1); - final DiscoveryPeer peer2 = DiscoveryPeer.fromIdAndEndpoint(Peer.randomId(), endpoint2); final PeerTable table = new PeerTable(Bytes.random(64)); + table.invalidateIP(endpoint1); final PeerTable.AddResult addResult1 = table.tryAdd(peer1); - assertThat(addResult1.getOutcome()).isEqualTo(PeerTable.AddResult.added().getOutcome()); - - final PeerTable.AddResult addResult2 = table.tryAdd(peer2); - assertThat(addResult2.getOutcome()).isEqualTo(PeerTable.AddResult.invalid().getOutcome()); + assertThat(addResult1.getOutcome()).isEqualTo(PeerTable.AddResult.invalid().getOutcome()); } @Test From 0cd51065d1a470c446df2cc7f1a0033cfeed170d Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:33:17 +1000 Subject: [PATCH 02/10] Keep track of blobs that are part of multiple transactions (#7723) * keep track of blobs that are part of multiple transactions Signed-off-by: stefan.pingel@consensys.net Signed-off-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> --- .../besu/ethereum/core/BlobTestFixture.java | 14 +- .../eth/transactions/TransactionPool.java | 23 +- .../AbstractTransactionPoolTest.java | 508 +-------------- .../AbstractTransactionPoolTestBase.java | 585 ++++++++++++++++++ .../BlobV1TransactionPoolTest.java | 141 +++++ 5 files changed, 756 insertions(+), 515 deletions(-) create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java create mode 100644 ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/BlobV1TransactionPoolTest.java diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java index 21e8630c8..9c3f62126 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlobTestFixture.java @@ -23,8 +23,6 @@ import org.hyperledger.besu.datatypes.KZGProof; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.evm.precompile.KZGPointEvalPrecompiledContract; -import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; @@ -36,6 +34,8 @@ import org.bouncycastle.crypto.digests.SHA256Digest; public class BlobTestFixture { + private byte byteValue = 0x00; + public BlobTestFixture() { try { // optimistically tear down a potential previous loaded trusted setup @@ -58,14 +58,8 @@ public class BlobTestFixture { ; public BlobTriplet createBlobTriplet() { - byte[] rawMaterial = {}; - try (InputStream readme = - BlobTestFixture.class.getResourceAsStream( - "/org/hyperledger/besu/ethereum/core/encoding/BlobDataFixture.bin")) { - rawMaterial = readme.readAllBytes(); - } catch (IOException e) { - fail("Failed to read blob file", e); - } + byte[] rawMaterial = new byte[131072]; + rawMaterial[0] = byteValue++; Bytes48 commitment = Bytes48.wrap(CKZG4844JNI.blobToKzgCommitment(rawMaterial)); 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 7bbf1abe3..f3ce1b4eb 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 @@ -61,6 +61,7 @@ import java.util.HashMap; import java.util.IntSummaryStatistics; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.OptionalLong; import java.util.Set; @@ -77,6 +78,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Multimaps; import org.apache.tuweni.bytes.Bytes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -107,8 +110,10 @@ public class TransactionPool implements BlockAddedObserver { private final SaveRestoreManager saveRestoreManager = new SaveRestoreManager(); private final Set
localSenders = ConcurrentHashMap.newKeySet(); private final EthScheduler.OrderedProcessor blockAddedEventOrderedProcessor; - private final Map mapOfBlobsInTransactionPool = - new HashMap<>(); + private final ListMultimap + mapOfBlobsInTransactionPool = + Multimaps.synchronizedListMultimap( + Multimaps.newListMultimap(new HashMap<>(), () -> new ArrayList<>(1))); public TransactionPool( final Supplier pendingTransactionsSupplier, @@ -660,6 +665,7 @@ public class TransactionPool implements BlockAddedObserver { } final List blobQuads = maybeBlobsWithCommitments.get().getBlobQuads(); + blobQuads.forEach(bq -> mapOfBlobsInTransactionPool.put(bq.versionedHash(), bq)); } @@ -672,15 +678,18 @@ public class TransactionPool implements BlockAddedObserver { } final List blobQuads = maybeBlobsWithCommitments.get().getBlobQuads(); - blobQuads.forEach(bq -> mapOfBlobsInTransactionPool.remove(bq.versionedHash())); + + blobQuads.forEach(bq -> mapOfBlobsInTransactionPool.remove(bq.versionedHash(), bq)); } public BlobsWithCommitments.BlobQuad getBlobQuad(final VersionedHash vh) { - BlobsWithCommitments.BlobQuad blobQuad = mapOfBlobsInTransactionPool.get(vh); - if (blobQuad == null) { - blobQuad = cacheForBlobsOfTransactionsAddedToABlock.get(vh); + try { + // returns an empty list if the key is not present, so getFirst() will throw + return mapOfBlobsInTransactionPool.get(vh).getFirst(); + } catch (NoSuchElementException e) { + // do nothing } - return blobQuad; + return cacheForBlobsOfTransactionsAddedToABlock.get(vh); } public boolean isEnabled() { 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 e5ec06fd3..656751bed 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 @@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.eth.transactions; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; -import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.hyperledger.besu.ethereum.mainnet.ValidationResult.valid; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT; @@ -29,275 +28,55 @@ import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.TRANSACTION_REPLACEMENT_UNDERPRICED; import static org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.TX_FEECAP_EXCEEDED; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.mockito.quality.Strictness.LENIENT; -import org.hyperledger.besu.config.GenesisConfigFile; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.ProtocolContext; -import org.hyperledger.besu.ethereum.chain.BadBlockManager; -import org.hyperledger.besu.ethereum.chain.MutableBlockchain; -import org.hyperledger.besu.ethereum.core.BlobTestFixture; import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Difficulty; -import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; -import org.hyperledger.besu.ethereum.core.MiningParameters; -import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.manager.EthPeer; -import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; -import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; import org.hyperledger.besu.ethereum.eth.manager.RespondingEthPeer; import org.hyperledger.besu.ethereum.eth.messages.EthPV65; -import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredTransactionPoolBaseFeeTest; -import org.hyperledger.besu.ethereum.eth.transactions.sorter.LegacyTransactionPoolBaseFeeTest; -import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; -import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; -import org.hyperledger.besu.evm.account.Account; -import org.hyperledger.besu.evm.internal.EvmConfiguration; -import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; -import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService; -import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidator; -import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidatorFactory; -import org.hyperledger.besu.testutil.DeterministicEthScheduler; import org.hyperledger.besu.util.number.Percentage; -import java.math.BigInteger; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Consumer; -import java.util.function.Function; import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; import org.junit.jupiter.api.condition.EnabledIf; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Answers; import org.mockito.ArgumentCaptor; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; @SuppressWarnings("unchecked") @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = LENIENT) -public abstract class AbstractTransactionPoolTest { - - protected static final KeyPair KEY_PAIR1 = - SignatureAlgorithmFactory.getInstance().generateKeyPair(); - private static final KeyPair KEY_PAIR2 = - SignatureAlgorithmFactory.getInstance().generateKeyPair(); - protected static final Wei BASE_FEE_FLOOR = Wei.of(7L); - protected static final Wei DEFAULT_MIN_GAS_PRICE = Wei.of(50L); - - protected final EthScheduler ethScheduler = new DeterministicEthScheduler(); - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - protected TransactionValidatorFactory transactionValidatorFactory; - - @Mock protected PendingTransactionAddedListener listener; - - @Mock protected TransactionsMessageSender transactionsMessageSender; - @Mock protected NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender; - @Mock protected ProtocolSpec protocolSpec; - - protected ProtocolSchedule protocolSchedule; - - protected final MetricsSystem metricsSystem = new NoOpMetricsSystem(); - protected MutableBlockchain blockchain; - protected TransactionBroadcaster transactionBroadcaster; - - protected PendingTransactions transactions; - protected final Transaction transaction0 = createTransaction(0); - protected final Transaction transaction1 = createTransaction(1); - protected final Transaction transactionBlob = createBlobTransaction(2); - - protected final Transaction transactionOtherSender = createTransaction(1, KEY_PAIR2); - private ExecutionContextTestFixture executionContext; - protected ProtocolContext protocolContext; - protected TransactionPool transactionPool; - protected long blockGasLimit; - protected EthProtocolManager ethProtocolManager; - protected EthContext ethContext; - private PeerTransactionTracker peerTransactionTracker; - private ArgumentCaptor syncTaskCapture; - - protected abstract PendingTransactions createPendingTransactions( - final TransactionPoolConfiguration poolConfig, - final BiFunction - transactionReplacementTester); - - protected TransactionTestFixture createBaseTransactionGasPriceMarket( - final int transactionNumber) { - return new TransactionTestFixture() - .nonce(transactionNumber) - .gasLimit(blockGasLimit) - .type(TransactionType.FRONTIER); - } - - protected TransactionTestFixture createBaseTransactionBaseFeeMarket(final int nonce) { - return new TransactionTestFixture() - .nonce(nonce) - .gasLimit(blockGasLimit) - .gasPrice(null) - .maxFeePerGas(Optional.of(Wei.of(5000L))) - .maxPriorityFeePerGas(Optional.of(Wei.of(1000L))) - .type(TransactionType.EIP1559); - } - - protected abstract ExecutionContextTestFixture createExecutionContextTestFixture(); - - protected static ExecutionContextTestFixture createExecutionContextTestFixtureBaseFeeMarket() { - final var genesisConfigFile = GenesisConfigFile.fromResource("/txpool-test-genesis.json"); - final ProtocolSchedule protocolSchedule = - new ProtocolScheduleBuilder( - genesisConfigFile.getConfigOptions(), - BigInteger.valueOf(1), - ProtocolSpecAdapters.create(0, Function.identity()), - new PrivacyParameters(), - false, - EvmConfiguration.DEFAULT, - MiningParameters.MINING_DISABLED, - new BadBlockManager(), - false, - new NoOpMetricsSystem()) - .createProtocolSchedule(); - final ExecutionContextTestFixture executionContextTestFixture = - ExecutionContextTestFixture.builder(genesisConfigFile) - .protocolSchedule(protocolSchedule) - .build(); - - final Block block = - new Block( - new BlockHeaderTestFixture() - .gasLimit( - executionContextTestFixture - .getBlockchain() - .getChainHeadBlock() - .getHeader() - .getGasLimit()) - .difficulty(Difficulty.ONE) - .baseFeePerGas(Wei.of(10L)) - .parentHash(executionContextTestFixture.getBlockchain().getChainHeadHash()) - .number(executionContextTestFixture.getBlockchain().getChainHeadBlockNumber() + 1) - .buildHeader(), - new BlockBody(List.of(), List.of())); - executionContextTestFixture.getBlockchain().appendBlock(block, List.of()); - - return executionContextTestFixture; - } - - protected abstract FeeMarket getFeeMarket(); - - @BeforeEach - public void setUp() { - executionContext = createExecutionContextTestFixture(); - protocolContext = executionContext.getProtocolContext(); - blockchain = executionContext.getBlockchain(); - when(protocolSpec.getTransactionValidatorFactory()).thenReturn(transactionValidatorFactory); - when(protocolSpec.getFeeMarket()).thenReturn(getFeeMarket()); - protocolSchedule = spy(executionContext.getProtocolSchedule()); - doReturn(protocolSpec).when(protocolSchedule).getByBlockHeader(any()); - blockGasLimit = blockchain.getChainHeadBlock().getHeader().getGasLimit(); - ethProtocolManager = EthProtocolManagerTestUtil.create(); - ethContext = spy(ethProtocolManager.ethContext()); - - final EthScheduler ethScheduler = spy(ethContext.getScheduler()); - syncTaskCapture = ArgumentCaptor.forClass(Runnable.class); - doNothing().when(ethScheduler).scheduleSyncWorkerTask(syncTaskCapture.capture()); - doReturn(ethScheduler).when(ethContext).getScheduler(); - - peerTransactionTracker = new PeerTransactionTracker(ethContext.getEthPeers()); - transactionBroadcaster = - spy( - new TransactionBroadcaster( - ethContext, - peerTransactionTracker, - transactionsMessageSender, - newPooledTransactionHashesMessageSender)); - - transactionPool = createTransactionPool(); - blockchain.observeBlockAdded(transactionPool); - } - - protected TransactionPool createTransactionPool() { - return createTransactionPool(b -> b.minGasPrice(Wei.of(2))); - } - - private TransactionPool createTransactionPool( - final Consumer configConsumer) { - final ImmutableTransactionPoolConfiguration.Builder configBuilder = - ImmutableTransactionPoolConfiguration.builder(); - configConsumer.accept(configBuilder); - final TransactionPoolConfiguration poolConfig = configBuilder.build(); - - final TransactionPoolReplacementHandler transactionReplacementHandler = - new TransactionPoolReplacementHandler( - poolConfig.getPriceBump(), poolConfig.getBlobPriceBump()); - - final BiFunction transactionReplacementTester = - (t1, t2) -> - transactionReplacementHandler.shouldReplace( - t1, t2, protocolContext.getBlockchain().getChainHeadHeader()); - - transactions = spy(createPendingTransactions(poolConfig, transactionReplacementTester)); - - final TransactionPool txPool = - new TransactionPool( - () -> transactions, - protocolSchedule, - protocolContext, - transactionBroadcaster, - ethContext, - new TransactionPoolMetrics(metricsSystem), - poolConfig, - new BlobCache()); - txPool.setEnabled(); - return txPool; - } +public abstract class AbstractTransactionPoolTest extends AbstractTransactionPoolTestBase { @ParameterizedTest @ValueSource(booleans = {true, false}) @@ -466,21 +245,21 @@ public abstract class AbstractTransactionPoolTest { public void shouldReAddBlobTxsWhenReorgHappens() { givenTransactionIsValid(transaction0); givenTransactionIsValid(transaction1); - givenTransactionIsValid(transactionBlob); + givenTransactionIsValid(transactionWithBlobs); addAndAssertRemoteTransactionsValid(transaction0); addAndAssertRemoteTransactionsValid(transaction1); - addAndAssertRemoteTransactionsValid(transactionBlob); + addAndAssertRemoteTransactionsValid(transactionWithBlobs); final BlockHeader commonParent = getHeaderForCurrentChainHead(); final Block originalFork1 = appendBlock(Difficulty.of(1000), commonParent, transaction0); final Block originalFork2 = appendBlock(Difficulty.of(10), originalFork1.getHeader(), transaction1); final Block originalFork3 = - appendBlock(Difficulty.of(1), originalFork2.getHeader(), transactionBlob); + appendBlock(Difficulty.of(1), originalFork2.getHeader(), transactionWithBlobs); assertTransactionNotPending(transaction0); assertTransactionNotPending(transaction1); - assertTransactionNotPending(transactionBlob); + assertTransactionNotPending(transactionWithBlobs); final Block reorgFork1 = appendBlock(Difficulty.ONE, commonParent); verifyChainHeadIs(originalFork3); @@ -493,14 +272,15 @@ public abstract class AbstractTransactionPoolTest { assertTransactionPending(transaction0); assertTransactionPending(transaction1); - assertTransactionPending(transactionBlob); + assertTransactionPending(transactionWithBlobs); - Optional maybeBlob = transactions.getTransactionByHash(transactionBlob.getHash()); + Optional maybeBlob = + transactions.getTransactionByHash(transactionWithBlobs.getHash()); assertThat(maybeBlob).isPresent(); Transaction restoredBlob = maybeBlob.get(); - assertThat(restoredBlob).isEqualTo(transactionBlob); + assertThat(restoredBlob).isEqualTo(transactionWithBlobs); assertThat(restoredBlob.getBlobsWithCommitments().get().getBlobQuads()) - .isEqualTo(transactionBlob.getBlobsWithCommitments().get().getBlobQuads()); + .isEqualTo(transactionWithBlobs.getBlobsWithCommitments().get().getBlobQuads()); } @ParameterizedTest @@ -1281,272 +1061,4 @@ public abstract class AbstractTransactionPoolTest { .map(PendingTransaction::getTransaction) .containsExactlyInAnyOrder(transaction1, transaction2a, transaction3); } - - private static TransactionPoolValidatorService getTransactionPoolValidatorServiceReturning( - final String errorMessage) { - return new TransactionPoolValidatorService() { - @Override - public PluginTransactionPoolValidator createTransactionValidator() { - return (transaction, isLocal, hasPriority) -> Optional.ofNullable(errorMessage); - } - - @Override - public void registerPluginTransactionValidatorFactory( - final PluginTransactionPoolValidatorFactory pluginTransactionPoolValidatorFactory) {} - }; - } - - @SuppressWarnings("unused") - private static boolean isBaseFeeMarket(final ExtensionContext extensionContext) { - final Class cz = extensionContext.getTestClass().get(); - - return cz.equals(LegacyTransactionPoolBaseFeeTest.class) - || cz.equals(LayeredTransactionPoolBaseFeeTest.class); - } - - protected void assertTransactionNotPending(final Transaction transaction) { - assertThat(transactions.getTransactionByHash(transaction.getHash())).isEmpty(); - } - - protected void addAndAssertRemoteTransactionInvalid(final Transaction tx) { - transactionPool.addRemoteTransactions(List.of(tx)); - - verify(transactionBroadcaster, never()).onTransactionsAdded(singletonList(tx)); - assertTransactionNotPending(tx); - } - - protected void assertTransactionPending(final Transaction t) { - assertThat(transactions.getTransactionByHash(t.getHash())).contains(t); - } - - protected void addAndAssertRemoteTransactionsValid(final Transaction... txs) { - addAndAssertRemoteTransactionsValid(false, txs); - } - - protected void addAndAssertRemotePriorityTransactionsValid(final Transaction... txs) { - addAndAssertRemoteTransactionsValid(true, txs); - } - - protected void addAndAssertRemoteTransactionsValid( - final boolean hasPriority, final Transaction... txs) { - transactionPool.addRemoteTransactions(List.of(txs)); - - verify(transactionBroadcaster) - .onTransactionsAdded( - argThat(btxs -> btxs.size() == txs.length && btxs.containsAll(List.of(txs)))); - Arrays.stream(txs).forEach(this::assertTransactionPending); - assertThat(transactions.getLocalTransactions()).doesNotContain(txs); - if (hasPriority) { - assertThat(transactions.getPriorityTransactions()).contains(txs); - } - } - - protected void addAndAssertTransactionViaApiValid( - final Transaction tx, final boolean disableLocalPriority) { - final ValidationResult result = - transactionPool.addTransactionViaApi(tx); - - assertThat(result.isValid()).isTrue(); - assertTransactionPending(tx); - verify(transactionBroadcaster).onTransactionsAdded(singletonList(tx)); - assertThat(transactions.getLocalTransactions()).contains(tx); - if (disableLocalPriority) { - assertThat(transactions.getPriorityTransactions()).doesNotContain(tx); - } else { - assertThat(transactions.getPriorityTransactions()).contains(tx); - } - } - - protected void addAndAssertTransactionViaApiInvalid( - final Transaction tx, final TransactionInvalidReason invalidReason) { - final ValidationResult result = - transactionPool.addTransactionViaApi(tx); - - assertThat(result.isValid()).isFalse(); - assertThat(result.getInvalidReason()).isEqualTo(invalidReason); - assertTransactionNotPending(tx); - verify(transactionBroadcaster, never()).onTransactionsAdded(singletonList(tx)); - } - - @SuppressWarnings("unchecked") - protected void givenTransactionIsValid(final Transaction transaction) { - when(transactionValidatorFactory - .get() - .validate(eq(transaction), any(Optional.class), any(Optional.class), any())) - .thenReturn(valid()); - when(transactionValidatorFactory - .get() - .validateForSender( - eq(transaction), nullable(Account.class), any(TransactionValidationParams.class))) - .thenReturn(valid()); - } - - protected abstract Block appendBlock( - final Difficulty difficulty, - final BlockHeader parentBlock, - final Transaction... transactionsToAdd); - - protected Transaction createTransactionGasPriceMarket( - final int transactionNumber, final Wei maxPrice) { - return createBaseTransaction(transactionNumber).gasPrice(maxPrice).createTransaction(KEY_PAIR1); - } - - protected Transaction createTransactionBaseFeeMarket(final int nonce, final Wei maxPrice) { - return createBaseTransaction(nonce) - .maxFeePerGas(Optional.of(maxPrice)) - .maxPriorityFeePerGas(Optional.of(maxPrice.divide(5L))) - .createTransaction(KEY_PAIR1); - } - - protected abstract TransactionTestFixture createBaseTransaction(final int nonce); - - protected Transaction createTransaction( - final int transactionNumber, final Optional maybeChainId) { - return createBaseTransaction(transactionNumber) - .chainId(maybeChainId) - .createTransaction(KEY_PAIR1); - } - - protected abstract Transaction createTransaction(final int nonce, final Wei maxPrice); - - protected Transaction createTransaction(final int nonce) { - return createTransaction(nonce, Optional.of(BigInteger.ONE)); - } - - protected Transaction createTransaction(final int nonce, final KeyPair keyPair) { - return createBaseTransaction(nonce).createTransaction(keyPair); - } - - protected void verifyChainHeadIs(final Block forkBlock2) { - assertThat(blockchain.getChainHeadHash()).isEqualTo(forkBlock2.getHash()); - } - - protected BlockHeader getHeaderForCurrentChainHead() { - return blockchain.getBlockHeader(blockchain.getChainHeadHash()).get(); - } - - protected void appendBlock(final Transaction... transactionsToAdd) { - appendBlock(Difficulty.ONE, getHeaderForCurrentChainHead(), transactionsToAdd); - } - - protected void protocolSupportsTxReplayProtection( - final long chainId, final boolean isSupportedAtCurrentBlock) { - when(protocolSpec.isReplayProtectionSupported()).thenReturn(isSupportedAtCurrentBlock); - when(protocolSchedule.getChainId()).thenReturn(Optional.of(BigInteger.valueOf(chainId))); - } - - protected void protocolDoesNotSupportTxReplayProtection() { - when(protocolSchedule.getChainId()).thenReturn(Optional.empty()); - } - - protected Transaction createTransactionWithoutChainId(final int transactionNumber) { - return createTransaction(transactionNumber, Optional.empty()); - } - - protected void whenBlockBaseFeeIs(final Wei baseFee) { - final BlockHeader header = - BlockHeaderBuilder.fromHeader(blockchain.getChainHeadHeader()) - .baseFee(baseFee) - .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) - .parentHash(blockchain.getChainHeadHash()) - .buildBlockHeader(); - blockchain.appendBlock(new Block(header, BlockBody.empty()), emptyList()); - } - - protected Transaction createFrontierTransaction(final int transactionNumber, final Wei gasPrice) { - return new TransactionTestFixture() - .nonce(transactionNumber) - .gasPrice(gasPrice) - .gasLimit(blockGasLimit) - .type(TransactionType.FRONTIER) - .createTransaction(KEY_PAIR1); - } - - protected Transaction createBlobTransaction(final int nonce) { - return new TransactionTestFixture() - .nonce(nonce) - .gasLimit(blockGasLimit) - .gasPrice(null) - .maxFeePerGas(Optional.of(Wei.of(5000L))) - .maxPriorityFeePerGas(Optional.of(Wei.of(1000L))) - .type(TransactionType.BLOB) - .blobsWithCommitments(Optional.of(new BlobTestFixture().createBlobsWithCommitments(6))) - .createTransaction(KEY_PAIR1); - } - - protected int addTxAndGetPendingTxsCount( - final Wei genesisBaseFee, - final Wei minGasPrice, - final Wei lastBlockBaseFee, - final Wei txMaxFeePerGas, - final boolean isLocal, - final boolean hasPriority) { - when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0, Optional.of(genesisBaseFee))); - whenBlockBaseFeeIs(lastBlockBaseFee); - - final Transaction transaction = createTransaction(0, txMaxFeePerGas); - if (hasPriority) { - transactionPool = - createTransactionPool( - b -> b.minGasPrice(minGasPrice).prioritySenders(Set.of(transaction.getSender()))); - } else { - transactionPool = - createTransactionPool(b -> b.minGasPrice(minGasPrice).noLocalPriority(true)); - } - - givenTransactionIsValid(transaction); - - if (isLocal) { - transactionPool.addTransactionViaApi(transaction); - } else { - transactionPool.addRemoteTransactions(List.of(transaction)); - } - - return transactions.size(); - } - - protected Block appendBlockGasPriceMarket( - final Difficulty difficulty, - final BlockHeader parentBlock, - final Transaction[] transactionsToAdd) { - final List transactionList = asList(transactionsToAdd); - final Block block = - new Block( - new BlockHeaderTestFixture() - .difficulty(difficulty) - .gasLimit(parentBlock.getGasLimit()) - .parentHash(parentBlock.getHash()) - .number(parentBlock.getNumber() + 1) - .buildHeader(), - new BlockBody(transactionList, emptyList())); - final List transactionReceipts = - transactionList.stream() - .map(transaction -> new TransactionReceipt(1, 1, emptyList(), Optional.empty())) - .collect(toList()); - blockchain.appendBlock(block, transactionReceipts); - return block; - } - - protected Block appendBlockBaseFeeMarket( - final Difficulty difficulty, - final BlockHeader parentBlock, - final Transaction[] transactionsToAdd) { - final List transactionList = asList(transactionsToAdd); - final Block block = - new Block( - new BlockHeaderTestFixture() - .baseFeePerGas(Wei.of(10L)) - .gasLimit(parentBlock.getGasLimit()) - .difficulty(difficulty) - .parentHash(parentBlock.getHash()) - .number(parentBlock.getNumber() + 1) - .buildHeader(), - new BlockBody(transactionList, emptyList())); - final List transactionReceipts = - transactionList.stream() - .map(transaction -> new TransactionReceipt(1, 1, emptyList(), Optional.empty())) - .collect(toList()); - blockchain.appendBlock(block, transactionReceipts); - return block; - } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java new file mode 100644 index 000000000..c3ca24a4e --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/AbstractTransactionPoolTestBase.java @@ -0,0 +1,585 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.transactions; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.mainnet.ValidationResult.valid; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.quality.Strictness.LENIENT; + +import org.hyperledger.besu.config.GenesisConfigFile; +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.chain.BadBlockManager; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.BlobTestFixture; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockBody; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.MiningParameters; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.eth.manager.EthContext; +import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; +import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManagerTestUtil; +import org.hyperledger.besu.ethereum.eth.manager.EthScheduler; +import org.hyperledger.besu.ethereum.eth.transactions.layered.LayeredTransactionPoolBaseFeeTest; +import org.hyperledger.besu.ethereum.eth.transactions.sorter.LegacyTransactionPoolBaseFeeTest; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; +import org.hyperledger.besu.evm.account.Account; +import org.hyperledger.besu.evm.internal.EvmConfiguration; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.TransactionPoolValidatorService; +import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidator; +import org.hyperledger.besu.plugin.services.txvalidator.PluginTransactionPoolValidatorFactory; +import org.hyperledger.besu.testutil.DeterministicEthScheduler; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; + +@SuppressWarnings("unchecked") +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = LENIENT) +public abstract class AbstractTransactionPoolTestBase { + + protected static final KeyPair KEY_PAIR1 = + SignatureAlgorithmFactory.getInstance().generateKeyPair(); + private static final KeyPair KEY_PAIR2 = + SignatureAlgorithmFactory.getInstance().generateKeyPair(); + protected static final Wei BASE_FEE_FLOOR = Wei.of(7L); + protected static final Wei DEFAULT_MIN_GAS_PRICE = Wei.of(50L); + + protected final EthScheduler ethScheduler = new DeterministicEthScheduler(); + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + protected TransactionValidatorFactory transactionValidatorFactory; + + @Mock protected PendingTransactionAddedListener listener; + + @Mock protected TransactionsMessageSender transactionsMessageSender; + @Mock protected NewPooledTransactionHashesMessageSender newPooledTransactionHashesMessageSender; + @Mock protected ProtocolSpec protocolSpec; + + protected ProtocolSchedule protocolSchedule; + + protected final MetricsSystem metricsSystem = new NoOpMetricsSystem(); + protected MutableBlockchain blockchain; + protected TransactionBroadcaster transactionBroadcaster; + + protected PendingTransactions transactions; + protected final Transaction transaction0 = createTransaction(0); + protected final Transaction transaction1 = createTransaction(1); + protected final Transaction transactionWithBlobs = createBlobTransaction(2); + protected final Transaction transactionWithBlobsReplacement = + createReplacementTransactionWithBlobs(2); + protected final Transaction transactionWithSameBlobs = + createBlobTransactionWithSameBlobs(3, transactionWithBlobs.getBlobsWithCommitments().get()); + protected final Transaction transactionWithSameBlobsReplacement = + createReplacementTransactionWithBlobs(3); + + protected final Transaction transactionOtherSender = createTransaction(1, KEY_PAIR2); + private ExecutionContextTestFixture executionContext; + protected ProtocolContext protocolContext; + protected TransactionPool transactionPool; + protected long blockGasLimit; + protected EthProtocolManager ethProtocolManager; + protected EthContext ethContext; + protected ArgumentCaptor syncTaskCapture; + protected PeerTransactionTracker peerTransactionTracker; + private BlobTestFixture blobTestFixture; + + protected abstract PendingTransactions createPendingTransactions( + final TransactionPoolConfiguration poolConfig, + final BiFunction + transactionReplacementTester); + + protected TransactionTestFixture createBaseTransactionGasPriceMarket( + final int transactionNumber) { + return new TransactionTestFixture() + .nonce(transactionNumber) + .gasLimit(blockGasLimit) + .type(TransactionType.FRONTIER); + } + + protected TransactionTestFixture createBaseTransactionBaseFeeMarket(final int nonce) { + return new TransactionTestFixture() + .nonce(nonce) + .gasLimit(blockGasLimit) + .gasPrice(null) + .maxFeePerGas(Optional.of(Wei.of(5000L))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1000L))) + .type(TransactionType.EIP1559); + } + + protected abstract ExecutionContextTestFixture createExecutionContextTestFixture(); + + protected static ExecutionContextTestFixture createExecutionContextTestFixtureBaseFeeMarket() { + final var genesisConfigFile = GenesisConfigFile.fromResource("/txpool-test-genesis.json"); + final ProtocolSchedule protocolSchedule = + new ProtocolScheduleBuilder( + genesisConfigFile.getConfigOptions(), + BigInteger.valueOf(1), + ProtocolSpecAdapters.create(0, Function.identity()), + new PrivacyParameters(), + false, + EvmConfiguration.DEFAULT, + MiningParameters.MINING_DISABLED, + new BadBlockManager(), + false, + new NoOpMetricsSystem()) + .createProtocolSchedule(); + final ExecutionContextTestFixture executionContextTestFixture = + ExecutionContextTestFixture.builder(genesisConfigFile) + .protocolSchedule(protocolSchedule) + .build(); + + final Block block = + new Block( + new BlockHeaderTestFixture() + .gasLimit( + executionContextTestFixture + .getBlockchain() + .getChainHeadBlock() + .getHeader() + .getGasLimit()) + .difficulty(Difficulty.ONE) + .baseFeePerGas(Wei.of(10L)) + .parentHash(executionContextTestFixture.getBlockchain().getChainHeadHash()) + .number(executionContextTestFixture.getBlockchain().getChainHeadBlockNumber() + 1) + .buildHeader(), + new BlockBody(List.of(), List.of())); + executionContextTestFixture.getBlockchain().appendBlock(block, List.of()); + + return executionContextTestFixture; + } + + protected abstract FeeMarket getFeeMarket(); + + @BeforeEach + public void setUp() { + executionContext = createExecutionContextTestFixture(); + protocolContext = executionContext.getProtocolContext(); + blockchain = executionContext.getBlockchain(); + when(protocolSpec.getTransactionValidatorFactory()).thenReturn(transactionValidatorFactory); + when(protocolSpec.getFeeMarket()).thenReturn(getFeeMarket()); + protocolSchedule = spy(executionContext.getProtocolSchedule()); + doReturn(protocolSpec).when(protocolSchedule).getByBlockHeader(any()); + blockGasLimit = blockchain.getChainHeadBlock().getHeader().getGasLimit(); + ethProtocolManager = EthProtocolManagerTestUtil.create(); + ethContext = spy(ethProtocolManager.ethContext()); + + final EthScheduler ethScheduler = spy(ethContext.getScheduler()); + syncTaskCapture = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(ethScheduler).scheduleSyncWorkerTask(syncTaskCapture.capture()); + doReturn(ethScheduler).when(ethContext).getScheduler(); + + peerTransactionTracker = new PeerTransactionTracker(ethContext.getEthPeers()); + transactionBroadcaster = + spy( + new TransactionBroadcaster( + ethContext, + peerTransactionTracker, + transactionsMessageSender, + newPooledTransactionHashesMessageSender)); + + transactionPool = createTransactionPool(); + blockchain.observeBlockAdded(transactionPool); + } + + protected TransactionPool createTransactionPool() { + return createTransactionPool(b -> b.minGasPrice(Wei.of(2))); + } + + TransactionPool createTransactionPool( + final Consumer configConsumer) { + final ImmutableTransactionPoolConfiguration.Builder configBuilder = + ImmutableTransactionPoolConfiguration.builder(); + configConsumer.accept(configBuilder); + final TransactionPoolConfiguration poolConfig = configBuilder.build(); + + final TransactionPoolReplacementHandler transactionReplacementHandler = + new TransactionPoolReplacementHandler( + poolConfig.getPriceBump(), poolConfig.getBlobPriceBump()); + + final BiFunction transactionReplacementTester = + (t1, t2) -> + transactionReplacementHandler.shouldReplace( + t1, t2, protocolContext.getBlockchain().getChainHeadHeader()); + + transactions = spy(createPendingTransactions(poolConfig, transactionReplacementTester)); + + final TransactionPool txPool = + new TransactionPool( + () -> transactions, + protocolSchedule, + protocolContext, + transactionBroadcaster, + ethContext, + new TransactionPoolMetrics(metricsSystem), + poolConfig, + new BlobCache()); + txPool.setEnabled(); + return txPool; + } + + static TransactionPoolValidatorService getTransactionPoolValidatorServiceReturning( + final String errorMessage) { + return new TransactionPoolValidatorService() { + @Override + public PluginTransactionPoolValidator createTransactionValidator() { + return (transaction, isLocal, hasPriority) -> Optional.ofNullable(errorMessage); + } + + @Override + public void registerPluginTransactionValidatorFactory( + final PluginTransactionPoolValidatorFactory pluginTransactionPoolValidatorFactory) {} + }; + } + + @SuppressWarnings("unused") + private static boolean isBaseFeeMarket(final ExtensionContext extensionContext) { + final Class cz = extensionContext.getTestClass().get(); + + return cz.equals(LegacyTransactionPoolBaseFeeTest.class) + || cz.equals(LayeredTransactionPoolBaseFeeTest.class) + || cz.equals(BlobV1TransactionPoolTest.class); + } + + protected void assertTransactionNotPending(final Transaction transaction) { + assertThat(transactions.getTransactionByHash(transaction.getHash())).isEmpty(); + } + + protected void addAndAssertRemoteTransactionInvalid(final Transaction tx) { + transactionPool.addRemoteTransactions(List.of(tx)); + + verify(transactionBroadcaster, never()).onTransactionsAdded(singletonList(tx)); + assertTransactionNotPending(tx); + } + + protected void assertTransactionPending(final Transaction t) { + assertThat(transactions.getTransactionByHash(t.getHash())).contains(t); + } + + protected void addAndAssertRemoteTransactionsValid(final Transaction... txs) { + addAndAssertRemoteTransactionsValid(false, txs); + } + + protected void addAndAssertRemotePriorityTransactionsValid(final Transaction... txs) { + addAndAssertRemoteTransactionsValid(true, txs); + } + + protected void addAndAssertRemoteTransactionsValid( + final boolean hasPriority, final Transaction... txs) { + transactionPool.addRemoteTransactions(List.of(txs)); + + verify(transactionBroadcaster) + .onTransactionsAdded( + argThat(btxs -> btxs.size() == txs.length && btxs.containsAll(List.of(txs)))); + Arrays.stream(txs).forEach(this::assertTransactionPending); + assertThat(transactions.getLocalTransactions()).doesNotContain(txs); + if (hasPriority) { + assertThat(transactions.getPriorityTransactions()).contains(txs); + } + } + + protected void addAndAssertTransactionViaApiValid( + final Transaction tx, final boolean disableLocalPriority) { + final ValidationResult result = + transactionPool.addTransactionViaApi(tx); + + assertThat(result.isValid()).isTrue(); + assertTransactionPending(tx); + verify(transactionBroadcaster).onTransactionsAdded(singletonList(tx)); + assertThat(transactions.getLocalTransactions()).contains(tx); + if (disableLocalPriority) { + assertThat(transactions.getPriorityTransactions()).doesNotContain(tx); + } else { + assertThat(transactions.getPriorityTransactions()).contains(tx); + } + } + + protected void addAndAssertTransactionViaApiInvalid( + final Transaction tx, final TransactionInvalidReason invalidReason) { + final ValidationResult result = + transactionPool.addTransactionViaApi(tx); + + assertThat(result.isValid()).isFalse(); + assertThat(result.getInvalidReason()).isEqualTo(invalidReason); + assertTransactionNotPending(tx); + verify(transactionBroadcaster, never()).onTransactionsAdded(singletonList(tx)); + } + + @SuppressWarnings("unchecked") + protected void givenTransactionIsValid(final Transaction transaction) { + when(transactionValidatorFactory + .get() + .validate(eq(transaction), any(Optional.class), any(Optional.class), any())) + .thenReturn(valid()); + when(transactionValidatorFactory + .get() + .validateForSender( + eq(transaction), nullable(Account.class), any(TransactionValidationParams.class))) + .thenReturn(valid()); + } + + protected abstract Block appendBlock( + final Difficulty difficulty, + final BlockHeader parentBlock, + final Transaction... transactionsToAdd); + + protected Transaction createTransactionGasPriceMarket( + final int transactionNumber, final Wei maxPrice) { + return createBaseTransaction(transactionNumber).gasPrice(maxPrice).createTransaction(KEY_PAIR1); + } + + protected Transaction createTransactionBaseFeeMarket(final int nonce, final Wei maxPrice) { + return createBaseTransaction(nonce) + .maxFeePerGas(Optional.of(maxPrice)) + .maxPriorityFeePerGas(Optional.of(maxPrice.divide(5L))) + .createTransaction(KEY_PAIR1); + } + + protected abstract TransactionTestFixture createBaseTransaction(final int nonce); + + protected Transaction createTransaction( + final int transactionNumber, final Optional maybeChainId) { + return createBaseTransaction(transactionNumber) + .chainId(maybeChainId) + .createTransaction(KEY_PAIR1); + } + + protected abstract Transaction createTransaction(final int nonce, final Wei maxPrice); + + protected Transaction createTransaction(final int nonce) { + return createTransaction(nonce, Optional.of(BigInteger.ONE)); + } + + protected Transaction createTransaction(final int nonce, final KeyPair keyPair) { + return createBaseTransaction(nonce).createTransaction(keyPair); + } + + protected void verifyChainHeadIs(final Block forkBlock2) { + assertThat(blockchain.getChainHeadHash()).isEqualTo(forkBlock2.getHash()); + } + + protected BlockHeader getHeaderForCurrentChainHead() { + return blockchain.getBlockHeader(blockchain.getChainHeadHash()).get(); + } + + protected void appendBlock(final Transaction... transactionsToAdd) { + appendBlock(Difficulty.ONE, getHeaderForCurrentChainHead(), transactionsToAdd); + } + + protected void protocolSupportsTxReplayProtection( + final long chainId, final boolean isSupportedAtCurrentBlock) { + when(protocolSpec.isReplayProtectionSupported()).thenReturn(isSupportedAtCurrentBlock); + when(protocolSchedule.getChainId()).thenReturn(Optional.of(BigInteger.valueOf(chainId))); + } + + protected void protocolDoesNotSupportTxReplayProtection() { + when(protocolSchedule.getChainId()).thenReturn(Optional.empty()); + } + + protected Transaction createTransactionWithoutChainId(final int transactionNumber) { + return createTransaction(transactionNumber, Optional.empty()); + } + + protected void whenBlockBaseFeeIs(final Wei baseFee) { + final BlockHeader header = + BlockHeaderBuilder.fromHeader(blockchain.getChainHeadHeader()) + .baseFee(baseFee) + .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) + .parentHash(blockchain.getChainHeadHash()) + .buildBlockHeader(); + blockchain.appendBlock(new Block(header, BlockBody.empty()), emptyList()); + } + + protected Transaction createFrontierTransaction(final int transactionNumber, final Wei gasPrice) { + return new TransactionTestFixture() + .nonce(transactionNumber) + .gasPrice(gasPrice) + .gasLimit(blockGasLimit) + .type(TransactionType.FRONTIER) + .createTransaction(KEY_PAIR1); + } + + protected Transaction createBlobTransaction(final int nonce) { + if (blobTestFixture == null) { + blobTestFixture = new BlobTestFixture(); + } + return new TransactionTestFixture() + .nonce(nonce) + .gasLimit(blockGasLimit) + .gasPrice(null) + .maxFeePerGas(Optional.of(Wei.of(5000L))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1000L))) + .type(TransactionType.BLOB) + .blobsWithCommitments(Optional.of(blobTestFixture.createBlobsWithCommitments(6))) + .createTransaction(KEY_PAIR1); + } + + protected Transaction createBlobTransactionWithSameBlobs( + final int nonce, final BlobsWithCommitments blobsWithCommitments) { + return new TransactionTestFixture() + .nonce(nonce) + .gasLimit(blockGasLimit) + .gasPrice(null) + .maxFeePerGas(Optional.of(Wei.of(5000L))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1000L))) + .type(TransactionType.BLOB) + .blobsWithCommitments(Optional.of(blobsWithCommitments)) + .createTransaction(KEY_PAIR1); + } + + protected Transaction createReplacementTransactionWithBlobs(final int nonce) { + if (blobTestFixture == null) { + blobTestFixture = new BlobTestFixture(); + } + return new TransactionTestFixture() + .nonce(nonce) + .gasLimit(blockGasLimit) + .gasPrice(null) + .maxFeePerGas(Optional.of(Wei.of(5000L * 10))) + .maxPriorityFeePerGas(Optional.of(Wei.of(1000L * 10))) + .maxFeePerBlobGas(Optional.of(Wei.of(5000L))) + .type(TransactionType.BLOB) + .blobsWithCommitments(Optional.of(blobTestFixture.createBlobsWithCommitments(6))) + .createTransaction(KEY_PAIR1); + } + + protected int addTxAndGetPendingTxsCount( + final Wei genesisBaseFee, + final Wei minGasPrice, + final Wei lastBlockBaseFee, + final Wei txMaxFeePerGas, + final boolean isLocal, + final boolean hasPriority) { + when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0, Optional.of(genesisBaseFee))); + whenBlockBaseFeeIs(lastBlockBaseFee); + + final Transaction transaction = createTransaction(0, txMaxFeePerGas); + if (hasPriority) { + transactionPool = + createTransactionPool( + b -> b.minGasPrice(minGasPrice).prioritySenders(Set.of(transaction.getSender()))); + } else { + transactionPool = + createTransactionPool(b -> b.minGasPrice(minGasPrice).noLocalPriority(true)); + } + + givenTransactionIsValid(transaction); + + if (isLocal) { + transactionPool.addTransactionViaApi(transaction); + } else { + transactionPool.addRemoteTransactions(List.of(transaction)); + } + + return transactions.size(); + } + + protected Block appendBlockGasPriceMarket( + final Difficulty difficulty, + final BlockHeader parentBlock, + final Transaction[] transactionsToAdd) { + final List transactionList = asList(transactionsToAdd); + final Block block = + new Block( + new BlockHeaderTestFixture() + .difficulty(difficulty) + .gasLimit(parentBlock.getGasLimit()) + .parentHash(parentBlock.getHash()) + .number(parentBlock.getNumber() + 1) + .buildHeader(), + new BlockBody(transactionList, emptyList())); + final List transactionReceipts = + transactionList.stream() + .map(transaction -> new TransactionReceipt(1, 1, emptyList(), Optional.empty())) + .collect(toList()); + blockchain.appendBlock(block, transactionReceipts); + return block; + } + + protected Block appendBlockBaseFeeMarket( + final Difficulty difficulty, + final BlockHeader parentBlock, + final Transaction[] transactionsToAdd) { + final List transactionList = asList(transactionsToAdd); + final Block block = + new Block( + new BlockHeaderTestFixture() + .baseFeePerGas(Wei.of(10L)) + .gasLimit(parentBlock.getGasLimit()) + .difficulty(difficulty) + .parentHash(parentBlock.getHash()) + .number(parentBlock.getNumber() + 1) + .buildHeader(), + new BlockBody(transactionList, emptyList())); + final List transactionReceipts = + transactionList.stream() + .map(transaction -> new TransactionReceipt(1, 1, emptyList(), Optional.empty())) + .collect(toList()); + blockchain.appendBlock(block, transactionReceipts); + return block; + } +} diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/BlobV1TransactionPoolTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/BlobV1TransactionPoolTest.java new file mode 100644 index 000000000..aa81215a6 --- /dev/null +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/BlobV1TransactionPoolTest.java @@ -0,0 +1,141 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.eth.transactions; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.datatypes.BlobsWithCommitments; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.ExecutionContextTestFixture; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionTestFixture; +import org.hyperledger.besu.ethereum.eth.transactions.sorter.BaseFeePendingTransactionsSorter; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.testutil.TestClock; + +import java.time.ZoneId; +import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; + +import org.junit.jupiter.api.Test; + +public class BlobV1TransactionPoolTest extends AbstractTransactionPoolTestBase { + + @Override + protected PendingTransactions createPendingTransactions( + final TransactionPoolConfiguration poolConfig, + final BiFunction + transactionReplacementTester) { + + return new BaseFeePendingTransactionsSorter( + poolConfig, + TestClock.system(ZoneId.systemDefault()), + metricsSystem, + protocolContext.getBlockchain()::getChainHeadHeader); + } + + @Override + protected Transaction createTransaction(final int transactionNumber, final Wei maxPrice) { + return createTransactionBaseFeeMarket(transactionNumber, maxPrice); + } + + @Override + protected TransactionTestFixture createBaseTransaction(final int transactionNumber) { + return createBaseTransactionBaseFeeMarket(transactionNumber); + } + + @Override + protected ExecutionContextTestFixture createExecutionContextTestFixture() { + return createExecutionContextTestFixtureBaseFeeMarket(); + } + + @Override + protected FeeMarket getFeeMarket() { + return FeeMarket.london(0L, Optional.of(BASE_FEE_FLOOR)); + } + + @Override + protected Block appendBlock( + final Difficulty difficulty, + final BlockHeader parentBlock, + final Transaction... transactionsToAdd) { + return appendBlockBaseFeeMarket(difficulty, parentBlock, transactionsToAdd); + } + + @Test + public void shouldReturnBlobWhenTransactionAddedToPool() { + givenTransactionIsValid(transactionWithBlobs); + + addAndAssertRemoteTransactionsValid(transactionWithBlobs); + + assertTransactionPending(transactionWithBlobs); + // assert that the blobs are returned from the tx pool + final List expectedBlobQuads = + transactionWithBlobs.getBlobsWithCommitments().get().getBlobQuads(); + + expectedBlobQuads.forEach( + bq -> assertThat(transactionPool.getBlobQuad(bq.versionedHash())).isEqualTo(bq)); + } + + @Test + public void shouldNotReturnBlobsWhenAllTxsContainingBlobsHaveBeenReplaced() { + givenTransactionIsValid(transactionWithBlobs); + givenTransactionIsValid(transactionWithBlobsReplacement); + givenTransactionIsValid(transactionWithSameBlobs); // contains same blobs as transactionBlob + givenTransactionIsValid(transactionWithSameBlobsReplacement); + + addAndAssertRemoteTransactionsValid(transactionWithBlobs); + assertTransactionPending(transactionWithBlobs); + + final List expectedBlobQuads = + transactionWithBlobs.getBlobsWithCommitments().get().getBlobQuads(); + + // assert that the blobs are returned from the tx pool + expectedBlobQuads.forEach( + bq -> assertThat(transactionPool.getBlobQuad(bq.versionedHash())).isEqualTo(bq)); + + // add different transaction that contains the same blobs + addAndAssertRemoteTransactionsValid(transactionWithSameBlobs); + + assertTransactionPending(transactionWithBlobs); + assertTransactionPending(transactionWithSameBlobs); + // assert that the blobs are still returned from the tx pool + expectedBlobQuads.forEach( + bq -> assertThat(transactionPool.getBlobQuad(bq.versionedHash())).isEqualTo(bq)); + + // replace the second blob transaction with tx with different blobs + addAndAssertRemoteTransactionsValid(transactionWithSameBlobsReplacement); + assertTransactionPending(transactionWithSameBlobsReplacement); + assertTransactionNotPending(transactionWithSameBlobs); + + // assert that the blob is still returned from the tx pool + expectedBlobQuads.forEach( + bq -> assertThat(transactionPool.getBlobQuad(bq.versionedHash())).isEqualTo(bq)); + + // replace the first blob transaction with tx with different blobs + addAndAssertRemoteTransactionsValid(transactionWithBlobsReplacement); + assertTransactionPending(transactionWithBlobsReplacement); + assertTransactionNotPending(transactionWithBlobs); + + // All txs containing the expected blobs have been replaced, + // so the blobs should no longer be returned from the tx pool + expectedBlobQuads.forEach( + bq -> assertThat(transactionPool.getBlobQuad(bq.versionedHash())).isNull()); + } +} From e4c1b5991c2c060080a1c9e349170e889070b792 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Wed, 9 Oct 2024 20:01:54 +1000 Subject: [PATCH 03/10] Fix RocksDBException: Busy during snapsync (#7746) Signed-off-by: Karim Taam Signed-off-by: Simon Dudley Co-authored-by: Karim Taam --- CHANGELOG.md | 3 +- .../request/heal/TrieNodeHealingRequest.java | 9 ++-- .../sync/snapsync/PersistDataStepTest.java | 48 ++++++++++++++++++- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 592b445bc..a9e5beb33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,8 @@ - Corrects a regression where custom plugin services are not initialized correctly. [#7625](https://github.com/hyperledger/besu/pull/7625) - Fix for IBFT2 chains using the BONSAI DB format [#7631](https://github.com/hyperledger/besu/pull/7631) - Fix reading `tx-pool-min-score` option from configuration file [#7623](https://github.com/hyperledger/besu/pull/7623) -- Fix an undhandled exception. [#7733](https://github.com/hyperledger/besu/issues/7733) +- Fix an unhandled PeerTable exception [#7733](https://github.com/hyperledger/besu/issues/7733) +- Fix RocksDBException: Busy leading to MerkleTrieException: Unable to load trie node value [#7745](https://github.com/hyperledger/besu/pull/7745) ## 24.9.1 diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java index 7e206232c..e62210872 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/heal/TrieNodeHealingRequest.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; @@ -44,7 +45,7 @@ public abstract class TrieNodeHealingRequest extends SnapDataRequest private final Bytes location; protected Bytes data; - protected boolean requiresPersisting = true; + protected AtomicBoolean requiresPersisting = new AtomicBoolean(true); protected TrieNodeHealingRequest(final Hash nodeHash, final Hash rootHash, final Bytes location) { super(TRIE_NODE, rootHash); @@ -65,7 +66,7 @@ public abstract class TrieNodeHealingRequest extends SnapDataRequest return 0; } int saved = 0; - if (requiresPersisting) { + if (requiresPersisting.getAndSet(false)) { checkNotNull(data, "Must set data before node can be persisted."); saved = doPersist( @@ -143,7 +144,7 @@ public abstract class TrieNodeHealingRequest extends SnapDataRequest } public boolean isRequiresPersisting() { - return requiresPersisting; + return requiresPersisting.get(); } public Bytes32 getNodeHash() { @@ -173,7 +174,7 @@ public abstract class TrieNodeHealingRequest extends SnapDataRequest } public void setRequiresPersisting(final boolean requiresPersisting) { - this.requiresPersisting = requiresPersisting; + this.requiresPersisting.set(requiresPersisting); } private boolean nodeIsHashReferencedDescendant(final Node node) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java index 0364dc758..766995b09 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java @@ -17,6 +17,9 @@ package org.hyperledger.besu.ethereum.eth.sync.snapsync; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Hash; @@ -25,12 +28,15 @@ import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.AccountRangeDataR import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.BytecodeRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.SnapDataRequest; import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.StorageRangeDataRequest; +import org.hyperledger.besu.ethereum.eth.sync.snapsync.request.heal.AccountTrieNodeHealingRequest; import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.storage.BonsaiWorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.trie.patricia.StoredMerklePatriciaTrie; import org.hyperledger.besu.ethereum.worldstate.DataStorageConfiguration; +import org.hyperledger.besu.ethereum.worldstate.WorldStateKeyValueStorage; import org.hyperledger.besu.ethereum.worldstate.WorldStateStorageCoordinator; import org.hyperledger.besu.services.tasks.Task; +import java.util.Collections; import java.util.List; import org.apache.tuweni.bytes.Bytes; @@ -39,9 +45,12 @@ import org.junit.jupiter.api.Test; public class PersistDataStepTest { + private final WorldStateKeyValueStorage worldStateKeyValueStorage = + spy( + new InMemoryKeyValueStorageProvider() + .createWorldStateStorage(DataStorageConfiguration.DEFAULT_CONFIG)); private final WorldStateStorageCoordinator worldStateStorageCoordinator = - new InMemoryKeyValueStorageProvider() - .createWorldStateStorageCoordinator(DataStorageConfiguration.DEFAULT_CONFIG); + new WorldStateStorageCoordinator(worldStateKeyValueStorage); private final SnapSyncProcessState snapSyncState = mock(SnapSyncProcessState.class); private final SnapWorldDownloadState downloadState = mock(SnapWorldDownloadState.class); @@ -67,6 +76,33 @@ public class PersistDataStepTest { assertDataPersisted(tasks); } + @Test + public void shouldPersistTrieNodeHealDataOnlyOnce() { + + final Bytes stateTrieNode = + Bytes.fromHexString( + "0xe2a0310e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf602"); + final Hash hash = Hash.hash(stateTrieNode); + final Bytes location = Bytes.of(0x02); + final AccountTrieNodeHealingRequest accountTrieNodeDataRequest = + SnapDataRequest.createAccountTrieNodeDataRequest(hash, location, Collections.emptySet()); + accountTrieNodeDataRequest.setData(stateTrieNode); + + final BonsaiWorldStateKeyValueStorage.Updater updater = + (BonsaiWorldStateKeyValueStorage.Updater) spy(worldStateKeyValueStorage.updater()); + when(worldStateKeyValueStorage.updater()) + .thenReturn(updater) + .thenReturn(mock(BonsaiWorldStateKeyValueStorage.Updater.class)); + + List> result = + persistDataStep.persist(List.of(new StubTask(accountTrieNodeDataRequest))); + + persistDataStep.persist(List.of(new StubTask(accountTrieNodeDataRequest))); + + verify(updater, times(1)).putAccountStateTrieNode(location, hash, stateTrieNode); + assertDataPersisted(result); + } + @Test public void shouldSkipPersistDataWhenNoData() { final List> tasks = TaskGenerator.createAccountRequest(false); @@ -110,6 +146,14 @@ public class PersistDataStepTest { .getStrategy(BonsaiWorldStateKeyValueStorage.class) .getCode(Hash.wrap(data.getCodeHash()), Hash.wrap(data.getAccountHash()))) .isPresent(); + } else if (task.getData() instanceof AccountTrieNodeHealingRequest) { + final AccountTrieNodeHealingRequest data = + (AccountTrieNodeHealingRequest) task.getData(); + assertThat( + worldStateStorageCoordinator + .getStrategy(BonsaiWorldStateKeyValueStorage.class) + .getTrieNodeUnsafe(data.getLocation())) + .isPresent(); } else { fail("not expected message"); } From 03a0cfad4b0b931ce85177517f92a278f5a10b46 Mon Sep 17 00:00:00 2001 From: Matt Whitehead Date: Wed, 9 Oct 2024 12:07:20 +0100 Subject: [PATCH 04/10] Support BFT mining coordinator being temporarily stopped while syncing (#7657) * Support BFT mining coordinator being temporarily stopped while syncing happens Signed-off-by: Matthew Whitehead * Apply same change to IbftBesuControllerBuilder Signed-off-by: Matthew Whitehead * Add changelog entry Signed-off-by: Matthew Whitehead * Add event queue start/stop test Signed-off-by: Matthew Whitehead * Add BFT mining coordinator tests Signed-off-by: Matthew Whitehead * Typo Signed-off-by: Matthew Whitehead * Update consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftEventQueue.java Co-authored-by: Sally MacFarlane Signed-off-by: Matt Whitehead * Update consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProcessor.java Co-authored-by: Sally MacFarlane Signed-off-by: Matt Whitehead --------- Signed-off-by: Matthew Whitehead Signed-off-by: Matt Whitehead Signed-off-by: Matt Whitehead Co-authored-by: Sally MacFarlane --- CHANGELOG.md | 1 + .../controller/IbftBesuControllerBuilder.java | 15 ++++++-- .../controller/QbftBesuControllerBuilder.java | 15 ++++++-- .../consensus/common/bft/BftEventQueue.java | 5 +++ .../consensus/common/bft/BftExecutors.java | 2 +- .../consensus/common/bft/BftProcessor.java | 9 ++++- .../blockcreation/BftMiningCoordinator.java | 13 +++++-- .../common/bft/BftEventQueueTest.java | 34 +++++++++++++++++++ .../BftMiningCoordinatorTest.java | 23 +++++++++++++ 9 files changed, 106 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9e5beb33..762ae66b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - Fix reading `tx-pool-min-score` option from configuration file [#7623](https://github.com/hyperledger/besu/pull/7623) - Fix an unhandled PeerTable exception [#7733](https://github.com/hyperledger/besu/issues/7733) - Fix RocksDBException: Busy leading to MerkleTrieException: Unable to load trie node value [#7745](https://github.com/hyperledger/besu/pull/7745) +- If a BFT validator node is syncing, pause block production until sync has completed [#7657](https://github.com/hyperledger/besu/pull/7657) ## 24.9.1 diff --git a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 58412029f..738dcfc59 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -253,9 +253,18 @@ public class IbftBesuControllerBuilder extends BftBesuControllerBuilder { .getValue() .getBlockPeriodSeconds())); - if (syncState.isInitialSyncPhaseDone()) { - ibftMiningCoordinator.enable(); - } + syncState.subscribeSyncStatus( + syncStatus -> { + if (syncState.syncTarget().isPresent()) { + // We're syncing so stop doing other stuff + LOG.info("Stopping IBFT mining coordinator while we are syncing"); + ibftMiningCoordinator.stop(); + } else { + LOG.info("Starting IBFT mining coordinator following sync"); + ibftMiningCoordinator.enable(); + ibftMiningCoordinator.start(); + } + }); syncState.subscribeCompletionReached( new BesuEvents.InitialSyncCompletionListener() { diff --git a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 60eac1799..498435e4a 100644 --- a/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -301,9 +301,18 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder { .getEmptyBlockPeriodSeconds()); }); - if (syncState.isInitialSyncPhaseDone()) { - miningCoordinator.enable(); - } + syncState.subscribeSyncStatus( + syncStatus -> { + if (syncState.syncTarget().isPresent()) { + // We're syncing so stop doing other stuff + LOG.info("Stopping QBFT mining coordinator while we are syncing"); + miningCoordinator.stop(); + } else { + LOG.info("Starting QBFT mining coordinator following sync"); + miningCoordinator.enable(); + miningCoordinator.start(); + } + }); syncState.subscribeCompletionReached( new BesuEvents.InitialSyncCompletionListener() { diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftEventQueue.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftEventQueue.java index 4221fd1fa..8f6190c4c 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftEventQueue.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftEventQueue.java @@ -48,6 +48,11 @@ public class BftEventQueue { started.set(true); } + /** Stop the event queue. No events will be queued for processing until it is started. */ + public void stop() { + started.set(false); + } + private boolean isStarted() { return started.get(); } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExecutors.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExecutors.java index 30038add3..709d65faa 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExecutors.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftExecutors.java @@ -78,7 +78,7 @@ public class BftExecutors { /** Start. */ public synchronized void start() { - if (state != State.IDLE) { + if (state != State.IDLE && state != State.STOPPED) { // Nothing to do return; } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProcessor.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProcessor.java index 93df77ea7..81be83b46 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProcessor.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BftProcessor.java @@ -44,8 +44,13 @@ public class BftProcessor implements Runnable { this.eventMultiplexer = eventMultiplexer; } + /** Indicate to the processor that it can be started */ + public synchronized void start() { + shutdown = false; + } + /** Indicate to the processor that it should gracefully stop at its next opportunity */ - public void stop() { + public synchronized void stop() { shutdown = true; } @@ -67,6 +72,8 @@ public class BftProcessor implements Runnable { while (!shutdown) { nextEvent().ifPresent(eventMultiplexer::handleBftEvent); } + + incomingQueue.stop(); } catch (final Throwable t) { LOG.error("BFT Mining thread has suffered a fatal error, mining has been halted", t); } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java index 83cd61beb..795a064b6 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinator.java @@ -93,7 +93,9 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv @Override public void start() { - if (state.compareAndSet(State.IDLE, State.RUNNING)) { + if (state.compareAndSet(State.IDLE, State.RUNNING) + || state.compareAndSet(State.STOPPED, State.RUNNING)) { + bftProcessor.start(); bftExecutors.start(); blockAddedObserverId = blockchain.observeBlockAdded(this); eventHandler.start(); @@ -110,7 +112,7 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv try { bftProcessor.awaitStop(); } catch (final InterruptedException e) { - LOG.debug("Interrupted while waiting for IbftProcessor to stop.", e); + LOG.debug("Interrupted while waiting for BftProcessor to stop.", e); Thread.currentThread().interrupt(); } bftExecutors.stop(); @@ -135,12 +137,17 @@ public class BftMiningCoordinator implements MiningCoordinator, BlockAddedObserv @Override public boolean disable() { + if (state.get() == State.PAUSED + || state.compareAndSet(State.IDLE, State.PAUSED) + || state.compareAndSet(State.RUNNING, State.PAUSED)) { + return true; + } return false; } @Override public boolean isMining() { - return true; + return state.get() == State.RUNNING; } @Override diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftEventQueueTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftEventQueueTest.java index b39bef3a4..6fbf701bc 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftEventQueueTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BftEventQueueTest.java @@ -134,6 +134,40 @@ public class BftEventQueueTest { assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNull(); } + @Test + public void supportsStopAndRestart() throws InterruptedException { + final BftEventQueue queue = new BftEventQueue(MAX_QUEUE_SIZE); + queue.start(); + + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNull(); + final DummyBftEvent dummyMessageEvent = new DummyBftEvent(); + final DummyRoundExpiryBftEvent dummyRoundTimerEvent = new DummyRoundExpiryBftEvent(); + final DummyNewChainHeadBftEvent dummyNewChainHeadEvent = new DummyNewChainHeadBftEvent(); + + queue.add(dummyMessageEvent); + queue.add(dummyRoundTimerEvent); + queue.add(dummyNewChainHeadEvent); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNotNull(); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNotNull(); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNotNull(); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNull(); + + queue.stop(); + queue.add(dummyMessageEvent); + queue.add(dummyRoundTimerEvent); + queue.add(dummyNewChainHeadEvent); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNull(); + + queue.start(); + queue.add(dummyMessageEvent); + queue.add(dummyRoundTimerEvent); + queue.add(dummyNewChainHeadEvent); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNotNull(); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNotNull(); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNotNull(); + assertThat(queue.poll(0, TimeUnit.MICROSECONDS)).isNull(); + } + @Test public void alwaysAddBlockTimerExpiryEvents() throws InterruptedException { final BftEventQueue queue = new BftEventQueue(MAX_QUEUE_SIZE); diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java index cb0dffba9..328f9fd7b 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftMiningCoordinatorTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.internal.verification.VerificationModeFactory.times; import org.hyperledger.besu.consensus.common.bft.BftEventQueue; import org.hyperledger.besu.consensus.common.bft.BftExecutors; @@ -82,6 +83,28 @@ public class BftMiningCoordinatorTest { verify(bftProcessor).stop(); } + @Test + public void restartsMiningAfterStop() { + assertThat(bftMiningCoordinator.isMining()).isFalse(); + bftMiningCoordinator.stop(); + verify(bftProcessor, never()).stop(); + + bftMiningCoordinator.enable(); + bftMiningCoordinator.start(); + assertThat(bftMiningCoordinator.isMining()).isTrue(); + + bftMiningCoordinator.stop(); + assertThat(bftMiningCoordinator.isMining()).isFalse(); + verify(bftProcessor).stop(); + + bftMiningCoordinator.start(); + assertThat(bftMiningCoordinator.isMining()).isTrue(); + + // BFT processor should be started once for every time the mining + // coordinator is restarted + verify(bftProcessor, times(2)).start(); + } + @Test public void getsMinTransactionGasPrice() { final Wei minGasPrice = Wei.of(10); From aac7c63b0866d78edccdabace956c32947172090 Mon Sep 17 00:00:00 2001 From: Simon Dudley Date: Thu, 10 Oct 2024 11:04:02 +1000 Subject: [PATCH 05/10] Rotate CHANGELOG for 24.10.0 release (#7752) Signed-off-by: Simon Dudley --- CHANGELOG.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 762ae66b1..64b684433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,23 @@ # Changelog ## [Unreleased] -- Add `--ephemery` network support for Ephemery Testnet [#7563](https://github.com/hyperledger/besu/pull/7563) thanks to [@gconnect](https://github.com/gconnect) -- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647) + +### Breaking Changes ### Upcoming Breaking Changes -- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release + +### Additions and Improvements + +### Bug fixes + +## 24.10.0 ### Breaking Changes - Besu will now fail to start if any plugins encounter errors during initialization. To allow Besu to continue running despite plugin errors, use the `--plugin-continue-on-error` option. [#7662](https://github.com/hyperledger/besu/pull/7662) +### Upcoming Breaking Changes +- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release + ### Additions and Improvements - Remove privacy test classes support [#7569](https://github.com/hyperledger/besu/pull/7569) - Add Blob Transaction Metrics [#7622](https://github.com/hyperledger/besu/pull/7622) @@ -21,6 +29,8 @@ - Expose chainId in the `BlockchainService` [7702](https://github.com/hyperledger/besu/pull/7702) - Use head block instead of safe block for snap sync [7536](https://github.com/hyperledger/besu/issues/7536) - Add support for `chainId` in `CallParameters` [#7720](https://github.com/hyperledger/besu/pull/7720) +- Add `--ephemery` network support for Ephemery Testnet [#7563](https://github.com/hyperledger/besu/pull/7563) thanks to [@gconnect](https://github.com/gconnect) +- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647) ### Bug fixes - Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575) From e723b622c88defe9e65c21209ca7f67437de5464 Mon Sep 17 00:00:00 2001 From: Preeti <35308865+pr9t@users.noreply.github.com> Date: Fri, 11 Oct 2024 04:44:34 +0530 Subject: [PATCH 06/10] Chore:Resolved java Util NoSuchElementException (#7730) * Chore:Resolved java Util NoSuchElementException Signed-off-by: Preeti <35308865+pr9t@users.noreply.github.com> * formatting Signed-off-by: Sally MacFarlane --------- Signed-off-by: Preeti <35308865+pr9t@users.noreply.github.com> Signed-off-by: Sally MacFarlane Co-authored-by: Sally MacFarlane --- .../api/jsonrpc/internal/methods/EthGetBlockReceipts.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockReceipts.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockReceipts.java index a113e4ee8..819ac5e1e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockReceipts.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetBlockReceipts.java @@ -95,7 +95,8 @@ public class EthGetBlockReceipts extends AbstractBlockParameterOrBlockHashMethod .map( block -> block.getTransactions().stream() - .map(tx -> txReceipt(tx).get()) + .map(this::txReceipt) + .flatMap(Optional::stream) .collect(Collectors.toList())) .orElse(new ArrayList<>()); From efb6906e1361c39c43783f9825c80bc3b45a1d40 Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Thu, 10 Oct 2024 17:43:17 -0600 Subject: [PATCH 07/10] Move EOF to the Osaka Fork (#7719) * Move EOF to the Osaka Fork * Ensure Osaka activations are working * Remove CancunEOF and PragueEOF forks * Move EOF tools to default to Osaka Signed-off-by: Danno Ferrin * remove eof tests that fail only because of fork Signed-off-by: Danno Ferrin * Restore CancunEOF * Update unit tests to use "Cancun" as pre-eof fork * Make PC in trace zeroed to start of code section 0 * Update extcall to consider precompiles warm * Add stack checking to CALLF operation Signed-off-by: Danno Ferrin --------- Signed-off-by: Danno Ferrin Co-authored-by: Sally MacFarlane --- .../org/hyperledger/besu/cli/BesuCommand.java | 2 +- .../besu/config/GenesisConfigOptions.java | 6 +- .../besu/config/JsonGenesisConfigOptions.java | 8 +- .../besu/config/StubGenesisConfigOptions.java | 13 ++- .../besu/config/GenesisConfigOptionsTest.java | 9 +- .../besu/datatypes/HardforkId.java | 2 - .../besu/ethereum/chain/GenesisState.java | 12 +-- .../mainnet/MainnetProtocolSpecFactory.java | 4 +- .../mainnet/MainnetProtocolSpecs.java | 13 ++- .../mainnet/ProtocolScheduleBuilder.java | 9 +- .../besu/evmtool/CodeValidateSubCommand.java | 2 +- .../besu/evmtool/EOFTestSubCommand.java | 4 +- .../evmtool/MainnetGenesisFileModule.java | 11 +- .../besu/evmtool/PrettyPrintSubCommand.java | 2 +- .../evmtool/benchmarks/BenchmarkExecutor.java | 16 +-- ...ue-eof-rjump.json => osaka-eof-rjump.json} | 43 +++++--- .../besu/evmtool/state-test/create-eof.json | 4 +- .../state-test/create-invalid-eof.json | 4 +- .../besu/evmtool/trace/create-eof-error.json | 2 +- .../besu/evmtool/trace/create-eof.json | 4 +- .../besu/evmtool/trace/eof-section.json | 8 +- .../hyperledger/besu/evmtool/trace/eof.json | 4 +- .../besu/evmtool/trace/initcode-error.json | 2 +- .../ReferenceTestProtocolSchedules.java | 11 +- .../ethereum/eof/EOFReferenceTestTools.java | 49 ++++++--- .../hyperledger/besu/evm/EvmSpecVersion.java | 8 +- .../org/hyperledger/besu/evm/MainnetEVMs.java | 102 +++--------------- .../besu/evm/fluent/EVMExecutor.java | 16 --- ...alculator.java => OsakaGasCalculator.java} | 6 +- .../operation/AbstractExtCallOperation.java | 27 ++--- .../besu/evm/operation/CallFOperation.java | 9 ++ .../besu/evm/tracing/StandardJsonTracer.java | 4 +- .../besu/evm/code/CodeFactoryTest.java | 8 +- .../hyperledger/besu/evm/code/CodeV0Test.java | 2 +- .../besu/evm/fluent/EVMExecutorTest.java | 6 +- ...rTest.java => OsakaGasCalculatorTest.java} | 6 +- .../besu/evm/internal/CodeCacheTest.java | 2 +- .../evm/operation/Create2OperationTest.java | 2 +- .../evm/operation/CreateOperationTest.java | 4 +- .../evm/operation/DataCopyOperationTest.java | 2 +- .../evm/operation/EofCreateOperationTest.java | 4 +- .../evm/operation/ExtCallOperationTest.java | 12 +-- .../ExtDelegateCallOperationTest.java | 12 +-- .../operation/ExtStaticCallOperationTest.java | 13 +-- .../besu/evm/operation/JumpOperationTest.java | 2 +- .../operation/SelfDestructOperationTest.java | 2 +- .../ContractCreationProcessorTest.java | 2 +- .../tracing/ExtendedOperationTracerTest.java | 4 +- .../besu/testfuzz/EofContainerSubCommand.java | 2 +- .../besu/testfuzz/InternalClient.java | 2 +- 50 files changed, 225 insertions(+), 278 deletions(-) rename ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/{prague-eof-rjump.json => osaka-eof-rjump.json} (92%) rename evm/src/main/java/org/hyperledger/besu/evm/gascalculator/{PragueEOFGasCalculator.java => OsakaGasCalculator.java} (89%) rename evm/src/test/java/org/hyperledger/besu/evm/gascalculator/{PragueEOFGasCalculatorTest.java => OsakaGasCalculatorTest.java} (88%) 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 c8c0eaf6a..678b489ba 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1407,7 +1407,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { if (genesisConfigOptionsSupplier.get().getCancunTime().isPresent() || genesisConfigOptionsSupplier.get().getCancunEOFTime().isPresent() || genesisConfigOptionsSupplier.get().getPragueTime().isPresent() - || genesisConfigOptionsSupplier.get().getPragueEOFTime().isPresent()) { + || genesisConfigOptionsSupplier.get().getOsakaTime().isPresent()) { if (kzgTrustedSetupFile != null) { KZGPointEvalPrecompiledContract.init(kzgTrustedSetupFile); } else { diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java index 07ddd0d7e..e2458c932 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -257,11 +257,11 @@ public interface GenesisConfigOptions { OptionalLong getPragueTime(); /** - * Gets Prague EOF time. + * Gets Osaka time. * - * @return the prague time + * @return the osaka time */ - OptionalLong getPragueEOFTime(); + OptionalLong getOsakaTime(); /** * Gets future eips time. diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index 83b1f48fb..51f85f0ec 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -308,8 +308,8 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { } @Override - public OptionalLong getPragueEOFTime() { - return getOptionalLong("pragueeoftime"); + public OptionalLong getOsakaTime() { + return getOptionalLong("osakatime"); } @Override @@ -486,7 +486,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { getCancunTime().ifPresent(l -> builder.put("cancunTime", l)); getCancunEOFTime().ifPresent(l -> builder.put("cancunEOFTime", l)); getPragueTime().ifPresent(l -> builder.put("pragueTime", l)); - getPragueEOFTime().ifPresent(l -> builder.put("pragueEOFTime", l)); + getOsakaTime().ifPresent(l -> builder.put("osakaTime", l)); getTerminalBlockNumber().ifPresent(l -> builder.put("terminalBlockNumber", l)); getTerminalBlockHash().ifPresent(h -> builder.put("terminalBlockHash", h.toHexString())); getFutureEipsTime().ifPresent(l -> builder.put("futureEipsTime", l)); @@ -640,7 +640,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { getCancunTime(), getCancunEOFTime(), getPragueTime(), - getPragueEOFTime(), + getOsakaTime(), getFutureEipsTime(), getExperimentalEipsTime()); // when adding forks add an entry to ${REPO_ROOT}/config/src/test/resources/all_forks.json diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index ee9584fd3..c9c8dad79 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -50,7 +50,7 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable private OptionalLong cancunTime = OptionalLong.empty(); private OptionalLong cancunEOFTime = OptionalLong.empty(); private OptionalLong pragueTime = OptionalLong.empty(); - private OptionalLong pragueEOFTime = OptionalLong.empty(); + private OptionalLong osakaTime = OptionalLong.empty(); private OptionalLong futureEipsTime = OptionalLong.empty(); private OptionalLong experimentalEipsTime = OptionalLong.empty(); private OptionalLong terminalBlockNumber = OptionalLong.empty(); @@ -252,8 +252,8 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable } @Override - public OptionalLong getPragueEOFTime() { - return pragueEOFTime; + public OptionalLong getOsakaTime() { + return osakaTime; } @Override @@ -671,14 +671,13 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions, Cloneable } /** - * PragueEOF time. + * Osaka time. * * @param timestamp the timestamp * @return the stub genesis config options */ - public StubGenesisConfigOptions pragueEOFTime(final long timestamp) { - pragueTime = OptionalLong.of(timestamp); - pragueEOFTime = pragueTime; + public StubGenesisConfigOptions osakaTime(final long timestamp) { + osakaTime = OptionalLong.of(timestamp); return this; } diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java index 69494a9c9..fe8149cc6 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java @@ -207,10 +207,9 @@ class GenesisConfigOptionsTest { } @Test - void shouldGetPragueEOFTime() { - final GenesisConfigOptions config = - fromConfigOptions(singletonMap("pragueEOFTime", 1670470143)); - assertThat(config.getPragueEOFTime()).hasValue(1670470143); + void shouldGetOsakaTime() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("osakaTime", 1670470143)); + assertThat(config.getOsakaTime()).hasValue(1670470143); } @Test @@ -247,7 +246,7 @@ class GenesisConfigOptionsTest { assertThat(config.getCancunTime()).isEmpty(); assertThat(config.getCancunEOFTime()).isEmpty(); assertThat(config.getPragueTime()).isEmpty(); - assertThat(config.getPragueEOFTime()).isEmpty(); + assertThat(config.getOsakaTime()).isEmpty(); assertThat(config.getFutureEipsTime()).isEmpty(); assertThat(config.getExperimentalEipsTime()).isEmpty(); } diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/HardforkId.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/HardforkId.java index 85ec84b4a..d8b938a1b 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/HardforkId.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/HardforkId.java @@ -81,8 +81,6 @@ public interface HardforkId { CANCUN_EOF(false, "Cancun + EOF"), /** Prague fork. */ PRAGUE(false, "Prague"), - /** Prague + EOF fork. */ - PRAGUE_EOF(false, "Prague + EOF"), /** Osaka fork. */ OSAKA(false, "Osaka"), /** Amsterdam fork. */ diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java index 00b20a017..c2243986c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/GenesisState.java @@ -312,7 +312,7 @@ public final class GenesisState { if (cancunEOFTimestamp.isPresent()) { return genesis.getTimestamp() >= cancunEOFTimestamp.getAsLong(); } - return isPragueEOFAtGenesis(genesis); + return false; } private static boolean isPragueAtGenesis(final GenesisConfigFile genesis) { @@ -320,13 +320,13 @@ public final class GenesisState { if (pragueTimestamp.isPresent()) { return genesis.getTimestamp() >= pragueTimestamp.getAsLong(); } - return isPragueEOFAtGenesis(genesis); + return isOsakaAtGenesis(genesis); } - private static boolean isPragueEOFAtGenesis(final GenesisConfigFile genesis) { - final OptionalLong pragueEOFTimestamp = genesis.getConfigOptions().getPragueEOFTime(); - if (pragueEOFTimestamp.isPresent()) { - return genesis.getTimestamp() >= pragueEOFTimestamp.getAsLong(); + private static boolean isOsakaAtGenesis(final GenesisConfigFile genesis) { + final OptionalLong osakaTimestamp = genesis.getConfigOptions().getOsakaTime(); + if (osakaTimestamp.isPresent()) { + return genesis.getTimestamp() >= osakaTimestamp.getAsLong(); } return isFutureEipsTimeAtGenesis(genesis); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java index 55bfb363b..615a47625 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecFactory.java @@ -224,8 +224,8 @@ public class MainnetProtocolSpecFactory { metricsSystem); } - public ProtocolSpecBuilder pragueEOFDefinition(final GenesisConfigOptions genesisConfigOptions) { - return MainnetProtocolSpecs.pragueEOFDefinition( + public ProtocolSpecBuilder osakaDefinition(final GenesisConfigOptions genesisConfigOptions) { + return MainnetProtocolSpecs.osakaDefinition( chainId, isRevertReasonEnabled, genesisConfigOptions, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index b5b2f678d..342617147 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -57,8 +57,8 @@ import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator; import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; +import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator; import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator; -import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator; import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator; @@ -815,7 +815,7 @@ public abstract class MainnetProtocolSpecs { .name("Prague"); } - static ProtocolSpecBuilder pragueEOFDefinition( + static ProtocolSpecBuilder osakaDefinition( final Optional chainId, final boolean enableRevertReason, final GenesisConfigOptions genesisConfigOptions, @@ -833,7 +833,7 @@ public abstract class MainnetProtocolSpecs { miningParameters, isParallelTxProcessingEnabled, metricsSystem); - return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("PragueEOF"); + return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("Osaka"); } private static ProtocolSpecBuilder addEOF( @@ -842,12 +842,11 @@ public abstract class MainnetProtocolSpecs { final ProtocolSpecBuilder protocolSpecBuilder) { return protocolSpecBuilder // EIP-7692 EOF v1 Gas calculator - .gasCalculator(PragueEOFGasCalculator::new) + .gasCalculator(OsakaGasCalculator::new) // EIP-7692 EOF v1 EVM and opcodes .evmBuilder( (gasCalculator, jdCacheConfig) -> - MainnetEVMs.pragueEOF( - gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) + MainnetEVMs.osaka(gasCalculator, chainId.orElse(BigInteger.ZERO), evmConfiguration)) // EIP-7698 EOF v1 creation transaction .contractCreationProcessorBuilder( evm -> @@ -867,7 +866,7 @@ public abstract class MainnetProtocolSpecs { final MiningParameters miningParameters, final boolean isParallelTxProcessingEnabled, final MetricsSystem metricsSystem) { - return pragueEOFDefinition( + return osakaDefinition( chainId, enableRevertReason, genesisConfigOptions, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java index beac906be..52003bc96 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.datatypes.HardforkId; +import org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId; import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.core.MiningParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters; @@ -277,7 +278,7 @@ public class ProtocolScheduleBuilder { lastForkBlock = validateForkOrder("Cancun", config.getCancunTime(), lastForkBlock); lastForkBlock = validateForkOrder("CancunEOF", config.getCancunEOFTime(), lastForkBlock); lastForkBlock = validateForkOrder("Prague", config.getPragueTime(), lastForkBlock); - lastForkBlock = validateForkOrder("PragueEOF", config.getPragueEOFTime(), lastForkBlock); + lastForkBlock = validateForkOrder("Osaka", config.getOsakaTime(), lastForkBlock); lastForkBlock = validateForkOrder("FutureEips", config.getFutureEipsTime(), lastForkBlock); lastForkBlock = validateForkOrder("ExperimentalEips", config.getExperimentalEipsTime(), lastForkBlock); @@ -413,9 +414,9 @@ public class ProtocolScheduleBuilder { config.getPragueTime(), specFactory.pragueDefinition(config)), timestampMilestone( - HardforkId.MainnetHardforkId.PRAGUE_EOF, - config.getPragueEOFTime(), - specFactory.pragueEOFDefinition(config)), + MainnetHardforkId.OSAKA, + config.getOsakaTime(), + specFactory.osakaDefinition(config)), timestampMilestone( HardforkId.MainnetHardforkId.FUTURE_EIPS, config.getFutureEipsTime(), diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java index d8be71cde..bc5ef06f0 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/CodeValidateSubCommand.java @@ -86,7 +86,7 @@ public class CodeValidateSubCommand implements Runnable { String fork = parentCommand != null && parentCommand.hasFork() ? parentCommand.getFork() - : EvmSpecVersion.PRAGUE.getName(); + : EvmSpecVersion.OSAKA.getName(); evm = Suppliers.memoize( diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java index fb28701f7..7906cfd95 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EOFTestSubCommand.java @@ -94,7 +94,7 @@ public class EOFTestSubCommand implements Runnable { } ProtocolSpec protocolSpec = ReferenceTestProtocolSchedules.getInstance() - .geSpecByName(fork == null ? EvmSpecVersion.PRAGUE.getName() : fork); + .geSpecByName(fork == null ? EvmSpecVersion.OSAKA.getName() : fork); evm = protocolSpec.getEvm(); final JavaType javaType = @@ -181,7 +181,7 @@ public class EOFTestSubCommand implements Runnable { continue; } TestResult actualResult; - if (evmVersion.ordinal() < EvmSpecVersion.PRAGUE_EOF.ordinal()) { + if (evmVersion.ordinal() < EvmSpecVersion.OSAKA.ordinal()) { actualResult = failed("EOF_InvalidCode"); } else { actualResult = considerCode(code); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java index 0ce7bf98f..8dc8a74c1 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/MainnetGenesisFileModule.java @@ -157,15 +157,16 @@ class MainnetGenesisFileModule extends GenesisFileModule { .chainId(chainId))), Map.entry( "prague", - createSchedule( - new StubGenesisConfigOptions().pragueTime(0).baseFeePerGas(0x0a).chainId(chainId))), - Map.entry( - "pragueeof", createSchedule( new StubGenesisConfigOptions() - .pragueEOFTime(0) + .pragueTime(0) + .osakaTime(0) // TODO remove this once osaka_devnet_0 launches .baseFeePerGas(0x0a) .chainId(chainId))), + Map.entry( + "osaka", + createSchedule( + new StubGenesisConfigOptions().osakaTime(0).baseFeePerGas(0x0a).chainId(chainId))), Map.entry( "futureeips", createSchedule( diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java index e24c24a21..c6fac3656 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/PrettyPrintSubCommand.java @@ -101,7 +101,7 @@ public class PrettyPrintSubCommand implements Runnable { "Pretty printing of legacy EVM is not supported. Patches welcome!"); } else { - String fork = EvmSpecVersion.PRAGUE.getName(); + String fork = EvmSpecVersion.OSAKA.getName(); if (parentCommand.hasFork()) { fork = parentCommand.getFork(); } diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java index 082fae7f6..35d5de5d6 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/benchmarks/BenchmarkExecutor.java @@ -30,8 +30,8 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; +import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator; import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator; -import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator; import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; import org.hyperledger.besu.evm.precompile.PrecompiledContract; @@ -142,17 +142,11 @@ public abstract class BenchmarkExecutor { case LONDON, PARIS -> new LondonGasCalculator(); case SHANGHAI -> new ShanghaiGasCalculator(); case CANCUN -> new CancunGasCalculator(); + case CANCUN_EOF -> new OsakaGasCalculator(); case PRAGUE -> new PragueGasCalculator(); - case CANCUN_EOF, - PRAGUE_EOF, - OSAKA, - AMSTERDAM, - BOGOTA, - POLIS, - BANGKOK, - FUTURE_EIPS, - EXPERIMENTAL_EIPS -> - new PragueEOFGasCalculator(); + case OSAKA -> new OsakaGasCalculator(); + case AMSTERDAM, BOGOTA, POLIS, BANGKOK, FUTURE_EIPS, EXPERIMENTAL_EIPS -> + new OsakaGasCalculator(); }; } diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/prague-eof-rjump.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json similarity index 92% rename from ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/prague-eof-rjump.json rename to ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json index b9d2e5417..8cca437e3 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/prague-eof-rjump.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/block-test/osaka-eof-rjump.json @@ -4,13 +4,13 @@ "stdin" ], "stdin": { - "tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_PragueEIP7692-blockchain_test]": { - "network": "Prague", + "tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]": { + "network": "Osaka", "genesisBlockHeader": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "coinbase": "0x0000000000000000000000000000000000000000", - "stateRoot": "0x34ccf8774a5b8833da9451a3f7f8a0af0147956c058f0831dab07c348d7ac0d9", + "stateRoot": "0xbeb30acb62768b375f7e7d36f6ba9240cb692ebd0ee04c9321c756cf4ff1c437", "transactionsTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "receiptTrie": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -28,7 +28,7 @@ "excessBlobGas": "0x00", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "requestsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "hash": "0xc9397e8a1b99cbb2b885852fde56de8fa686091a4f4430163f5237d7aaf33a14" + "hash": "0x367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9" }, "pre": { "0x00000000219ab540356cbb839cbe05303d7705fa": { @@ -75,6 +75,12 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd", "storage": {} }, + "0x00b42dbf2194e931e80326d950320f7d9dbeac02": { + "nonce": "0x01", + "balance": "0x00", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd", + "storage": {} + }, "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { "nonce": "0x01", "balance": "0x00", @@ -161,12 +167,18 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146090573615156028575f545f5260205ff35b366038141561012e5760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061012e57600154600101600155600354806003026004013381556001015f3581556001016020359055600101600355005b6003546002548082038060101160a4575060105b5f5b81811460dd5780604c02838201600302600401805490600101805490600101549160601b83528260140152906034015260010160a6565b910180921460ed579060025560f8565b90505f6002555f6003555b5f548061049d141561010757505f5b60015460028282011161011c5750505f610122565b01600290035b5f555f600155604c025ff35b5f5ffd", "storage": {} }, + "0x00b42dbf2194e931e80326d950320f7d9dbeac02": { + "nonce": "0x01", + "balance": "0x00", + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe146098573615156028575f545f5260205ff35b36606014156101445760115f54600182026001905f5b5f82111560595781019083028483029004916001019190603e565b90939004341061014457600154600101600155600354806004026004013381556001015f35815560010160203581556001016040359055600101600355005b6003546002548082038060011160ac575060015b5f5b81811460f15780607402838201600402600401805490600101805490600101805490600101549260601b84529083601401528260340152906054015260010160ae565b9101809214610103579060025561010e565b90505f6002555f6003555b5f548061049d141561011d57505f5b6001546001828201116101325750505f610138565b01600190035b5f555f6001556074025ff35b5f5ffd", + "storage": {} + }, "0x0aae40965e6800cd9b1f4b05ff21581047e3f91e": { "nonce": "0x01", "balance": "0x00", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500", "storage": { - "0x00": "0xc9397e8a1b99cbb2b885852fde56de8fa686091a4f4430163f5237d7aaf33a14" + "0x00": "0x367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9" } }, "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { @@ -182,14 +194,15 @@ "storage": {} } }, - "genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a034ccf8774a5b8833da9451a3f7f8a0af0147956c058f0831dab07c348d7ac0d9a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0c0", + "lastblockhash": "0xfb5d1d0e218fa7873bc188f07f3e0a7c78027ff6e6e199c48ba1facd3c3726fd", + "genesisRLP": "0xf90262f9025ba00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0beb30acb62768b375f7e7d36f6ba9240cb692ebd0ee04c9321c756cf4ff1c437a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808088016345785d8a0000808000a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421c0c0c0c0", "blocks": [ { "blockHeader": { - "parentHash": "0xc9397e8a1b99cbb2b885852fde56de8fa686091a4f4430163f5237d7aaf33a14", + "parentHash": "0x367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9", "uncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "coinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", - "stateRoot": "0x1a4885d1f64bac16e5ab17fb13e23fb5d1a0ec2ca4519c81714683f69c8d9a84", + "stateRoot": "0x4ab70cbe1abe50d6bb3c8cdb3e9e66111f142cd68ab73870e9ce9e0dd1d6ead2", "transactionsTrie": "0xec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3", "receiptTrie": "0x9593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafa", "bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -207,7 +220,7 @@ "excessBlobGas": "0x00", "parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "requestsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "hash": "0x879cf54bf493b6585db592b1b24ec30a8a7fbe3b9146d3fb20ca36200f2aca87" + "hash": "0xfb5d1d0e218fa7873bc188f07f3e0a7c78027ff6e6e199c48ba1facd3c3726fd" }, "transactions": [ { @@ -229,22 +242,22 @@ "withdrawals": [], "depositRequests": [], "withdrawalRequests": [], - "rlp": "0xf902c9f9025fa0c9397e8a1b99cbb2b885852fde56de8fa686091a4f4430163f5237d7aaf33a14a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa01a4885d1f64bac16e5ab17fb13e23fb5d1a0ec2ca4519c81714683f69c8d9a84a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0c0", + "consolidationRequests": [], + "rlp": "0xf902c9f9025fa0367310df4a31070aa9a5c92cb61ab8bb2742db0162619ed77594fbec6f0ddbd9a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942adc25665018aa1fe0e6bc666dac8fc2697ff9baa04ab70cbe1abe50d6bb3c8cdb3e9e66111f142cd68ab73870e9ce9e0dd1d6ead2a0ec9d10cff79619f2df45db8c66526ef3fbd32d283fdd2dcc9b55c0efe643d8c3a09593f56abf23bcbb26d27b0c6e46a56415d9103ed6b4d8ac7b4182f9f250cafab9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800188016345785d8a000082a8648203e800a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a00000000000000000000000000000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f862f860800a83989680940000000000000000000000000000000000001000808026a0e5d462429669f661291a8dc4c49a092cfd4922b6f3f31c9189a2f4adf5ecd730a001494afaf472fbb80bcb107ffeb918a2b9115f454027840615d6d20d63c69ac0c0c0c0", "blocknumber": "1" } ], - "lastblockhash": "0x879cf54bf493b6585db592b1b24ec30a8a7fbe3b9146d3fb20ca36200f2aca87", "sealEngine": "NoProof", "_info": { - "hash": "0xbfd1223f9b5b8dbf202178f7c1f18dc089cb24e54c9cb7fc9831907547e937c4", + "hash": "0xd0cc15d832c8c0b9cf5bdc0eab79c3b632193a11fde3d5ef32bb07e8c65ba6bd", "comment": "`execution-spec-tests` generated test", - "filling-transition-tool": "Hyperledger Besu evm 24.7-develop-8ca7129", + "filling-transition-tool": "Hyperledger Besu evm 24.9-develop-0d63955", "description": "Test function documentation:\nEOF1V4200_0002 (Valid) EOF code containing RJUMP (Zero)", - "url": "https://github.com/ethereum/execution-spec-tests/blob/891a6111370c89d4ce89bf91589c6d5ff6785158/tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py#L63", + "url": "https://github.com/ethereum/execution-spec-tests/blob/96efd737b258eeb8efb615e9123d931b6dfda302/tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py#L44", "reference-spec": "https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4200.md", "reference-spec-version": "17d4a8d12d2b5e0f2985c866376c16c8c6df7cba" } } }, - "stdout": "Considering tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_PragueEIP7692-blockchain_test]\nBlock 1 (0x879cf54bf493b6585db592b1b24ec30a8a7fbe3b9146d3fb20ca36200f2aca87) Imported\nChain import successful - tests/prague/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_PragueEIP7692-blockchain_test]\n" + "stdout": "Considering tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\nBlock 1 (0xfb5d1d0e218fa7873bc188f07f3e0a7c78027ff6e6e199c48ba1facd3c3726fd) Imported\nChain import successful - tests/osaka/eip7692_eof_v1/eip4200_relative_jumps/test_rjump.py::test_rjump_zero[fork_Osaka-blockchain_test]\n" } diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-eof.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-eof.json index e92404304..72ada37da 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-eof.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-eof.json @@ -45,7 +45,7 @@ }, "out": "0x", "post": { - "CancunEOF": [ + "Osaka": [ { "hash": "0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3", "logs": "0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940", @@ -79,7 +79,7 @@ {"pc":5,"section":0,"op":95,"gas":"0x793d71","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"}, {"pc":6,"section":0,"op":95,"gas":"0x793d6f","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH0"}, {"pc":7,"section":0,"op":238,"immediate":"0x00","gas":"0x793d6d","gasCost":"0x0","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"RETURNCONTRACT"}, - {"output":"","gasUsed":"0xe433","test":"create-eof","fork":"CancunEOF","d":0,"g":0,"v":0,"postHash":"0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3","postLogsHash":"0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940","pass":true}, + {"output":"","gasUsed":"0xe433","test":"create-eof","fork":"Osaka","d":0,"g":0,"v":0,"postHash":"0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3","postLogsHash":"0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940","pass":true}, {"pc":0,"op":239,"gas":"0x794068","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"}, {"output":"","gasUsed":"0x7a1200","test":"create-eof","fork":"Cancun","d":0,"g":0,"v":0,"postHash":"0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":true,"error":"INVALID_OPERATION"} ] diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-invalid-eof.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-invalid-eof.json index e2eb67602..f3448aa5a 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-invalid-eof.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/state-test/create-invalid-eof.json @@ -45,7 +45,7 @@ }, "out": "0x", "post": { - "Prague": [ + "Osaka": [ { "hash": "0x1a8642a04dae90535f00f53d3a30284c4db051d508a653db89eb100ba9aecbf3", "logs": "0xf48b954a6a6f4ce6b28e4950b7027413f4bdc8f459df6003b6e8d7a1567c8940", @@ -71,7 +71,7 @@ } }, "stdout": [ - {"output":"","gasUsed":"0xd198","test":"create-eof","fork":"Prague","d":0,"g":0,"v":0,"postHash":"0x2a9c58298ba5d4ec86ca682b9fcc9ff67c3fc44dbd39f85a2f9b74bfe4e5178e","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":false,"error":"Invalid EOF Layout: unexpected_header_kind expected 1 actual 17"}, + {"output":"","gasUsed":"0xd198","test":"create-eof","fork":"Osaka","d":0,"g":0,"v":0,"postHash":"0x2a9c58298ba5d4ec86ca682b9fcc9ff67c3fc44dbd39f85a2f9b74bfe4e5178e","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":false,"error":"Invalid EOF Layout: unexpected_header_kind expected 1 actual 17"}, {"pc":0,"op":239,"gas":"0x794068","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"INVALID","error":"Bad instruction"}, {"output":"","gasUsed":"0x7a1200","test":"create-eof","fork":"Cancun","d":0,"g":0,"v":0,"postHash":"0xaa80d89bc89f58da8de41d3894bd1a241896ff91f7a5964edaefb39e8e3a4a98","postLogsHash":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","pass":true,"error":"INVALID_OPERATION"} ] diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof-error.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof-error.json index cd4c3fa14..0b1396f26 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof-error.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof-error.json @@ -8,7 +8,7 @@ "--coinbase", "4444588443C3A91288C5002483449ABA1054192B", "--fork", - "CancunEOF" + "Osaka" ], "stdin": "", "stdout": "EOF Code Invalid : incompatible_container_kind opcode STOP is only valid for runtime.\n" diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof.json index 1fa459916..6740c8671 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/create-eof.json @@ -8,7 +8,7 @@ "--coinbase", "4444588443C3A91288C5002483449ABA1054192B", "--fork", - "CancunEOF" + "Osaka" ], "stdin": "", "stdout": [ @@ -20,6 +20,6 @@ {"pc":5,"section":0,"op":95,"gas":"0x2540be109","gasCost":"0x2","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH0"}, {"pc":6,"section":0,"op":95,"gas":"0x2540be107","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH0"}, {"pc":7,"section":0,"op":238,"immediate":"0x00","gas":"0x2540be105","gasCost":"0x0","memSize":0,"stack":["0x0","0x0"],"depth":1,"refund":0,"opName":"RETURNCONTRACT"}, - {"stateRoot":"0x9790b070a5749acec6a7252a867f795df3c2cb5b800fb509ea259a1c0b5d96c1","output":"0x","gasUsed":"0x129b","pass":true,"fork":"CancunEOF"} + {"stateRoot":"0x9790b070a5749acec6a7252a867f795df3c2cb5b800fb509ea259a1c0b5d96c1","output":"0x","gasUsed":"0x129b","pass":true,"fork":"Osaka"} ] } \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof-section.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof-section.json index 439c69195..f25557fa7 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof-section.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof-section.json @@ -7,17 +7,17 @@ "--coinbase", "4444588443C3A91288C5002483449ABA1054192B", "--fork", - "PragueEOF" + "Osaka" ], "stdin": "", "stdout": [ {"pc":0,"section":0,"op":227,"immediate":"0x0002","gas":"0x2540be400","gasCost":"0x5","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"CALLF"}, - {"pc":0,"section":2,"op":229,"immediate":"0x0002","gas":"0x2540be3fb","gasCost":"0x5","memSize":0,"stack":[],"depth":1,"functionDepth":1,"refund":0,"opName":"JUMPF"}, - {"pc":0,"section":1,"op":228,"gas":"0x2540be3f6","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"functionDepth":1,"refund":0,"opName":"RETF"}, + {"pc":11,"section":2,"op":229,"immediate":"0x0001","gas":"0x2540be3fb","gasCost":"0x5","memSize":0,"stack":[],"depth":1,"functionDepth":1,"refund":0,"opName":"JUMPF"}, + {"pc":10,"section":1,"op":228,"gas":"0x2540be3f6","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"functionDepth":1,"refund":0,"opName":"RETF"}, {"pc":3,"section":0,"op":97,"immediate":"0x2015","gas":"0x2540be3f3","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH2"}, {"pc":6,"section":0,"op":96,"immediate":"0x01","gas":"0x2540be3f0","gasCost":"0x3","memSize":0,"stack":["0x2015"],"depth":1,"refund":0,"opName":"PUSH1"}, {"pc":8,"section":0,"op":85,"gas":"0x2540be3ed","gasCost":"0x5654","memSize":0,"stack":["0x2015","0x1"],"depth":1,"refund":0,"opName":"SSTORE"}, {"pc":9,"section":0,"op":0,"gas":"0x2540b8d99","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"}, - {"stateRoot":"0x761f723ceabb467d438fe74abf025c10bf65592b84ec389850038eb572f2b0fa","output":"0x","gasUsed":"0x5667","pass":true,"fork":"PragueEOF"} + {"stateRoot":"0x761f723ceabb467d438fe74abf025c10bf65592b84ec389850038eb572f2b0fa","output":"0x","gasUsed":"0x5667","pass":true,"fork":"Osaka"} ] } \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof.json index c9553c920..ddce2bf2a 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/eof.json @@ -7,11 +7,11 @@ "--coinbase", "4444588443C3A91288C5002483449ABA1054192B", "--fork", - "PragueEOF" + "Osaka" ], "stdin": "", "stdout": [ {"pc":0,"section":0,"op":0,"gas":"0x2540be400","gasCost":"0x0","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP"}, - {"stateRoot":"0xdae5f2c233bf9fbb7413d06ce744a3345dbf971b5bb5638736c0388f43a61a4b","output":"0x","gasUsed":"0x0","pass":true,"fork":"PragueEOF"} + {"stateRoot":"0xdae5f2c233bf9fbb7413d06ce744a3345dbf971b5bb5638736c0388f43a61a4b","output":"0x","gasUsed":"0x0","pass":true,"fork":"Osaka"} ] } \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/initcode-error.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/initcode-error.json index b88134778..4225259fa 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/initcode-error.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/trace/initcode-error.json @@ -7,7 +7,7 @@ "--coinbase", "4444588443C3A91288C5002483449ABA1054192B", "--fork", - "CancunEOF" + "Osaka" ], "stdin": "", "stdout": "To evaluate INITCODE mode EOF code use the --create flag\n" diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index bcdf5e25d..976c8e70d 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -105,8 +105,15 @@ public class ReferenceTestProtocolSchedules { Map.entry( "CancunToPragueAtTime15k", createSchedule(genesisStub.clone().cancunTime(0).pragueTime(15000))), - Map.entry("Prague", createSchedule(genesisStub.clone().pragueEOFTime(0))), - Map.entry("Osaka", createSchedule(genesisStub.clone().futureEipsTime(0))), + Map.entry( + "Prague", + createSchedule( + genesisStub + .clone() + .pragueTime(0) + .osakaTime(0) // TODO remove this once osaka_devnet_0 ships + )), + Map.entry("Osaka", createSchedule(genesisStub.clone().osakaTime(0))), Map.entry("Amsterdam", createSchedule(genesisStub.clone().futureEipsTime(0))), Map.entry("Bogota", createSchedule(genesisStub.clone().futureEipsTime(0))), Map.entry("Polis", createSchedule(genesisStub.clone().futureEipsTime(0))), diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java index 6a736831f..334bb0be3 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/eof/EOFReferenceTestTools.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.eof; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; import java.nio.file.Path; import java.util.Arrays; @@ -33,6 +34,7 @@ import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedul import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.code.CodeInvalid; +import org.hyperledger.besu.evm.code.CodeV1; import org.hyperledger.besu.evm.code.EOFLayout; import org.hyperledger.besu.testutil.JsonTestParameters; @@ -41,7 +43,7 @@ public class EOFReferenceTestTools { static { final String eips = - System.getProperty("test.ethereum.eof.eips", "Prague,Osaka,Amsterdam,Bogota,Polis,Bangkok"); + System.getProperty("test.ethereum.eof.eips", "Osaka,Amsterdam,Bogota,Polis,Bangkok"); EIPS_TO_RUN = Arrays.asList(eips.split(",")); } @@ -79,6 +81,10 @@ public class EOFReferenceTestTools { if (EIPS_TO_RUN.isEmpty()) { params.ignoreAll(); } + + // EOF was moved from Prague to Osaka + params.ignore("-Prague\\["); + } private EOFReferenceTestTools() { @@ -132,28 +138,37 @@ public class EOFReferenceTestTools { } else { parsedCode = evm.getCodeUncached(code); } + if (expected.result()) { assertThat(parsedCode.isValid()) .withFailMessage( () -> "Valid code failed with " + ((CodeInvalid) parsedCode).getInvalidReason()) .isTrue(); - } else { - assertThat(parsedCode.isValid()) - .withFailMessage("Invalid code expected " + expected.exception() + " but was valid") - .isFalse(); - if (name.contains("eip7692")) { - // if the test is from EEST, validate the exception name. - assertThat(((CodeInvalid) parsedCode).getInvalidReason()) - .withFailMessage( - () -> - "Expected exception :%s actual exception: %s" - .formatted( - expected.exception(), - (parsedCode.isValid() - ? null - : ((CodeInvalid) parsedCode).getInvalidReason()))) - .containsIgnoringCase(expected.exception().replace("EOFException.", "")); + } else if (parsedCode.isValid()) { + if (parsedCode instanceof CodeV1 codeV1 + && expected.exception().contains("EOF_IncompatibleContainerKind")) { + // one last container type check + var parsedMode = codeV1.getEofLayout().containerMode().get(); + String actual = parsedMode == null ? "RUNTIME" : parsedMode.toString(); + String expectedContainerKind = containerKind == null ? "RUNTIME" : containerKind; + assertThat(actual) + .withFailMessage("EOF_IncompatibleContainerKind expected") + .isNotEqualTo(expectedContainerKind); + } else { + fail("Invalid code expected " + expected.exception() + " but was valid"); } + } else if (name.contains("eip7692")) { + // if the test is from EEST, validate the exception name. + assertThat(((CodeInvalid) parsedCode).getInvalidReason()) + .withFailMessage( + () -> + "Expected exception :%s actual exception: %s" + .formatted( + expected.exception(), + (parsedCode.isValid() + ? null + : ((CodeInvalid) parsedCode).getInvalidReason()))) + .containsIgnoringCase(expected.exception().replace("EOFException.", "")); } } else { assertThat(false) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java index 7d4344c6b..d675496d7 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/EvmSpecVersion.java @@ -55,8 +55,6 @@ public enum EvmSpecVersion { CANCUN_EOF(MainnetHardforkId.CANCUN_EOF, 0x6000, 0xc000, 1), /** Prague evm spec version. */ PRAGUE(MainnetHardforkId.PRAGUE, 0x6000, 0xc000, 0), - /** PragueEOF evm spec version. */ - PRAGUE_EOF(MainnetHardforkId.PRAGUE_EOF, 0x6000, 0xc000, 1), /** Osaka evm spec version. */ OSAKA(MainnetHardforkId.OSAKA, 0x6000, 0xc000, 1), /** Amsterdam evm spec version. */ @@ -183,11 +181,11 @@ public enum EvmSpecVersion { * @return the EVM spec version for that fork, or null if no fork matched. */ public static EvmSpecVersion fromName(final String name) { - // TODO remove once PragueEOF settles + // TODO remove once CancunEOF tests are removed from EEST if ("prague".equalsIgnoreCase(name)) { - return EvmSpecVersion.PRAGUE_EOF; + return EvmSpecVersion.OSAKA; } - // TODO remove once PragueEOF settles + // TODO remove once CancunEOF tests are removed from EEST if ("cancuneof".equalsIgnoreCase(name)) { return EvmSpecVersion.CANCUN_EOF; } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java index 998776d71..482a34209 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -23,8 +23,8 @@ import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; +import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator; import org.hyperledger.besu.evm.gascalculator.PetersburgGasCalculator; -import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator; import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator; @@ -1025,72 +1025,70 @@ public class MainnetEVMs { final GasCalculator gasCalculator, final BigInteger chainID) { registerCancunOperations(registry, gasCalculator, chainID); - - // TODO add EOF operations here once PragueEOF is collapsed into Prague } /** - * PragueEOF evm. + * Osaka evm. * * @param evmConfiguration the evm configuration * @return the evm */ - public static EVM pragueEOF(final EvmConfiguration evmConfiguration) { - return pragueEOF(DEV_NET_CHAIN_ID, evmConfiguration); + public static EVM osaka(final EvmConfiguration evmConfiguration) { + return osaka(DEV_NET_CHAIN_ID, evmConfiguration); } /** - * PragueEOF evm. + * Osaka evm. * * @param chainId the chain id * @param evmConfiguration the evm configuration * @return the evm */ - public static EVM pragueEOF(final BigInteger chainId, final EvmConfiguration evmConfiguration) { - return pragueEOF(new PragueEOFGasCalculator(), chainId, evmConfiguration); + public static EVM osaka(final BigInteger chainId, final EvmConfiguration evmConfiguration) { + return osaka(new OsakaGasCalculator(), chainId, evmConfiguration); } /** - * PragueEOF evm. + * Osaka evm. * * @param gasCalculator the gas calculator * @param chainId the chain id * @param evmConfiguration the evm configuration * @return the evm */ - public static EVM pragueEOF( + public static EVM osaka( final GasCalculator gasCalculator, final BigInteger chainId, final EvmConfiguration evmConfiguration) { return new EVM( - pragueEOFOperations(gasCalculator, chainId), + osakaOperations(gasCalculator, chainId), gasCalculator, evmConfiguration, - EvmSpecVersion.PRAGUE_EOF); + EvmSpecVersion.OSAKA); } /** - * Operation registry for PragueEOF's operations. + * Operation registry for Osaka's operations. * * @param gasCalculator the gas calculator * @param chainId the chain id * @return the operation registry */ - public static OperationRegistry pragueEOFOperations( + public static OperationRegistry osakaOperations( final GasCalculator gasCalculator, final BigInteger chainId) { OperationRegistry operationRegistry = new OperationRegistry(); - registerPragueEOFOperations(operationRegistry, gasCalculator, chainId); + registerOsakaOperations(operationRegistry, gasCalculator, chainId); return operationRegistry; } /** - * Register PragueEOF's operations. + * Register Osaka's operations. * * @param registry the registry * @param gasCalculator the gas calculator * @param chainID the chain id */ - public static void registerPragueEOFOperations( + public static void registerOsakaOperations( final OperationRegistry registry, final GasCalculator gasCalculator, final BigInteger chainID) { @@ -1140,74 +1138,6 @@ public class MainnetEVMs { registry.put(new ReturnContractOperation(gasCalculator)); } - /** - * Osaka evm. - * - * @param evmConfiguration the evm configuration - * @return the evm - */ - public static EVM osaka(final EvmConfiguration evmConfiguration) { - return osaka(DEV_NET_CHAIN_ID, evmConfiguration); - } - - /** - * Osaka evm. - * - * @param chainId the chain id - * @param evmConfiguration the evm configuration - * @return the evm - */ - public static EVM osaka(final BigInteger chainId, final EvmConfiguration evmConfiguration) { - return osaka(new PragueGasCalculator(), chainId, evmConfiguration); - } - - /** - * Osaka evm. - * - * @param gasCalculator the gas calculator - * @param chainId the chain id - * @param evmConfiguration the evm configuration - * @return the evm - */ - public static EVM osaka( - final GasCalculator gasCalculator, - final BigInteger chainId, - final EvmConfiguration evmConfiguration) { - return new EVM( - osakaOperations(gasCalculator, chainId), - gasCalculator, - evmConfiguration, - EvmSpecVersion.OSAKA); - } - - /** - * Operation registry for osaka's operations. - * - * @param gasCalculator the gas calculator - * @param chainId the chain id - * @return the operation registry - */ - public static OperationRegistry osakaOperations( - final GasCalculator gasCalculator, final BigInteger chainId) { - OperationRegistry operationRegistry = new OperationRegistry(); - registerOsakaOperations(operationRegistry, gasCalculator, chainId); - return operationRegistry; - } - - /** - * Register osaka operations. - * - * @param registry the registry - * @param gasCalculator the gas calculator - * @param chainID the chain id - */ - public static void registerOsakaOperations( - final OperationRegistry registry, - final GasCalculator gasCalculator, - final BigInteger chainID) { - registerPragueEOFOperations(registry, gasCalculator, chainID); - } - /** * Amsterdam evm. * diff --git a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java index a182ae945..fbf62f3e4 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/fluent/EVMExecutor.java @@ -164,7 +164,6 @@ public class EVMExecutor { case CANCUN -> cancun(chainId, evmConfiguration); case CANCUN_EOF -> cancunEOF(chainId, evmConfiguration); case PRAGUE -> prague(chainId, evmConfiguration); - case PRAGUE_EOF -> pragueEOF(chainId, evmConfiguration); case OSAKA -> osaka(chainId, evmConfiguration); case AMSTERDAM -> amsterdam(chainId, evmConfiguration); case BOGOTA -> bogota(chainId, evmConfiguration); @@ -525,21 +524,6 @@ public class EVMExecutor { return executor; } - /** - * Instantiate PragueEOF evm executor. - * - * @param chainId the chain ID - * @param evmConfiguration the evm configuration - * @return the evm executor - */ - public static EVMExecutor pragueEOF( - final BigInteger chainId, final EvmConfiguration evmConfiguration) { - final EVMExecutor executor = new EVMExecutor(MainnetEVMs.pragueEOF(chainId, evmConfiguration)); - executor.precompileContractRegistry = - MainnetPrecompiledContracts.prague(executor.evm.getGasCalculator()); - return executor; - } - /** * Instantiate Osaka evm executor. * diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueEOFGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java similarity index 89% rename from evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueEOFGasCalculator.java rename to evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java index 5fa2fe872..b4155dac5 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueEOFGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java @@ -26,13 +26,13 @@ import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2; *
  • TBD * */ -public class PragueEOFGasCalculator extends PragueGasCalculator { +public class OsakaGasCalculator extends PragueGasCalculator { static final long MIN_RETAINED_GAS = 5_000; static final long MIN_CALLEE_GAS = 2300; /** Instantiates a new Prague Gas Calculator. */ - public PragueEOFGasCalculator() { + public OsakaGasCalculator() { this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]); } @@ -41,7 +41,7 @@ public class PragueEOFGasCalculator extends PragueGasCalculator { * * @param maxPrecompile the max precompile */ - protected PragueEOFGasCalculator(final int maxPrecompile) { + protected OsakaGasCalculator(final int maxPrecompile) { super(maxPrecompile); } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java index c82e8c163..7a0296bf5 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractExtCallOperation.java @@ -109,15 +109,16 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { long inputOffset = inputDataOffset(frame); long inputLength = inputDataLength(frame); + GasCalculator gasCalculator = gasCalculator(); if (!zeroValue && isStatic(frame)) { return new OperationResult( - gasCalculator().callValueTransferGasCost(), ExceptionalHaltReason.ILLEGAL_STATE_CHANGE); + gasCalculator.callValueTransferGasCost(), ExceptionalHaltReason.ILLEGAL_STATE_CHANGE); } if (toBytes.size() > Address.SIZE) { return new OperationResult( - gasCalculator().memoryExpansionGasCost(frame, inputOffset, inputLength) - + (zeroValue ? 0 : gasCalculator().callValueTransferGasCost()) - + gasCalculator().getColdAccountAccessCost(), + gasCalculator.memoryExpansionGasCost(frame, inputOffset, inputLength) + + (zeroValue ? 0 : gasCalculator.callValueTransferGasCost()) + + gasCalculator.getColdAccountAccessCost(), ExceptionalHaltReason.ADDRESS_OUT_OF_RANGE); } Address to = Words.toAddress(toBytes); @@ -125,7 +126,7 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { if (contract != null) { final DelegatedCodeGasCostHelper.Result result = - deductDelegatedCodeGasCost(frame, gasCalculator(), contract); + deductDelegatedCodeGasCost(frame, gasCalculator, contract); if (result.status() != DelegatedCodeGasCostHelper.Status.SUCCESS) { return new Operation.OperationResult( result.gasCost(), ExceptionalHaltReason.INSUFFICIENT_GAS); @@ -134,12 +135,12 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { boolean accountCreation = contract == null && !zeroValue; long cost = - gasCalculator().memoryExpansionGasCost(frame, inputOffset, inputLength) - + (zeroValue ? 0 : gasCalculator().callValueTransferGasCost()) - + (frame.warmUpAddress(to) - ? gasCalculator().getWarmStorageReadCost() - : gasCalculator().getColdAccountAccessCost()) - + (accountCreation ? gasCalculator().newAccountGasCost() : 0); + gasCalculator.memoryExpansionGasCost(frame, inputOffset, inputLength) + + (zeroValue ? 0 : gasCalculator.callValueTransferGasCost()) + + (frame.warmUpAddress(to) || gasCalculator.isPrecompile(to) + ? gasCalculator.getWarmStorageReadCost() + : gasCalculator.getColdAccountAccessCost()) + + (accountCreation ? gasCalculator.newAccountGasCost() : 0); long currentGas = frame.getRemainingGas() - cost; if (currentGas < 0) { return new OperationResult(cost, ExceptionalHaltReason.INSUFFICIENT_GAS); @@ -163,14 +164,14 @@ public abstract class AbstractExtCallOperation extends AbstractCallOperation { return softFailure(frame, cost); } - long retainedGas = Math.max(currentGas / 64, gasCalculator().getMinRetainedGas()); + long retainedGas = Math.max(currentGas / 64, gasCalculator.getMinRetainedGas()); long childGas = currentGas - retainedGas; final Account account = frame.getWorldUpdater().get(frame.getRecipientAddress()); final Wei balance = (zeroValue || account == null) ? Wei.ZERO : account.getBalance(); // There myst be a minimum gas for a call to have access to. - if (childGas < gasCalculator().getMinCalleeGas()) { + if (childGas < gasCalculator.getMinCalleeGas()) { return softFailure(frame, cost); } // transferring value you don't have is not a halting exception, just a failure diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/CallFOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/CallFOperation.java index c69906341..e1eb96f03 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/CallFOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/CallFOperation.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.evm.operation; import org.hyperledger.besu.evm.Code; import org.hyperledger.besu.evm.EVM; import org.hyperledger.besu.evm.code.CodeSection; +import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.internal.ReturnStack; @@ -30,6 +31,9 @@ public class CallFOperation extends AbstractOperation { /** The Call F success. */ static final OperationResult callfSuccess = new OperationResult(5, null); + static final OperationResult callfStackOverflow = + new OperationResult(5, ExceptionalHaltReason.TOO_MANY_STACK_ITEMS); + /** * Instantiates a new Call F operation. * @@ -49,6 +53,11 @@ public class CallFOperation extends AbstractOperation { int pc = frame.getPC(); int section = code.readBigEndianU16(pc + 1); CodeSection info = code.getCodeSection(section); + int operandStackSize = frame.stackSize(); + if (operandStackSize >= 1024 + || operandStackSize > 1024 - info.getMaxStackHeight() + info.getInputs()) { + return callfStackOverflow; + } frame.getReturnStack().push(new ReturnStack.ReturnStackItem(frame.getSection(), pc + 2)); frame.setPC(info.getEntryPoint() - 1); // will be +1ed at end of operations loop frame.setSection(section); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java index a289c665d..baf052ba4 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/tracing/StandardJsonTracer.java @@ -127,9 +127,7 @@ public class StandardJsonTracer implements OperationTracer { for (int i = messageFrame.stackSize() - 1; i >= 0; i--) { stack.add("\"" + shortBytes(messageFrame.getStackItem(i)) + "\""); } - pc = - messageFrame.getPC() - - messageFrame.getCode().getCodeSection(messageFrame.getSection()).getEntryPoint(); + pc = messageFrame.getPC() - messageFrame.getCode().getCodeSection(0).getEntryPoint(); section = messageFrame.getSection(); gas = shortNumber(messageFrame.getRemainingGas()); memorySize = messageFrame.memoryWordSize() * 32; diff --git a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java index 6f60ab786..ac27d3f21 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeFactoryTest.java @@ -594,26 +594,26 @@ class CodeFactoryTest { } private static void validCode(final String str) { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); Code code = evm.getCodeUncached(bytesFromPrettyPrint(str)); assertThat(code.isValid()).isTrue(); } private static void invalidCode(final String str, final String error) { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); Code code = evm.getCodeUncached(bytesFromPrettyPrint(str)); assertThat(code.isValid()).isFalse(); assertThat(((CodeInvalid) code).getInvalidReason()).contains(error); } private static void invalidCode(final String str) { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); Code code = evm.getCodeUncached(bytesFromPrettyPrint(str)); assertThat(code.isValid()).isFalse(); } private static void invalidCodeForCreation(final String str) { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); Code code = evm.getCodeForCreation(bytesFromPrettyPrint(str)); assertThat(code.isValid()).isFalse(); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java index 3b16b1c92..54d457e62 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/code/CodeV0Test.java @@ -47,7 +47,7 @@ class CodeV0Test { @BeforeEach void startUp() { - evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); } @Test diff --git a/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java index aa9dcdb23..eaa8dbc8c 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/fluent/EVMExecutorTest.java @@ -131,9 +131,13 @@ class EVMExecutorTest { assertThat(cancunEOFEVM.getChainId()).contains(defaultChainId); EVMExecutor pragueEVM = - EVMExecutor.pragueEOF(defaultChainId.toBigInteger(), EvmConfiguration.DEFAULT); + EVMExecutor.prague(defaultChainId.toBigInteger(), EvmConfiguration.DEFAULT); assertThat(pragueEVM.getChainId()).contains(defaultChainId); + EVMExecutor osakaEVM = + EVMExecutor.osaka(defaultChainId.toBigInteger(), EvmConfiguration.DEFAULT); + assertThat(osakaEVM.getChainId()).contains(defaultChainId); + EVMExecutor futureEipsVM = EVMExecutor.futureEips(EvmConfiguration.DEFAULT); assertThat(futureEipsVM.getChainId()).contains(defaultChainId); } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueEOFGasCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java similarity index 88% rename from evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueEOFGasCalculatorTest.java rename to evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java index 46fe1dcba..3236c13e8 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueEOFGasCalculatorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java @@ -20,11 +20,11 @@ import org.hyperledger.besu.datatypes.Address; import org.junit.jupiter.api.Test; -class PragueEOFGasCalculatorTest { +class OsakaGasCalculatorTest { @Test void testPrecompileSize() { - PragueEOFGasCalculator subject = new PragueEOFGasCalculator(); + OsakaGasCalculator subject = new OsakaGasCalculator(); assertThat(subject.isPrecompile(Address.precompiled(0x14))).isFalse(); assertThat(subject.isPrecompile(Address.BLS12_MAP_FP2_TO_G2)).isTrue(); } @@ -32,7 +32,7 @@ class PragueEOFGasCalculatorTest { @Test void testNewConstants() { CancunGasCalculator cancunGas = new CancunGasCalculator(); - PragueEOFGasCalculator praugeGasCalculator = new PragueEOFGasCalculator(); + OsakaGasCalculator praugeGasCalculator = new OsakaGasCalculator(); assertThat(praugeGasCalculator.getMinCalleeGas()).isGreaterThan(cancunGas.getMinCalleeGas()); assertThat(praugeGasCalculator.getMinRetainedGas()) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java b/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java index 7b8a74b0c..cffd7ef5f 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/internal/CodeCacheTest.java @@ -30,7 +30,7 @@ class CodeCacheTest { @Test void testScale() { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); final Bytes contractBytes = Bytes.fromHexString("0xDEAD" + op + "BEEF" + op + "B0B0" + op + "C0DE" + op + "FACE"); final CodeScale scale = new CodeScale(); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/Create2OperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/Create2OperationTest.java index 4b2a5449e..a70b09a60 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/Create2OperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/Create2OperationTest.java @@ -56,7 +56,7 @@ public class Create2OperationTest { private MessageFrame messageFrame; private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final MutableAccount account = mock(MutableAccount.class); - private final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + private final EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); private final MutableAccount newAccount = mock(MutableAccount.class); private final Create2Operation operation = diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/CreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/CreateOperationTest.java index 482df37fd..697d87ef1 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/CreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/CreateOperationTest.java @@ -219,7 +219,7 @@ class CreateOperationTest { @Test void eofV1CannotCall() { - final EVM pragueEvm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + final EVM pragueEvm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); final UInt256 memoryOffset = UInt256.fromHexString("0xFF"); final UInt256 memoryLength = UInt256.valueOf(SIMPLE_CREATE.size()); final MessageFrame messageFrame = @@ -248,7 +248,7 @@ class CreateOperationTest { final UInt256 memoryLength, final UInt256 value, final int depth) { - final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + final EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); final MessageFrame messageFrame = MessageFrame.builder() .type(MessageFrame.Type.CONTRACT_CREATION) diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/DataCopyOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/DataCopyOperationTest.java index af5922aa0..aa2ed37b5 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/DataCopyOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/DataCopyOperationTest.java @@ -36,7 +36,7 @@ import org.junit.jupiter.params.provider.MethodSource; class DataCopyOperationTest { - static EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + static EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); static Collection datacopyTestVector() { return Arrays.asList( diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/EofCreateOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/EofCreateOperationTest.java index d5d1212df..5e9be6266 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/EofCreateOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/EofCreateOperationTest.java @@ -62,7 +62,7 @@ class EofCreateOperationTest { @Test void innerContractIsCorrect() { - final EVM evm = MainnetEVMs.cancunEOF(EvmConfiguration.DEFAULT); + final EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); Code code = evm.getCodeUncached(INNER_CONTRACT); assertThat(code.isValid()).isTrue(); @@ -92,7 +92,7 @@ class EofCreateOperationTest { @Test void eofCreatePassesInCallData() { Bytes outerContract = EOF_CREATE_CONTRACT; - final EVM evm = MainnetEVMs.cancunEOF(EvmConfiguration.DEFAULT); + final EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); Code code = evm.getCodeUncached(outerContract); if (!code.isValid()) { diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java index 93b101150..ee974c15c 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtCallOperationTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; -import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator; +import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -44,7 +44,7 @@ public class ExtCallOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final MutableAccount account = mock(MutableAccount.class); - private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + private static final EVM EOF_EVM = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); public static final Code LEGACY_CODE = EOF_EVM.getCodeUncached(Bytes.of(ExtCallOperation.OPCODE, 1)); public static final Code SIMPLE_EOF = @@ -115,7 +115,7 @@ public class ExtCallOperationTest { final Bytes stackItem, final boolean validCode, final boolean warmAddress) { - final ExtCallOperation operation = new ExtCallOperation(new PragueEOFGasCalculator()); + final ExtCallOperation operation = new ExtCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() @@ -206,7 +206,7 @@ public class ExtCallOperationTest { final Wei valueSent, final Wei valueWeiHave, final boolean isStatic) { - final ExtCallOperation operation = new ExtCallOperation(new PragueEOFGasCalculator()); + final ExtCallOperation operation = new ExtCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() @@ -242,7 +242,7 @@ public class ExtCallOperationTest { @Test void overflowTest() { - final ExtCallOperation operation = new ExtCallOperation(new PragueEOFGasCalculator()); + final ExtCallOperation operation = new ExtCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() @@ -281,7 +281,7 @@ public class ExtCallOperationTest { @Test void legacyTest() { - final ExtCallOperation operation = new ExtCallOperation(new PragueEOFGasCalculator()); + final ExtCallOperation operation = new ExtCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java index 62a10dcc2..b08635748 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtDelegateCallOperationTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; -import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator; +import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -45,7 +45,7 @@ public class ExtDelegateCallOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final MutableAccount account = mock(MutableAccount.class); // private final MutableAccount targetAccount = mock(MutableAccount.class); - private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + private static final EVM EOF_EVM = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); public static final Code LEGACY_CODE = EOF_EVM.getCodeUncached(Bytes.of(ExtDelegateCallOperation.OPCODE, 1)); public static final Code SIMPLE_EOF = @@ -119,7 +119,7 @@ public class ExtDelegateCallOperationTest { final boolean validCode, final boolean warmAddress) { final ExtDelegateCallOperation operation = - new ExtDelegateCallOperation(new PragueEOFGasCalculator()); + new ExtDelegateCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() @@ -180,7 +180,7 @@ public class ExtDelegateCallOperationTest { final ExceptionalHaltReason haltReason, final Bytes stackItem) { final ExtDelegateCallOperation operation = - new ExtDelegateCallOperation(new PragueEOFGasCalculator()); + new ExtDelegateCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() @@ -227,7 +227,7 @@ public class ExtDelegateCallOperationTest { @Test void overflowTest() { final ExtDelegateCallOperation operation = - new ExtDelegateCallOperation(new PragueEOFGasCalculator()); + new ExtDelegateCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() .initialGas(400000) @@ -265,7 +265,7 @@ public class ExtDelegateCallOperationTest { @Test void legacyTest() { final ExtDelegateCallOperation operation = - new ExtDelegateCallOperation(new PragueEOFGasCalculator()); + new ExtDelegateCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java index ed306e89c..6b96b960c 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/ExtStaticCallOperationTest.java @@ -27,7 +27,7 @@ import org.hyperledger.besu.evm.MainnetEVMs; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.frame.ExceptionalHaltReason; import org.hyperledger.besu.evm.frame.MessageFrame; -import org.hyperledger.besu.evm.gascalculator.PragueEOFGasCalculator; +import org.hyperledger.besu.evm.gascalculator.OsakaGasCalculator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -44,7 +44,7 @@ public class ExtStaticCallOperationTest { private final WorldUpdater worldUpdater = mock(WorldUpdater.class); private final MutableAccount account = mock(MutableAccount.class); - private static final EVM EOF_EVM = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + private static final EVM EOF_EVM = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); public static final Code LEGACY_CODE = EOF_EVM.getCodeUncached(Bytes.of(ExtStaticCallOperation.OPCODE, 1)); public static final Code SIMPLE_EOF = @@ -115,8 +115,7 @@ public class ExtStaticCallOperationTest { final Bytes stackItem, final boolean validCode, final boolean warmAddress) { - final ExtStaticCallOperation operation = - new ExtStaticCallOperation(new PragueEOFGasCalculator()); + final ExtStaticCallOperation operation = new ExtStaticCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() @@ -152,8 +151,7 @@ public class ExtStaticCallOperationTest { @Test void overflowTest() { - final ExtStaticCallOperation operation = - new ExtStaticCallOperation(new PragueEOFGasCalculator()); + final ExtStaticCallOperation operation = new ExtStaticCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() .initialGas(400000) @@ -190,8 +188,7 @@ public class ExtStaticCallOperationTest { @Test void legacyTest() { - final ExtStaticCallOperation operation = - new ExtStaticCallOperation(new PragueEOFGasCalculator()); + final ExtStaticCallOperation operation = new ExtStaticCallOperation(new OsakaGasCalculator()); final var messageFrame = new TestMessageFrameBuilder() diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/JumpOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/JumpOperationTest.java index 7b9fab338..c97c81b02 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/JumpOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/JumpOperationTest.java @@ -56,7 +56,7 @@ class JumpOperationTest { @BeforeEach void init() { - evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); } @Test diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operation/SelfDestructOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operation/SelfDestructOperationTest.java index d3a3db754..8fbd4d142 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operation/SelfDestructOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operation/SelfDestructOperationTest.java @@ -55,7 +55,7 @@ public class SelfDestructOperationTest { @Mock private WorldUpdater worldUpdater; @Mock private MutableAccount accountOriginator; @Mock private MutableAccount accountBeneficiary; - private final EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + private final EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); private final SelfDestructOperation frontierOperation = new SelfDestructOperation(new ConstantinopleGasCalculator()); diff --git a/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java index 3420df88d..8b3d6ac51 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/processor/ContractCreationProcessorTest.java @@ -45,7 +45,7 @@ import org.mockito.junit.jupiter.MockitoExtension; class ContractCreationProcessorTest extends AbstractMessageProcessorTest { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); private ContractCreationProcessor processor; diff --git a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java index bd043f933..90c6adff3 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/tracing/ExtendedOperationTracerTest.java @@ -55,7 +55,7 @@ class ExtendedOperationTracerTest { @Test void shouldCallTraceAccountCreationResultIfIsExtendedTracing() { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); final ContractCreationProcessor contractCreationProcessor = new ContractCreationProcessor(evm, false, Collections.emptyList(), 0); @@ -69,7 +69,7 @@ class ExtendedOperationTracerTest { @Test void shouldNotCallTraceAccountCreationResultIfIsNotExtendedTracing() { - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); final ContractCreationProcessor contractCreationProcessor = new ContractCreationProcessor(evm, false, Collections.emptyList(), 0); diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java index 27c4547d2..9b4d6e2e6 100644 --- a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/EofContainerSubCommand.java @@ -119,7 +119,7 @@ public class EofContainerSubCommand implements Runnable { .constructParametricType(Map.class, String.class, EOFTestCaseSpec.class); List fuzzingClients = new ArrayList<>(); - EVM evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + EVM evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); long validContainers; long totalContainers; diff --git a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/InternalClient.java b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/InternalClient.java index a6d7035fe..5d2adb8e9 100644 --- a/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/InternalClient.java +++ b/testfuzz/src/main/java/org/hyperledger/besu/testfuzz/InternalClient.java @@ -31,7 +31,7 @@ class InternalClient implements FuzzingClient { public InternalClient(final String clientName) { this.name = clientName; - this.evm = MainnetEVMs.pragueEOF(EvmConfiguration.DEFAULT); + this.evm = MainnetEVMs.osaka(EvmConfiguration.DEFAULT); } @Override From f9bed5930c29a0b8e891b77471fe570ad0e4e3db Mon Sep 17 00:00:00 2001 From: Stefan Pingel <16143240+pinges@users.noreply.github.com> Date: Fri, 11 Oct 2024 14:15:37 +1000 Subject: [PATCH 08/10] don't do too much work when transaction pool is disabled (#7753) Signed-off-by: stefan.pingel@consensys.net --- .../NewPooledTransactionHashesMessageHandler.java | 8 ++++---- .../eth/transactions/TransactionsMessageHandler.java | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java index ab909eada..f2e9378fd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/NewPooledTransactionHashesMessageHandler.java @@ -45,11 +45,11 @@ class NewPooledTransactionHashesMessageHandler implements EthMessages.MessageCal @Override public void exec(final EthMessage message) { - final Capability capability = message.getPeer().getConnection().capability(EthProtocol.NAME); - final NewPooledTransactionHashesMessage transactionsMessage = - NewPooledTransactionHashesMessage.readFrom(message.getData(), capability); - final Instant startedAt = now(); if (isEnabled.get()) { + final Capability capability = message.getPeer().getConnection().capability(EthProtocol.NAME); + final NewPooledTransactionHashesMessage transactionsMessage = + NewPooledTransactionHashesMessage.readFrom(message.getData(), capability); + final Instant startedAt = now(); scheduler.scheduleTxWorkerTask( () -> transactionsMessageProcessor.processNewPooledTransactionHashesMessage( diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java index 3160d1a9c..b6bbf442d 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionsMessageHandler.java @@ -43,9 +43,10 @@ class TransactionsMessageHandler implements EthMessages.MessageCallback { @Override public void exec(final EthMessage message) { - final TransactionsMessage transactionsMessage = TransactionsMessage.readFrom(message.getData()); - final Instant startedAt = now(); if (isEnabled.get()) { + final TransactionsMessage transactionsMessage = + TransactionsMessage.readFrom(message.getData()); + final Instant startedAt = now(); scheduler.scheduleTxWorkerTask( () -> transactionsMessageProcessor.processTransactionsMessage( From 174d4281dabe21e53d556bccda40c591d2d34605 Mon Sep 17 00:00:00 2001 From: Bhanu Pulluri <59369753+pullurib@users.noreply.github.com> Date: Fri, 11 Oct 2024 00:51:45 -0400 Subject: [PATCH 09/10] Add null pointer check and testcase for snapsync tasks (#7724) Signed-off-by: Bhanu Pulluri Co-authored-by: Bhanu Pulluri Co-authored-by: Sally MacFarlane --- .../request/StorageRangeDataRequest.java | 4 ++++ .../sync/snapsync/CompleteTaskStepTest.java | 4 ++-- .../sync/snapsync/PersistDataStepTest.java | 23 +++++++++++++++++-- .../eth/sync/snapsync/TaskGenerator.java | 14 ++++++++--- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java index 4c5092630..c405e2525 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/request/StorageRangeDataRequest.java @@ -179,6 +179,10 @@ public class StorageRangeDataRequest extends SnapDataRequest { final StackTrie.TaskElement taskElement = stackTrie.getElement(startKeyHash); + if (null == taskElement) { + return Stream.empty(); + } + findNewBeginElementInRange(storageRoot, taskElement.proofs(), taskElement.keys(), endKeyHash) .ifPresent( missingRightElement -> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java index 2bfc58a3b..b78f2b10e 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/CompleteTaskStepTest.java @@ -116,7 +116,7 @@ public class CompleteTaskStepTest { @Test public void shouldMarkSnapsyncTaskCompleteWhenData() { - final List> requests = TaskGenerator.createAccountRequest(true); + final List> requests = TaskGenerator.createAccountRequest(true, false); requests.stream() .map(StubTask.class::cast) .forEach( @@ -132,7 +132,7 @@ public class CompleteTaskStepTest { @Test public void shouldMarkSnapsyncTaskAsFailedWhenNoData() { - final List> requests = TaskGenerator.createAccountRequest(false); + final List> requests = TaskGenerator.createAccountRequest(false, false); requests.stream() .map(StubTask.class::cast) .forEach( diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java index 766995b09..963293be0 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/PersistDataStepTest.java @@ -68,7 +68,7 @@ public class PersistDataStepTest { @Test public void shouldPersistDataWhenPresent() { - final List> tasks = TaskGenerator.createAccountRequest(true); + final List> tasks = TaskGenerator.createAccountRequest(true, false); final List> result = persistDataStep.persist(tasks); assertThat(result).isSameAs(tasks); @@ -105,7 +105,7 @@ public class PersistDataStepTest { @Test public void shouldSkipPersistDataWhenNoData() { - final List> tasks = TaskGenerator.createAccountRequest(false); + final List> tasks = TaskGenerator.createAccountRequest(false, false); final List> result = persistDataStep.persist(tasks); assertThat(result).isSameAs(tasks); @@ -116,6 +116,25 @@ public class PersistDataStepTest { .isEmpty(); } + @Test + public void shouldHandleNullTaskElementInTrie() { + // Create a StorageRangeDataRequest where taskElement might be null or incomplete + List> tasks = TaskGenerator.createAccountRequest(false, true); + + try { + List> result = persistDataStep.persist(tasks); + + // check for proper handling of null taskElement + assertThat(result).isSameAs(tasks); + assertThat(result) + .isNotNull(); // Make sure the result isn't null even with the bad taskElement + } catch (NullPointerException e) { + fail( + "NullPointerException occurred during persist step, taskElement might be null: " + + e.getMessage()); + } + } + private void assertDataPersisted(final List> tasks) { tasks.forEach( task -> { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java index 0e3915bc7..0b3a17ccc 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/snapsync/TaskGenerator.java @@ -44,7 +44,8 @@ import org.apache.tuweni.bytes.Bytes32; public class TaskGenerator { - public static List> createAccountRequest(final boolean withData) { + public static List> createAccountRequest( + final boolean withData, final boolean withNullTaskElement) { final BonsaiWorldStateKeyValueStorage worldStateKeyValueStorage = new BonsaiWorldStateKeyValueStorage( @@ -91,7 +92,8 @@ public class TaskGenerator { rootHash, accountHash, stateTrieAccountValue.getStorageRoot(), - withData); + withData, + withNullTaskElement); final BytecodeRequest bytecodeRequest = createBytecodeDataRequest( worldStateKeyValueStorage, @@ -112,7 +114,8 @@ public class TaskGenerator { final Hash rootHash, final Hash accountHash, final Bytes32 storageRoot, - final boolean withData) { + final boolean withData, + final boolean withNullTaskElement) { final RangeStorageEntriesCollector collector = RangeStorageEntriesCollector.createCollector( @@ -140,6 +143,11 @@ public class TaskGenerator { request.setProofValid(true); request.addResponse(null, worldStateProofProvider, slots, new ArrayDeque<>()); } + + if (withNullTaskElement) { + // setting isValidProof to true to simulate a null task element. + request.setProofValid(true); + } return request; } From d5ee9b7bb1e852ce2c367d130d818591c1771770 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 11 Oct 2024 10:28:39 +0200 Subject: [PATCH 10/10] Fix eth_feeHistory rewards when bounded by configuration (#7750) Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + .../internal/methods/EthFeeHistory.java | 45 +++++++----- .../jsonrpc/methods/EthJsonRpcMethods.java | 6 +- .../internal/methods/EthFeeHistoryTest.java | 69 ++++++++++++++++--- 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64b684433..5c26ef6e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Additions and Improvements ### Bug fixes +- Fix eth_feeHistory rewards when bounded by configuration [#7750](https://github.com/hyperledger/besu/pull/7750) ## 24.10.0 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java index b95746dad..2c5c6afd0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; -import static java.util.stream.Collectors.toUnmodifiableList; import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; import org.hyperledger.besu.datatypes.Hash; @@ -32,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSucces import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; @@ -57,9 +57,11 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Streams; +import org.apache.tuweni.units.bigints.UInt256s; public class EthFeeHistory implements JsonRpcMethod { private final ProtocolSchedule protocolSchedule; + private final BlockchainQueries blockchainQueries; private final Blockchain blockchain; private final MiningCoordinator miningCoordinator; private final ApiConfiguration apiConfiguration; @@ -70,13 +72,14 @@ public class EthFeeHistory implements JsonRpcMethod { public EthFeeHistory( final ProtocolSchedule protocolSchedule, - final Blockchain blockchain, + final BlockchainQueries blockchainQueries, final MiningCoordinator miningCoordinator, final ApiConfiguration apiConfiguration) { this.protocolSchedule = protocolSchedule; - this.blockchain = blockchain; + this.blockchainQueries = blockchainQueries; this.miningCoordinator = miningCoordinator; this.apiConfiguration = apiConfiguration; + this.blockchain = blockchainQueries.getBlockchain(); this.cache = Caffeine.newBuilder().maximumSize(MAXIMUM_CACHE_SIZE).build(); } @@ -136,7 +139,8 @@ public class EthFeeHistory implements JsonRpcMethod { final List gasUsedRatios = getGasUsedRatios(blockHeaderRange); final List blobGasUsedRatios = getBlobGasUsedRatios(blockHeaderRange); final Optional>> maybeRewards = - maybeRewardPercentiles.map(rewards -> getRewards(rewards, blockHeaderRange)); + maybeRewardPercentiles.map( + percentiles -> getRewards(percentiles, blockHeaderRange, nextBaseFee)); return new JsonRpcSuccessResponse( requestId, createFeeHistoryResult( @@ -203,17 +207,19 @@ public class EthFeeHistory implements JsonRpcMethod { } private List> getRewards( - final List rewardPercentiles, final List blockHeaders) { + final List rewardPercentiles, + final List blockHeaders, + final Wei nextBaseFee) { var sortedPercentiles = rewardPercentiles.stream().sorted().toList(); return blockHeaders.stream() .parallel() - .map(blockHeader -> calculateBlockHeaderReward(sortedPercentiles, blockHeader)) + .map(blockHeader -> calculateBlockHeaderReward(sortedPercentiles, blockHeader, nextBaseFee)) .flatMap(Optional::stream) .toList(); } private Optional> calculateBlockHeaderReward( - final List sortedPercentiles, final BlockHeader blockHeader) { + final List sortedPercentiles, final BlockHeader blockHeader, final Wei nextBaseFee) { // Create a new key for the reward cache final RewardCacheKey key = new RewardCacheKey(blockHeader.getBlockHash(), sortedPercentiles); @@ -226,7 +232,7 @@ public class EthFeeHistory implements JsonRpcMethod { Optional block = blockchain.getBlockByHash(blockHeader.getBlockHash()); return block.map( b -> { - List rewards = computeRewards(sortedPercentiles, b); + List rewards = computeRewards(sortedPercentiles, b, nextBaseFee); // Put the computed rewards in the cache for future use cache.put(key, rewards); return rewards; @@ -237,7 +243,8 @@ public class EthFeeHistory implements JsonRpcMethod { record TransactionInfo(Transaction transaction, Long gasUsed, Wei effectivePriorityFeePerGas) {} @VisibleForTesting - public List computeRewards(final List rewardPercentiles, final Block block) { + public List computeRewards( + final List rewardPercentiles, final Block block, final Wei nextBaseFee) { final List transactions = block.getBody().getTransactions(); if (transactions.isEmpty()) { // all 0's for empty block @@ -253,7 +260,7 @@ public class EthFeeHistory implements JsonRpcMethod { // If the priority fee boundary is set, return the bounded rewards. Otherwise, return the real // rewards. if (apiConfiguration.isGasAndPriorityFeeLimitingEnabled()) { - return boundRewards(realRewards); + return boundRewards(realRewards, nextBaseFee); } else { return realRewards; } @@ -292,16 +299,20 @@ public class EthFeeHistory implements JsonRpcMethod { * This method returns a list of bounded rewards. * * @param rewards The list of rewards to be bounded. + * @param nextBaseFee The base fee of the next block. * @return The list of bounded rewards. */ - private List boundRewards(final List rewards) { - Wei minPriorityFee = miningCoordinator.getMinPriorityFeePerGas(); - Wei lowerBound = - minPriorityFee + private List boundRewards(final List rewards, final Wei nextBaseFee) { + final Wei lowerBoundGasPrice = blockchainQueries.gasPriceLowerBound(); + final Wei lowerBoundPriorityFee = lowerBoundGasPrice.subtract(nextBaseFee); + final Wei minPriorityFee = miningCoordinator.getMinPriorityFeePerGas(); + final Wei forcedMinPriorityFee = UInt256s.max(minPriorityFee, lowerBoundPriorityFee); + final Wei lowerBound = + forcedMinPriorityFee .multiply(apiConfiguration.getLowerBoundGasAndPriorityFeeCoefficient()) .divide(100); - Wei upperBound = - minPriorityFee + final Wei upperBound = + forcedMinPriorityFee .multiply(apiConfiguration.getUpperBoundGasAndPriorityFeeCoefficient()) .divide(100); @@ -438,7 +449,7 @@ public class EthFeeHistory implements JsonRpcMethod { .oldestBlock(oldestBlock) .baseFeePerGas( Stream.concat(explicitlyRequestedBaseFees.stream(), Stream.of(nextBaseFee)) - .collect(toUnmodifiableList())) + .toList()) .baseFeePerBlobGas(requestedBlobBaseFees) .gasUsedRatio(gasUsedRatios) .blobGasUsedRatio(blobGasUsedRatio) 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 5baa11064..de5662692 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 @@ -132,11 +132,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods { blockchainQueries.getWorldStateArchive(), protocolSchedule, apiConfiguration.getGasCap())), - new EthFeeHistory( - protocolSchedule, - blockchainQueries.getBlockchain(), - miningCoordinator, - apiConfiguration), + new EthFeeHistory(protocolSchedule, blockchainQueries, miningCoordinator, apiConfiguration), new EthGetCode(blockchainQueries), new EthGetLogs(blockchainQueries, apiConfiguration.getMaxLogsRange()), new EthGetProof(blockchainQueries), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java index a04cb06c6..f34f336e0 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistoryResult; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -69,6 +70,7 @@ import org.junit.jupiter.api.Test; public class EthFeeHistoryTest { final BlockDataGenerator gen = new BlockDataGenerator(); + private BlockchainQueries blockchainQueries; private MutableBlockchain blockchain; private EthFeeHistory method; private ProtocolSchedule protocolSchedule; @@ -82,14 +84,15 @@ public class EthFeeHistoryTest { gen.blockSequence(genesisBlock, 10) .forEach(block -> blockchain.appendBlock(block, gen.receipts(block))); miningCoordinator = mock(MergeCoordinator.class); - when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE); + + blockchainQueries = mockBlockchainQueries(blockchain, Wei.of(7)); mockFork(); method = new EthFeeHistory( protocolSchedule, - blockchain, + blockchainQueries, miningCoordinator, ImmutableApiConfiguration.builder().build()); } @@ -139,11 +142,16 @@ public class EthFeeHistoryTest { Block block = mock(Block.class); Blockchain blockchain = mockBlockchainTransactionsWithPriorityFee(block); + final var blockchainQueries = mockBlockchainQueries(blockchain, Wei.of(7)); + EthFeeHistory ethFeeHistory = new EthFeeHistory( - null, blockchain, miningCoordinator, ImmutableApiConfiguration.builder().build()); + null, + blockchainQueries, + miningCoordinator, + ImmutableApiConfiguration.builder().build()); - List rewards = ethFeeHistory.computeRewards(rewardPercentiles, block); + List rewards = ethFeeHistory.computeRewards(rewardPercentiles, block, Wei.of(7)); // Define the expected rewards for each percentile // The expected rewards match the fees of the transactions at each percentile in the @@ -179,14 +187,51 @@ public class EthFeeHistoryTest { .upperBoundGasAndPriorityFeeCoefficient(500L) .build(); // Max reward = Wei.One * 500L / 100 = 5.0 - EthFeeHistory ethFeeHistory = - new EthFeeHistory(null, blockchain, miningCoordinator, apiConfiguration); + final var blockchainQueries = mockBlockchainQueries(blockchain, Wei.of(7)); + when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE); - List rewards = ethFeeHistory.computeRewards(rewardPercentiles, block); + EthFeeHistory ethFeeHistory = + new EthFeeHistory(null, blockchainQueries, miningCoordinator, apiConfiguration); + + List rewards = ethFeeHistory.computeRewards(rewardPercentiles, block, Wei.of(7)); // Define the expected bounded rewards for each percentile List expectedBoundedRewards = Stream.of(2, 2, 2, 4, 5, 5, 5, 5, 5).map(Wei::of).toList(); - assertThat(expectedBoundedRewards).isEqualTo(rewards); + assertThat(rewards).isEqualTo(expectedBoundedRewards); + } + + @Test + public void shouldApplyLowerBoundRewardsCorrectly() { + // This test checks that the rewards are correctly bounded by the lower and upper limits, + // when the calculated lower bound for the priority fee is greater than the configured one. + // Configured minPriorityFeePerGas is 0 wei, minGasPrice is 10 wei and baseFee is 8 wei, + // so for a tx to be mined the minPriorityFeePerGas is raised to 2 wei before applying the + // coefficients. + + List rewardPercentiles = + Arrays.asList(0.0, 5.0, 10.0, 27.50, 31.0, 59.0, 60.0, 61.0, 100.0); + + Block block = mock(Block.class); + Blockchain blockchain = mockBlockchainTransactionsWithPriorityFee(block); + + ApiConfiguration apiConfiguration = + ImmutableApiConfiguration.builder() + .isGasAndPriorityFeeLimitingEnabled(true) + .lowerBoundGasAndPriorityFeeCoefficient(200L) // Min reward = 2 * 200L / 100 = 4.0 + .upperBoundGasAndPriorityFeeCoefficient(300L) + .build(); // Max reward = 2 * 300L / 100 = 6.0 + + final var blockchainQueries = mockBlockchainQueries(blockchain, Wei.of(10)); + when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ZERO); + + EthFeeHistory ethFeeHistory = + new EthFeeHistory(null, blockchainQueries, miningCoordinator, apiConfiguration); + + List rewards = ethFeeHistory.computeRewards(rewardPercentiles, block, Wei.of(8)); + + // Define the expected bounded rewards for each percentile + List expectedBoundedRewards = Stream.of(4, 4, 4, 4, 5, 6, 6, 6, 6).map(Wei::of).toList(); + assertThat(rewards).isEqualTo(expectedBoundedRewards); } private Blockchain mockBlockchainTransactionsWithPriorityFee(final Block block) { @@ -399,4 +444,12 @@ public class EthFeeHistoryTest { return method.response( new JsonRpcRequestContext(new JsonRpcRequest("2.0", "eth_feeHistory", params))); } + + private BlockchainQueries mockBlockchainQueries( + final Blockchain blockchain, final Wei gasPriceLowerBound) { + final var blockchainQueries = mock(BlockchainQueries.class); + when(blockchainQueries.getBlockchain()).thenReturn(blockchain); + when(blockchainQueries.gasPriceLowerBound()).thenReturn(gasPriceLowerBound); + return blockchainQueries; + } }