From 4be39be532c426fd60e9fc6c7f938fe6ac0eac13 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 22 Nov 2024 18:01:30 +1100 Subject: [PATCH 01/38] initial implementation of block simulator Signed-off-by: Gabriel-Trintinalia --- .../org/hyperledger/besu/cli/BesuCommand.java | 6 ++ .../services/BlockSimulatorServiceImpl.java | 70 +++++++++++++++++++ .../common/MigratingMiningCoordinator.java | 9 +++ .../blockcreation/BftMiningCoordinator.java | 10 +++ .../merge/blockcreation/MergeCoordinator.java | 9 +++ .../blockcreation/TransitionCoordinator.java | 11 +++ .../AbstractMiningCoordinator.java | 10 +++ .../ethereum/blockcreation/BlockMiner.java | 18 +++++ .../blockcreation/MiningCoordinator.java | 15 ++++ .../blockcreation/NoopMiningCoordinator.java | 9 +++ .../services/BlockSimulationService.java | 37 ++++++++++ 11 files changed, 204 insertions(+) create mode 100644 besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java 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 c12b405e53f..613399f5163 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -155,6 +155,7 @@ import org.hyperledger.besu.plugin.data.EnodeURL; import org.hyperledger.besu.plugin.services.BesuConfiguration; import org.hyperledger.besu.plugin.services.BesuEvents; +import org.hyperledger.besu.plugin.services.BlockSimulationService; import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.MetricsSystem; import org.hyperledger.besu.plugin.services.PermissioningService; @@ -180,6 +181,7 @@ import org.hyperledger.besu.services.BesuConfigurationImpl; import org.hyperledger.besu.services.BesuEventsImpl; import org.hyperledger.besu.services.BesuPluginContextImpl; +import org.hyperledger.besu.services.BlockSimulatorServiceImpl; import org.hyperledger.besu.services.BlockchainServiceImpl; import org.hyperledger.besu.services.P2PServiceImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; @@ -1301,6 +1303,10 @@ private void startPlugins(final Runner runner) { miningParametersSupplier.get()), besuController.getProtocolSchedule())); + besuPluginContext.addService( + BlockSimulationService.class, + new BlockSimulatorServiceImpl(besuController.getMiningCoordinator())); + besuController.getAdditionalPluginServices().appendPluginServices(besuPluginContext); besuPluginContext.startPlugins(); } diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java new file mode 100644 index 00000000000..7672e38a5ff --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -0,0 +1,70 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.services; + +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockContext; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.services.BlockSimulationService; + +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class BlockSimulatorServiceImpl implements BlockSimulationService { + private final MiningCoordinator miningCoordinator; + + public BlockSimulatorServiceImpl(final MiningCoordinator miningCoordinator) { + this.miningCoordinator = miningCoordinator; + } + + @Override + public BlockContext simulate( + final BlockHeader parentHeader, + final List transactions, + final long timestamp) { + + org.hyperledger.besu.ethereum.core.BlockHeader parentHeaderCore = + (org.hyperledger.besu.ethereum.core.BlockHeader) parentHeader; + + List coreTransactions = + transactions.stream().map(t -> (org.hyperledger.besu.ethereum.core.Transaction) t).toList(); + + Block block = + miningCoordinator + .createBlock(parentHeaderCore, coreTransactions, Collections.emptyList(), timestamp) + .orElseThrow(() -> new IllegalArgumentException("Unable to create block.")); + + return blockContext(block::getHeader, block::getBody); + } + + private BlockContext blockContext( + final Supplier headerSupplier, final Supplier bodySupplier) { + return new BlockContext() { + @Override + public BlockHeader getBlockHeader() { + return headerSupplier.get(); + } + + @Override + public BlockBody getBlockBody() { + return bodySupplier.get(); + } + }; + } +} diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java index 6450a108fd9..c2c27f52d9b 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java @@ -125,6 +125,15 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.empty(); } + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + return Optional.empty(); + } + @Override public void changeTargetGasLimit(final Long targetGasLimit) { activeMiningCoordinator.changeTargetGasLimit(targetGasLimit); 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 795a064b6bc..1a298f0f986 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 @@ -180,6 +180,16 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.empty(); } + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + // One-off block creation has not been implemented + return Optional.empty(); + } + @Override public void changeTargetGasLimit(final Long targetGasLimit) { blockCreatorFactory.changeTargetGasLimit(targetGasLimit); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 7570e97d4d6..60b4b04fe97 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -241,6 +241,15 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti throw new UnsupportedOperationException("random is required"); } + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + throw new UnsupportedOperationException("random is required"); + } + @Override public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index 681c6f334bc..030fe901f61 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -127,6 +127,17 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti (MiningCoordinator coordinator) -> coordinator.createBlock(parentHeader, timestamp)); } + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + return dispatchFunctionAccordingToMergeState( + (MiningCoordinator coordinator) -> + coordinator.createBlock(parentHeader, transactions, ommers, timestamp)); + } + @Override public void addEthHashObserver(final PoWObserver observer) { if (this.miningCoordinator instanceof PoWMiningCoordinator) { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java index 9c939b91bc8..feade1240e8 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java @@ -79,6 +79,16 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.of(miner.createBlock(parentHeader, timestamp).getBlock()); } + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + final M miner = executor.createMiner(minedBlockObservers, ethHashObservers, parentHeader); + return Optional.of(miner.createBlock(parentHeader, transactions, ommers, timestamp).getBlock()); + } + @Override public void start() { synchronized (this) { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java index f51451f2930..2cfd1aa4ff6 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java @@ -124,6 +124,24 @@ public BlockCreationResult createBlock(final BlockHeader parentHeader, final lon return blockCreator.createBlock(Optional.empty(), Optional.empty(), timestamp, parentHeader); } + /** + * Create a block with the given transactions, ommers and timestamp. + * + * @param parentHeader The header of the parent of the block to be produced + * @param transactions The list of transactions which may be included. + * @param ommers The list of ommers to include. + * @param timestamp unix timestamp of the new block. + * @return the newly created block. + */ + public BlockCreationResult createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + final BlockCreator blockCreator = this.blockCreatorFactory.apply(parentHeader); + return blockCreator.createBlock(transactions, ommers, timestamp, parentHeader); + } + protected boolean shouldImportBlock(final Block block) throws InterruptedException { return true; } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java index d1a91083b63..df092d48f9d 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java @@ -112,6 +112,21 @@ Optional createBlock( */ Optional createBlock(final BlockHeader parentHeader, final long timestamp); + /** + * Creates a block if possible, otherwise return an empty result + * + * @param parentHeader The parent block's header + * @param transactions The list of transactions to include + * @param ommers The list of ommers to include + * @param timestamp unix timestamp of the new block. + * @return If supported, returns the block that was created, otherwise an empty response. + */ + Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp); + default void addEthHashObserver(final PoWObserver observer) {} void changeTargetGasLimit(final Long targetGasLimit); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java index 8b5624f847a..ea958d840e4 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java @@ -84,6 +84,15 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.empty(); } + @Override + public Optional createBlock( + final BlockHeader parentHeader, + final List transactions, + final List ommers, + final long timestamp) { + return Optional.empty(); + } + @Override public void changeTargetGasLimit(final Long targetGasLimit) {} } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java new file mode 100644 index 00000000000..0730d900bf1 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -0,0 +1,37 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.services; + +import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.plugin.data.BlockContext; +import org.hyperledger.besu.plugin.data.BlockHeader; + +import java.util.List; + +public interface BlockSimulationService extends BesuService { + /** + * Simulate the creation of a block given a parent header, a list of transactions, and a + * timestamp. + * + * @param parentHeader the parent header + * @param transactions the transactions to include in the block + * @param timestamp the timestamp of the block + * @return the block context + */ + BlockContext simulate( + final BlockHeader parentHeader, + final List transactions, + final long timestamp); +} From 668176ef691aed78df2f2fd22cf1b204fa5bb37f Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Sat, 23 Nov 2024 19:38:38 +1100 Subject: [PATCH 02/38] Implement eth_simulateV1 Signed-off-by: Gabriel-Trintinalia --- .../org/hyperledger/besu/cli/BesuCommand.java | 7 +- .../services/BlockSimulatorServiceImpl.java | 59 ++-- .../blockcreation/CliqueMinerExecutor.java | 6 + .../common/MigratingMiningCoordinator.java | 6 + .../blockcreation/BftBlockCreatorFactory.java | 10 + .../blockcreation/BftMiningCoordinator.java | 6 + .../merge/blockcreation/MergeCoordinator.java | 6 + .../blockcreation/TransitionCoordinator.java | 6 + .../besu/datatypes/BlockOverrides.java | 140 ++++++++++ .../besu/ethereum/api/jsonrpc/RpcMethod.java | 1 + .../internal/methods/EthSimulateV1.java | 112 ++++++++ .../parameters/BlockStateCallsParameter.java | 55 ++++ .../parameters/JsonBlockStateCall.java | 34 +++ .../jsonrpc/methods/EthJsonRpcMethods.java | 7 + .../blockcreation/AbstractMinerExecutor.java | 3 + .../AbstractMiningCoordinator.java | 6 + .../blockcreation/MiningCoordinator.java | 3 + .../blockcreation/NoopMiningCoordinator.java | 6 + .../blockcreation/PoWMinerExecutor.java | 6 + .../blockcreation/PoWMiningCoordinator.java | 6 + .../transaction/BlockSimulationResult.java | 43 +++ .../ethereum/transaction/BlockSimulator.java | 259 ++++++++++++++++++ .../ethereum/transaction/BlockStateCall.java | 40 +++ .../transaction/TransactionSimulator.java | 24 +- .../services/BlockSimulationService.java | 5 +- 25 files changed, 830 insertions(+), 26 deletions(-) create mode 100644 datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java 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 613399f5163..1b7cc3d9054 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1305,7 +1305,12 @@ private void startPlugins(final Runner runner) { besuPluginContext.addService( BlockSimulationService.class, - new BlockSimulatorServiceImpl(besuController.getMiningCoordinator())); + new BlockSimulatorServiceImpl( + besuController.getProtocolContext().getWorldStateArchive(), + besuController.getProtocolContext().getBlockchain(), + miningParametersSupplier.get(), + besuController.getProtocolSchedule(), + apiConfiguration.getGasCap())); besuController.getAdditionalPluginServices().appendPluginServices(besuPluginContext); besuPluginContext.startPlugins(); diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 7672e38a5ff..2095a4bc6d1 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -14,56 +14,75 @@ */ package org.hyperledger.besu.services; +import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; -import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; +import org.hyperledger.besu.ethereum.transaction.BlockSimulator; +import org.hyperledger.besu.ethereum.transaction.BlockStateCall; +import org.hyperledger.besu.ethereum.transaction.CallParameter; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.data.BlockBody; import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.services.BlockSimulationService; -import java.util.Collections; import java.util.List; -import java.util.function.Supplier; public class BlockSimulatorServiceImpl implements BlockSimulationService { - private final MiningCoordinator miningCoordinator; + private final BlockSimulator blockSimulator; - public BlockSimulatorServiceImpl(final MiningCoordinator miningCoordinator) { - this.miningCoordinator = miningCoordinator; + public BlockSimulatorServiceImpl( + final WorldStateArchive worldStateArchive, + final Blockchain blockchain, + final MiningConfiguration miningConfiguration, + final ProtocolSchedule protocolSchedule, + final long rpcGasCap) { + + blockSimulator = + new BlockSimulator( + blockchain, + worldStateArchive, + protocolSchedule, + rpcGasCap, + () -> miningConfiguration.getCoinbase().orElseThrow(), + miningConfiguration::getTargetGasLimit); } @Override public BlockContext simulate( final BlockHeader parentHeader, final List transactions, - final long timestamp) { + final BlockOverrides blockOverrides) { org.hyperledger.besu.ethereum.core.BlockHeader parentHeaderCore = (org.hyperledger.besu.ethereum.core.BlockHeader) parentHeader; - List coreTransactions = - transactions.stream().map(t -> (org.hyperledger.besu.ethereum.core.Transaction) t).toList(); + List callParameters = + transactions.stream().map(CallParameter::fromTransaction).toList(); - Block block = - miningCoordinator - .createBlock(parentHeaderCore, coreTransactions, Collections.emptyList(), timestamp) - .orElseThrow(() -> new IllegalArgumentException("Unable to create block.")); + BlockStateCall blockStateCall = new BlockStateCall(callParameters, blockOverrides); - return blockContext(block::getHeader, block::getBody); - } + BlockSimulationResult result = blockSimulator.simulate(parentHeaderCore, blockStateCall); + + if (result.getResult().isFailed()) { + throw new IllegalArgumentException("Unable to create block."); + } - private BlockContext blockContext( - final Supplier headerSupplier, final Supplier bodySupplier) { + if (result.getBlock().isEmpty()) { + throw new IllegalArgumentException("Unable to create block."); + } return new BlockContext() { @Override public BlockHeader getBlockHeader() { - return headerSupplier.get(); + return result.getBlock().get().getHeader(); } @Override public BlockBody getBlockBody() { - return bodySupplier.get(); + return result.getBlock().get().getBody(); } }; } diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java index 998a237e916..6216ece892b 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -38,6 +38,7 @@ import java.util.Collection; import java.util.List; import java.util.Optional; +import java.util.OptionalLong; import java.util.function.Function; import com.google.common.annotations.VisibleForTesting; @@ -122,6 +123,11 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } + @Override + public OptionalLong getTargetGasLimit() { + return miningConfiguration.getTargetGasLimit(); + } + /** * Calculate extra data bytes. * diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java index c2c27f52d9b..f20162a3495 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.CompletableFuture; import com.google.common.annotations.VisibleForTesting; @@ -112,6 +113,11 @@ public Optional
getCoinbase() { return activeMiningCoordinator.getCoinbase(); } + @Override + public OptionalLong getTargetGasLimit() { + return activeMiningCoordinator.getTargetGasLimit(); + } + @Override public Optional createBlock( final BlockHeader parentHeader, diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java index 1349bbf4619..de05fc4b5e3 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.OptionalLong; import org.apache.tuweni.bytes.Bytes; @@ -140,6 +141,15 @@ public Wei getMinTransactionGasPrice() { return miningConfiguration.getMinTransactionGasPrice(); } + /** + * Gets target gas limit. + * + * @return the target gas limit + */ + public OptionalLong getTargetGasLimit() { + return miningConfiguration.getTargetGasLimit(); + } + /** * Gets min priority fee per gas * 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 1a298f0f986..1be66a5670a 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 @@ -31,6 +31,7 @@ import java.util.List; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; @@ -165,6 +166,11 @@ public Optional
getCoinbase() { return Optional.of(blockCreatorFactory.getLocalAddress()); } + @Override + public OptionalLong getTargetGasLimit() { + return blockCreatorFactory.getTargetGasLimit(); + } + @Override public Optional createBlock( final BlockHeader parentHeader, diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 60b4b04fe97..115691ba859 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -53,6 +53,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -228,6 +229,11 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } + @Override + public OptionalLong getTargetGasLimit() { + return miningConfiguration.getTargetGasLimit(); + } + @Override public Optional createBlock( final BlockHeader parentHeader, diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index 030fe901f61..6581a7e1ca4 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.CompletableFuture; import org.apache.tuweni.bytes.Bytes32; @@ -111,6 +112,11 @@ public Optional
getCoinbase() { return dispatchFunctionAccordingToMergeState(MiningCoordinator::getCoinbase); } + @Override + public OptionalLong getTargetGasLimit() { + return dispatchFunctionAccordingToMergeState(MiningCoordinator::getTargetGasLimit); + } + @Override public Optional createBlock( final BlockHeader parentHeader, diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java new file mode 100644 index 00000000000..a74750f420a --- /dev/null +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -0,0 +1,140 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.datatypes; + +import java.math.BigInteger; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BlockOverrides { + private final Optional timestamp; + private final Optional blockNumber; + private final Optional prevRandao; + private final Optional gasLimit; + private final Optional
feeRecipient; + private final Optional baseFeePerGas; + private final Optional blobBaseFee; + + @JsonCreator + public BlockOverrides( + @JsonProperty("timestamp") final Optional timestamp, + @JsonProperty("blockNumber") final Optional blockNumber, + @JsonProperty("prevRandao") final Optional prevRandao, + @JsonProperty("gasLimit") final Optional gasLimit, + @JsonProperty("feeRecipient") final Optional
feeRecipient, + @JsonProperty("baseFeePerGas") final Optional baseFeePerGas, + @JsonProperty("blobBaseFee") final Optional blobBaseFee) { + this.timestamp = timestamp; + this.blockNumber = blockNumber; + this.prevRandao = prevRandao; + this.gasLimit = gasLimit; + this.feeRecipient = feeRecipient; + this.baseFeePerGas = baseFeePerGas; + this.blobBaseFee = blobBaseFee; + } + + private BlockOverrides(final Builder builder) { + this.blockNumber = Optional.ofNullable(builder.blockNumber); + this.prevRandao = Optional.ofNullable(builder.prevRandao); + this.timestamp = Optional.ofNullable(builder.timestamp); + this.gasLimit = Optional.ofNullable(builder.gasLimit); + this.feeRecipient = Optional.ofNullable(builder.feeRecipient); + this.baseFeePerGas = Optional.ofNullable(builder.baseFeePerGas); + this.blobBaseFee = Optional.ofNullable(builder.blobBaseFee); + } + + public Optional getBlockNumber() { + return blockNumber; + } + + public Optional getPrevRandao() { + return prevRandao; + } + + public Optional getTimestamp() { + return timestamp; + } + + public Optional getGasLimit() { + return gasLimit; + } + + public Optional
getFeeRecipient() { + return feeRecipient; + } + + public Optional getBaseFeePerGas() { + return baseFeePerGas; + } + + public Optional getBlobBaseFee() { + return blobBaseFee; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Long timestamp; + private Long blockNumber; + private BigInteger prevRandao; + private Long gasLimit; + private Address feeRecipient; + private Wei baseFeePerGas; + private Long blobBaseFee; + + public Builder timestamp(final Long timestamp) { + this.timestamp = timestamp; + return this; + } + + public Builder blockNumber(final Long blockNumber) { + this.blockNumber = blockNumber; + return this; + } + + public Builder prevRandao(final BigInteger prevRandao) { + this.prevRandao = prevRandao; + return this; + } + + public Builder gasLimit(final Long gasLimit) { + this.gasLimit = gasLimit; + return this; + } + + public Builder feeRecipient(final Address feeRecipient) { + this.feeRecipient = feeRecipient; + return this; + } + + public Builder baseFeePerGas(final Wei baseFeePerGas) { + this.baseFeePerGas = baseFeePerGas; + return this; + } + + public Builder blobBaseFee(final Long blobBaseFee) { + this.blobBaseFee = blobBaseFee; + return this; + } + + public BlockOverrides build() { + return new BlockOverrides(this); + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index f8bc597ff7c..2768b738820 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -140,6 +140,7 @@ public enum RpcMethod { ETH_SUBMIT_WORK("eth_submitWork"), ETH_SUBSCRIBE("eth_subscribe"), ETH_SYNCING("eth_syncing"), + ETH_SIMULATE_V1("eth_simulateV1"), ETH_UNINSTALL_FILTER("eth_uninstallFilter"), ETH_UNSUBSCRIBE("eth_unsubscribe"), IBFT_DISCARD_VALIDATOR_VOTE("ibft_discardValidatorVote"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java new file mode 100644 index 00000000000..8da2a139555 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -0,0 +1,112 @@ +/* + * Copyright ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; + +import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND; + +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockStateCallsParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; +import org.hyperledger.besu.ethereum.transaction.BlockSimulator; + +public class EthSimulateV1 extends AbstractBlockParameterOrBlockHashMethod { + private final BlockSimulator blockSimulator; + private final BlockResultFactory blockResultFactory; + + public EthSimulateV1( + final BlockchainQueries blockchainQueries, + final ProtocolSchedule protocolSchedule, + final long rpcGasCap, + final MiningCoordinator miningCoordinator, + final BlockResultFactory blockResultFactory) { + super(blockchainQueries); + this.blockResultFactory = blockResultFactory; + this.blockSimulator = + new BlockSimulator( + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive(), + protocolSchedule, + rpcGasCap, + () -> miningCoordinator.getCoinbase().orElseThrow(), + miningCoordinator::getTargetGasLimit); + } + + @Override + public String getName() { + return RpcMethod.ETH_SIMULATE_V1.getMethodName(); + } + + @Override + protected BlockParameterOrBlockHash blockParameterOrBlockHash( + final JsonRpcRequestContext request) { + try { + return request.getRequiredParameter(1, BlockParameterOrBlockHash.class); + } catch (JsonRpcParameterException e) { + throw new InvalidJsonRpcParameters( + "Invalid block or block hash parameters (index 1)", RpcErrorType.INVALID_BLOCK_PARAMS, e); + } + } + + @Override + protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) { + final BlockHeader header = blockchainQueries.get().getBlockHeaderByHash(blockHash).orElse(null); + + if (header == null) { + return errorResponse(request, BLOCK_NOT_FOUND); + } + return resultByBlockHeader(request, header); + } + + @Override + protected Object resultByBlockHeader( + final JsonRpcRequestContext request, final BlockHeader header) { + try { + BlockStateCallsParameter parameter = + request.getRequiredParameter(0, BlockStateCallsParameter.class); + BlockSimulationResult result = + blockSimulator.simulate(header, parameter.getBlockStateCalls().getFirst()); + + if (result.getResult().isSuccessful() && result.getBlock().isPresent()) { + return blockResultFactory.transactionComplete(result.getBlock().get()); + } + return null; + } catch (JsonRpcParameterException e) { + throw new RuntimeException(e); + } + } + + private JsonRpcErrorResponse errorResponse( + final JsonRpcRequestContext request, final RpcErrorType rpcErrorType) { + return errorResponse(request, new JsonRpcError(rpcErrorType)); + } + + private JsonRpcErrorResponse errorResponse( + final JsonRpcRequestContext request, final JsonRpcError jsonRpcError) { + return new JsonRpcErrorResponse(request.getRequest().getId(), jsonRpcError); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java new file mode 100644 index 00000000000..215dca382fe --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java @@ -0,0 +1,55 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class BlockStateCallsParameter { + @JsonProperty("blockStateCalls") + private List blockStateCalls; + + @JsonProperty("validation") + private boolean validation; + + @JsonProperty("traceTransfers") + private boolean traceTransfers; + + // Getters + + public List getBlockStateCalls() { + return blockStateCalls; + } + + public boolean isValidation() { + return validation; + } + + public boolean isTraceTransfers() { + return traceTransfers; + } + + public static class StateOverride { + @JsonProperty("balance") + private String balance; + + // Getters + + public String getBalance() { + return balance; + } + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java new file mode 100644 index 00000000000..8e9ba8b42e6 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java @@ -0,0 +1,34 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; + +import org.hyperledger.besu.datatypes.BlockOverrides; +import org.hyperledger.besu.ethereum.transaction.BlockStateCall; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class JsonBlockStateCall extends BlockStateCall { + @JsonCreator + public JsonBlockStateCall( + @JsonProperty("calls") final List calls, + @JsonProperty("blockOverrides") final BlockOverrides blockOverrides) { + super(calls, blockOverrides); + } +} 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 de5662692ff..97c74c8ff02 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 @@ -60,6 +60,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthProtocolVersion; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendRawTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendTransaction; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSimulateV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSubmitHashRate; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSubmitWork; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSyncing; @@ -132,6 +133,12 @@ protected Map create() { blockchainQueries.getWorldStateArchive(), protocolSchedule, apiConfiguration.getGasCap())), + new EthSimulateV1( + blockchainQueries, + protocolSchedule, + apiConfiguration.getGasCap(), + miningCoordinator, + blockResult), new EthFeeHistory(protocolSchedule, blockchainQueries, miningCoordinator, apiConfiguration), new EthGetCode(blockchainQueries), new EthGetLogs(blockchainQueries, apiConfiguration.getMaxLogsRange()), diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java index 4d2b1274c67..9320103ff28 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -111,6 +112,8 @@ public Wei getMinPriorityFeePerGas() { public abstract Optional
getCoinbase(); + public abstract OptionalLong getTargetGasLimit(); + public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { } else { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java index feade1240e8..b54f4439606 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -225,6 +226,11 @@ public Optional
getCoinbase() { return executor.getCoinbase(); } + @Override + public OptionalLong getTargetGasLimit() { + return executor.getTargetGasLimit(); + } + protected abstract boolean newChainHeadInvalidatesMiningOperation( final BlockHeader newChainHeadHeader); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java index df092d48f9d..e3d6cc0951b 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Optional; +import java.util.OptionalLong; public interface MiningCoordinator { @@ -65,6 +66,8 @@ default void setCoinbase(final Address coinbase) { Optional
getCoinbase(); + OptionalLong getTargetGasLimit(); + default Optional hashesPerSecond() { return Optional.empty(); } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java index ea958d840e4..9685643274e 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Optional; +import java.util.OptionalLong; public class NoopMiningCoordinator implements MiningCoordinator { @@ -71,6 +72,11 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } + @Override + public OptionalLong getTargetGasLimit() { + return miningConfiguration.getTargetGasLimit(); + } + @Override public Optional createBlock( final BlockHeader parentHeader, diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java index f17b7989d2a..4df7b1c026d 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; +import java.util.OptionalLong; import java.util.function.Function; public class PoWMinerExecutor extends AbstractMinerExecutor { @@ -116,6 +117,11 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } + @Override + public OptionalLong getTargetGasLimit() { + return miningConfiguration.getTargetGasLimit(); + } + public EpochCalculator getEpochCalculator() { return epochCalculator; } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java index 1c94bb7821a..c5a230f4751 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.mainnet.PoWSolverInputs; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.TimeUnit; import com.google.common.cache.Cache; @@ -66,6 +67,11 @@ public void setCoinbase(final Address coinbase) { executor.setCoinbase(coinbase); } + @Override + public OptionalLong getTargetGasLimit() { + return executor.getTargetGasLimit(); + } + public void setStratumMiningEnabled(final boolean stratumMiningEnabled) { executor.setStratumMiningEnabled(stratumMiningEnabled); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java new file mode 100644 index 00000000000..1ceb7b3e6f1 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -0,0 +1,43 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.transaction; + +import org.hyperledger.besu.ethereum.BlockProcessingResult; +import org.hyperledger.besu.ethereum.core.Block; + +import java.util.Optional; + +public class BlockSimulationResult { + final Block block; + final BlockProcessingResult result; + + public BlockSimulationResult(final Block block, final BlockProcessingResult result) { + this.block = block; + this.result = result; + } + + public BlockSimulationResult(final BlockProcessingResult result) { + this.block = null; + this.result = result; + } + + public Optional getBlock() { + return Optional.ofNullable(block); + } + + public BlockProcessingResult getResult() { + return result; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java new file mode 100644 index 00000000000..3a04a31e0f1 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -0,0 +1,259 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.transaction; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlockOverrides; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.BlockProcessingOutputs; +import org.hyperledger.besu.ethereum.BlockProcessingResult; +import org.hyperledger.besu.ethereum.chain.Blockchain; +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.Difficulty; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.mainnet.BodyValidation; +import org.hyperledger.besu.ethereum.mainnet.DifficultyCalculator; +import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; +import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.OptionalLong; +import java.util.function.Supplier; + +import org.apache.tuweni.bytes.Bytes; + +public class BlockSimulator { + private final TransactionSimulator transactionSimulator; + private final WorldStateArchive worldStateArchive; + private final ProtocolSchedule protocolSchedule; + + private final Supplier
coinbaseSupplier; + private final Supplier nextGasSupplier; + + public BlockSimulator( + final Blockchain blockchain, + final WorldStateArchive worldStateArchive, + final ProtocolSchedule protocolSchedule, + final long rpcGasCap, + final Supplier
coinbaseSupplier, + final Supplier nextGasSupplier) { + this.worldStateArchive = worldStateArchive; + this.protocolSchedule = protocolSchedule; + this.coinbaseSupplier = coinbaseSupplier; + this.nextGasSupplier = nextGasSupplier; + this.transactionSimulator = + new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, rpcGasCap); + } + + public BlockSimulationResult simulate( + final BlockHeader header, final BlockStateCall blockStateCall) { + + long currentGasUsed = 0; + final List receipts = new ArrayList<>(); + final List transactions = new ArrayList<>(); + + final BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); + + long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); + final ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); + + final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); + + final BlockHeader blockHeader = overrideBlockHeader(header, blockOverrides, newProtocolSpec); + + final MiningBeneficiaryCalculator miningBeneficiaryCalculator = + getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); + + try (final MutableWorldState ws = getWorldState(header)) { + WorldUpdater updater = ws.updater(); + + for (CallParameter callParameter : blockStateCall.getCalls()) { + final WorldUpdater localUpdater = updater.updater(); + final Optional transactionSimulatorResult = + transactionSimulator.processWithWorldUpdater( + callParameter, + Optional.empty(), + buildTransactionValidationParams(), + OperationTracer.NO_TRACING, + blockHeader, + localUpdater, + miningBeneficiaryCalculator); + + if (transactionSimulatorResult.isEmpty()) { + return new BlockSimulationResult( + new BlockProcessingResult(Optional.empty(), "Transaction processing failed")); + } + + TransactionProcessingResult transactionProcessingResult = + transactionSimulatorResult.get().result(); + + if (transactionProcessingResult.isSuccessful()) { + localUpdater.commit(); + currentGasUsed += + callParameter.getGasLimit() - transactionProcessingResult.getGasRemaining(); + + Transaction transaction = transactionSimulatorResult.get().transaction(); + transactions.add(transaction); + final TransactionReceipt transactionReceipt = + transactionReceiptFactory.create( + transaction.getType(), transactionProcessingResult, ws, currentGasUsed); + receipts.add(transactionReceipt); + } else { + return new BlockSimulationResult( + new BlockProcessingResult( + Optional.empty(), + transactionProcessingResult + .getInvalidReason() + .orElse("Transaction processing failed"))); + } + } + + updater.commit(); + BlockHeader finalBlockHeader = + createFinalBlockHeader(blockHeader, ws, transactions, receipts, currentGasUsed); + + Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); + BlockProcessingOutputs outputs = new BlockProcessingOutputs(ws, receipts); + BlockProcessingResult result = new BlockProcessingResult(Optional.of(outputs)); + return new BlockSimulationResult(block, result); + + } catch (final Exception e) { + throw new RuntimeException("Error simulating block", e); + } + } + + private BlockHeader overrideBlockHeader( + final BlockHeader header, + final BlockOverrides blockOverrides, + final ProtocolSpec newProtocolSpec) { + long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); + long blockNumber = blockOverrides.getBlockNumber().orElse(header.getNumber() + 1); + + return BlockHeaderBuilder.createDefault() + .parentHash(header.getHash()) + .coinbase(blockOverrides.getFeeRecipient().orElse(coinbaseSupplier.get())) + .difficulty(Difficulty.of(getNextDifficulty(newProtocolSpec, header, timestamp))) + .number(blockNumber) + .gasLimit( + blockOverrides + .getGasLimit() + .orElse(getNextGasLimit(newProtocolSpec, header, blockNumber))) + .timestamp(timestamp) + .baseFee( + blockOverrides + .getBaseFeePerGas() + .orElse(getNextBaseFee(newProtocolSpec, header, blockNumber))) + .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) + .extraData(Bytes.wrap(new byte[32 + 65])) + .buildBlockHeader(); + } + + private BlockHeader createFinalBlockHeader( + final BlockHeader blockHeader, + final MutableWorldState ws, + final List transactions, + final List receipts, + final long currentGasUsed) { + + return BlockHeaderBuilder.createDefault() + .populateFrom(blockHeader) + .ommersHash(BodyValidation.ommersHash(List.of())) + .stateRoot(ws.rootHash()) + .transactionsRoot(BodyValidation.transactionsRoot(transactions)) + .receiptsRoot(BodyValidation.receiptsRoot(receipts)) + .logsBloom(BodyValidation.logsBloom(receipts)) + .gasUsed(currentGasUsed) + .withdrawalsRoot(null) + .requestsHash(null) + .extraData(Bytes.wrap(new byte[32 + 65])) + .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) + .buildBlockHeader(); + } + + private MutableWorldState getWorldState(final BlockHeader header) { + return worldStateArchive + .getMutable(header, false) + .orElseThrow( + () -> + new IllegalArgumentException( + "Public world state not available for block " + header.toLogString())); + } + + private ImmutableTransactionValidationParams buildTransactionValidationParams() { + return ImmutableTransactionValidationParams.builder() + .from(TransactionValidationParams.processingBlock()) + .build(); + } + + private long getNextGasLimit( + final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long blockNumber) { + return protocolSpec + .getGasLimitCalculator() + .nextGasLimit( + parentHeader.getGasLimit(), + nextGasSupplier.get().orElse(parentHeader.getGasLimit()), + blockNumber); + } + + private BigInteger getNextDifficulty( + final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long timestamp) { + final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); + return difficultyCalculator.nextDifficulty(timestamp, parentHeader); + } + + private MiningBeneficiaryCalculator getMiningBeneficiaryCalculator( + final BlockOverrides blockOverrides, final ProtocolSpec newProtocolSpec) { + if (blockOverrides.getFeeRecipient().isPresent()) { + return blockHeader -> blockOverrides.getFeeRecipient().get(); + } else { + return newProtocolSpec.getMiningBeneficiaryCalculator(); + } + } + + private Wei getNextBaseFee( + final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long blockNumber) { + final Wei baseFee = + Optional.of(protocolSpec.getFeeMarket()) + .filter(FeeMarket::implementsBaseFee) + .map(BaseFeeMarket.class::cast) + .map( + feeMarket -> + feeMarket.computeBaseFee( + blockNumber, + parentHeader.getBaseFee().orElse(Wei.ZERO), + parentHeader.getGasUsed(), + feeMarket.targetGasUsed(parentHeader))) + .orElse(null); + return baseFee; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java new file mode 100644 index 00000000000..826a19b26e1 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java @@ -0,0 +1,40 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.transaction; + +import org.hyperledger.besu.datatypes.BlockOverrides; + +import java.util.List; + +public class BlockStateCall { + + private final BlockOverrides blockOverrides; + + private final List calls; + + public BlockStateCall( + final List calls, final BlockOverrides blockOverrides) { + this.calls = calls; + this.blockOverrides = blockOverrides; + } + + public BlockOverrides getBlockOverrides() { + return blockOverrides; + } + + public List getCalls() { + return calls; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index 1c6140f1d1f..6d7b03d5cd4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; +import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; @@ -269,6 +270,25 @@ public Optional processWithWorldUpdater( final OperationTracer operationTracer, final BlockHeader header, final WorldUpdater updater) { + return processWithWorldUpdater( + callParams, + maybeStateOverrides, + transactionValidationParams, + operationTracer, + header, + updater, + protocolSchedule.getByBlockHeader(header).getMiningBeneficiaryCalculator()); + } + + @Nonnull + public Optional processWithWorldUpdater( + final CallParameter callParams, + final Optional maybeStateOverrides, + final TransactionValidationParams transactionValidationParams, + final OperationTracer operationTracer, + final BlockHeader header, + final WorldUpdater updater, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator) { final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(header); final Address senderAddress = @@ -335,9 +355,7 @@ public Optional processWithWorldUpdater( updater, blockHeaderToProcess, transaction, - protocolSpec - .getMiningBeneficiaryCalculator() - .calculateBeneficiary(blockHeaderToProcess), + miningBeneficiaryCalculator.calculateBeneficiary(blockHeaderToProcess), new CachingBlockHashLookup(blockHeaderToProcess, blockchain), false, transactionValidationParams, diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 0730d900bf1..bbdb1c25917 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.plugin.services; +import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; @@ -27,11 +28,11 @@ public interface BlockSimulationService extends BesuService { * * @param parentHeader the parent header * @param transactions the transactions to include in the block - * @param timestamp the timestamp of the block + * @param blockOverrides the blockSimulationOverride of the block * @return the block context */ BlockContext simulate( final BlockHeader parentHeader, final List transactions, - final long timestamp); + final BlockOverrides blockOverrides); } From 924efbc7341ad66cae98ab07afc318d542ea1d49 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Sun, 24 Nov 2024 01:23:02 +1100 Subject: [PATCH 03/38] Implement simulate v1 Signed-off-by: Gabriel-Trintinalia --- .../org/hyperledger/besu/cli/BesuCommand.java | 4 ++ .../services/BlockSimulatorServiceImpl.java | 30 +++-------- .../besu/services/BlockchainServiceImpl.java | 2 +- .../besu/services/MiningServiceImpl.java | 37 +++++++++++++ .../besu/datatypes/BlockOverrides.java | 46 +++++++++++++++- .../internal/methods/EthSimulateV1.java | 12 +++-- .../transaction/BlockSimulationResult.java | 47 +++++++++++++---- .../ethereum/transaction/BlockSimulator.java | 52 ++++++++++++++----- .../plugin/data/BlockSimulationResult.java | 26 ++++++++++ .../services/BlockSimulationService.java | 7 +-- .../plugin/services/BlockchainService.java | 3 +- .../besu/plugin/services/MiningService.java | 20 +++++++ 12 files changed, 230 insertions(+), 56 deletions(-) create mode 100644 besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java create mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java 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 1b7cc3d9054..183c1a43db7 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -158,6 +158,7 @@ import org.hyperledger.besu.plugin.services.BlockSimulationService; import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.MiningService; import org.hyperledger.besu.plugin.services.PermissioningService; import org.hyperledger.besu.plugin.services.PicoCLIOptions; import org.hyperledger.besu.plugin.services.PrivacyPluginService; @@ -183,6 +184,7 @@ import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BlockSimulatorServiceImpl; import org.hyperledger.besu.services.BlockchainServiceImpl; +import org.hyperledger.besu.services.MiningServiceImpl; import org.hyperledger.besu.services.P2PServiceImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PicoCLIOptionsImpl; @@ -1283,6 +1285,8 @@ private void startPlugins(final Runner runner) { besuController.getSyncState(), besuController.getProtocolContext().getWorldStateArchive())); + besuPluginContext.addService( + MiningService.class, new MiningServiceImpl(besuController.getMiningCoordinator())); besuPluginContext.addService(P2PService.class, new P2PServiceImpl(runner.getP2PNetwork())); besuPluginContext.addService( diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 2095a4bc6d1..3f252a279a2 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -16,7 +16,7 @@ import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; -import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; @@ -24,8 +24,6 @@ import org.hyperledger.besu.ethereum.transaction.BlockStateCall; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; -import org.hyperledger.besu.plugin.data.BlockBody; -import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.services.BlockSimulationService; @@ -36,7 +34,7 @@ public class BlockSimulatorServiceImpl implements BlockSimulationService { public BlockSimulatorServiceImpl( final WorldStateArchive worldStateArchive, - final Blockchain blockchain, + final MutableBlockchain blockchain, final MiningConfiguration miningConfiguration, final ProtocolSchedule protocolSchedule, final long rpcGasCap) { @@ -52,10 +50,11 @@ public BlockSimulatorServiceImpl( } @Override - public BlockContext simulate( + public BlockSimulationResult simulate( final BlockHeader parentHeader, final List transactions, - final BlockOverrides blockOverrides) { + final BlockOverrides blockOverrides, + final boolean shouldPersist) { org.hyperledger.besu.ethereum.core.BlockHeader parentHeaderCore = (org.hyperledger.besu.ethereum.core.BlockHeader) parentHeader; @@ -65,25 +64,12 @@ public BlockContext simulate( BlockStateCall blockStateCall = new BlockStateCall(callParameters, blockOverrides); - BlockSimulationResult result = blockSimulator.simulate(parentHeaderCore, blockStateCall); + BlockSimulationResult result = + blockSimulator.simulate(parentHeaderCore, blockStateCall, shouldPersist); if (result.getResult().isFailed()) { throw new IllegalArgumentException("Unable to create block."); } - - if (result.getBlock().isEmpty()) { - throw new IllegalArgumentException("Unable to create block."); - } - return new BlockContext() { - @Override - public BlockHeader getBlockHeader() { - return result.getBlock().get().getHeader(); - } - - @Override - public BlockBody getBlockBody() { - return result.getBlock().get().getBody(); - } - }; + return result; } } diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java index 76b4d7e1509..b1893ef37fb 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockchainServiceImpl.java @@ -108,7 +108,7 @@ public Optional> getReceiptsByBlockHash(final Hash bloc public void storeBlock( final BlockHeader blockHeader, final BlockBody blockBody, - final List receipts) { + final List receipts) { final org.hyperledger.besu.ethereum.core.BlockHeader coreHeader = (org.hyperledger.besu.ethereum.core.BlockHeader) blockHeader; final org.hyperledger.besu.ethereum.core.BlockBody coreBody = diff --git a/besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java new file mode 100644 index 00000000000..8fb8fdb8353 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.services; + +import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.plugin.services.MiningService; + +public class MiningServiceImpl implements MiningService { + + final MiningCoordinator miningCoordinator; + + public MiningServiceImpl(final MiningCoordinator miningCoordinator) { + this.miningCoordinator = miningCoordinator; + } + + @Override + public void stop() { + miningCoordinator.stop(); + } + + @Override + public void start() { + miningCoordinator.start(); + } +} diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java index a74750f420a..f217d6e7cf9 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes; public class BlockOverrides { private final Optional timestamp; @@ -28,6 +29,9 @@ public class BlockOverrides { private final Optional
feeRecipient; private final Optional baseFeePerGas; private final Optional blobBaseFee; + private final Optional stateRoot; + private final Optional difficulty; + private final Optional extraData; @JsonCreator public BlockOverrides( @@ -37,7 +41,10 @@ public BlockOverrides( @JsonProperty("gasLimit") final Optional gasLimit, @JsonProperty("feeRecipient") final Optional
feeRecipient, @JsonProperty("baseFeePerGas") final Optional baseFeePerGas, - @JsonProperty("blobBaseFee") final Optional blobBaseFee) { + @JsonProperty("blobBaseFee") final Optional blobBaseFee, + @JsonProperty("stateRoot") final Optional stateRoot, + @JsonProperty("difficult") final Optional difficulty, + @JsonProperty("extraData") final Optional extraData) { this.timestamp = timestamp; this.blockNumber = blockNumber; this.prevRandao = prevRandao; @@ -45,6 +52,9 @@ public BlockOverrides( this.feeRecipient = feeRecipient; this.baseFeePerGas = baseFeePerGas; this.blobBaseFee = blobBaseFee; + this.stateRoot = stateRoot; + this.difficulty = difficulty; + this.extraData = extraData; } private BlockOverrides(final Builder builder) { @@ -55,6 +65,10 @@ private BlockOverrides(final Builder builder) { this.feeRecipient = Optional.ofNullable(builder.feeRecipient); this.baseFeePerGas = Optional.ofNullable(builder.baseFeePerGas); this.blobBaseFee = Optional.ofNullable(builder.blobBaseFee); + this.stateRoot = Optional.ofNullable(builder.stateRoot); + this.difficulty = Optional.ofNullable(builder.difficulty); + this.extraData = Optional.ofNullable(builder.extraData); + ; } public Optional getBlockNumber() { @@ -85,6 +99,18 @@ public Optional getBlobBaseFee() { return blobBaseFee; } + public Optional getStateRoot() { + return stateRoot; + } + + public Optional getDifficulty() { + return difficulty; + } + + public Optional getExtraData() { + return extraData; + } + public static Builder builder() { return new Builder(); } @@ -97,6 +123,9 @@ public static class Builder { private Address feeRecipient; private Wei baseFeePerGas; private Long blobBaseFee; + private Hash stateRoot; + private BigInteger difficulty; + private Bytes extraData; public Builder timestamp(final Long timestamp) { this.timestamp = timestamp; @@ -133,6 +162,21 @@ public Builder blobBaseFee(final Long blobBaseFee) { return this; } + public Builder stateRoot(final Hash stateRoot) { + this.stateRoot = stateRoot; + return this; + } + + public Builder difficulty(final BigInteger difficulty) { + this.difficulty = difficulty; + return this; + } + + public Builder extraData(final Bytes extraData) { + this.extraData = extraData; + return this; + } + public BlockOverrides build() { return new BlockOverrides(this); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index 8da2a139555..f696d0bc49f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -29,6 +29,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +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.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; @@ -48,7 +50,7 @@ public EthSimulateV1( this.blockResultFactory = blockResultFactory; this.blockSimulator = new BlockSimulator( - blockchainQueries.getBlockchain(), + null, blockchainQueries.getWorldStateArchive(), protocolSchedule, rpcGasCap, @@ -91,8 +93,12 @@ protected Object resultByBlockHeader( BlockSimulationResult result = blockSimulator.simulate(header, parameter.getBlockStateCalls().getFirst()); - if (result.getResult().isSuccessful() && result.getBlock().isPresent()) { - return blockResultFactory.transactionComplete(result.getBlock().get()); + if (result.getResult().isSuccessful()) { + Block block = + new Block( + (BlockHeader) result.getBlockHeader().get(), + (BlockBody) result.getBlockBody().get()); + return blockResultFactory.transactionComplete(block); } return null; } catch (JsonRpcParameterException e) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 1ceb7b3e6f1..0c5e8110c02 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -15,29 +15,54 @@ package org.hyperledger.besu.ethereum.transaction; import org.hyperledger.besu.ethereum.BlockProcessingResult; -import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.plugin.data.BlockBody; +import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.TransactionReceipt; +import java.util.List; import java.util.Optional; -public class BlockSimulationResult { - final Block block; +public class BlockSimulationResult + implements org.hyperledger.besu.plugin.data.BlockSimulationResult { + final BlockHeader blockHeader; + final BlockBody blockBody; + final List receipts; final BlockProcessingResult result; - public BlockSimulationResult(final Block block, final BlockProcessingResult result) { - this.block = block; - this.result = result; - } - public BlockSimulationResult(final BlockProcessingResult result) { - this.block = null; + this.receipts = null; + this.blockHeader = null; + this.blockBody = null; this.result = result; } - public Optional getBlock() { - return Optional.ofNullable(block); + public BlockSimulationResult( + final BlockHeader blockHeader, + final BlockBody blockBody, + final List receipts, + final BlockProcessingResult result) { + this.blockHeader = blockHeader; + this.blockBody = blockBody; + this.receipts = receipts; + this.result = result; } public BlockProcessingResult getResult() { return result; } + + @Override + public Optional getBlockHeader() { + return Optional.ofNullable(blockHeader); + } + + @Override + public Optional getBlockBody() { + return Optional.ofNullable(blockBody); + } + + @Override + public Optional> getReceipts() { + return Optional.ofNullable(receipts); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 3a04a31e0f1..e7eb86bf5a3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; -import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -60,13 +60,16 @@ public class BlockSimulator { private final Supplier
coinbaseSupplier; private final Supplier nextGasSupplier; + private final MutableBlockchain blockchain; + public BlockSimulator( - final Blockchain blockchain, + final MutableBlockchain blockchain, final WorldStateArchive worldStateArchive, final ProtocolSchedule protocolSchedule, final long rpcGasCap, final Supplier
coinbaseSupplier, final Supplier nextGasSupplier) { + this.blockchain = blockchain; this.worldStateArchive = worldStateArchive; this.protocolSchedule = protocolSchedule; this.coinbaseSupplier = coinbaseSupplier; @@ -77,6 +80,11 @@ public BlockSimulator( public BlockSimulationResult simulate( final BlockHeader header, final BlockStateCall blockStateCall) { + return simulate(header, blockStateCall, false); + } + + public BlockSimulationResult simulate( + final BlockHeader header, final BlockStateCall blockStateCall, final boolean shouldPersist) { long currentGasUsed = 0; final List receipts = new ArrayList<>(); @@ -94,7 +102,7 @@ public BlockSimulationResult simulate( final MiningBeneficiaryCalculator miningBeneficiaryCalculator = getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); - try (final MutableWorldState ws = getWorldState(header)) { + try (final MutableWorldState ws = getWorldState(header, shouldPersist)) { WorldUpdater updater = ws.updater(); for (CallParameter callParameter : blockStateCall.getCalls()) { @@ -140,12 +148,18 @@ public BlockSimulationResult simulate( updater.commit(); BlockHeader finalBlockHeader = - createFinalBlockHeader(blockHeader, ws, transactions, receipts, currentGasUsed); + createFinalBlockHeader( + blockHeader, ws, transactions, blockOverrides, receipts, currentGasUsed); + if (shouldPersist) { + ws.persist(finalBlockHeader); + blockchain.storeBlock( + new Block(finalBlockHeader, new BlockBody(transactions, List.of())), receipts); + } Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); BlockProcessingOutputs outputs = new BlockProcessingOutputs(ws, receipts); BlockProcessingResult result = new BlockProcessingResult(Optional.of(outputs)); - return new BlockSimulationResult(block, result); + return new BlockSimulationResult(block.getHeader(), block.getBody(), receipts, result); } catch (final Exception e) { throw new RuntimeException("Error simulating block", e); @@ -162,7 +176,8 @@ private BlockHeader overrideBlockHeader( return BlockHeaderBuilder.createDefault() .parentHash(header.getHash()) .coinbase(blockOverrides.getFeeRecipient().orElse(coinbaseSupplier.get())) - .difficulty(Difficulty.of(getNextDifficulty(newProtocolSpec, header, timestamp))) + .difficulty( + Difficulty.of(getNextDifficulty(blockOverrides, newProtocolSpec, header, timestamp))) .number(blockNumber) .gasLimit( blockOverrides @@ -174,7 +189,7 @@ private BlockHeader overrideBlockHeader( .getBaseFeePerGas() .orElse(getNextBaseFee(newProtocolSpec, header, blockNumber))) .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) - .extraData(Bytes.wrap(new byte[32 + 65])) + .extraData(blockOverrides.getExtraData().orElse(Bytes.EMPTY)) .buildBlockHeader(); } @@ -182,27 +197,28 @@ private BlockHeader createFinalBlockHeader( final BlockHeader blockHeader, final MutableWorldState ws, final List transactions, + final BlockOverrides blockOverrides, final List receipts, final long currentGasUsed) { return BlockHeaderBuilder.createDefault() .populateFrom(blockHeader) .ommersHash(BodyValidation.ommersHash(List.of())) - .stateRoot(ws.rootHash()) + .stateRoot(blockOverrides.getStateRoot().orElse(ws.rootHash())) .transactionsRoot(BodyValidation.transactionsRoot(transactions)) .receiptsRoot(BodyValidation.receiptsRoot(receipts)) .logsBloom(BodyValidation.logsBloom(receipts)) .gasUsed(currentGasUsed) .withdrawalsRoot(null) .requestsHash(null) - .extraData(Bytes.wrap(new byte[32 + 65])) .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) + .extraData(blockOverrides.getExtraData().orElse(Bytes.EMPTY)) .buildBlockHeader(); } - private MutableWorldState getWorldState(final BlockHeader header) { + private MutableWorldState getWorldState(final BlockHeader header, final boolean shouldPersist) { return worldStateArchive - .getMutable(header, false) + .getMutable(header, shouldPersist) .orElseThrow( () -> new IllegalArgumentException( @@ -226,9 +242,17 @@ private long getNextGasLimit( } private BigInteger getNextDifficulty( - final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long timestamp) { - final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); - return difficultyCalculator.nextDifficulty(timestamp, parentHeader); + final BlockOverrides blockOverrides, + final ProtocolSpec protocolSpec, + final BlockHeader parentHeader, + final long timestamp) { + + if (blockOverrides.getDifficulty().isPresent()) { + return blockOverrides.getDifficulty().get(); + } else { + final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); + return difficultyCalculator.nextDifficulty(timestamp, parentHeader); + } } private MiningBeneficiaryCalculator getMiningBeneficiaryCalculator( diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java new file mode 100644 index 00000000000..d5bdb224607 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -0,0 +1,26 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.data; + +import java.util.List; +import java.util.Optional; + +public interface BlockSimulationResult { + Optional getBlockHeader(); + + Optional getBlockBody(); + + Optional> getReceipts(); +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index bbdb1c25917..9ad4dd530de 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -16,8 +16,8 @@ import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; -import org.hyperledger.besu.plugin.data.BlockContext; import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.BlockSimulationResult; import java.util.List; @@ -31,8 +31,9 @@ public interface BlockSimulationService extends BesuService { * @param blockOverrides the blockSimulationOverride of the block * @return the block context */ - BlockContext simulate( + BlockSimulationResult simulate( final BlockHeader parentHeader, final List transactions, - final BlockOverrides blockOverrides); + final BlockOverrides blockOverrides, + final boolean shouldPersist); } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java index a89d1144af7..12d21d789b3 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockchainService.java @@ -59,7 +59,8 @@ public interface BlockchainService extends BesuService { * @param blockBody the block body * @param receipts the transaction receipts */ - void storeBlock(BlockHeader blockHeader, BlockBody blockBody, List receipts); + void storeBlock( + BlockHeader blockHeader, BlockBody blockBody, List receipts); /** * Get the block header of the chain head diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java new file mode 100644 index 00000000000..253a1c8e0d3 --- /dev/null +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java @@ -0,0 +1,20 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.plugin.services; + +public interface MiningService extends BesuService { + void start(); + void stop(); +} From 36393c4f73c97643bb8e66e38a06cc34ffa384e0 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Sun, 24 Nov 2024 01:43:04 +1100 Subject: [PATCH 04/38] Remove blockchain Signed-off-by: Gabriel-Trintinalia --- .../api/jsonrpc/internal/methods/EthSimulateV1.java | 2 +- .../besu/ethereum/transaction/BlockSimulator.java | 9 ++------- .../hyperledger/besu/plugin/services/MiningService.java | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index f696d0bc49f..d55ee27d51d 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -50,7 +50,7 @@ public EthSimulateV1( this.blockResultFactory = blockResultFactory; this.blockSimulator = new BlockSimulator( - null, + blockchainQueries.getBlockchain(), blockchainQueries.getWorldStateArchive(), protocolSchedule, rpcGasCap, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index e7eb86bf5a3..42b3904c749 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -19,7 +19,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; -import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -60,16 +60,13 @@ public class BlockSimulator { private final Supplier
coinbaseSupplier; private final Supplier nextGasSupplier; - private final MutableBlockchain blockchain; - public BlockSimulator( - final MutableBlockchain blockchain, + final Blockchain blockchain, final WorldStateArchive worldStateArchive, final ProtocolSchedule protocolSchedule, final long rpcGasCap, final Supplier
coinbaseSupplier, final Supplier nextGasSupplier) { - this.blockchain = blockchain; this.worldStateArchive = worldStateArchive; this.protocolSchedule = protocolSchedule; this.coinbaseSupplier = coinbaseSupplier; @@ -153,8 +150,6 @@ public BlockSimulationResult simulate( if (shouldPersist) { ws.persist(finalBlockHeader); - blockchain.storeBlock( - new Block(finalBlockHeader, new BlockBody(transactions, List.of())), receipts); } Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); BlockProcessingOutputs outputs = new BlockProcessingOutputs(ws, receipts); diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java index 253a1c8e0d3..df8d0ce4330 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java @@ -16,5 +16,6 @@ public interface MiningService extends BesuService { void start(); + void stop(); } From 0de4e6587bdb531cdd77025acd6e0804d5c22313 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Sun, 24 Nov 2024 19:13:51 +1100 Subject: [PATCH 05/38] Add initial test for simulate v1 Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 8 +- .../besu/datatypes/BlockOverrides.java | 55 ++++++--- .../internal/methods/EthSimulateV1.java | 34 +++-- .../parameters/BlockStateCallsParameter.java | 14 +-- .../parameters/JsonBlockStateCall.java | 6 +- .../jsonrpc/methods/EthJsonRpcMethods.java | 6 +- .../methods/JsonRpcMethodsFactory.java | 1 + .../AbstractJsonRpcHttpServiceTest.java | 3 + .../EthSimulateV1JsonRpcHttpBySpecTest.java | 53 ++++++++ .../eth/simulateV1/chain-data/blocks.bin | Bin 0 -> 23075 bytes .../eth/simulateV1/chain-data/genesis.json | 116 ++++++++++++++++++ .../eth/simulateV1/specs/eth_simulateV1.json | 72 +++++++++++ .../ethereum/transaction/BlockSimulator.java | 62 +++++++--- .../ethereum/transaction/BlockStateCall.java | 19 ++- 14 files changed, 392 insertions(+), 57 deletions(-) create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java create mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/blocks.bin create mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json create mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 3f252a279a2..95a93933036 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.services; +import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; @@ -45,7 +46,7 @@ public BlockSimulatorServiceImpl( worldStateArchive, protocolSchedule, rpcGasCap, - () -> miningConfiguration.getCoinbase().orElseThrow(), + miningConfiguration::getCoinbase, miningConfiguration::getTargetGasLimit); } @@ -62,10 +63,11 @@ public BlockSimulationResult simulate( List callParameters = transactions.stream().map(CallParameter::fromTransaction).toList(); - BlockStateCall blockStateCall = new BlockStateCall(callParameters, blockOverrides); + BlockStateCall blockStateCall = + new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap()); BlockSimulationResult result = - blockSimulator.simulate(parentHeaderCore, blockStateCall, shouldPersist); + blockSimulator.simulate(parentHeaderCore, blockStateCall, true, shouldPersist); if (result.getResult().isFailed()) { throw new IllegalArgumentException("Unable to create block."); diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java index f217d6e7cf9..20c3c3c7dff 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -14,17 +14,21 @@ */ package org.hyperledger.besu.datatypes; +import static com.google.common.base.Preconditions.checkArgument; + import java.math.BigInteger; import java.util.Optional; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.checkerframework.checker.signedness.qual.Unsigned; public class BlockOverrides { private final Optional timestamp; private final Optional blockNumber; - private final Optional prevRandao; + private final Optional prevRandao; private final Optional gasLimit; private final Optional
feeRecipient; private final Optional baseFeePerGas; @@ -35,23 +39,23 @@ public class BlockOverrides { @JsonCreator public BlockOverrides( - @JsonProperty("timestamp") final Optional timestamp, - @JsonProperty("blockNumber") final Optional blockNumber, - @JsonProperty("prevRandao") final Optional prevRandao, - @JsonProperty("gasLimit") final Optional gasLimit, + @JsonProperty("timestamp") final Optional timestamp, + @JsonProperty("number") final Optional blockNumber, + @JsonProperty("prevRandao") final Optional prevRandao, + @JsonProperty("gasLimit") final Optional gasLimit, @JsonProperty("feeRecipient") final Optional
feeRecipient, @JsonProperty("baseFeePerGas") final Optional baseFeePerGas, - @JsonProperty("blobBaseFee") final Optional blobBaseFee, + @JsonProperty("blobBaseFee") final Optional blobBaseFee, @JsonProperty("stateRoot") final Optional stateRoot, @JsonProperty("difficult") final Optional difficulty, @JsonProperty("extraData") final Optional extraData) { - this.timestamp = timestamp; - this.blockNumber = blockNumber; + this.timestamp = timestamp.map(UnsignedLongParameter::getValue); + this.blockNumber = blockNumber.map(UnsignedLongParameter::getValue); this.prevRandao = prevRandao; - this.gasLimit = gasLimit; + this.gasLimit = gasLimit.map(UnsignedLongParameter::getValue); this.feeRecipient = feeRecipient; this.baseFeePerGas = baseFeePerGas; - this.blobBaseFee = blobBaseFee; + this.blobBaseFee = blobBaseFee.map(UnsignedLongParameter::getValue); this.stateRoot = stateRoot; this.difficulty = difficulty; this.extraData = extraData; @@ -68,14 +72,13 @@ private BlockOverrides(final Builder builder) { this.stateRoot = Optional.ofNullable(builder.stateRoot); this.difficulty = Optional.ofNullable(builder.difficulty); this.extraData = Optional.ofNullable(builder.extraData); - ; } public Optional getBlockNumber() { return blockNumber; } - public Optional getPrevRandao() { + public Optional getPrevRandao() { return prevRandao; } @@ -118,7 +121,7 @@ public static Builder builder() { public static class Builder { private Long timestamp; private Long blockNumber; - private BigInteger prevRandao; + private Bytes32 prevRandao; private Long gasLimit; private Address feeRecipient; private Wei baseFeePerGas; @@ -137,7 +140,7 @@ public Builder blockNumber(final Long blockNumber) { return this; } - public Builder prevRandao(final BigInteger prevRandao) { + public Builder prevRandao(final Bytes32 prevRandao) { this.prevRandao = prevRandao; return this; } @@ -181,4 +184,28 @@ public BlockOverrides build() { return new BlockOverrides(this); } } + + private static class UnsignedLongParameter { + + @Unsigned private final long value; + + @JsonCreator + public UnsignedLongParameter(final String value) { + checkArgument(value != null); + if (value.startsWith("0x")) { + this.value = Long.parseUnsignedLong(value.substring(2), 16); + } else { + this.value = Long.parseUnsignedLong(value, 16); + } + } + + @JsonCreator + public UnsignedLongParameter(final @Unsigned long value) { + this.value = value; + } + + public @Unsigned long getValue() { + return value; + } + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index d55ee27d51d..cbcc403a3c1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright contributors to Besu. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -27,15 +27,20 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; +import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; 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.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; +import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; +import java.util.List; + public class EthSimulateV1 extends AbstractBlockParameterOrBlockHashMethod { private final BlockSimulator blockSimulator; private final BlockResultFactory blockResultFactory; @@ -44,18 +49,19 @@ public EthSimulateV1( final BlockchainQueries blockchainQueries, final ProtocolSchedule protocolSchedule, final long rpcGasCap, - final MiningCoordinator miningCoordinator, + final MiningConfiguration miningConfiguration, final BlockResultFactory blockResultFactory) { super(blockchainQueries); this.blockResultFactory = blockResultFactory; + this.blockSimulator = new BlockSimulator( blockchainQueries.getBlockchain(), blockchainQueries.getWorldStateArchive(), protocolSchedule, rpcGasCap, - () -> miningCoordinator.getCoinbase().orElseThrow(), - miningCoordinator::getTargetGasLimit); + miningConfiguration::getCoinbase, + miningConfiguration::getTargetGasLimit); } @Override @@ -91,14 +97,15 @@ protected Object resultByBlockHeader( BlockStateCallsParameter parameter = request.getRequiredParameter(0, BlockStateCallsParameter.class); BlockSimulationResult result = - blockSimulator.simulate(header, parameter.getBlockStateCalls().getFirst()); + blockSimulator.simulate( + header, parameter.getBlockStateCalls().getFirst(), parameter.isValidation(), false); if (result.getResult().isSuccessful()) { Block block = new Block( (BlockHeader) result.getBlockHeader().get(), (BlockBody) result.getBlockBody().get()); - return blockResultFactory.transactionComplete(block); + return blockResultFactory.transactionHash(blockByHashWithTxHashes(block)); } return null; } catch (JsonRpcParameterException e) { @@ -115,4 +122,17 @@ private JsonRpcErrorResponse errorResponse( final JsonRpcRequestContext request, final JsonRpcError jsonRpcError) { return new JsonRpcErrorResponse(request.getRequest().getId(), jsonRpcError); } + + public BlockWithMetadata blockByHashWithTxHashes(final Block block) { + final int size = block.calculateSize(); + + final List txs = + block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); + + final List ommers = + block.getBody().getOmmers().stream().map(BlockHeader::getHash).toList(); + + return new BlockWithMetadata<>( + block.getHeader(), txs, ommers, Difficulty.ZERO, size, block.getBody().getWithdrawals()); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java index 215dca382fe..fc9c5e9d38c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java @@ -14,13 +14,14 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; +import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.annotation.JsonProperty; public class BlockStateCallsParameter { @JsonProperty("blockStateCalls") - private List blockStateCalls; + private final List blockStateCalls = new ArrayList<>(); @JsonProperty("validation") private boolean validation; @@ -41,15 +42,4 @@ public boolean isValidation() { public boolean isTraceTransfers() { return traceTransfers; } - - public static class StateOverride { - @JsonProperty("balance") - private String balance; - - // Getters - - public String getBalance() { - return balance; - } - } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java index 8e9ba8b42e6..0dc55ebfa07 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; +import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.ethereum.transaction.BlockStateCall; @@ -28,7 +29,8 @@ public class JsonBlockStateCall extends BlockStateCall { @JsonCreator public JsonBlockStateCall( @JsonProperty("calls") final List calls, - @JsonProperty("blockOverrides") final BlockOverrides blockOverrides) { - super(calls, blockOverrides); + @JsonProperty("blockOverrides") final BlockOverrides blockOverrides, + @JsonProperty("stateOverrides") final AccountOverrideMap stateOverrides) { + super(calls, blockOverrides, stateOverrides); } } 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 97c74c8ff02..e8fb5f31401 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 @@ -69,6 +69,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; @@ -87,6 +88,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods { private final ProtocolSchedule protocolSchedule; private final FilterManager filterManager; private final TransactionPool transactionPool; + private final MiningConfiguration miningConfiguration; private final MiningCoordinator miningCoordinator; private final Set supportedCapabilities; private final ApiConfiguration apiConfiguration; @@ -97,6 +99,7 @@ public EthJsonRpcMethods( final ProtocolSchedule protocolSchedule, final FilterManager filterManager, final TransactionPool transactionPool, + final MiningConfiguration miningConfiguration, final MiningCoordinator miningCoordinator, final Set supportedCapabilities, final ApiConfiguration apiConfiguration) { @@ -105,6 +108,7 @@ public EthJsonRpcMethods( this.protocolSchedule = protocolSchedule; this.filterManager = filterManager; this.transactionPool = transactionPool; + this.miningConfiguration = miningConfiguration; this.miningCoordinator = miningCoordinator; this.supportedCapabilities = supportedCapabilities; this.apiConfiguration = apiConfiguration; @@ -137,7 +141,7 @@ protected Map create() { blockchainQueries, protocolSchedule, apiConfiguration.getGasCap(), - miningCoordinator, + miningConfiguration, blockResult), new EthFeeHistory(protocolSchedule, blockchainQueries, miningCoordinator, apiConfiguration), new EthGetCode(blockchainQueries), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index 2e68576fca7..3b42ef3d448 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -129,6 +129,7 @@ public Map methods( protocolSchedule, filterManager, transactionPool, + miningConfiguration, miningCoordinator, supportedCapabilities, apiConfiguration), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java index db896a94856..a04f100a251 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.config.StubGenesisConfigOptions; +import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.ApiConfiguration; import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration; @@ -146,6 +147,8 @@ protected Map getRpcMethods( .thenReturn(ValidationResult.invalid(TransactionInvalidReason.NONCE_TOO_LOW)); final PrivacyParameters privacyParameters = mock(PrivacyParameters.class); + when(miningConfiguration.getCoinbase()).thenReturn(Optional.of(Address.ZERO)); + final BlockchainQueries blockchainQueries = new BlockchainQueries( blockchainSetupUtil.getProtocolSchedule(), diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java new file mode 100644 index 00000000000..52cdb4bd87f --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java @@ -0,0 +1,53 @@ +/* + * Copyright ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.bonsai; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; +import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; +import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class EthSimulateV1JsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { + + @Override + @BeforeEach + public void setup() throws Exception { + setupBonsaiBlockchain(); + startService(); + } + + @Override + protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat dataStorageFormat) { + return createBlockchainSetupUtil( + "eth/simulateV1/chain-data/genesis.json", + "eth/simulateV1/chain-data/blocks.bin", + dataStorageFormat); + } + + public static Object[][] specs() { + return findSpecFiles(new String[] {"eth/simulateV1/specs"}); + } + + @Test + void dryRunDetector() { + assertThat(true) + .withFailMessage("This test is here so gradle --dry-run executes this class") + .isTrue(); + } +} diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/blocks.bin b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/blocks.bin new file mode 100644 index 0000000000000000000000000000000000000000..57c416125a98e4d0c3becd849ec4417631f39768 GIT binary patch literal 23075 zcmeHubzD@>8}9DXigZaXjYzjr3rI*eC?Sm?-AXMj3J8Lrf^d`)L6K6F7C}j+l~u3@y?ugW;o}4_IY;CtYZ45-x`RZXCgG9?>Brl$o3PG!#RSj~ z5y%EBk&Jugodo`e99ny?QfTP^i zgn;?q!{Mb8W{1Qu;AV%+K*!8LOJ*RsAZ;@!SOJ~OpmQa3egd5fpmQN~jvO9AHBolF zf(QVHuGO$8w0j+4V!WNws3B#0h4{G4(WOwMZj-t)qi+9s0E@Z6m52AVuPlQBtb3u*?=|Fpg0HPGUvnovy>}1PrY3|@)W$t0_ zZg;`j45V#FVn(oOWCjv8`$%iP1tv37G;rKM5H*OvjAYZud}|I>hnUfST{*RuB8ft8 zuc=ty;oM&Dg6V+AFhe6MyE>Mhj!&;S8MFY+V*CR*7rVV~o$|@9^srso$av**`sC%o zV5j9ZTwas8gW-v1l)C>yOG6RESwb4(CIT#j1WOmR%(;N&k zgMIzmx2$^s@em%C@$17}U06UojsP9;>Js9~guJ=V6B0{m;Q0Gz${(p}sDk*`FgWuX zrHuz84deZfwk$preMi~il3887jyZzD#5`m34-X?UNzU794AU7iSkKgMh9#|6-XX_| z@i0N)#{4BF3e}BNWwu|nZz|TN=AfZxY2!Gtwn}}N;j~40vx7AP69{BlS%3K=z#Y+^ z3)hhBb>XgWI?jD(>z0^W+7VA9ZCW7w>9dMBKRI#1l2X<@Ul`s$rVIi11X0#g!6y1V?&?N-v z35GVHuw}aj+8vL!|1d+jjQyqujJpfv=sBRMd5O?7;C?geCsoMymUcaW;E)|mJWWIP zCz!}x#c<<)!9*^2T6w^+xR<&5hsgLpU3O-zR4&2u{&+;~OJkyU_&KL_ND9IaGZg9W zW(b(U5Dw3j+kKqBdzg_S2fcmToSlfs49{Q>`&N^UnzufjJUE$~%yHEs&s?$0o_Xn^ z`INAuN%9N7xlaHQ%{2$*_^ql)CH1q7%wCe1+VO=$wl9o1Y2{894dKEOwpiPZ<0`C~7Mmi9mpZzAyB25y;Nl)?t@Y&jfA z@Nc1%6O~=AZqy;+ERlKr)b=y`5F|=ilai3?s`3SEM>`LM5#rPjhaqHvpWNp?GqBuy z_)X1uj>!-kYVF{ZrMQlMwyq%Zqd~2wPLtpyXyAbX{=6w!#(_dft=Z2{reD%__b2<) z>oJvZRd5TFuOvaP0sfd3!6(vFW{Q~NCD}+>gRuMgG&^x)G7>+iIC{_Ape*eMBf56C zhV#3f_32=<#9)w4{qxS!UtjP)yV05Y3^7@`+3j%gO!zampfqQpGa@GMg&)}Bz=7;r zRP)+K6u<*=X{EaYsrX%Qasu~yPpTi;_zUKiV_B0Z$KyP#wP!l z7$-JEMp!zlxsYeQnFu%^p9P=w^GkTx8J%v`soX57I|#JjAZJ+RH>h1QyiV|Bjk$cy z-mh3GqBVfxt{QXUi1Ij~50HAs^mGZ5#kloH+4+-j`CIu^=(_646N@d2Tp>8~8{P-s zdr;67*f&k+H}#z=3|;P_;dT>>HvTx<0n;CMerNp_b?<(}Gb*f#qs~2NoH!8f9ObI?wA- zM)USA$CZm<)CNWX@M+cDlf<$%H$Dg{NlsefubkGu^x4>SXtSxiyi=a{EF4e_3CnQt z95|P033|kg0oTqNFT+5*s*@J+CRwQIm>L9l&wofJS2?iQ;6GHeyyoOU>1IIss8c)2;f?p}O+%ujPuTm($QOJ>ZF&#lH!tTAOosPQ&`*?}DqLTGY@>ND>vi*- znXQx@Zsml?5vCP|#16D0K!S9Cl|s zh~717!sAoMxWx@PvzB)g@#RaM=x;tEkw8ue2l~6V*gu{&3=BFf(kRBXkx%P3APLi_ zzIkDwOFR6E_A(&XKB|rpP+O!th-X*Q;x~lRU}k4YknJQ9S21+ClHE2?Ghpw2*d|MX5XgWzCGKw9zZ+u!1sE0Dzaalf}lILoi!?b zKNh_T5FB#{r)JYR{sgC(nf*TiT@U>A>hB4F=@bO>=ZF= z_RFsP*5>xJExMihH8Zd0=r(n977u1Z(9ijWd-Sq0e02doa=j zHAbDt=CNAGLVj$(fB+MW#ys`HN2Cu@;!>CLn`2&&g)Y%gDTvWYL>yBz;rz>pu6uMr zv+fp$@{9tecml~BALbje%;LJ|`7LQHk&0=d$-r}Zc0xSckS-g@l3hDbyjqb~rrzP9 z%S(CI1T5Fw(=37Pb1HnNt2H}C@As>dITQpj902*>g18M>ogHHF(Cz)WKcXR^eNlso z*qp_#dk!GN$O3`Kgx3Hgo0`S32c zy944ud<*M*CjP>pCZR>ar*(@*S>Y9UGY)=Aet>5PBY)vod`ORr``jrq>xHax!ej%E*joyeA{f1 z#Lcf)&wem{?4$$^rac&l4*T%-sDI=Wvx*rV3}Kn4zJ7<=3@w&g4{4`nW+`%b0a}jN zq||$j;wq*?T^Sg)ALzM|mLiH-BN!xm^06lkJN8K&;@|CTCX=fFP?SsRKkp3d;*cD! zNBm~!C((IPa<07j&OR|_ev=#m>j58Kp)E2n&|E}s#v=SUy%_PatSNYo+%>$ZLw5DH zH&rWx+x=lZUV!$n>6l+iua9mUevU0akB+ISsEQi7ah_DXo2#&&lj}ZSO7feVh7rX+ zs(R6w!e;fKx26l+_ST=hN<@E}8}svmx}4P@&MWcDBIPN$7H%fEJ~96*FFk0`;QM?A z!vSYn$oN7oIiY&%by7Esq}bu-fG3v0B^-drJl!~g3R9cJg)PrKnf8@{#^d!myR3)P z5QCD!r3wT};~heAr&RXbsq+O<<@~A(uMU*NU9Y?_u3R5n&i`nhht=bmhRR#GfE7^;WdwZ;=+soy_X7 zpFdZ`%Zn(oUFK%d@lZJS*=P>$Ch>yH;B{COJaQfU65&l6igf4nQ&9(rvU`?-MMBj# zvrpgHgqIiDOszX#amTYJex!mIR){a$_ysc%tLzF1+hW>hfcl^Xjh%SO=^MBeSeYJ+ z5;QN4G_&a2$Zf60)ag{vZtc@IWMK3nPy}wOP5Q!}yJGFCr;3pvoOgSacB>h!Z_d6} z)b-NM;wipn{0S@X{gz_0aPMeN*uv7$7220I{Jwyln%5aCxD#HK_|{9&x;K)vpZFjR z0)mst)yJ!)8F<9@=^OIB3D4+p1BW)$L{Iiia<`5(P=%ci2hjQ^+{^l|i^XAqsql`C zWm^;2mozfpSXIZFWe>-ThhC9A0qA^^YdCKrxS=F1{*xI zEeLyxy;&HH28D|A>%$jBUZgiU)q1T7d!O3lrD=cy1MB(dlf{dR%@~9CX9l{rNPD(! z53C9wxn-5Mh54ZyIK{DS^ZY3d6}DoQ_3i$6`{E9!zQAcuUk`4_)4|tSlTli#8HEP| zokP9%8bDp$B!a0CSsy zaf1}gxaY(CPmJuG92l9)9@goU3tga^3b=RXS|t(>pnD{V2p!7sU7fNWFvxCXf}wL{ z21i%6b7U14_8;+t8UWtC0P~04$PqBqFc9oNQMzsT*;U)>XLl877hf~X9jAK$gbVrF ziQeR%+g*W&vchq8n3p4-!k^#)Wk&rJkeV{>o5wc^FT2U-@J09DLTupZ(H!WkIf+4z zmz_*y77`DfhSh1=KirSJJ8_3qN-d=kdwj(oTdMPmU(Iu$GK0Csb+8j6j4~AIZu(#J z4FHrtEH{^h21N|q4Avx@J(vzQt0plOXarD8N+>B_qK^Oq4~aQxM^#dYq&1~hS6TMJwkS4cDOqz2?_)+aF86)vpr{3iq@A>$w$@N!(=m^_VMP98ruHnfg><{c^-bY>>NxbV$G(g>kz+IIO$oL zi2B$XSt6hN(MTZ$#!C1R0wINzH%drx%hQxSjwmgeIH@8~LlX9ZMxbu^xmwVaJ|2|= zoWM~0FT?q@z8#Jfp#D1NmR|RTY@tOu=z~~?l5%I!NNX=_Uu`4c@me(=@rXl#gDpn} zm)fVL@euNh=4hZcuwzJ5U4} z<^KBdzWs#5zYPFX*nDT$>;6w1B70=ey?Zf)tRVkE_b&N)s_?@7rJDikMsK-u5z_m5_=#J&?sJVm9WXT3Sd7a>nF4 z>Lz;f?m7nVK7B(C4n=yu_=`{btJUc(mkp@v{+TLYqz)BYzf5$TXFP(PPl2jYmsx|% zJj9XXgx>Ub*B@*hW0l%4I|3i z&aia((ir1EZw-%e%!Iq)I{xLXIKnHIxhnV#$;q0sl4WX5;vY^Pt6TZs^bHs|Bu6BI zapB54p%x)2)-`>l#6&$mnb9PZb=i5%=wnnvz)AgV6Ak%i=PVNnBd)R7-X$&=vANh8 zpY$^C_6zWuWhKI!?sxZddXs+wD_d4)A1{S*Jfe}X2%W30DP+!#z?eInaY=8bH9wlc zUixyq@C`rU82oPb^)~s$n6i@9ESe5>nU><7nI!u=8DZA<_=sbiP(&(k9U=kT8mABV zEHZj5&lJmBAv#5QXl1B^G-2ibo6!rDl|^b-{t|hutY&>r-q!RhC9N4V;Qn-SrC;Q+ z?F3`xG|s`qw(bvVz#+@DJgzBP+uG(_Rg)^JDIIE`(e+X~43XuM==p->T0kXmKIekG z6v1%o?JnAkT+t&-ce3t^T{Sg*~6#Dop^8N&>{_i)#@zBT{yh?TYPk@)?=+#C5 zuG;Jqr?bLL_KvZ%%F0Mw9dW^=hO@~O(6hN^5?t{R$)jq-Af2MoO)2Ki_+~Q%1F@6O zdS96@r2zH=1ovze#S_-S8vEo8JvbEUy6G3crhtJ+Vio7lkvfQVfYQ55D}bZ}Uc?$h z;iV#b-&FAg>z75q2Be#ltV*n&<{~HUe3T>wpD*b+HAIP5M``>L&dGA8ee#B3Z^9o7 zk7_Wml!(EeFpJe!cpjg6VCxeXcyW?q!Ms~4@Gx_Znfgir;Osm^biG9<4i|4xk|OFb z(|v<;9Z8%OLv|5$2B`~J4-xjzy;**&+IGHnPXpR{`S2!h5YAf(@UWh{=di&ENoW4j zb&ImF>JCfxlgmN?8+c(V$l=oLfx0jbb|>wgsB22YV>n$dRO^GrE!9DqNTLM6O7IZ= zz<0O!!NUl@d3>j+t!bgz@H1BHm@z2b^Mw28jIl^OsFlmIn>8Mr!t3=$WQMYH%d;3e zn~PB+fBRc^GVQ`~6IBr{gfi<&rTi(n;X8%UK>v*M?}Fd(;``p|Cq=AwzU_=FL<#! zp}BlJT=$d$GB{!A0EMG+=vSJwO+bD{LtvO7P4uNma)iDb?E!b2C?RcM6E1A0j$$oP zAYUla6eb+3k6{kNCybifa66D2Is zOshYMSHfxHkG~~K$auXhq?;7)p!M2&nM_AzYz@aba@Nc?@O`(4iE{ZSZvJUBsOiSy@I|7pvb~AQ#$kP z5{XNCY~7u*$FY%ahAZ()7{ViG-yr;$c9!wSx(5KH7)XSB%x>iQgsX8EAIx8P9)`cL z@g-Keb=}fCav)I{@JhOtlmx!6B)@@cb8Wte2u%N^Jvz5@&HkitQcz*kafB`N_UymW zJ(uwKN~vZDXTD6f7eCZFeDv%Y<+B5yTIkLmHq68zQaAv}H`BcAyq*6HIvghPiRmJ) zOrXK&+v74C?w4xy*K4}A_Hj}c@XnTh@>&5T>V?Kl&$hdb=l+@AV6s`yJ$!4^wbB(H z!N{MPc&ws`gxBCAYiu2Es6(7s4U&_}jJ}6U=VAqmpE-u<6k>2BlZ*LE!1V@ykGGuc zH)>n}46DxPv1A9#QW^xJPe;paRI`+FGFd*=-&%qx3*En&isTPi1SsXkY2o?Gf$YpY z%aMds;*WjAtKQG`$5yU2a3`PWB2Mf&@R$67#gMK40h_n+DjS>Ot1_<>o9c0-*$2N+ zu5QtY-FuWm1z0pRE={;3OSFF3Y_u>w6>zD?uWpVUq~m= z{bP1p-;Ua~{jx+M&t8J=)&5h#`;X-}2Kd2kK!W7lb@~%PI<%}}_gg^PR&MVMl}uEm z6pP?w&FT*xpCM&}yG<2YWIESwjezwovK?86)bEowtf5Hf_P-Erg-!F48>V*M{~RRp z!(*kb$~HJNx$X=2u9}7HW0pFf^?J+0kJ!l5#h>K@1JCgq<{m7D2}#$EsK!P;?jZOm zpkS6ZXnO+BG_fsGfDE8}SE^!by;N|tjyu{w)M$>RE^?t?*g~L&7bb(LzwWe8-mrmx zy)}#|lPn5aviKK?|bgI>KAFtKc$W3>pLuA$SVFNAV$Kl&J?fULJvA%Fp z;k(vPjX^r{fD?#QQ(nIwH-()UB<6t8B`g~w%IlAZw>~o-yiw2hk_iJC8Rx0EhX~~^ zrCUp&bZ^3c_hF)HpwX$N^@z-iA^E#^{=c9C!SQzhQAWY%PXH1B*tk3(9jiiRtg-@e zNHJ24D|^nAQvaEne^gLHqNznYNl7RS$O!k%+)7H+Xv&q||ri!AnUbX&=}KAws##M}G%1^^tps6STs-agu>ByirEK1#^u zp~BhxgxOJ#W06bqMZQ=7c5$_=Fp&IdlSXl5a70@N&pjPO$mg?EmB?L9v$r>z5Mf8r zbNvhbM7~xOoYem^=jDawd@Pw`MHOdR*1hef-T64#5(dwPK9N`iSR#kD&sMHnbzL7g zeosf@y|&)XnuPo~e-J6gyJx|dKOkim237(^UBFOaPLH;Z&%;t0M0)FM3w&Cn%o<&X zNC7g35oHlg8Ph&X!};z074jX$K9ny5{4{T8Pm6p$u*~w8LA<M4geXYOUvOcOsS%N9TMC@;$CO`H93 zfLpnV{$&MaMXsAKp@MZs)oY)H0H}exw!wW()$lH3obQ5oTiBpzz_y}-Z!?0OV!N@E zL-DsONUlQ!-5w7^S}?ao&vqXwhoUkRA%dYQJBbWk;u3Egq1)D-V!N@Mo1rRD5QJ!# z)gb8*k}JVb=Iw-R?Z`i5Z7;#MYfyCYbz30t_SDn8l)(3-v|0IeJl$5Uj zmewGnSjdiOZOXeYu~Oh;|FXlYUY;+}4kpLTz7Tr#Wy=Mc+()0A;0i^$`}9}mCXC-j z&&Cdn$}FE2(WkO@u4}(PrGK+&MZ06QiA--?mJ#qT#hzvrWNLparhd6lb+gNKCbWig zBGzg-TZE%)~9zY#bOhc>7mCLaf!=!}TDy3P$h>G8cl`BdfMcg6bU}L$9(dLd_P>Xq5@i(FyI<0vrpjgfOoe1Q-Kp#U&5p+et-O* z2~J~0czuDq2jzRGW!**VEIla+QL{eIR^uvr$6-a&twuQTCR#IRSlz_?>g81X$K(?y zrvwUOUY9%8Ew=0Qh4l7+#p8W<}NcpCuO}Z!?C}wkW z?qNfiKMwchku2fpb2!9&p4p=LRdfd4+#_D>Wk6A3g@U&=q}vagaAG;VIxX2mf+HWN z<<#RgqPGKg*szdH1v6_MA_D+9P(JwkFxQ*&#qtdGc6Ex)QQB|YDh?RBxD!u@N_+h! z$f>8Rn(?H2E6s(8`Z$ypIkNgv%-1c!*b5#|hfA-`Hvvbk=^Lk+Kf=J-JdxBr6ic6f z%q_U)Y)IF&B5$hcb*7KNE4fu#jFRrACy54Lmp<3u?XK#u}3@$ECV!S6us zYwT~=;NKg5*;YdLB2nnu1pT)0t2+Egov=OQF39Z}eo@&0z3mbE8sA?81%coMJ4}V2 zEGX(vKn~AJ%I3Eqx2@eKIemNBgoPe!Q#vv%baH&IbxAMqdY;99)QsX;7otny`-2mF z;83J@+nL4V|;kGk4YJ<0eJT4%yMrE4;wLUvqjcqZpc zxwrmTg@ZlvG=}lign-OOWcj<}pZYe5QdTZvxVTBG_iTEqM89 z>|-AA-E%3lEum$g@ls-yxFrikc=P{y(~zi6jL_2PSDy;LQ8;M;tPBw@W$eSgeo#d$ z#_&yGz5*rh+{lQs!N*(Lkkv=2zzH1pdcXIWm)7FP&dP}1RU;JYt4oA|9|_S!j<&Dl zzu%{D1h)V3zaWZW;Fz4{^6clHbR4ev$p&Bfk^YoT0WvJV>{}E<*p=PO)`0EFnsb5) z6P(o*^xbh(1F1*aUg$91mLE?^qiS8si-_3AOa;-qMokzxWy~RTrPRLlcFyr*vX1^{ z%gqXCN!9cruqYtip(|;Ka^=ecO>J}WYwKDugO*lWkQ@{C;2J;$xNLnAGQ=>*aOjIw z<~zEjo2b*2S0cc6G7PBaz4RP@j+407ob}=l_VQl%zDoC zZAa1}BHT;43pVlfcd*ooo25GP-Vp*&X;M0GVwdMh&IW2Y&(e?7x;!vqO6u;wbh8DQ zaDRS+1S(`8Bg6G8!GWV1-y~eVZyH~#jOf>AzP3@63q`tqk%+#fOJB!9_o`6LU1GKK z_4L;+++Dm;LXX~UAscX%;Xj^t4f~e#wSkLTD-3ld2u`>IRI}+piGKoAxW_^LK%a8 z|8+_(O!<~0=idjYp-)Z-g(BSzpdMFzE-m23fjK(&8m8zG!?PhWdY-u7NE{tgtw>A) z^))q)7>y&qyO9FJgvFGzcN#Ah*bzN7JWmeTVKMP$7-#SneCWnq@ws7f;2wzm1+k=j z?iRKVsG^Pv5hjeD>)#|!>@Bs94Cm0}T$i~cb1t8pW7o6n*H~>7KG2XbNjDp%QVG18%uF7_cg*#WM>(F{0(~=@S=}77lS+kdO3Wu z<-mu6V=u}F%f8^Ic)gt?m%fU-qKqVrlec7jwFy&>j`#ICo>&y8U1G#aQG5@50_u8U z{F(qMurRR_TmvuNc@kVXJep=8$v?yqZaLCQfqdcTEQ))4WOwqzpHB)$Bk;ssVzYJ;5YPuHsfeF6K;nZ72nLVekD1`Ws-g{Lvd7^8>IQd=( zK!bHM>e-z(3+1aL_m6=i7O9Lvl|&#eUoSJMch_ z{U++SFNJLv-{)|m9f2h%8wC7GNaF}Q9{eA<2XnJkR7y7&E~8TLv}eKvgyduHPO~q{)l${5b(jg zRd#8Bp3jmRia|~XKuRZ;CWI@;x`|9X4;Wgi(;TQEAUe~wPvwY#w=)}b z4ekF-at0?x?{*Ci8=0TE6_OEn&vqg7Rd7;=8dohplljXhE^m=G~p}(D~4)|_PK^OTbw~RJ{m#^CDJYBIx7=z!}Zr*b^ndvB} z61z|39Q)nQR5r{cF2&uP_~)HH?k3{~$rd)BO)|Z*IP9I_Pq?6B)XK^nlQ+kgAZvdKwG90c%SUrs*vneEb%s(VI$3TJMV2J0&__qa z&_8qwzyJa&>JC)|3FwMr>b+Nucf)>fWRo5M5}wmss1pgkFe%Xehdr9_>f$neawSEGzd;Q;6_CxIs zWF-RG2L zV+lMk+k-;t7WCN(@ld3@=AY_1NECJ!-)FK*3CsH=PP>x8b>ixS!D)eq8*6Jh*PWP2 z@Rc%V;`@s~sdj}Q*9SCU5`u!qBTLo74n4`fS?trf_R(65*i{6>xb=;5F>k~^i6a3< zF9Jp3esWYB44iqua{xbQ>v3lLJJDBu{-@b|Is5K5VKaJEW4@7ODPIT9NA=I8$iBXf zjS%Jq1z->xmyz8vi5fdWCpfCruHb33PvS`KP59&2eyYKM00}+oi%5JdGRX`q5g@`X zb@M%W72W4gt0o^~ET>cq0Gyt8R?RMNaVAp7aNWRJlbFv#oIb9fWP9D3jp^vBeH~#h zwKvO;=+YiDO#}RKNnLN)$A8wITDqFW7R@7*(rlR|7)#y|^6{0hn8i~7CzF69)GOIf zYv^7cOKf`Vk<&kw>$)BP$qLKz|ZsFqGm!X5S{{Whmx_oHX0}JQ#25783F%OzyPkiMH~?Vz!k`*9HaroNPC}}VHRQFXO4bw9 zb$t3$_jub4jCW}Ox#VX)dJm5;DHrFk?{DhW_OBXlxv~44@1)IN8k2l9fbfIuEaNXE z&dHl=&2@4u>(`H_CjqdGw_dMUt_Ye0XO{9jsa8}i#{pPp*AhGRV2jWKm-LV!EdQrk z2MRaTUa&EEyO=!QxK@j>mD!&Cm*26c0TPcDdSokY=dTfiRg$QAZWJszdh@ui;E2|b zCb!ka-T@97ULd(MepI6H`f_xwfwNtTEbi)=@x=0xstv6ZtrV!k6IfUYKYG6rsik~S zT1teFkDfZ^v3L?bfu#+u4QSwn1&QI2tu8-D!uG4`W)6QD&#zLItFdpN_b2faPdc(S zO(9{Y(lRtA%}(nWLrLj1+6XMfwYR=L1eFK#$ql+HPWJjI&Jq)*WrGrUmN2uEqm+Td zz(PNAQptW>d`en&2?NZ>#7}i^*!9xGyvz?gW(;iHAJ6+@0`<7V{}UQSFqHkr35GWB zM%+#b-M0Stil1Be2Oly%cRt`{QES>s(A~;Em2lGSct#$c2&(*(c*g9_&id^K{Py>_ z^L2z8HF5_XO)&Yap%hm$04D7(AMN53EE%*(Gi^K-zdt=83l2qk&;G^dy|iakTK#}6 z_CK@b#*XXnTS)HNsoc?fb8EiJXH%;^?|r!B@$OSus_A9*kHLW6$V#$SefEVTkQ~zT zd^0ftoAGn5S;j|mog1$aE_MY2Y|lO&uj81$&+_3V&lUQ~rm#v|kh4rYKHrO~)HX8C z+Af5J83V5GyCUA#d>)@|Yq_A`l%1~o=Z}xx# z68T0=$tyjr@y?Q@7xgd?uB-9tubwG@A0c@YL~~h85U{5`|AgD#_n?gdPgvfAsIo9^ z=ZRi7hYBNMOqdnB=i_}6=frPr8b(x4bO4`zva0$&Zw@w>_9%D4(=sLy;Vu8W`#Bq7LMD9aeEv7g6aYB3 z6tvd|p7ALzLOsNoytKGDDBRiIxn1q`)kZ|}YjFV`3L8ag?*pa94>ZE2BBHyt?j0Gv z68!NI>x9=3C)25?C@O{gnO71xY}r{jlJ@vkz8kh)alQ~OW`?*(@3l1sQ#?6g+6a#H zzl2`X7XBOAWt;JoB2Tz=6}z#C>Swm%IS$WCF`sYi;a_(HERqtMu!Y{s%bdn~7h$K% z+FSHoBbG&a>3vs8P^gX)$NxV)@q1K;lcAv(d3qw~Rl7etTe*tHHX=$cH*Jn_a>opNG2uGuzIFu*^YfyVPmyTr9t_l&zCFf!8xH7ZIt9( zZMtdSAD>V_Mz9RV5=!Cx=+zYTZz@(F-;Z_AWoqOd?)@+`@j+QH&E`oY*wn7b=|HF) zPRTn!3Z|A&pw}J|4H%`xK7i-h@Ba9@TJQ>`1`4 z^?j!a491)?tQ2X44CF)-Gm+tzG1b6b>6A%RfOJm&jnb2ZEiKx!6lJxzLt7h`fmmXF z*DWpN)zSkkQxWz`d$aubC8oXO6Riqkh31t;^LdR=2_C&PZf%LY6h~~hs%OxTc@3n% viviG|>hN6}P)ol9d92ZHLS@1y$^kR0;bhRO$Z!l@c)j literal 0 HcmV?d00001 diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json new file mode 100644 index 00000000000..96e91f7111e --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json @@ -0,0 +1,116 @@ +{ + "config": { + "chainId": 3503995874084926, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "mergeNetsplitBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "terminalTotalDifficulty": 131072, + "terminalTotalDifficultyPassed": true, + "ethash": {} + }, + "nonce": "0x0", + "timestamp": "0x0", + "extraData": "0x68697665636861696e", + "gasLimit": "0x23f3e20", + "difficulty": "0x20000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "000f3df6d732807ef1319fb7b8bb8522d0beac02": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", + "balance": "0x2a" + }, + "0c2c51a0990aee1d73c1228de158688341557508": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "14e46043e63d0e3cdcf2530519f4cfaf35058cb2": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "16c57edf7fa9d9525378b0b81bf8a3ced0620c1c": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "1f4924b14f34e24159387c0a4cdbaa32f3ddb0cf": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "1f5bde34b4afc686f136c7a3cb6ec376f7357759": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "2d389075be5be9f2246ad654ce152cf05990b209": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "3ae75c08b4c907eb63a8960c45b86e1e9ab6123c": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "4340ee1b812acb40a1eb561c019c327b243b92df": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "4a0f1452281bcec5bd90c3dce6162a5995bfe9df": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "4dde844b71bcdf95512fb4dc94e84fb67b512ed8": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "5f552da00dfb4d3749d9e62dcee3c918855a86a0": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "654aa64f5fbefb84c270ec74211b81ca8c44a72e": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "717f8aa2b982bee0e29f573d31df288663e1ce16": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "7435ed30a8b4aeb0877cef0c6e8cffe834eb865f": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "7dcd17433742f4c0ca53122ab541d0ba67fc27df": { + "code": "0x3680600080376000206000548082558060010160005560005263656d697460206000a2", + "balance": "0x0" + }, + "83c7e323d189f18725ac510004fdc2941f8c4a78": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "84e75c28348fb86acea1a93a39426d7d60f4cc46": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "8bebc8ba651aee624937e7d897853ac30c95a067": { + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000003" + }, + "balance": "0x1", + "nonce": "0x1" + }, + "c7b99a164efd027a93f147376cc7da7c67c6bbe0": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "d803681e487e6ac18053afc5a6cd813c86ec3e4d": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "e7d13f7aa2a838d24c59b40186a0aca1e21cffcc": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + }, + "eda8645ba6948855e3b3cd596bbb07596d59c603": { + "balance": "0xc097ce7bc90715b34b9f1000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x3b9aca00", + "excessBlobGas": null, + "blobGasUsed": null +} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json new file mode 100644 index 00000000000..31cd1cff3c7 --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json @@ -0,0 +1,72 @@ +{ + "request": { + "jsonrpc": "2.0", + "id": 1, + "method": "eth_simulateV1", + "params": [ + { + "blockStateCalls": [ + { + "stateOverrides": { + "0xc000000000000000000000000000000000000000": { + "balance": "0x3e8" + } + }, + "calls": [ + { + "from": "0xc000000000000000000000000000000000000000", + "to": "0xc100000000000000000000000000000000000000", + "value": "0x3e8" + }, + { + "from": "0xc100000000000000000000000000000000000000", + "to": "0xc200000000000000000000000000000000000000", + "value": "0x3e8" + } + ] + } + ] + }, + "0x3" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "number": "0x4", + "hash": "0x43554dd08fc12190549d7946b63288982fec040efad79dc69c4ef96c7a734375", + "timestamp": "0x1f", + "gasLimit": "0x4c4b40", + "gasUsed": "0xa410", + "feeRecipient": "0x0000000000000000000000000000000000000000", + "baseFeePerGas": "0x2310a91d", + "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", + "calls": [ + { + "returnData": "0x", + "logs": [], + "gasUsed": "0x5208", + "status": "0x1" + }, + { + "returnData": "0x", + "logs": [], + "gasUsed": "0x5208", + "status": "0x1" + } + ] + } + ] + } + ] + }, + "statusCode": 200 +} + + diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 42b3904c749..aed4b878082 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.transaction; +import org.hyperledger.besu.datatypes.AccountOverride; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Wei; @@ -40,6 +41,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; @@ -51,13 +53,14 @@ import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.units.bigints.UInt256; public class BlockSimulator { private final TransactionSimulator transactionSimulator; private final WorldStateArchive worldStateArchive; private final ProtocolSchedule protocolSchedule; - private final Supplier
coinbaseSupplier; + private final Supplier> coinbaseSupplier; private final Supplier nextGasSupplier; public BlockSimulator( @@ -65,7 +68,7 @@ public BlockSimulator( final WorldStateArchive worldStateArchive, final ProtocolSchedule protocolSchedule, final long rpcGasCap, - final Supplier
coinbaseSupplier, + final Supplier> coinbaseSupplier, final Supplier nextGasSupplier) { this.worldStateArchive = worldStateArchive; this.protocolSchedule = protocolSchedule; @@ -76,19 +79,16 @@ public BlockSimulator( } public BlockSimulationResult simulate( - final BlockHeader header, final BlockStateCall blockStateCall) { - return simulate(header, blockStateCall, false); - } - - public BlockSimulationResult simulate( - final BlockHeader header, final BlockStateCall blockStateCall, final boolean shouldPersist) { + final BlockHeader header, + final BlockStateCall blockStateCall, + final boolean shouldValidate, + final boolean shouldPersist) { long currentGasUsed = 0; final List receipts = new ArrayList<>(); final List transactions = new ArrayList<>(); final BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); - long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); final ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); @@ -102,13 +102,21 @@ public BlockSimulationResult simulate( try (final MutableWorldState ws = getWorldState(header, shouldPersist)) { WorldUpdater updater = ws.updater(); + if (blockStateCall.getAccountOverrides().isPresent()) { + for (Address accountToOverride : blockStateCall.getAccountOverrides().get().keySet()) { + final AccountOverride overrides = + blockStateCall.getAccountOverrides().get().get(accountToOverride); + applyOverrides(updater.getOrCreate(accountToOverride), overrides); + } + } + for (CallParameter callParameter : blockStateCall.getCalls()) { final WorldUpdater localUpdater = updater.updater(); final Optional transactionSimulatorResult = transactionSimulator.processWithWorldUpdater( callParameter, Optional.empty(), - buildTransactionValidationParams(), + buildTransactionValidationParams(shouldValidate), OperationTracer.NO_TRACING, blockHeader, localUpdater, @@ -124,8 +132,7 @@ public BlockSimulationResult simulate( if (transactionProcessingResult.isSuccessful()) { localUpdater.commit(); - currentGasUsed += - callParameter.getGasLimit() - transactionProcessingResult.getGasRemaining(); + currentGasUsed += transactionProcessingResult.getEstimateGasUsedByTransaction(); Transaction transaction = transactionSimulatorResult.get().transaction(); transactions.add(transaction); @@ -161,6 +168,22 @@ public BlockSimulationResult simulate( } } + private void applyOverrides(final MutableAccount account, final AccountOverride override) { + override.getNonce().ifPresent(account::setNonce); + if (override.getBalance().isPresent()) { + account.setBalance(override.getBalance().get()); + } + override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n))); + override + .getStateDiff() + .ifPresent( + d -> + d.forEach( + (key, value) -> + account.setStorageValue( + UInt256.fromHexString(key), UInt256.fromHexString(value)))); + } + private BlockHeader overrideBlockHeader( final BlockHeader header, final BlockOverrides blockOverrides, @@ -170,7 +193,7 @@ private BlockHeader overrideBlockHeader( return BlockHeaderBuilder.createDefault() .parentHash(header.getHash()) - .coinbase(blockOverrides.getFeeRecipient().orElse(coinbaseSupplier.get())) + .coinbase(blockOverrides.getFeeRecipient().orElse(coinbaseSupplier.get().orElseThrow())) .difficulty( Difficulty.of(getNextDifficulty(blockOverrides, newProtocolSpec, header, timestamp))) .number(blockNumber) @@ -220,9 +243,18 @@ private MutableWorldState getWorldState(final BlockHeader header, final boolean "Public world state not available for block " + header.toLogString())); } - private ImmutableTransactionValidationParams buildTransactionValidationParams() { + private ImmutableTransactionValidationParams buildTransactionValidationParams( + final boolean shouldValidate) { + + if (shouldValidate) { + return ImmutableTransactionValidationParams.builder() + .from(TransactionValidationParams.processingBlock()) + .build(); + } + return ImmutableTransactionValidationParams.builder() - .from(TransactionValidationParams.processingBlock()) + .from(TransactionValidationParams.transactionSimulator()) + .isAllowExceedingBalance(true) .build(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java index 826a19b26e1..44aa9d3e3bc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java @@ -14,9 +14,12 @@ */ package org.hyperledger.besu.ethereum.transaction; +import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.BlockOverrides; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class BlockStateCall { @@ -24,16 +27,26 @@ public class BlockStateCall { private final List calls; + private final AccountOverrideMap accountOverrides; + public BlockStateCall( - final List calls, final BlockOverrides blockOverrides) { - this.calls = calls; - this.blockOverrides = blockOverrides; + final List calls, + final BlockOverrides blockOverrides, + final AccountOverrideMap accountOverrides) { + this.calls = calls != null ? calls : new ArrayList<>(); + this.blockOverrides = + blockOverrides != null ? blockOverrides : BlockOverrides.builder().build(); + this.accountOverrides = accountOverrides; } public BlockOverrides getBlockOverrides() { return blockOverrides; } + public Optional getAccountOverrides() { + return Optional.of(accountOverrides); + } + public List getCalls() { return calls; } From 5778e0a658f6f4dac0f3a8b41b746358fad36c66 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 11:52:39 +1100 Subject: [PATCH 06/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../ethereum/transaction/BlockSimulator.java | 43 ++++++++++--------- .../ethereum/transaction/BlockStateCall.java | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index aed4b878082..3883192f7da 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.transaction; import org.hyperledger.besu.datatypes.AccountOverride; +import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Wei; @@ -94,7 +95,8 @@ public BlockSimulationResult simulate( final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); - final BlockHeader blockHeader = overrideBlockHeader(header, blockOverrides, newProtocolSpec); + final BlockHeader blockHeader = + applyBlockHeaderOverrides(header, blockOverrides, newProtocolSpec); final MiningBeneficiaryCalculator miningBeneficiaryCalculator = getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); @@ -103,11 +105,7 @@ public BlockSimulationResult simulate( WorldUpdater updater = ws.updater(); if (blockStateCall.getAccountOverrides().isPresent()) { - for (Address accountToOverride : blockStateCall.getAccountOverrides().get().keySet()) { - final AccountOverride overrides = - blockStateCall.getAccountOverrides().get().get(accountToOverride); - applyOverrides(updater.getOrCreate(accountToOverride), overrides); - } + applyStateOverrides(blockStateCall.getAccountOverrides().get(), updater); } for (CallParameter callParameter : blockStateCall.getCalls()) { @@ -168,23 +166,28 @@ public BlockSimulationResult simulate( } } - private void applyOverrides(final MutableAccount account, final AccountOverride override) { - override.getNonce().ifPresent(account::setNonce); - if (override.getBalance().isPresent()) { - account.setBalance(override.getBalance().get()); + private void applyStateOverrides( + final AccountOverrideMap accountOverrideMap, WorldUpdater updater) { + for (Address accountToOverride : accountOverrideMap.keySet()) { + final AccountOverride override = accountOverrideMap.get(accountToOverride); + MutableAccount account = updater.getOrCreate(accountToOverride); + override.getNonce().ifPresent(account::setNonce); + if (override.getBalance().isPresent()) { + account.setBalance(override.getBalance().get()); + } + override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n))); + override + .getStateDiff() + .ifPresent( + d -> + d.forEach( + (key, value) -> + account.setStorageValue( + UInt256.fromHexString(key), UInt256.fromHexString(value)))); } - override.getCode().ifPresent(n -> account.setCode(Bytes.fromHexString(n))); - override - .getStateDiff() - .ifPresent( - d -> - d.forEach( - (key, value) -> - account.setStorageValue( - UInt256.fromHexString(key), UInt256.fromHexString(value)))); } - private BlockHeader overrideBlockHeader( + private BlockHeader applyBlockHeaderOverrides( final BlockHeader header, final BlockOverrides blockOverrides, final ProtocolSpec newProtocolSpec) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java index 44aa9d3e3bc..b28287fa80a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java @@ -44,7 +44,7 @@ public BlockOverrides getBlockOverrides() { } public Optional getAccountOverrides() { - return Optional.of(accountOverrides); + return Optional.ofNullable(accountOverrides); } public List getCalls() { From 1964c3a28ecb1775cad22424e45258bf25a6d897 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 12:47:10 +1100 Subject: [PATCH 07/38] remove non necessary code Signed-off-by: Gabriel-Trintinalia --- .../common/MigratingMiningCoordinator.java | 15 --------------- .../blockcreation/BftMiningCoordinator.java | 16 ---------------- .../blockcreation/TransitionCoordinator.java | 17 ----------------- .../blockcreation/AbstractMinerExecutor.java | 3 --- .../AbstractMiningCoordinator.java | 16 ---------------- .../blockcreation/MiningCoordinator.java | 18 ------------------ .../blockcreation/NoopMiningCoordinator.java | 15 --------------- .../blockcreation/PoWMinerExecutor.java | 6 ------ 8 files changed, 106 deletions(-) diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java index f20162a3495..6450a108fd9 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/MigratingMiningCoordinator.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.CompletableFuture; import com.google.common.annotations.VisibleForTesting; @@ -113,11 +112,6 @@ public Optional
getCoinbase() { return activeMiningCoordinator.getCoinbase(); } - @Override - public OptionalLong getTargetGasLimit() { - return activeMiningCoordinator.getTargetGasLimit(); - } - @Override public Optional createBlock( final BlockHeader parentHeader, @@ -131,15 +125,6 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.empty(); } - @Override - public Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - return Optional.empty(); - } - @Override public void changeTargetGasLimit(final Long targetGasLimit) { activeMiningCoordinator.changeTargetGasLimit(targetGasLimit); 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 1be66a5670a..795a064b6bc 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 @@ -31,7 +31,6 @@ import java.util.List; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; @@ -166,11 +165,6 @@ public Optional
getCoinbase() { return Optional.of(blockCreatorFactory.getLocalAddress()); } - @Override - public OptionalLong getTargetGasLimit() { - return blockCreatorFactory.getTargetGasLimit(); - } - @Override public Optional createBlock( final BlockHeader parentHeader, @@ -186,16 +180,6 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.empty(); } - @Override - public Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - // One-off block creation has not been implemented - return Optional.empty(); - } - @Override public void changeTargetGasLimit(final Long targetGasLimit) { blockCreatorFactory.changeTargetGasLimit(targetGasLimit); diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java index 6581a7e1ca4..681c6f334bc 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java @@ -31,7 +31,6 @@ import java.util.List; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.CompletableFuture; import org.apache.tuweni.bytes.Bytes32; @@ -112,11 +111,6 @@ public Optional
getCoinbase() { return dispatchFunctionAccordingToMergeState(MiningCoordinator::getCoinbase); } - @Override - public OptionalLong getTargetGasLimit() { - return dispatchFunctionAccordingToMergeState(MiningCoordinator::getTargetGasLimit); - } - @Override public Optional createBlock( final BlockHeader parentHeader, @@ -133,17 +127,6 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti (MiningCoordinator coordinator) -> coordinator.createBlock(parentHeader, timestamp)); } - @Override - public Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - return dispatchFunctionAccordingToMergeState( - (MiningCoordinator coordinator) -> - coordinator.createBlock(parentHeader, transactions, ommers, timestamp)); - } - @Override public void addEthHashObserver(final PoWObserver observer) { if (this.miningCoordinator instanceof PoWMiningCoordinator) { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java index 9320103ff28..4d2b1274c67 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMinerExecutor.java @@ -28,7 +28,6 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -112,8 +111,6 @@ public Wei getMinPriorityFeePerGas() { public abstract Optional
getCoinbase(); - public abstract OptionalLong getTargetGasLimit(); - public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { } else { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java index b54f4439606..9c939b91bc8 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -80,16 +79,6 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.of(miner.createBlock(parentHeader, timestamp).getBlock()); } - @Override - public Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - final M miner = executor.createMiner(minedBlockObservers, ethHashObservers, parentHeader); - return Optional.of(miner.createBlock(parentHeader, transactions, ommers, timestamp).getBlock()); - } - @Override public void start() { synchronized (this) { @@ -226,11 +215,6 @@ public Optional
getCoinbase() { return executor.getCoinbase(); } - @Override - public OptionalLong getTargetGasLimit() { - return executor.getTargetGasLimit(); - } - protected abstract boolean newChainHeadInvalidatesMiningOperation( final BlockHeader newChainHeadHeader); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java index e3d6cc0951b..d1a91083b63 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/MiningCoordinator.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Optional; -import java.util.OptionalLong; public interface MiningCoordinator { @@ -66,8 +65,6 @@ default void setCoinbase(final Address coinbase) { Optional
getCoinbase(); - OptionalLong getTargetGasLimit(); - default Optional hashesPerSecond() { return Optional.empty(); } @@ -115,21 +112,6 @@ Optional createBlock( */ Optional createBlock(final BlockHeader parentHeader, final long timestamp); - /** - * Creates a block if possible, otherwise return an empty result - * - * @param parentHeader The parent block's header - * @param transactions The list of transactions to include - * @param ommers The list of ommers to include - * @param timestamp unix timestamp of the new block. - * @return If supported, returns the block that was created, otherwise an empty response. - */ - Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp); - default void addEthHashObserver(final PoWObserver observer) {} void changeTargetGasLimit(final Long targetGasLimit); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java index 9685643274e..8b5624f847a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/NoopMiningCoordinator.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Optional; -import java.util.OptionalLong; public class NoopMiningCoordinator implements MiningCoordinator { @@ -72,11 +71,6 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } - @Override - public OptionalLong getTargetGasLimit() { - return miningConfiguration.getTargetGasLimit(); - } - @Override public Optional createBlock( final BlockHeader parentHeader, @@ -90,15 +84,6 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti return Optional.empty(); } - @Override - public Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - return Optional.empty(); - } - @Override public void changeTargetGasLimit(final Long targetGasLimit) {} } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java index 4df7b1c026d..f17b7989d2a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMinerExecutor.java @@ -29,7 +29,6 @@ import org.hyperledger.besu.util.Subscribers; import java.util.Optional; -import java.util.OptionalLong; import java.util.function.Function; public class PoWMinerExecutor extends AbstractMinerExecutor { @@ -117,11 +116,6 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } - @Override - public OptionalLong getTargetGasLimit() { - return miningConfiguration.getTargetGasLimit(); - } - public EpochCalculator getEpochCalculator() { return epochCalculator; } From 652f4a51d4f236d9b0996b610930ff7f2f7ac7c0 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 12:51:41 +1100 Subject: [PATCH 08/38] remove non necessary code Signed-off-by: Gabriel-Trintinalia --- .../blockcreation/CliqueMinerExecutor.java | 6 ------ .../blockcreation/BftBlockCreatorFactory.java | 10 ---------- .../merge/blockcreation/MergeCoordinator.java | 15 --------------- .../ethereum/blockcreation/BlockMiner.java | 18 ------------------ .../blockcreation/PoWMiningCoordinator.java | 6 ------ 5 files changed, 55 deletions(-) diff --git a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java index 6216ece892b..998a237e916 100644 --- a/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java +++ b/consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java @@ -38,7 +38,6 @@ import java.util.Collection; import java.util.List; import java.util.Optional; -import java.util.OptionalLong; import java.util.function.Function; import com.google.common.annotations.VisibleForTesting; @@ -123,11 +122,6 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } - @Override - public OptionalLong getTargetGasLimit() { - return miningConfiguration.getTargetGasLimit(); - } - /** * Calculate extra data bytes. * diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java index de05fc4b5e3..1349bbf4619 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/blockcreation/BftBlockCreatorFactory.java @@ -41,7 +41,6 @@ import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.OptionalLong; import org.apache.tuweni.bytes.Bytes; @@ -141,15 +140,6 @@ public Wei getMinTransactionGasPrice() { return miningConfiguration.getMinTransactionGasPrice(); } - /** - * Gets target gas limit. - * - * @return the target gas limit - */ - public OptionalLong getTargetGasLimit() { - return miningConfiguration.getTargetGasLimit(); - } - /** * Gets min priority fee per gas * diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java index 115691ba859..7570e97d4d6 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java @@ -53,7 +53,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -229,11 +228,6 @@ public Optional
getCoinbase() { return miningConfiguration.getCoinbase(); } - @Override - public OptionalLong getTargetGasLimit() { - return miningConfiguration.getTargetGasLimit(); - } - @Override public Optional createBlock( final BlockHeader parentHeader, @@ -247,15 +241,6 @@ public Optional createBlock(final BlockHeader parentHeader, final long ti throw new UnsupportedOperationException("random is required"); } - @Override - public Optional createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - throw new UnsupportedOperationException("random is required"); - } - @Override public void changeTargetGasLimit(final Long newTargetGasLimit) { if (AbstractGasLimitSpecification.isValidTargetGasLimit(newTargetGasLimit)) { diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java index 2cfd1aa4ff6..f51451f2930 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java @@ -124,24 +124,6 @@ public BlockCreationResult createBlock(final BlockHeader parentHeader, final lon return blockCreator.createBlock(Optional.empty(), Optional.empty(), timestamp, parentHeader); } - /** - * Create a block with the given transactions, ommers and timestamp. - * - * @param parentHeader The header of the parent of the block to be produced - * @param transactions The list of transactions which may be included. - * @param ommers The list of ommers to include. - * @param timestamp unix timestamp of the new block. - * @return the newly created block. - */ - public BlockCreationResult createBlock( - final BlockHeader parentHeader, - final List transactions, - final List ommers, - final long timestamp) { - final BlockCreator blockCreator = this.blockCreatorFactory.apply(parentHeader); - return blockCreator.createBlock(transactions, ommers, timestamp, parentHeader); - } - protected boolean shouldImportBlock(final Block block) throws InterruptedException { return true; } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java index c5a230f4751..1c94bb7821a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/PoWMiningCoordinator.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.ethereum.mainnet.PoWSolverInputs; import java.util.Optional; -import java.util.OptionalLong; import java.util.concurrent.TimeUnit; import com.google.common.cache.Cache; @@ -67,11 +66,6 @@ public void setCoinbase(final Address coinbase) { executor.setCoinbase(coinbase); } - @Override - public OptionalLong getTargetGasLimit() { - return executor.getTargetGasLimit(); - } - public void setStratumMiningEnabled(final boolean stratumMiningEnabled) { executor.setStratumMiningEnabled(stratumMiningEnabled); } From ac53d95781d233bfac6c89b56b97d135c1f566d9 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 12:54:37 +1100 Subject: [PATCH 09/38] remove non necessary code Signed-off-by: Gabriel-Trintinalia --- .../org/hyperledger/besu/cli/BesuCommand.java | 4 -- .../besu/services/MiningServiceImpl.java | 37 ------------------- .../besu/plugin/services/MiningService.java | 21 ----------- 3 files changed, 62 deletions(-) delete mode 100644 besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java delete mode 100644 plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java 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 183c1a43db7..1b7cc3d9054 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -158,7 +158,6 @@ import org.hyperledger.besu.plugin.services.BlockSimulationService; import org.hyperledger.besu.plugin.services.BlockchainService; import org.hyperledger.besu.plugin.services.MetricsSystem; -import org.hyperledger.besu.plugin.services.MiningService; import org.hyperledger.besu.plugin.services.PermissioningService; import org.hyperledger.besu.plugin.services.PicoCLIOptions; import org.hyperledger.besu.plugin.services.PrivacyPluginService; @@ -184,7 +183,6 @@ import org.hyperledger.besu.services.BesuPluginContextImpl; import org.hyperledger.besu.services.BlockSimulatorServiceImpl; import org.hyperledger.besu.services.BlockchainServiceImpl; -import org.hyperledger.besu.services.MiningServiceImpl; import org.hyperledger.besu.services.P2PServiceImpl; import org.hyperledger.besu.services.PermissioningServiceImpl; import org.hyperledger.besu.services.PicoCLIOptionsImpl; @@ -1285,8 +1283,6 @@ private void startPlugins(final Runner runner) { besuController.getSyncState(), besuController.getProtocolContext().getWorldStateArchive())); - besuPluginContext.addService( - MiningService.class, new MiningServiceImpl(besuController.getMiningCoordinator())); besuPluginContext.addService(P2PService.class, new P2PServiceImpl(runner.getP2PNetwork())); besuPluginContext.addService( diff --git a/besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java deleted file mode 100644 index 8fb8fdb8353..00000000000 --- a/besu/src/main/java/org/hyperledger/besu/services/MiningServiceImpl.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright contributors to Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.services; - -import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; -import org.hyperledger.besu.plugin.services.MiningService; - -public class MiningServiceImpl implements MiningService { - - final MiningCoordinator miningCoordinator; - - public MiningServiceImpl(final MiningCoordinator miningCoordinator) { - this.miningCoordinator = miningCoordinator; - } - - @Override - public void stop() { - miningCoordinator.stop(); - } - - @Override - public void start() { - miningCoordinator.start(); - } -} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java deleted file mode 100644 index df8d0ce4330..00000000000 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/MiningService.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright contributors to Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.plugin.services; - -public interface MiningService extends BesuService { - void start(); - - void stop(); -} From 71dc6843c25588b78b11f80931bb57b5856dd7a6 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 15:05:51 +1100 Subject: [PATCH 10/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 8 +- .../internal/methods/EthSimulateV1.java | 30 ++-- .../transaction/BlockSimulationResult.java | 72 +++++---- .../ethereum/transaction/BlockSimulator.java | 152 +++++++++++------- .../plugin/data/BlockSimulationResult.java | 9 +- 5 files changed, 155 insertions(+), 116 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 95a93933036..122ea61f0e7 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -66,12 +66,8 @@ public BlockSimulationResult simulate( BlockStateCall blockStateCall = new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap()); - BlockSimulationResult result = - blockSimulator.simulate(parentHeaderCore, blockStateCall, true, shouldPersist); + var result = blockSimulator.simulate(parentHeaderCore, blockStateCall, true, shouldPersist); - if (result.getResult().isFailed()) { - throw new IllegalArgumentException("Unable to create block."); - } - return result; + return result.orElseThrow(); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index cbcc403a3c1..551062e9e95 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -25,20 +25,21 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; 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.Difficulty; import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; +import java.util.ArrayList; import java.util.List; public class EthSimulateV1 extends AbstractBlockParameterOrBlockHashMethod { @@ -96,18 +97,21 @@ protected Object resultByBlockHeader( try { BlockStateCallsParameter parameter = request.getRequiredParameter(0, BlockStateCallsParameter.class); - BlockSimulationResult result = - blockSimulator.simulate( - header, parameter.getBlockStateCalls().getFirst(), parameter.isValidation(), false); - - if (result.getResult().isSuccessful()) { - Block block = - new Block( - (BlockHeader) result.getBlockHeader().get(), - (BlockBody) result.getBlockBody().get()); - return blockResultFactory.transactionHash(blockByHashWithTxHashes(block)); + + List results = new ArrayList<>(); + for (var blockStateCall : parameter.getBlockStateCalls()) { + var result = + blockSimulator.simulate(header, blockStateCall, parameter.isValidation(), false); + + results.add( + result + .map( + blockSimulationResult -> + blockResultFactory.transactionHash( + blockByHashWithTxHashes(blockSimulationResult.getBlock()))) + .orElse(null)); } - return null; + return new JsonRpcSuccessResponse(request.getRequest().getId(), results); } catch (JsonRpcParameterException e) { throw new RuntimeException(e); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 0c5e8110c02..8ce0b3c3089 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -14,55 +14,67 @@ */ package org.hyperledger.besu.ethereum.transaction; -import org.hyperledger.besu.ethereum.BlockProcessingResult; +import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.plugin.data.BlockBody; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.TransactionReceipt; +import java.util.ArrayList; import java.util.List; -import java.util.Optional; public class BlockSimulationResult implements org.hyperledger.besu.plugin.data.BlockSimulationResult { - final BlockHeader blockHeader; - final BlockBody blockBody; - final List receipts; - final BlockProcessingResult result; + final Block block; + final BlockTransactionSimulationResult blockTransactionSimulationResult; + final List receipts; - public BlockSimulationResult(final BlockProcessingResult result) { - this.receipts = null; - this.blockHeader = null; - this.blockBody = null; - this.result = result; - } - - public BlockSimulationResult( - final BlockHeader blockHeader, - final BlockBody blockBody, + private BlockSimulationResult( + final Block block, final List receipts, - final BlockProcessingResult result) { - this.blockHeader = blockHeader; - this.blockBody = blockBody; - this.receipts = receipts; - this.result = result; + final BlockTransactionSimulationResult blockTransactionSimulationResult) { + this.block = block; + this.receipts = new ArrayList<>(receipts); + this.blockTransactionSimulationResult = blockTransactionSimulationResult; } - public BlockProcessingResult getResult() { - return result; + public static BlockSimulationResult successful( + final Block block, + final List receipts, + final BlockTransactionSimulationResult blockTransactionSimulationResult) { + return new BlockSimulationResult(block, receipts, blockTransactionSimulationResult); } @Override - public Optional getBlockHeader() { - return Optional.ofNullable(blockHeader); + public BlockHeader getBlockHeader() { + return block.getHeader(); } @Override - public Optional getBlockBody() { - return Optional.ofNullable(blockBody); + public BlockBody getBlockBody() { + return block.getBody(); } - @Override - public Optional> getReceipts() { - return Optional.ofNullable(receipts); + public Block getBlock() { + return block; + } + + public List getTransactionReceipts() { + return receipts; + } + + public BlockTransactionSimulationResult getBlockTransactionSimulationResult() { + return blockTransactionSimulationResult; + } + + public static class BlockTransactionSimulationResult { + List calls = new ArrayList<>(); + + void add(final TransactionSimulatorResult callResult) { + calls.add(callResult); + } + + List getCalls() { + return calls; + } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 3883192f7da..b820fd5ab5c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -19,8 +19,6 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.BlockProcessingOutputs; -import org.hyperledger.besu.ethereum.BlockProcessingResult; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -79,22 +77,16 @@ public BlockSimulator( new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, rpcGasCap); } - public BlockSimulationResult simulate( + public Optional simulate( final BlockHeader header, final BlockStateCall blockStateCall, final boolean shouldValidate, final boolean shouldPersist) { - long currentGasUsed = 0; - final List receipts = new ArrayList<>(); - final List transactions = new ArrayList<>(); - final BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); final ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); - final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); - final BlockHeader blockHeader = applyBlockHeaderOverrides(header, blockOverrides, newProtocolSpec); @@ -107,67 +99,107 @@ public BlockSimulationResult simulate( if (blockStateCall.getAccountOverrides().isPresent()) { applyStateOverrides(blockStateCall.getAccountOverrides().get(), updater); } + BlockSimulationResult.BlockTransactionSimulationResult blockTransactionSimulationResult = + processTransactions( + blockHeader, blockStateCall, updater, shouldValidate, miningBeneficiaryCalculator); + + updater.commit(); + + return Optional.of( + processPostExecution( + blockHeader, + ws, + blockTransactionSimulationResult, + blockOverrides, + newProtocolSpec, + shouldPersist)); + + } catch (final Exception e) { + return Optional.empty(); + } + } - for (CallParameter callParameter : blockStateCall.getCalls()) { - final WorldUpdater localUpdater = updater.updater(); - final Optional transactionSimulatorResult = - transactionSimulator.processWithWorldUpdater( - callParameter, - Optional.empty(), - buildTransactionValidationParams(shouldValidate), - OperationTracer.NO_TRACING, - blockHeader, - localUpdater, - miningBeneficiaryCalculator); - - if (transactionSimulatorResult.isEmpty()) { - return new BlockSimulationResult( - new BlockProcessingResult(Optional.empty(), "Transaction processing failed")); - } - - TransactionProcessingResult transactionProcessingResult = - transactionSimulatorResult.get().result(); - - if (transactionProcessingResult.isSuccessful()) { - localUpdater.commit(); - currentGasUsed += transactionProcessingResult.getEstimateGasUsedByTransaction(); - - Transaction transaction = transactionSimulatorResult.get().transaction(); - transactions.add(transaction); - final TransactionReceipt transactionReceipt = - transactionReceiptFactory.create( - transaction.getType(), transactionProcessingResult, ws, currentGasUsed); - receipts.add(transactionReceipt); - } else { - return new BlockSimulationResult( - new BlockProcessingResult( - Optional.empty(), - transactionProcessingResult - .getInvalidReason() - .orElse("Transaction processing failed"))); - } + private BlockSimulationResult.BlockTransactionSimulationResult processTransactions( + final BlockHeader blockHeader, + final BlockStateCall blockStateCall, + final WorldUpdater updater, + final boolean shouldValidate, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator) { + BlockSimulationResult.BlockTransactionSimulationResult blockTransactionSimulationResult = + new BlockSimulationResult.BlockTransactionSimulationResult(); + + for (CallParameter callParameter : blockStateCall.getCalls()) { + final WorldUpdater localUpdater = updater.updater(); + final Optional transactionSimulatorResult = + transactionSimulator.processWithWorldUpdater( + callParameter, + Optional.empty(), + buildTransactionValidationParams(shouldValidate), + OperationTracer.NO_TRACING, + blockHeader, + localUpdater, + miningBeneficiaryCalculator); + + if (transactionSimulatorResult.isEmpty()) { + throw new RuntimeException("Transaction simulator result is empty"); } - updater.commit(); - BlockHeader finalBlockHeader = - createFinalBlockHeader( - blockHeader, ws, transactions, blockOverrides, receipts, currentGasUsed); + blockTransactionSimulationResult.add(transactionSimulatorResult.get()); + + TransactionProcessingResult transactionProcessingResult = + transactionSimulatorResult.get().result(); - if (shouldPersist) { - ws.persist(finalBlockHeader); + if (transactionProcessingResult.isSuccessful()) { + localUpdater.commit(); } - Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); - BlockProcessingOutputs outputs = new BlockProcessingOutputs(ws, receipts); - BlockProcessingResult result = new BlockProcessingResult(Optional.of(outputs)); - return new BlockSimulationResult(block.getHeader(), block.getBody(), receipts, result); + } + return blockTransactionSimulationResult; + } - } catch (final Exception e) { - throw new RuntimeException("Error simulating block", e); + private BlockSimulationResult processPostExecution( + final BlockHeader blockHeader, + final MutableWorldState ws, + final BlockSimulationResult.BlockTransactionSimulationResult blockTransactionSimulationResult, + final BlockOverrides blockOverrides, + final ProtocolSpec newProtocolSpec, + final boolean shouldPersist) { + + long currentGasUsed = 0; + final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); + final List receipts = new ArrayList<>(); + final List transactions = new ArrayList<>(); + + for (TransactionSimulatorResult transactionSimulatorResult : + blockTransactionSimulationResult.getCalls()) { + TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); + + if (transactionProcessingResult.isSuccessful()) { + final Transaction transaction = transactionSimulatorResult.transaction(); + + currentGasUsed += transactionProcessingResult.getEstimateGasUsedByTransaction(); + + final TransactionReceipt transactionReceipt = + transactionReceiptFactory.create( + transaction.getType(), transactionProcessingResult, ws, currentGasUsed); + receipts.add(transactionReceipt); + transactions.add(transaction); + } + } + + BlockHeader finalBlockHeader = + createFinalBlockHeader( + blockHeader, ws, transactions, blockOverrides, receipts, currentGasUsed); + + Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); + + if (shouldPersist) { + ws.persist(finalBlockHeader); } + return BlockSimulationResult.successful(block, receipts, blockTransactionSimulationResult); } private void applyStateOverrides( - final AccountOverrideMap accountOverrideMap, WorldUpdater updater) { + final AccountOverrideMap accountOverrideMap, final WorldUpdater updater) { for (Address accountToOverride : accountOverrideMap.keySet()) { final AccountOverride override = accountOverrideMap.get(accountToOverride); MutableAccount account = updater.getOrCreate(accountToOverride); diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java index d5bdb224607..4fc6a65fdb3 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -14,13 +14,8 @@ */ package org.hyperledger.besu.plugin.data; -import java.util.List; -import java.util.Optional; - public interface BlockSimulationResult { - Optional getBlockHeader(); - - Optional getBlockBody(); + BlockHeader getBlockHeader(); - Optional> getReceipts(); + BlockBody getBlockBody(); } From 572244ad8f3318a34d07e96c8ff49498ba4cc584 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 15:47:58 +1100 Subject: [PATCH 11/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../jsonrpc/internal/parameters/BlockStateCallsParameter.java | 2 -- .../besu/ethereum/transaction/BlockSimulationResult.java | 3 ++- .../hyperledger/besu/plugin/data/BlockSimulationResult.java | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java index fc9c5e9d38c..3d9493e84be 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java @@ -29,8 +29,6 @@ public class BlockStateCallsParameter { @JsonProperty("traceTransfers") private boolean traceTransfers; - // Getters - public List getBlockStateCalls() { return blockStateCalls; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 8ce0b3c3089..f777e3bc7d3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -58,7 +58,8 @@ public Block getBlock() { return block; } - public List getTransactionReceipts() { + @Override + public List getReceipts() { return receipts; } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java index 4fc6a65fdb3..964d35b5119 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -14,8 +14,12 @@ */ package org.hyperledger.besu.plugin.data; +import java.util.List; + public interface BlockSimulationResult { BlockHeader getBlockHeader(); BlockBody getBlockBody(); + + List getReceipts(); } From 91d9645e391703f8bbb5191757ed990190cc0834 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 25 Nov 2024 23:28:54 +1100 Subject: [PATCH 12/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 18 +++- .../internal/methods/EthSimulateV1.java | 3 +- .../parameters/JsonBlockStateCall.java | 5 +- .../transaction/BlockSimulationResult.java | 43 ++------- .../ethereum/transaction/BlockSimulator.java | 96 +++++++------------ .../ethereum/transaction/BlockStateCall.java | 10 +- .../plugin/data/BlockSimulationResult.java | 21 +++- 7 files changed, 88 insertions(+), 108 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 122ea61f0e7..34794a654a3 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -20,12 +20,13 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; import org.hyperledger.besu.ethereum.transaction.BlockStateCall; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.data.BlockHeader; +import org.hyperledger.besu.plugin.data.BlockSimulationResult; +import org.hyperledger.besu.plugin.data.TransactionSimulationResult; import org.hyperledger.besu.plugin.services.BlockSimulationService; import java.util.List; @@ -64,10 +65,19 @@ public BlockSimulationResult simulate( transactions.stream().map(CallParameter::fromTransaction).toList(); BlockStateCall blockStateCall = - new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap()); + new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap(), true); - var result = blockSimulator.simulate(parentHeaderCore, blockStateCall, true, shouldPersist); + var result = blockSimulator.simulate(parentHeaderCore, blockStateCall); - return result.orElseThrow(); + if (result.isEmpty()) { + throw new RuntimeException("Block simulation failed"); + } + return new BlockSimulationResult( + result.get().getBlockHeader(), + result.get().getTransactionSimulations().stream() + .map( + simulation -> + new TransactionSimulationResult(simulation.transaction(), simulation.result())) + .toList()); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index 551062e9e95..f3b0684305c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -100,8 +100,7 @@ protected Object resultByBlockHeader( List results = new ArrayList<>(); for (var blockStateCall : parameter.getBlockStateCalls()) { - var result = - blockSimulator.simulate(header, blockStateCall, parameter.isValidation(), false); + var result = blockSimulator.simulate(header, blockStateCall); results.add( result diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java index 0dc55ebfa07..e18178fba50 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java @@ -30,7 +30,8 @@ public class JsonBlockStateCall extends BlockStateCall { public JsonBlockStateCall( @JsonProperty("calls") final List calls, @JsonProperty("blockOverrides") final BlockOverrides blockOverrides, - @JsonProperty("stateOverrides") final AccountOverrideMap stateOverrides) { - super(calls, blockOverrides, stateOverrides); + @JsonProperty("stateOverrides") final AccountOverrideMap stateOverrides, + @JsonProperty("validation") final boolean validation) { + super(calls, blockOverrides, stateOverrides, validation); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index f777e3bc7d3..b8f9a79b196 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -22,60 +22,37 @@ import java.util.ArrayList; import java.util.List; -public class BlockSimulationResult - implements org.hyperledger.besu.plugin.data.BlockSimulationResult { +public class BlockSimulationResult { final Block block; - final BlockTransactionSimulationResult blockTransactionSimulationResult; final List receipts; + List transactionSimulations = new ArrayList<>(); - private BlockSimulationResult( + public BlockSimulationResult( final Block block, final List receipts, - final BlockTransactionSimulationResult blockTransactionSimulationResult) { + final List transactionSimulations) { this.block = block; this.receipts = new ArrayList<>(receipts); - this.blockTransactionSimulationResult = blockTransactionSimulationResult; + this.transactionSimulations = transactionSimulations; } - public static BlockSimulationResult successful( - final Block block, - final List receipts, - final BlockTransactionSimulationResult blockTransactionSimulationResult) { - return new BlockSimulationResult(block, receipts, blockTransactionSimulationResult); - } - - @Override public BlockHeader getBlockHeader() { return block.getHeader(); } - @Override public BlockBody getBlockBody() { return block.getBody(); } - public Block getBlock() { - return block; - } - - @Override - public List getReceipts() { + public List getReceipts() { return receipts; } - public BlockTransactionSimulationResult getBlockTransactionSimulationResult() { - return blockTransactionSimulationResult; + public List getTransactionSimulations() { + return transactionSimulations; } - public static class BlockTransactionSimulationResult { - List calls = new ArrayList<>(); - - void add(final TransactionSimulatorResult callResult) { - calls.add(callResult); - } - - List getCalls() { - return calls; - } + public Block getBlock() { + return block; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index b820fd5ab5c..e0ca49f66fd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -78,63 +78,50 @@ public BlockSimulator( } public Optional simulate( - final BlockHeader header, - final BlockStateCall blockStateCall, - final boolean shouldValidate, - final boolean shouldPersist) { + final BlockHeader header, final BlockStateCall blockStateCall) { - final BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); - long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); - final ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); + try (final MutableWorldState ws = getWorldState(header)) { - final BlockHeader blockHeader = - applyBlockHeaderOverrides(header, blockOverrides, newProtocolSpec); + WorldUpdater updater = ws.updater(); + final BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); + long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); + final ProtocolSpec newProtocolSpec = + protocolSchedule.getForNextBlockHeader(header, timestamp); - final MiningBeneficiaryCalculator miningBeneficiaryCalculator = - getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); + final BlockHeader blockHeader = + applyBlockHeaderOverrides(header, blockOverrides, newProtocolSpec); - try (final MutableWorldState ws = getWorldState(header, shouldPersist)) { - WorldUpdater updater = ws.updater(); + final MiningBeneficiaryCalculator miningBeneficiaryCalculator = + getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); if (blockStateCall.getAccountOverrides().isPresent()) { applyStateOverrides(blockStateCall.getAccountOverrides().get(), updater); } - BlockSimulationResult.BlockTransactionSimulationResult blockTransactionSimulationResult = - processTransactions( - blockHeader, blockStateCall, updater, shouldValidate, miningBeneficiaryCalculator); - + List transactionSimulatorResults = + processTransactions(blockHeader, blockStateCall, updater, miningBeneficiaryCalculator); updater.commit(); return Optional.of( processPostExecution( - blockHeader, - ws, - blockTransactionSimulationResult, - blockOverrides, - newProtocolSpec, - shouldPersist)); - + blockHeader, ws, transactionSimulatorResults, blockOverrides, newProtocolSpec)); } catch (final Exception e) { - return Optional.empty(); + throw new RuntimeException("Error simulating block", e); } } - private BlockSimulationResult.BlockTransactionSimulationResult processTransactions( + private List processTransactions( final BlockHeader blockHeader, final BlockStateCall blockStateCall, final WorldUpdater updater, - final boolean shouldValidate, final MiningBeneficiaryCalculator miningBeneficiaryCalculator) { - BlockSimulationResult.BlockTransactionSimulationResult blockTransactionSimulationResult = - new BlockSimulationResult.BlockTransactionSimulationResult(); - + List transactionSimulations = new ArrayList<>(); for (CallParameter callParameter : blockStateCall.getCalls()) { final WorldUpdater localUpdater = updater.updater(); final Optional transactionSimulatorResult = transactionSimulator.processWithWorldUpdater( callParameter, Optional.empty(), - buildTransactionValidationParams(shouldValidate), + buildTransactionValidationParams(blockStateCall.isValidate()), OperationTracer.NO_TRACING, blockHeader, localUpdater, @@ -143,9 +130,7 @@ private BlockSimulationResult.BlockTransactionSimulationResult processTransactio if (transactionSimulatorResult.isEmpty()) { throw new RuntimeException("Transaction simulator result is empty"); } - - blockTransactionSimulationResult.add(transactionSimulatorResult.get()); - + transactionSimulations.add(transactionSimulatorResult.get()); TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.get().result(); @@ -153,31 +138,27 @@ private BlockSimulationResult.BlockTransactionSimulationResult processTransactio localUpdater.commit(); } } - return blockTransactionSimulationResult; + return transactionSimulations; } private BlockSimulationResult processPostExecution( final BlockHeader blockHeader, final MutableWorldState ws, - final BlockSimulationResult.BlockTransactionSimulationResult blockTransactionSimulationResult, + final List transactionSimulations, final BlockOverrides blockOverrides, - final ProtocolSpec newProtocolSpec, - final boolean shouldPersist) { + final ProtocolSpec newProtocolSpec) { long currentGasUsed = 0; final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); final List receipts = new ArrayList<>(); final List transactions = new ArrayList<>(); - for (TransactionSimulatorResult transactionSimulatorResult : - blockTransactionSimulationResult.getCalls()) { + for (TransactionSimulatorResult transactionSimulatorResult : transactionSimulations) { TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); if (transactionProcessingResult.isSuccessful()) { final Transaction transaction = transactionSimulatorResult.transaction(); - - currentGasUsed += transactionProcessingResult.getEstimateGasUsedByTransaction(); - + currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining(); final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( transaction.getType(), transactionProcessingResult, ws, currentGasUsed); @@ -191,11 +172,7 @@ private BlockSimulationResult processPostExecution( blockHeader, ws, transactions, blockOverrides, receipts, currentGasUsed); Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); - - if (shouldPersist) { - ws.persist(finalBlockHeader); - } - return BlockSimulationResult.successful(block, receipts, blockTransactionSimulationResult); + return new BlockSimulationResult(block, receipts, transactionSimulations); } private void applyStateOverrides( @@ -230,7 +207,10 @@ private BlockHeader applyBlockHeaderOverrides( .parentHash(header.getHash()) .coinbase(blockOverrides.getFeeRecipient().orElse(coinbaseSupplier.get().orElseThrow())) .difficulty( - Difficulty.of(getNextDifficulty(blockOverrides, newProtocolSpec, header, timestamp))) + Difficulty.of( + blockOverrides + .getDifficulty() + .orElse(getNextDifficulty(newProtocolSpec, header, timestamp)))) .number(blockNumber) .gasLimit( blockOverrides @@ -269,9 +249,9 @@ private BlockHeader createFinalBlockHeader( .buildBlockHeader(); } - private MutableWorldState getWorldState(final BlockHeader header, final boolean shouldPersist) { + private MutableWorldState getWorldState(final BlockHeader header) { return worldStateArchive - .getMutable(header, shouldPersist) + .getMutable(header, false) .orElseThrow( () -> new IllegalArgumentException( @@ -304,17 +284,9 @@ private long getNextGasLimit( } private BigInteger getNextDifficulty( - final BlockOverrides blockOverrides, - final ProtocolSpec protocolSpec, - final BlockHeader parentHeader, - final long timestamp) { - - if (blockOverrides.getDifficulty().isPresent()) { - return blockOverrides.getDifficulty().get(); - } else { - final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); - return difficultyCalculator.nextDifficulty(timestamp, parentHeader); - } + final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long timestamp) { + final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); + return difficultyCalculator.nextDifficulty(timestamp, parentHeader); } private MiningBeneficiaryCalculator getMiningBeneficiaryCalculator( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java index b28287fa80a..0ea8dc6cc9f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java @@ -29,14 +29,22 @@ public class BlockStateCall { private final AccountOverrideMap accountOverrides; + private final boolean validation; + public BlockStateCall( final List calls, final BlockOverrides blockOverrides, - final AccountOverrideMap accountOverrides) { + final AccountOverrideMap accountOverrides, + final boolean validation) { this.calls = calls != null ? calls : new ArrayList<>(); this.blockOverrides = blockOverrides != null ? blockOverrides : BlockOverrides.builder().build(); this.accountOverrides = accountOverrides; + this.validation = validation; + } + + public boolean isValidate() { + return validation; } public BlockOverrides getBlockOverrides() { diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java index 964d35b5119..2934cf83398 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -16,10 +16,23 @@ import java.util.List; -public interface BlockSimulationResult { - BlockHeader getBlockHeader(); +public class BlockSimulationResult { - BlockBody getBlockBody(); + final BlockHeader blockHeader; + final List transactionSimulationResults; - List getReceipts(); + public BlockSimulationResult( + final BlockHeader blockHeader, + final List transactionSimulationResults) { + this.blockHeader = blockHeader; + this.transactionSimulationResults = transactionSimulationResults; + } + + public BlockHeader getBlockHeader() { + return blockHeader; + } + + public List getTransactionSimulationResults() { + return transactionSimulationResults; + } } From 2615eb594c03cfe6d295c3db55fb59227af6b78b Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 11:15:31 +1100 Subject: [PATCH 13/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../hyperledger/besu/services/BlockSimulatorServiceImpl.java | 2 +- .../ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java | 2 +- .../besu/ethereum/transaction/BlockSimulationResult.java | 2 +- .../hyperledger/besu/ethereum/transaction/BlockSimulator.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 34794a654a3..af8b24beef7 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -67,7 +67,7 @@ public BlockSimulationResult simulate( BlockStateCall blockStateCall = new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap(), true); - var result = blockSimulator.simulate(parentHeaderCore, blockStateCall); + var result = blockSimulator.process(parentHeaderCore, blockStateCall); if (result.isEmpty()) { throw new RuntimeException("Block simulation failed"); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index f3b0684305c..3f90a2e1228 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -100,7 +100,7 @@ protected Object resultByBlockHeader( List results = new ArrayList<>(); for (var blockStateCall : parameter.getBlockStateCalls()) { - var result = blockSimulator.simulate(header, blockStateCall); + var result = blockSimulator.process(header, blockStateCall); results.add( result diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index b8f9a79b196..5cebf1128ad 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -25,7 +25,7 @@ public class BlockSimulationResult { final Block block; final List receipts; - List transactionSimulations = new ArrayList<>(); + List transactionSimulations; public BlockSimulationResult( final Block block, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index e0ca49f66fd..7d44faf61bd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -77,7 +77,7 @@ public BlockSimulator( new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, rpcGasCap); } - public Optional simulate( + public Optional process( final BlockHeader header, final BlockStateCall blockStateCall) { try (final MutableWorldState ws = getWorldState(header)) { From 612ffc94e15bc3d243ada1f3821b7af06cc6dc4b Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 12:08:25 +1100 Subject: [PATCH 14/38] Refactor code Signed-off-by: Gabriel-Trintinalia --- .../internal/methods/EthSimulateV1.java | 30 +-- .../ethereum/transaction/BlockSimulator.java | 173 ++++++++++++------ 2 files changed, 131 insertions(+), 72 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index 3f90a2e1228..58700688e2e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -27,7 +27,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; @@ -39,7 +38,6 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; -import java.util.ArrayList; import java.util.List; public class EthSimulateV1 extends AbstractBlockParameterOrBlockHashMethod { @@ -98,19 +96,14 @@ protected Object resultByBlockHeader( BlockStateCallsParameter parameter = request.getRequiredParameter(0, BlockStateCallsParameter.class); - List results = new ArrayList<>(); - for (var blockStateCall : parameter.getBlockStateCalls()) { - var result = blockSimulator.process(header, blockStateCall); - - results.add( - result - .map( - blockSimulationResult -> - blockResultFactory.transactionHash( - blockByHashWithTxHashes(blockSimulationResult.getBlock()))) - .orElse(null)); - } - return new JsonRpcSuccessResponse(request.getRequest().getId(), results); + var response = + blockSimulator.process(header, parameter.getBlockStateCalls()).stream() + .map( + blockSimulationResult -> + blockResultFactory.transactionHash( + blockByHashWithTxHashes(blockSimulationResult.getBlock()))); + + return new JsonRpcSuccessResponse(request.getRequest().getId(), response); } catch (JsonRpcParameterException e) { throw new RuntimeException(e); } @@ -118,12 +111,7 @@ protected Object resultByBlockHeader( private JsonRpcErrorResponse errorResponse( final JsonRpcRequestContext request, final RpcErrorType rpcErrorType) { - return errorResponse(request, new JsonRpcError(rpcErrorType)); - } - - private JsonRpcErrorResponse errorResponse( - final JsonRpcRequestContext request, final JsonRpcError jsonRpcError) { - return new JsonRpcErrorResponse(request.getRequest().getId(), jsonRpcError); + return new JsonRpcErrorResponse(request.getRequest().getId(), new JsonRpcError(rpcErrorType)); } public BlockWithMetadata blockByHashWithTxHashes(final Block block) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 7d44faf61bd..822fdb7d798 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; +import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.DifficultyCalculator; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; @@ -54,6 +55,10 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; +/** + * BlockSimulator is responsible for simulating the execution of a block. It processes transactions + * and applies state overrides to simulate the block execution. + */ public class BlockSimulator { private final TransactionSimulator transactionSimulator; private final WorldStateArchive worldStateArchive; @@ -77,36 +82,66 @@ public BlockSimulator( new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, rpcGasCap); } + public List process( + final BlockHeader header, final List blockStateCalls) { + try (final MutableWorldState ws = getWorldState(header)) { + return processWithMutableWorldState(header, blockStateCalls, ws); + } catch (final Exception e) { + throw new RuntimeException("Error simulating block", e); + } + } + public Optional process( final BlockHeader header, final BlockStateCall blockStateCall) { - try (final MutableWorldState ws = getWorldState(header)) { + return Optional.of(processWithMutableWorldState(header, blockStateCall, ws)); + } catch (final Exception e) { + throw new RuntimeException("Error simulating block", e); + } + } + + /** + * Processes a list of BlockStateCalls sequentially, collecting the results. + * + * @param header The block header for all simulations. + * @param blockStateCalls The list of BlockStateCalls to process. + * @param worldState The initial MutableWorldState to start with. + * @return A list of BlockSimulationResult objects from processing each BlockStateCall. + */ + private List processWithMutableWorldState( + final BlockHeader header, + final List blockStateCalls, + final MutableWorldState worldState) { + List simulationResults = new ArrayList<>(); + for (BlockStateCall blockStateCall : blockStateCalls) { + BlockSimulationResult simulationResult = + processWithMutableWorldState(header, blockStateCall, worldState); + simulationResults.add(simulationResult); + } + return simulationResults; + } - WorldUpdater updater = ws.updater(); - final BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); - long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); - final ProtocolSpec newProtocolSpec = - protocolSchedule.getForNextBlockHeader(header, timestamp); + protected BlockSimulationResult processWithMutableWorldState( + final BlockHeader header, final BlockStateCall blockStateCall, final MutableWorldState ws) { + WorldUpdater updater = ws.updater(); + BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); + long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); + ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); - final BlockHeader blockHeader = - applyBlockHeaderOverrides(header, blockOverrides, newProtocolSpec); + BlockHeader blockHeader = applyBlockHeaderOverrides(header, newProtocolSpec, blockOverrides); + blockStateCall + .getAccountOverrides() + .ifPresent(overrides -> applyStateOverrides(overrides, updater)); - final MiningBeneficiaryCalculator miningBeneficiaryCalculator = - getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); + MiningBeneficiaryCalculator miningBeneficiaryCalculator = + getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); - if (blockStateCall.getAccountOverrides().isPresent()) { - applyStateOverrides(blockStateCall.getAccountOverrides().get(), updater); - } - List transactionSimulatorResults = - processTransactions(blockHeader, blockStateCall, updater, miningBeneficiaryCalculator); - updater.commit(); + List transactionSimulatorResults = + processTransactions(blockHeader, blockStateCall, updater, miningBeneficiaryCalculator); + updater.commit(); - return Optional.of( - processPostExecution( - blockHeader, ws, transactionSimulatorResults, blockOverrides, newProtocolSpec)); - } catch (final Exception e) { - throw new RuntimeException("Error simulating block", e); - } + return processPostExecution( + blockHeader, ws, transactionSimulatorResults, blockOverrides, newProtocolSpec); } private List processTransactions( @@ -116,29 +151,43 @@ private List processTransactions( final MiningBeneficiaryCalculator miningBeneficiaryCalculator) { List transactionSimulations = new ArrayList<>(); for (CallParameter callParameter : blockStateCall.getCalls()) { - final WorldUpdater localUpdater = updater.updater(); - final Optional transactionSimulatorResult = - transactionSimulator.processWithWorldUpdater( + transactionSimulations.add( + processTransaction( callParameter, - Optional.empty(), - buildTransactionValidationParams(blockStateCall.isValidate()), - OperationTracer.NO_TRACING, blockHeader, - localUpdater, - miningBeneficiaryCalculator); + updater, + miningBeneficiaryCalculator, + blockStateCall.isValidate())); + } + return transactionSimulations; + } - if (transactionSimulatorResult.isEmpty()) { - throw new RuntimeException("Transaction simulator result is empty"); - } - transactionSimulations.add(transactionSimulatorResult.get()); - TransactionProcessingResult transactionProcessingResult = - transactionSimulatorResult.get().result(); + private TransactionSimulatorResult processTransaction( + final CallParameter callParameter, + final BlockHeader blockHeader, + final WorldUpdater updater, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator, + final boolean shouldValidate) { + final WorldUpdater localUpdater = updater.updater(); + final Optional transactionSimulatorResult = + transactionSimulator.processWithWorldUpdater( + callParameter, + Optional.empty(), + buildTransactionValidationParams(shouldValidate), + OperationTracer.NO_TRACING, + blockHeader, + localUpdater, + miningBeneficiaryCalculator); + + if (transactionSimulatorResult.isEmpty()) { + throw new RuntimeException("Transaction simulator result is empty"); + } - if (transactionProcessingResult.isSuccessful()) { - localUpdater.commit(); - } + TransactionSimulatorResult result = transactionSimulatorResult.get(); + if (result.result().isSuccessful()) { + localUpdater.commit(); } - return transactionSimulations; + return result; } private BlockSimulationResult processPostExecution( @@ -155,26 +204,48 @@ private BlockSimulationResult processPostExecution( for (TransactionSimulatorResult transactionSimulatorResult : transactionSimulations) { TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); - if (transactionProcessingResult.isSuccessful()) { - final Transaction transaction = transactionSimulatorResult.transaction(); - currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining(); - final TransactionReceipt transactionReceipt = - transactionReceiptFactory.create( - transaction.getType(), transactionProcessingResult, ws, currentGasUsed); - receipts.add(transactionReceipt); - transactions.add(transaction); + processSuccessfulTransaction( + transactionSimulatorResult, + ws, + transactionReceiptFactory, + receipts, + transactions, + currentGasUsed); + currentGasUsed += + transactionSimulatorResult.transaction().getGasLimit() + - transactionProcessingResult.getGasRemaining(); } } BlockHeader finalBlockHeader = createFinalBlockHeader( blockHeader, ws, transactions, blockOverrides, receipts, currentGasUsed); - Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); return new BlockSimulationResult(block, receipts, transactionSimulations); } + private void processSuccessfulTransaction( + final TransactionSimulatorResult transactionSimulatorResult, + final MutableWorldState ws, + final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, + final List receipts, + final List transactions, + final long currentGasUsed) { + TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); + final Transaction transaction = transactionSimulatorResult.transaction(); + final TransactionReceipt transactionReceipt = + transactionReceiptFactory.create( + transaction.getType(), + transactionProcessingResult, + ws, + currentGasUsed + + transaction.getGasLimit() + - transactionProcessingResult.getGasRemaining()); + receipts.add(transactionReceipt); + transactions.add(transaction); + } + private void applyStateOverrides( final AccountOverrideMap accountOverrideMap, final WorldUpdater updater) { for (Address accountToOverride : accountOverrideMap.keySet()) { @@ -198,8 +269,8 @@ private void applyStateOverrides( private BlockHeader applyBlockHeaderOverrides( final BlockHeader header, - final BlockOverrides blockOverrides, - final ProtocolSpec newProtocolSpec) { + final ProtocolSpec newProtocolSpec, + final BlockOverrides blockOverrides) { long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); long blockNumber = blockOverrides.getBlockNumber().orElse(header.getNumber() + 1); From a8260548fdd19a8919f800c3250b914630988cdf Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 12:51:02 +1100 Subject: [PATCH 15/38] Add transaction processing result to output Signed-off-by: Gabriel-Trintinalia --- .../internal/methods/EthSimulateV1.java | 52 ++++++---- .../jsonrpc/internal/results/BlockResult.java | 19 ++++ .../results/TransactionProcessingResult.java | 96 +++++++++++++++++++ .../jsonrpc/methods/EthJsonRpcMethods.java | 6 +- 4 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index 58700688e2e..d6ffa75a554 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -27,8 +27,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory; -import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionHashResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionResult; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -36,22 +38,21 @@ import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; import java.util.List; +import java.util.stream.Collectors; public class EthSimulateV1 extends AbstractBlockParameterOrBlockHashMethod { private final BlockSimulator blockSimulator; - private final BlockResultFactory blockResultFactory; public EthSimulateV1( final BlockchainQueries blockchainQueries, final ProtocolSchedule protocolSchedule, final long rpcGasCap, - final MiningConfiguration miningConfiguration, - final BlockResultFactory blockResultFactory) { + final MiningConfiguration miningConfiguration) { super(blockchainQueries); - this.blockResultFactory = blockResultFactory; this.blockSimulator = new BlockSimulator( @@ -98,10 +99,7 @@ protected Object resultByBlockHeader( var response = blockSimulator.process(header, parameter.getBlockStateCalls()).stream() - .map( - blockSimulationResult -> - blockResultFactory.transactionHash( - blockByHashWithTxHashes(blockSimulationResult.getBlock()))); + .map(this::mapResponse); return new JsonRpcSuccessResponse(request.getRequest().getId(), response); } catch (JsonRpcParameterException e) { @@ -114,16 +112,38 @@ private JsonRpcErrorResponse errorResponse( return new JsonRpcErrorResponse(request.getRequest().getId(), new JsonRpcError(rpcErrorType)); } - public BlockWithMetadata blockByHashWithTxHashes(final Block block) { + public BlockResult mapResponse(final BlockSimulationResult result) { + Block block = result.getBlock(); final int size = block.calculateSize(); final List txs = block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); - final List ommers = - block.getBody().getOmmers().stream().map(BlockHeader::getHash).toList(); - - return new BlockWithMetadata<>( - block.getHeader(), txs, ommers, Difficulty.ZERO, size, block.getBody().getWithdrawals()); + var transactionResults = + result.getTransactionSimulations().stream() + .map( + r -> + new TransactionProcessingResult( + r.result().isSuccessful() ? 1 : 0, + r.result().getOutput(), + r.result().getGasRemaining(), + null, + null)) + .toList(); + + final List transactionHashes = + txs.stream() + .map(Hash::toString) + .map(TransactionHashResult::new) + .collect(Collectors.toList()); + return new BlockResult( + block.getHeader(), + transactionHashes, + List.of(), + transactionResults, + Difficulty.ZERO, + size, + false, + block.getBody().getWithdrawals()); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java index 25e6763edac..b7ec631299e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java @@ -89,6 +89,7 @@ public class BlockResult implements JsonRpcResult { private final String excessBlobGas; private final String parentBeaconBlockRoot; private final String targetBlobCount; + private final List transactionProcessingResults; public BlockResult( final BlockHeader header, @@ -107,6 +108,18 @@ public BlockResult( final int size, final boolean includeCoinbase, final Optional> withdrawals) { + this(header, transactions, ommers, null, totalDifficulty, size, includeCoinbase, withdrawals); + } + + public BlockResult( + final BlockHeader header, + final List transactions, + final List ommers, + final List transactionProcessingResults, + final Difficulty totalDifficulty, + final int size, + final boolean includeCoinbase, + final Optional> withdrawals) { this.number = Quantity.create(header.getNumber()); this.hash = header.getHash().toString(); this.mixHash = header.getMixHash().toString(); @@ -128,6 +141,7 @@ public BlockResult( this.timestamp = Quantity.create(header.getTimestamp()); this.ommers = ommers; this.transactions = transactions; + this.transactionProcessingResults = transactionProcessingResults; this.coinbase = includeCoinbase ? header.getCoinbase().toString() : null; this.withdrawalsRoot = header.getWithdrawalsRoot().map(Hash::toString).orElse(null); this.withdrawals = @@ -282,4 +296,9 @@ public String getParentBeaconBlockRoot() { public String getTargetBlobCount() { return targetBlobCount; } + + @JsonGetter(value = "calls") + public List getTransactionProcessingResults() { + return transactionProcessingResults; + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java new file mode 100644 index 00000000000..37fbb0a2550 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java @@ -0,0 +1,96 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes; + +public class TransactionProcessingResult { + @JsonProperty("status") + private final String status; + + @JsonProperty("returnData") + private final String returnData; + + @JsonProperty("gasUsed") + private final String gasUsed; + + @JsonProperty("error") + private final ErrorDetails error; + + @JsonProperty("logs") + private final List logs; + + public TransactionProcessingResult( + @JsonProperty("status") final int status, + @JsonProperty("returnData") final Bytes returnData, + @JsonProperty("gasUsed") final long gasUsed, + @JsonProperty("error") final ErrorDetails error, + @JsonProperty("logs") final List logs) { + this.status = Quantity.create(status); + ; + this.returnData = returnData.toString(); + ; + this.gasUsed = Quantity.create(gasUsed); + this.error = error; + this.logs = logs; + } + + public String getStatus() { + return status; + } + + public String getReturnData() { + return returnData; + } + + public String getGasUsed() { + return gasUsed; + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + public ErrorDetails getError() { + return error; + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + public List getLogs() { + return logs; + } + + public record ErrorDetails( + @JsonProperty("code") long code, + @JsonProperty("message") String message, + @JsonProperty("data") Bytes data) { + + @Override + public long code() { + return code; + } + + @Override + public String message() { + return message; + } + + @Override + public Bytes data() { + return data; + } + } +} 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 e8fb5f31401..3e21db2e3da 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 @@ -138,11 +138,7 @@ protected Map create() { protocolSchedule, apiConfiguration.getGasCap())), new EthSimulateV1( - blockchainQueries, - protocolSchedule, - apiConfiguration.getGasCap(), - miningConfiguration, - blockResult), + blockchainQueries, protocolSchedule, apiConfiguration.getGasCap(), miningConfiguration), new EthFeeHistory(protocolSchedule, blockchainQueries, miningCoordinator, apiConfiguration), new EthGetCode(blockchainQueries), new EthGetLogs(blockchainQueries, apiConfiguration.getMaxLogsRange()), From aa0d2d9e9f7f8d946a9b7de7af96c7e44a4a3857 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 13:28:57 +1100 Subject: [PATCH 16/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 7 +--- .../internal/methods/EthSimulateV1.java | 34 +++++++------------ .../ethereum/transaction/BlockSimulator.java | 20 +++++------ 3 files changed, 23 insertions(+), 38 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index af8b24beef7..c84611c3841 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -43,12 +43,7 @@ public BlockSimulatorServiceImpl( blockSimulator = new BlockSimulator( - blockchain, - worldStateArchive, - protocolSchedule, - rpcGasCap, - miningConfiguration::getCoinbase, - miningConfiguration::getTargetGasLimit); + blockchain, worldStateArchive, protocolSchedule, rpcGasCap, miningConfiguration); } @Override diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index d6ffa75a554..74942fab410 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -53,15 +53,13 @@ public EthSimulateV1( final long rpcGasCap, final MiningConfiguration miningConfiguration) { super(blockchainQueries); - this.blockSimulator = new BlockSimulator( blockchainQueries.getBlockchain(), blockchainQueries.getWorldStateArchive(), protocolSchedule, rpcGasCap, - miningConfiguration::getCoinbase, - miningConfiguration::getTargetGasLimit); + miningConfiguration); } @Override @@ -82,12 +80,11 @@ protected BlockParameterOrBlockHash blockParameterOrBlockHash( @Override protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) { - final BlockHeader header = blockchainQueries.get().getBlockHeaderByHash(blockHash).orElse(null); - - if (header == null) { - return errorResponse(request, BLOCK_NOT_FOUND); - } - return resultByBlockHeader(request, header); + return blockchainQueries + .get() + .getBlockHeaderByHash(blockHash) + .map(header -> resultByBlockHeader(request, header)) + .orElseGet(() -> errorResponse(request, BLOCK_NOT_FOUND)); } @Override @@ -96,11 +93,10 @@ protected Object resultByBlockHeader( try { BlockStateCallsParameter parameter = request.getRequiredParameter(0, BlockStateCallsParameter.class); - - var response = + List response = blockSimulator.process(header, parameter.getBlockStateCalls()).stream() - .map(this::mapResponse); - + .map(this::convertResponse) + .collect(Collectors.toList()); return new JsonRpcSuccessResponse(request.getRequest().getId(), response); } catch (JsonRpcParameterException e) { throw new RuntimeException(e); @@ -112,13 +108,9 @@ private JsonRpcErrorResponse errorResponse( return new JsonRpcErrorResponse(request.getRequest().getId(), new JsonRpcError(rpcErrorType)); } - public BlockResult mapResponse(final BlockSimulationResult result) { + private BlockResult convertResponse(final BlockSimulationResult result) { Block block = result.getBlock(); - final int size = block.calculateSize(); - - final List txs = - block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); - + var txs = block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); var transactionResults = result.getTransactionSimulations().stream() .map( @@ -131,7 +123,7 @@ public BlockResult mapResponse(final BlockSimulationResult result) { null)) .toList(); - final List transactionHashes = + List transactionHashes = txs.stream() .map(Hash::toString) .map(TransactionHashResult::new) @@ -142,7 +134,7 @@ public BlockResult mapResponse(final BlockSimulationResult result) { List.of(), transactionResults, Difficulty.ZERO, - size, + block.calculateSize(), false, block.getBody().getWithdrawals()); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 822fdb7d798..d21ac87358f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; @@ -49,8 +50,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.OptionalLong; -import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; @@ -63,21 +62,17 @@ public class BlockSimulator { private final TransactionSimulator transactionSimulator; private final WorldStateArchive worldStateArchive; private final ProtocolSchedule protocolSchedule; - - private final Supplier> coinbaseSupplier; - private final Supplier nextGasSupplier; + private final MiningConfiguration miningConfiguration; public BlockSimulator( final Blockchain blockchain, final WorldStateArchive worldStateArchive, final ProtocolSchedule protocolSchedule, final long rpcGasCap, - final Supplier> coinbaseSupplier, - final Supplier nextGasSupplier) { + final MiningConfiguration miningConfiguration) { this.worldStateArchive = worldStateArchive; this.protocolSchedule = protocolSchedule; - this.coinbaseSupplier = coinbaseSupplier; - this.nextGasSupplier = nextGasSupplier; + this.miningConfiguration = miningConfiguration; this.transactionSimulator = new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, rpcGasCap); } @@ -276,7 +271,10 @@ private BlockHeader applyBlockHeaderOverrides( return BlockHeaderBuilder.createDefault() .parentHash(header.getHash()) - .coinbase(blockOverrides.getFeeRecipient().orElse(coinbaseSupplier.get().orElseThrow())) + .coinbase( + blockOverrides + .getFeeRecipient() + .orElse(miningConfiguration.getCoinbase().orElseThrow())) .difficulty( Difficulty.of( blockOverrides @@ -350,7 +348,7 @@ private long getNextGasLimit( .getGasLimitCalculator() .nextGasLimit( parentHeader.getGasLimit(), - nextGasSupplier.get().orElse(parentHeader.getGasLimit()), + miningConfiguration.getTargetGasLimit().orElse(parentHeader.getGasLimit()), blockNumber); } From c6ac81b83f6e815ced73bf6cbf704fe53e5367dd Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 13:49:41 +1100 Subject: [PATCH 17/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 18 ++++++------------ .../ethereum/transaction/BlockSimulator.java | 4 ++-- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index c84611c3841..ad5ca2312ff 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -48,28 +48,22 @@ public BlockSimulatorServiceImpl( @Override public BlockSimulationResult simulate( - final BlockHeader parentHeader, + final BlockHeader header, final List transactions, final BlockOverrides blockOverrides, final boolean shouldPersist) { - org.hyperledger.besu.ethereum.core.BlockHeader parentHeaderCore = - (org.hyperledger.besu.ethereum.core.BlockHeader) parentHeader; - - List callParameters = - transactions.stream().map(CallParameter::fromTransaction).toList(); + var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; + var callParameters = transactions.stream().map(CallParameter::fromTransaction).toList(); BlockStateCall blockStateCall = new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap(), true); - var result = blockSimulator.process(parentHeaderCore, blockStateCall); + var result = blockSimulator.process(headerCore, blockStateCall); - if (result.isEmpty()) { - throw new RuntimeException("Block simulation failed"); - } return new BlockSimulationResult( - result.get().getBlockHeader(), - result.get().getTransactionSimulations().stream() + result.getBlockHeader(), + result.getTransactionSimulations().stream() .map( simulation -> new TransactionSimulationResult(simulation.transaction(), simulation.result())) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index d21ac87358f..d6c034064ac 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -86,10 +86,10 @@ public List process( } } - public Optional process( + public BlockSimulationResult process( final BlockHeader header, final BlockStateCall blockStateCall) { try (final MutableWorldState ws = getWorldState(header)) { - return Optional.of(processWithMutableWorldState(header, blockStateCall, ws)); + return processWithMutableWorldState(header, blockStateCall, ws); } catch (final Exception e) { throw new RuntimeException("Error simulating block", e); } From 10263283d87993b4afbc9914130dfbe8d22920b5 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 14:49:35 +1100 Subject: [PATCH 18/38] Expose rest of body Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 37 ++++++++-- .../transaction/PersistingBlockSimulator.java | 73 +++++++++++++++++++ .../plugin/data/BlockSimulationResult.java | 14 ++++ .../services/BlockSimulationService.java | 6 +- 4 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index ad5ca2312ff..df10117e8b1 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.ethereum.transaction.BlockSimulator; import org.hyperledger.besu.ethereum.transaction.BlockStateCall; import org.hyperledger.besu.ethereum.transaction.CallParameter; +import org.hyperledger.besu.ethereum.transaction.PersistingBlockSimulator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.BlockSimulationResult; @@ -33,6 +34,7 @@ public class BlockSimulatorServiceImpl implements BlockSimulationService { private final BlockSimulator blockSimulator; + private final WorldStateArchive worldStateArchive; public BlockSimulatorServiceImpl( final WorldStateArchive worldStateArchive, @@ -40,29 +42,50 @@ public BlockSimulatorServiceImpl( final MiningConfiguration miningConfiguration, final ProtocolSchedule protocolSchedule, final long rpcGasCap) { - blockSimulator = new BlockSimulator( blockchain, worldStateArchive, protocolSchedule, rpcGasCap, miningConfiguration); + this.worldStateArchive = worldStateArchive; } @Override public BlockSimulationResult simulate( final BlockHeader header, final List transactions, - final BlockOverrides blockOverrides, - final boolean shouldPersist) { + final BlockOverrides blockOverrides) { + BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); + var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; + var result = blockSimulator.process(headerCore, blockStateCall); + return response(result); + } + + @Override + public BlockSimulationResult simulateAndPersist( + final BlockHeader header, + final List transactions, + final BlockOverrides blockOverrides) { + BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; - var callParameters = transactions.stream().map(CallParameter::fromTransaction).toList(); - BlockStateCall blockStateCall = - new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap(), true); + PersistingBlockSimulator persistingBlockSimulator = + new PersistingBlockSimulator(blockSimulator, worldStateArchive); + var result = persistingBlockSimulator.process(headerCore, blockStateCall); + return response(result); + } - var result = blockSimulator.process(headerCore, blockStateCall); + private BlockStateCall createBlockStateCall( + final List transactions, final BlockOverrides blockOverrides) { + var callParameters = transactions.stream().map(CallParameter::fromTransaction).toList(); + return new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap(), true); + } + private BlockSimulationResult response( + final org.hyperledger.besu.ethereum.transaction.BlockSimulationResult result) { return new BlockSimulationResult( result.getBlockHeader(), + result.getBlockBody(), + result.getReceipts(), result.getTransactionSimulations().stream() .map( simulation -> diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java new file mode 100644 index 00000000000..9dc26c63fd4 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java @@ -0,0 +1,73 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.transaction; + +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; + +/** + * BlockSimulator is responsible for simulating the execution of a block. It processes transactions + * and applies state overrides to simulate the block execution. + */ +public class PersistingBlockSimulator { + private final BlockSimulator blockSimulator; + private final WorldStateArchive worldStateArchive; + + /** + * Construct a new PersistingBlockSimulator. + * + * @param blockSimulator The block simulator to use. + * @param worldStateArchive The world state archive to use. + */ + public PersistingBlockSimulator( + final BlockSimulator blockSimulator, final WorldStateArchive worldStateArchive) { + this.blockSimulator = blockSimulator; + this.worldStateArchive = worldStateArchive; + } + + /** + * Process a block with the given header and state call. + * + * @param header The block header to process. + * @param blockStateCall The block state call to use. + * @return The result of processing the block. + */ + public BlockSimulationResult process( + final BlockHeader header, final BlockStateCall blockStateCall) { + try (final MutableWorldState ws = getWorldState(header)) { + var result = blockSimulator.processWithMutableWorldState(header, blockStateCall, ws); + ws.persist(result.getBlock().getHeader()); + return result; + } catch (final Exception e) { + throw new RuntimeException("Error simulating block", e); + } + } + + /** + * Process a block with the given header and state call. + * + * @param header The block header to process. + * @return The result of processing the block. + */ + private MutableWorldState getWorldState(final BlockHeader header) { + return worldStateArchive + .getMutable(header, true) + .orElseThrow( + () -> + new IllegalArgumentException( + "Public world state not available for block " + header.toLogString())); + } +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java index 2934cf83398..fa0acf63cce 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -19,12 +19,18 @@ public class BlockSimulationResult { final BlockHeader blockHeader; + final BlockBody blockBody; + final List receipts; final List transactionSimulationResults; public BlockSimulationResult( final BlockHeader blockHeader, + final BlockBody blockBody, + final List receipts, final List transactionSimulationResults) { this.blockHeader = blockHeader; + this.blockBody = blockBody; + this.receipts = receipts; this.transactionSimulationResults = transactionSimulationResults; } @@ -32,6 +38,14 @@ public BlockHeader getBlockHeader() { return blockHeader; } + public BlockBody getBlockBody() { + return blockBody; + } + + public List getReceipts() { + return receipts; + } + public List getTransactionSimulationResults() { return transactionSimulationResults; } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 9ad4dd530de..4863b0d90f3 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -34,6 +34,8 @@ public interface BlockSimulationService extends BesuService { BlockSimulationResult simulate( final BlockHeader parentHeader, final List transactions, - final BlockOverrides blockOverrides, - final boolean shouldPersist); + final BlockOverrides blockOverrides); + + BlockSimulationResult simulateAndPersist( + BlockHeader header, List transactions, BlockOverrides blockOverrides); } From 638260860771794edca7f544c746c73b32822e0a Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 26 Nov 2024 20:12:24 +1100 Subject: [PATCH 19/38] Simplify code Signed-off-by: Gabriel-Trintinalia --- .../internal/methods/EthSimulateV1.java | 84 +++++++++++-------- .../results/TransactionProcessingResult.java | 3 +- .../ethereum/transaction/BlockSimulator.java | 25 ++---- .../plugin/data/BlockSimulationResult.java | 4 +- 4 files changed, 63 insertions(+), 53 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index 74942fab410..f88b2aad7d7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockStateCallsParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonBlockStateCall; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; @@ -91,51 +92,68 @@ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Ha protected Object resultByBlockHeader( final JsonRpcRequestContext request, final BlockHeader header) { try { - BlockStateCallsParameter parameter = - request.getRequiredParameter(0, BlockStateCallsParameter.class); - List response = - blockSimulator.process(header, parameter.getBlockStateCalls()).stream() - .map(this::convertResponse) - .collect(Collectors.toList()); - return new JsonRpcSuccessResponse(request.getRequest().getId(), response); + + var blockStateCalls = getBlockStateCalls(request); + var simulationResults = blockSimulator.process(header, blockStateCalls); + + var jsonResponse = createResponse(simulationResults, request); + return new JsonRpcSuccessResponse(request.getRequest().getId(), jsonResponse); } catch (JsonRpcParameterException e) { throw new RuntimeException(e); } } + private List getBlockStateCalls(final JsonRpcRequestContext request) + throws JsonRpcParameterException { + BlockStateCallsParameter parameter = + request.getRequiredParameter(0, BlockStateCallsParameter.class); + return parameter.getBlockStateCalls(); + } + private JsonRpcErrorResponse errorResponse( final JsonRpcRequestContext request, final RpcErrorType rpcErrorType) { return new JsonRpcErrorResponse(request.getRequest().getId(), new JsonRpcError(rpcErrorType)); } - private BlockResult convertResponse(final BlockSimulationResult result) { - Block block = result.getBlock(); - var txs = block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); - var transactionResults = - result.getTransactionSimulations().stream() + private JsonRpcSuccessResponse createResponse( + final List simulationResult, final JsonRpcRequestContext request) { + var response = + simulationResult.stream() .map( - r -> - new TransactionProcessingResult( - r.result().isSuccessful() ? 1 : 0, - r.result().getOutput(), - r.result().getGasRemaining(), - null, - null)) + result -> { + Block block = result.getBlock(); + var txs = + block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); + var transactionResults = + result.getTransactionSimulations().stream() + .map(this::createTransactionProcessingResult) + .toList(); + List transactionHashes = + txs.stream() + .map(Hash::toString) + .map(TransactionHashResult::new) + .collect(Collectors.toList()); + return new BlockResult( + block.getHeader(), + transactionHashes, + List.of(), + transactionResults, + Difficulty.ZERO, + block.calculateSize(), + false, + block.getBody().getWithdrawals()); + }) .toList(); + return new JsonRpcSuccessResponse(request.getRequest().getId(), response); + } - List transactionHashes = - txs.stream() - .map(Hash::toString) - .map(TransactionHashResult::new) - .collect(Collectors.toList()); - return new BlockResult( - block.getHeader(), - transactionHashes, - List.of(), - transactionResults, - Difficulty.ZERO, - block.calculateSize(), - false, - block.getBody().getWithdrawals()); + private TransactionProcessingResult createTransactionProcessingResult( + final org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult simulatorResult) { + return new TransactionProcessingResult( + simulatorResult.result().isSuccessful() ? 1 : 0, + simulatorResult.result().getOutput(), + simulatorResult.result().getGasRemaining(), + null, // TODO ADD ERROR + null);// TODO ADD LOG } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java index 37fbb0a2550..b1473f3beef 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java @@ -43,9 +43,8 @@ public TransactionProcessingResult( @JsonProperty("error") final ErrorDetails error, @JsonProperty("logs") final List logs) { this.status = Quantity.create(status); - ; this.returnData = returnData.toString(); - ; + this.gasUsed = Quantity.create(gasUsed); this.error = error; this.logs = logs; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index d6c034064ac..399ec0250ff 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -31,7 +31,6 @@ import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; -import org.hyperledger.besu.ethereum.mainnet.DifficultyCalculator; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; @@ -46,7 +45,6 @@ import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; -import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -179,9 +177,11 @@ private TransactionSimulatorResult processTransaction( } TransactionSimulatorResult result = transactionSimulatorResult.get(); - if (result.result().isSuccessful()) { - localUpdater.commit(); + if (result.result().isInvalid()) { + throw new RuntimeException( + "Transaction simulator result is invalid: " + result.result().getValidationResult()); } + localUpdater.commit(); return result; } @@ -271,21 +271,20 @@ private BlockHeader applyBlockHeaderOverrides( return BlockHeaderBuilder.createDefault() .parentHash(header.getHash()) + .timestamp(timestamp) + .number(blockNumber) .coinbase( blockOverrides .getFeeRecipient() .orElse(miningConfiguration.getCoinbase().orElseThrow())) .difficulty( - Difficulty.of( - blockOverrides - .getDifficulty() - .orElse(getNextDifficulty(newProtocolSpec, header, timestamp)))) - .number(blockNumber) + blockOverrides.getDifficulty().isPresent() + ? Difficulty.of(blockOverrides.getDifficulty().get()) + : header.getDifficulty()) .gasLimit( blockOverrides .getGasLimit() .orElse(getNextGasLimit(newProtocolSpec, header, blockNumber))) - .timestamp(timestamp) .baseFee( blockOverrides .getBaseFeePerGas() @@ -352,12 +351,6 @@ private long getNextGasLimit( blockNumber); } - private BigInteger getNextDifficulty( - final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long timestamp) { - final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); - return difficultyCalculator.nextDifficulty(timestamp, parentHeader); - } - private MiningBeneficiaryCalculator getMiningBeneficiaryCalculator( final BlockOverrides blockOverrides, final ProtocolSpec newProtocolSpec) { if (blockOverrides.getFeeRecipient().isPresent()) { diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java index fa0acf63cce..603aaf53627 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -39,11 +39,11 @@ public BlockHeader getBlockHeader() { } public BlockBody getBlockBody() { - return blockBody; + return blockBody; } public List getReceipts() { - return receipts; + return receipts; } public List getTransactionSimulationResults() { From 46cf54457f911d1a1fb8eda6b4fb30c560ff5ad1 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Wed, 27 Nov 2024 10:23:44 +1100 Subject: [PATCH 20/38] Merge main into branch Signed-off-by: Gabriel-Trintinalia --- plugin-api/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index d504767138d..0717efe4bde 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'PKvPlngg7BfdZ4Jinh0IUsyFOLvNaQU72VD4BHia/WM=' + knownHash = '/xQo+PiE37qGwGqHlNG9LJjVfodGMfudbxMS72F9qjk=' } check.dependsOn('checkAPIChanges') From 9661fedd5e51f50f56bb35bf6647ecfc69e93d2a Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Wed, 27 Nov 2024 16:22:45 +1100 Subject: [PATCH 21/38] Remove PersistingBlockSimulator Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 43 +++++++++-- .../internal/methods/EthSimulateV1.java | 2 +- .../ethereum/transaction/BlockSimulator.java | 2 +- .../transaction/PersistingBlockSimulator.java | 73 ------------------- .../services/BlockSimulationService.java | 19 ++++- 5 files changed, 55 insertions(+), 84 deletions(-) delete mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index df10117e8b1..430556051be 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -19,12 +19,13 @@ import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.MiningConfiguration; +import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; import org.hyperledger.besu.ethereum.transaction.BlockStateCall; import org.hyperledger.besu.ethereum.transaction.CallParameter; -import org.hyperledger.besu.ethereum.transaction.PersistingBlockSimulator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.BlockSimulationResult; import org.hyperledger.besu.plugin.data.TransactionSimulationResult; @@ -48,6 +49,14 @@ public BlockSimulatorServiceImpl( this.worldStateArchive = worldStateArchive; } + /** + * Simulate the creation of a block given header, a list of transactions, and blockOverrides. + * + * @param header the header + * @param transactions the transactions to include in the block + * @param blockOverrides the blockSimulationOverride of the block + * @return the block context + */ @Override public BlockSimulationResult simulate( final BlockHeader header, @@ -60,18 +69,42 @@ public BlockSimulationResult simulate( return response(result); } + /** + * NOTE: This method is experimental and should be used with caution. It may result in database + * inconsistencies if not used properly. Use only in specific scenarios where its behavior is well + * understood. + * + * @param header the block header + * @param transactions the transactions to include in the block + * @param blockOverrides the blockSimulationOverride of the block + * @return the block context + */ + @Unstable @Override public BlockSimulationResult simulateAndPersist( final BlockHeader header, final List transactions, final BlockOverrides blockOverrides) { + BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; + try (final MutableWorldState ws = getWorldState(headerCore)) { + var result = blockSimulator.processWithMutableWorldState(headerCore, blockStateCall, ws); + ws.persist(result.getBlock().getHeader()); + return response(result); + } catch (final Exception e) { + throw new RuntimeException("Error simulating block", e); + } + } - PersistingBlockSimulator persistingBlockSimulator = - new PersistingBlockSimulator(blockSimulator, worldStateArchive); - var result = persistingBlockSimulator.process(headerCore, blockStateCall); - return response(result); + private MutableWorldState getWorldState( + final org.hyperledger.besu.ethereum.core.BlockHeader header) { + return worldStateArchive + .getMutable(header, true) + .orElseThrow( + () -> + new IllegalArgumentException( + "Public world state not available for block " + header.toLogString())); } private BlockStateCall createBlockStateCall( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java index f88b2aad7d7..69bbe1096ee 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java @@ -154,6 +154,6 @@ private TransactionProcessingResult createTransactionProcessingResult( simulatorResult.result().getOutput(), simulatorResult.result().getGasRemaining(), null, // TODO ADD ERROR - null);// TODO ADD LOG + null); // TODO ADD LOG } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 399ec0250ff..782866e9b69 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -114,7 +114,7 @@ private List processWithMutableWorldState( return simulationResults; } - protected BlockSimulationResult processWithMutableWorldState( + public BlockSimulationResult processWithMutableWorldState( final BlockHeader header, final BlockStateCall blockStateCall, final MutableWorldState ws) { WorldUpdater updater = ws.updater(); BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java deleted file mode 100644 index 9dc26c63fd4..00000000000 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/PersistingBlockSimulator.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright contributors to Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.transaction; - -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.MutableWorldState; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; - -/** - * BlockSimulator is responsible for simulating the execution of a block. It processes transactions - * and applies state overrides to simulate the block execution. - */ -public class PersistingBlockSimulator { - private final BlockSimulator blockSimulator; - private final WorldStateArchive worldStateArchive; - - /** - * Construct a new PersistingBlockSimulator. - * - * @param blockSimulator The block simulator to use. - * @param worldStateArchive The world state archive to use. - */ - public PersistingBlockSimulator( - final BlockSimulator blockSimulator, final WorldStateArchive worldStateArchive) { - this.blockSimulator = blockSimulator; - this.worldStateArchive = worldStateArchive; - } - - /** - * Process a block with the given header and state call. - * - * @param header The block header to process. - * @param blockStateCall The block state call to use. - * @return The result of processing the block. - */ - public BlockSimulationResult process( - final BlockHeader header, final BlockStateCall blockStateCall) { - try (final MutableWorldState ws = getWorldState(header)) { - var result = blockSimulator.processWithMutableWorldState(header, blockStateCall, ws); - ws.persist(result.getBlock().getHeader()); - return result; - } catch (final Exception e) { - throw new RuntimeException("Error simulating block", e); - } - } - - /** - * Process a block with the given header and state call. - * - * @param header The block header to process. - * @return The result of processing the block. - */ - private MutableWorldState getWorldState(final BlockHeader header) { - return worldStateArchive - .getMutable(header, true) - .orElseThrow( - () -> - new IllegalArgumentException( - "Public world state not available for block " + header.toLogString())); - } -} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 4863b0d90f3..61e375e9f1a 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.plugin.Unstable; import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.BlockSimulationResult; @@ -23,19 +24,29 @@ public interface BlockSimulationService extends BesuService { /** - * Simulate the creation of a block given a parent header, a list of transactions, and a - * timestamp. + * Simulate the creation of a block given header, a list of transactions, and blockOverrides. * - * @param parentHeader the parent header + * @param header the header * @param transactions the transactions to include in the block * @param blockOverrides the blockSimulationOverride of the block * @return the block context */ BlockSimulationResult simulate( - final BlockHeader parentHeader, + final BlockHeader header, final List transactions, final BlockOverrides blockOverrides); + /** + * NOTE: This method is experimental and should be used with caution. It may result in database + * inconsistencies if not used properly. Use only in specific scenarios where its behavior is well + * understood. + * + * @param header the block header + * @param transactions the transactions to include in the block + * @param blockOverrides the blockSimulationOverride of the block + * @return the block context + */ + @Unstable BlockSimulationResult simulateAndPersist( BlockHeader header, List transactions, BlockOverrides blockOverrides); } From dc9f802bb4e4e7068caf81fa5a48405d2f579569 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 2 Dec 2024 13:31:03 +1100 Subject: [PATCH 22/38] Bug fixes Signed-off-by: Gabriel-Trintinalia --- .../besu/datatypes/BlockOverrides.java | 30 ++- .../ethereum/transaction/BlockSimulator.java | 179 ++++++++---------- .../transaction/TransactionSimulator.java | 21 +- 3 files changed, 121 insertions(+), 109 deletions(-) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java index 20c3c3c7dff..00383d08f7c 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -28,6 +28,7 @@ public class BlockOverrides { private final Optional timestamp; private final Optional blockNumber; + private final Optional blockHash; private final Optional prevRandao; private final Optional gasLimit; private final Optional
feeRecipient; @@ -36,11 +37,13 @@ public class BlockOverrides { private final Optional stateRoot; private final Optional difficulty; private final Optional extraData; + private final Optional mixHashOrPrevRandao; @JsonCreator public BlockOverrides( @JsonProperty("timestamp") final Optional timestamp, @JsonProperty("number") final Optional blockNumber, + @JsonProperty("hash") final Optional blockHash, @JsonProperty("prevRandao") final Optional prevRandao, @JsonProperty("gasLimit") final Optional gasLimit, @JsonProperty("feeRecipient") final Optional
feeRecipient, @@ -48,9 +51,11 @@ public BlockOverrides( @JsonProperty("blobBaseFee") final Optional blobBaseFee, @JsonProperty("stateRoot") final Optional stateRoot, @JsonProperty("difficult") final Optional difficulty, - @JsonProperty("extraData") final Optional extraData) { + @JsonProperty("extraData") final Optional extraData, + @JsonProperty("mixHashOrPrevRandao") final Optional mixHashOrPrevRandao) { this.timestamp = timestamp.map(UnsignedLongParameter::getValue); this.blockNumber = blockNumber.map(UnsignedLongParameter::getValue); + this.blockHash = blockHash; this.prevRandao = prevRandao; this.gasLimit = gasLimit.map(UnsignedLongParameter::getValue); this.feeRecipient = feeRecipient; @@ -59,10 +64,12 @@ public BlockOverrides( this.stateRoot = stateRoot; this.difficulty = difficulty; this.extraData = extraData; + this.mixHashOrPrevRandao = mixHashOrPrevRandao; } private BlockOverrides(final Builder builder) { this.blockNumber = Optional.ofNullable(builder.blockNumber); + this.blockHash = Optional.ofNullable(builder.blockHash); this.prevRandao = Optional.ofNullable(builder.prevRandao); this.timestamp = Optional.ofNullable(builder.timestamp); this.gasLimit = Optional.ofNullable(builder.gasLimit); @@ -72,12 +79,17 @@ private BlockOverrides(final Builder builder) { this.stateRoot = Optional.ofNullable(builder.stateRoot); this.difficulty = Optional.ofNullable(builder.difficulty); this.extraData = Optional.ofNullable(builder.extraData); + this.mixHashOrPrevRandao = Optional.ofNullable(builder.mixHashOrPrevRandao); } public Optional getBlockNumber() { return blockNumber; } + public Optional getBlockHash() { + return blockHash; + } + public Optional getPrevRandao() { return prevRandao; } @@ -114,6 +126,10 @@ public Optional getExtraData() { return extraData; } + public Optional getMixHashOrPrevRandao() { + return mixHashOrPrevRandao; + } + public static Builder builder() { return new Builder(); } @@ -121,6 +137,7 @@ public static Builder builder() { public static class Builder { private Long timestamp; private Long blockNumber; + private Hash blockHash; private Bytes32 prevRandao; private Long gasLimit; private Address feeRecipient; @@ -129,6 +146,7 @@ public static class Builder { private Hash stateRoot; private BigInteger difficulty; private Bytes extraData; + private Hash mixHashOrPrevRandao; public Builder timestamp(final Long timestamp) { this.timestamp = timestamp; @@ -140,6 +158,11 @@ public Builder blockNumber(final Long blockNumber) { return this; } + public Builder blockHash(final Hash blockHash) { + this.blockHash = blockHash; + return this; + } + public Builder prevRandao(final Bytes32 prevRandao) { this.prevRandao = prevRandao; return this; @@ -180,6 +203,11 @@ public Builder extraData(final Bytes extraData) { return this; } + public Builder mixHashOrPrevRandao(final Hash mixHashOrPrevRandao) { + this.mixHashOrPrevRandao = mixHashOrPrevRandao; + return this; + } + public BlockOverrides build() { return new BlockOverrides(this); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 782866e9b69..a32438a376f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -18,18 +18,20 @@ import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.BlockOverrides; +import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; 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.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.ParsedExtraData; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -116,131 +118,85 @@ private List processWithMutableWorldState( public BlockSimulationResult processWithMutableWorldState( final BlockHeader header, final BlockStateCall blockStateCall, final MutableWorldState ws) { - WorldUpdater updater = ws.updater(); BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); + ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); + // Apply block header overrides BlockHeader blockHeader = applyBlockHeaderOverrides(header, newProtocolSpec, blockOverrides); + + // Apply state overrides blockStateCall .getAccountOverrides() - .ifPresent(overrides -> applyStateOverrides(overrides, updater)); + .ifPresent( + overrides -> { + var updater = ws.updater(); + applyStateOverrides(overrides, updater); + updater.commit(); + }); + + long currentGasUsed = 0; + final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); + final List receipts = new ArrayList<>(); + final List transactions = new ArrayList<>(); + List transactionSimulations = new ArrayList<>(); MiningBeneficiaryCalculator miningBeneficiaryCalculator = getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); - List transactionSimulatorResults = - processTransactions(blockHeader, blockStateCall, updater, miningBeneficiaryCalculator); - updater.commit(); - - return processPostExecution( - blockHeader, ws, transactionSimulatorResults, blockOverrides, newProtocolSpec); - } - - private List processTransactions( - final BlockHeader blockHeader, - final BlockStateCall blockStateCall, - final WorldUpdater updater, - final MiningBeneficiaryCalculator miningBeneficiaryCalculator) { - List transactionSimulations = new ArrayList<>(); for (CallParameter callParameter : blockStateCall.getCalls()) { - transactionSimulations.add( - processTransaction( + final WorldUpdater transactionUpdater = ws.updater(); + + final Optional transactionSimulatorResult = + transactionSimulator.processWithWorldUpdater( callParameter, + Optional.empty(), + buildTransactionValidationParams(blockStateCall.isValidate()), + OperationTracer.NO_TRACING, blockHeader, - updater, - miningBeneficiaryCalculator, - blockStateCall.isValidate())); - } - return transactionSimulations; - } + transactionUpdater, + miningBeneficiaryCalculator); - private TransactionSimulatorResult processTransaction( - final CallParameter callParameter, - final BlockHeader blockHeader, - final WorldUpdater updater, - final MiningBeneficiaryCalculator miningBeneficiaryCalculator, - final boolean shouldValidate) { - final WorldUpdater localUpdater = updater.updater(); - final Optional transactionSimulatorResult = - transactionSimulator.processWithWorldUpdater( - callParameter, - Optional.empty(), - buildTransactionValidationParams(shouldValidate), - OperationTracer.NO_TRACING, - blockHeader, - localUpdater, - miningBeneficiaryCalculator); + if (transactionSimulatorResult.isEmpty()) { + throw new RuntimeException("Transaction simulator result is empty"); + } - if (transactionSimulatorResult.isEmpty()) { - throw new RuntimeException("Transaction simulator result is empty"); - } + TransactionSimulatorResult result = transactionSimulatorResult.get(); + if (result.result().isInvalid()) { + throw new RuntimeException( + "Transaction simulator result is invalid: " + result.result().getValidationResult()); + } + transactionSimulations.add(transactionSimulatorResult.get()); - TransactionSimulatorResult result = transactionSimulatorResult.get(); - if (result.result().isInvalid()) { - throw new RuntimeException( - "Transaction simulator result is invalid: " + result.result().getValidationResult()); - } - localUpdater.commit(); - return result; - } + transactionUpdater.commit(); - private BlockSimulationResult processPostExecution( - final BlockHeader blockHeader, - final MutableWorldState ws, - final List transactionSimulations, - final BlockOverrides blockOverrides, - final ProtocolSpec newProtocolSpec) { + TransactionProcessingResult transactionProcessingResult = + transactionSimulatorResult.get().result(); + final Transaction transaction = transactionSimulatorResult.get().transaction(); - long currentGasUsed = 0; - final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); - final List receipts = new ArrayList<>(); - final List transactions = new ArrayList<>(); + currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining(); - for (TransactionSimulatorResult transactionSimulatorResult : transactionSimulations) { - TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); - if (transactionProcessingResult.isSuccessful()) { - processSuccessfulTransaction( - transactionSimulatorResult, - ws, - transactionReceiptFactory, - receipts, - transactions, - currentGasUsed); - currentGasUsed += - transactionSimulatorResult.transaction().getGasLimit() - - transactionProcessingResult.getGasRemaining(); - } + final TransactionReceipt transactionReceipt = + transactionReceiptFactory.create( + transaction.getType(), transactionProcessingResult, ws, currentGasUsed); + + receipts.add(transactionReceipt); + transactions.add(transaction); } BlockHeader finalBlockHeader = createFinalBlockHeader( - blockHeader, ws, transactions, blockOverrides, receipts, currentGasUsed); + blockHeader, + ws, + transactions, + blockStateCall.getBlockOverrides(), + receipts, + currentGasUsed); Block block = new Block(finalBlockHeader, new BlockBody(transactions, List.of())); return new BlockSimulationResult(block, receipts, transactionSimulations); } - private void processSuccessfulTransaction( - final TransactionSimulatorResult transactionSimulatorResult, - final MutableWorldState ws, - final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, - final List receipts, - final List transactions, - final long currentGasUsed) { - TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); - final Transaction transaction = transactionSimulatorResult.transaction(); - final TransactionReceipt transactionReceipt = - transactionReceiptFactory.create( - transaction.getType(), - transactionProcessingResult, - ws, - currentGasUsed - + transaction.getGasLimit() - - transactionProcessingResult.getGasRemaining()); - receipts.add(transactionReceipt); - transactions.add(transaction); - } - private void applyStateOverrides( final AccountOverrideMap accountOverrideMap, final WorldUpdater updater) { for (Address accountToOverride : accountOverrideMap.keySet()) { @@ -289,8 +245,9 @@ private BlockHeader applyBlockHeaderOverrides( blockOverrides .getBaseFeePerGas() .orElse(getNextBaseFee(newProtocolSpec, header, blockNumber))) - .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) + .mixHash(blockOverrides.getMixHashOrPrevRandao().orElse(Hash.EMPTY)) .extraData(blockOverrides.getExtraData().orElse(Bytes.EMPTY)) + .blockHeaderFunctions(new SimulatorBlockHeaderFunctions(blockOverrides)) .buildBlockHeader(); } @@ -312,8 +269,9 @@ private BlockHeader createFinalBlockHeader( .gasUsed(currentGasUsed) .withdrawalsRoot(null) .requestsHash(null) - .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) + .mixHash(blockOverrides.getMixHashOrPrevRandao().orElse(Hash.EMPTY)) .extraData(blockOverrides.getExtraData().orElse(Bytes.EMPTY)) + .blockHeaderFunctions(new SimulatorBlockHeaderFunctions(blockOverrides)) .buildBlockHeader(); } @@ -376,4 +334,25 @@ private Wei getNextBaseFee( .orElse(null); return baseFee; } + + private static class SimulatorBlockHeaderFunctions implements BlockHeaderFunctions { + + private final BlockOverrides blockOverrides; + private final MainnetBlockHeaderFunctions blockHeaderFunctions = + new MainnetBlockHeaderFunctions(); + + private SimulatorBlockHeaderFunctions(final BlockOverrides blockOverrides) { + this.blockOverrides = blockOverrides; + } + + @Override + public Hash hash(final BlockHeader header) { + return blockOverrides.getBlockHash().orElseGet(() -> blockHeaderFunctions.hash(header)); + } + + @Override + public ParsedExtraData parseExtraData(final BlockHeader header) { + return blockHeaderFunctions.parseExtraData(header); + } + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index 6d7b03d5cd4..d07558a28a0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -338,7 +338,6 @@ public Optional processWithWorldUpdater( buildTransaction( callParams, transactionValidationParams, - header, senderAddress, nonce, simulationGasCap, @@ -418,7 +417,6 @@ private long calculateSimulationGasCap( private Optional buildTransaction( final CallParameter callParams, final TransactionValidationParams transactionValidationParams, - final BlockHeader header, final Address senderAddress, final long nonce, final long gasLimit, @@ -455,12 +453,19 @@ private Optional buildTransaction( maxPriorityFeePerGas = callParams.getMaxPriorityFeePerGas().orElse(gasPrice); maxFeePerBlobGas = callParams.getMaxFeePerBlobGas().orElse(blobGasPrice); } - if (header.getBaseFee().isEmpty()) { - transactionBuilder.gasPrice(gasPrice); - } else if (protocolSchedule.getChainId().isPresent()) { - transactionBuilder.maxFeePerGas(maxFeePerGas).maxPriorityFeePerGas(maxPriorityFeePerGas); - } else { - return Optional.empty(); + + if (protocolSchedule.getChainId().isPresent()) { + if (callParams.getMaxPriorityFeePerGas().isEmpty() + && callParams.getMaxFeePerGas().isEmpty()) { + transactionBuilder.gasPrice(gasPrice); + } + } + + if (protocolSchedule.getChainId().isPresent()) { + if (callParams.getMaxPriorityFeePerGas().isPresent() + || callParams.getMaxFeePerGas().isPresent()) { + transactionBuilder.maxFeePerGas(maxFeePerGas).maxPriorityFeePerGas(maxPriorityFeePerGas); + } } transactionBuilder.guessType(); From 7e482e1b3c694fc7008c7aa510afe5f1b14c0b2c Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 9 Dec 2024 13:39:50 +1100 Subject: [PATCH 23/38] Split PR into block simulator and eth_simulate v1 Signed-off-by: Gabriel-Trintinalia --- .../besu/ethereum/api/jsonrpc/RpcMethod.java | 1 - .../internal/methods/EthSimulateV1.java | 159 ------------------ .../jsonrpc/methods/EthJsonRpcMethods.java | 6 - .../methods/JsonRpcMethodsFactory.java | 1 - .../EthSimulateV1JsonRpcHttpBySpecTest.java | 53 ------ .../eth/simulateV1/chain-data/blocks.bin | Bin 23075 -> 0 bytes .../eth/simulateV1/chain-data/genesis.json | 116 ------------- .../eth/simulateV1/specs/eth_simulateV1.json | 72 -------- 8 files changed, 408 deletions(-) delete mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java delete mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java delete mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/blocks.bin delete mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json delete mode 100644 ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index 2768b738820..f8bc597ff7c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -140,7 +140,6 @@ public enum RpcMethod { ETH_SUBMIT_WORK("eth_submitWork"), ETH_SUBSCRIBE("eth_subscribe"), ETH_SYNCING("eth_syncing"), - ETH_SIMULATE_V1("eth_simulateV1"), ETH_UNINSTALL_FILTER("eth_uninstallFilter"), ETH_UNSUBSCRIBE("eth_unsubscribe"), IBFT_DISCARD_VALIDATOR_VOTE("ibft_discardValidatorVote"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java deleted file mode 100644 index 69bbe1096ee..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthSimulateV1.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright contributors to Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; - -import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND; - -import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockStateCallsParameter; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonBlockStateCall; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter.JsonRpcParameterException; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResult; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionHashResult; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionProcessingResult; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.TransactionResult; -import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -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.MiningConfiguration; -import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; -import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; -import org.hyperledger.besu.ethereum.transaction.BlockSimulator; - -import java.util.List; -import java.util.stream.Collectors; - -public class EthSimulateV1 extends AbstractBlockParameterOrBlockHashMethod { - private final BlockSimulator blockSimulator; - - public EthSimulateV1( - final BlockchainQueries blockchainQueries, - final ProtocolSchedule protocolSchedule, - final long rpcGasCap, - final MiningConfiguration miningConfiguration) { - super(blockchainQueries); - this.blockSimulator = - new BlockSimulator( - blockchainQueries.getBlockchain(), - blockchainQueries.getWorldStateArchive(), - protocolSchedule, - rpcGasCap, - miningConfiguration); - } - - @Override - public String getName() { - return RpcMethod.ETH_SIMULATE_V1.getMethodName(); - } - - @Override - protected BlockParameterOrBlockHash blockParameterOrBlockHash( - final JsonRpcRequestContext request) { - try { - return request.getRequiredParameter(1, BlockParameterOrBlockHash.class); - } catch (JsonRpcParameterException e) { - throw new InvalidJsonRpcParameters( - "Invalid block or block hash parameters (index 1)", RpcErrorType.INVALID_BLOCK_PARAMS, e); - } - } - - @Override - protected Object resultByBlockHash(final JsonRpcRequestContext request, final Hash blockHash) { - return blockchainQueries - .get() - .getBlockHeaderByHash(blockHash) - .map(header -> resultByBlockHeader(request, header)) - .orElseGet(() -> errorResponse(request, BLOCK_NOT_FOUND)); - } - - @Override - protected Object resultByBlockHeader( - final JsonRpcRequestContext request, final BlockHeader header) { - try { - - var blockStateCalls = getBlockStateCalls(request); - var simulationResults = blockSimulator.process(header, blockStateCalls); - - var jsonResponse = createResponse(simulationResults, request); - return new JsonRpcSuccessResponse(request.getRequest().getId(), jsonResponse); - } catch (JsonRpcParameterException e) { - throw new RuntimeException(e); - } - } - - private List getBlockStateCalls(final JsonRpcRequestContext request) - throws JsonRpcParameterException { - BlockStateCallsParameter parameter = - request.getRequiredParameter(0, BlockStateCallsParameter.class); - return parameter.getBlockStateCalls(); - } - - private JsonRpcErrorResponse errorResponse( - final JsonRpcRequestContext request, final RpcErrorType rpcErrorType) { - return new JsonRpcErrorResponse(request.getRequest().getId(), new JsonRpcError(rpcErrorType)); - } - - private JsonRpcSuccessResponse createResponse( - final List simulationResult, final JsonRpcRequestContext request) { - var response = - simulationResult.stream() - .map( - result -> { - Block block = result.getBlock(); - var txs = - block.getBody().getTransactions().stream().map(Transaction::getHash).toList(); - var transactionResults = - result.getTransactionSimulations().stream() - .map(this::createTransactionProcessingResult) - .toList(); - List transactionHashes = - txs.stream() - .map(Hash::toString) - .map(TransactionHashResult::new) - .collect(Collectors.toList()); - return new BlockResult( - block.getHeader(), - transactionHashes, - List.of(), - transactionResults, - Difficulty.ZERO, - block.calculateSize(), - false, - block.getBody().getWithdrawals()); - }) - .toList(); - return new JsonRpcSuccessResponse(request.getRequest().getId(), response); - } - - private TransactionProcessingResult createTransactionProcessingResult( - final org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult simulatorResult) { - return new TransactionProcessingResult( - simulatorResult.result().isSuccessful() ? 1 : 0, - simulatorResult.result().getOutput(), - simulatorResult.result().getGasRemaining(), - null, // TODO ADD ERROR - null); // TODO ADD LOG - } -} 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 4b15e8ed11a..46ad62f9f38 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 @@ -60,7 +60,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthProtocolVersion; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendRawTransaction; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSendTransaction; -import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSimulateV1; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSubmitHashRate; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSubmitWork; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthSyncing; @@ -88,7 +87,6 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods { private final ProtocolSchedule protocolSchedule; private final FilterManager filterManager; private final TransactionPool transactionPool; - private final MiningConfiguration miningConfiguration; private final MiningCoordinator miningCoordinator; private final Set supportedCapabilities; private final ApiConfiguration apiConfiguration; @@ -100,7 +98,6 @@ public EthJsonRpcMethods( final ProtocolSchedule protocolSchedule, final FilterManager filterManager, final TransactionPool transactionPool, - final MiningConfiguration miningConfiguration, final MiningCoordinator miningCoordinator, final Set supportedCapabilities, final ApiConfiguration apiConfiguration, @@ -110,7 +107,6 @@ public EthJsonRpcMethods( this.protocolSchedule = protocolSchedule; this.filterManager = filterManager; this.transactionPool = transactionPool; - this.miningConfiguration = miningConfiguration; this.miningCoordinator = miningCoordinator; this.supportedCapabilities = supportedCapabilities; this.apiConfiguration = apiConfiguration; @@ -134,8 +130,6 @@ protected Map create() { new EthGetBlockTransactionCountByNumber(blockchainQueries), new EthGetBlockTransactionCountByHash(blockchainQueries), new EthCall(blockchainQueries, transactionSimulator), - new EthSimulateV1( - blockchainQueries, protocolSchedule, apiConfiguration.getGasCap(), miningConfiguration), new EthFeeHistory(protocolSchedule, blockchainQueries, miningCoordinator, apiConfiguration), new EthGetCode(blockchainQueries), new EthGetLogs(blockchainQueries, apiConfiguration.getMaxLogsRange()), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java index 6ef4e86e1ed..476da3ee304 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java @@ -131,7 +131,6 @@ public Map methods( protocolSchedule, filterManager, transactionPool, - miningConfiguration, miningCoordinator, supportedCapabilities, apiConfiguration, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java deleted file mode 100644 index 52cdb4bd87f..00000000000 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/bonsai/EthSimulateV1JsonRpcHttpBySpecTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.jsonrpc.bonsai; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.hyperledger.besu.ethereum.api.jsonrpc.AbstractJsonRpcHttpBySpecTest; -import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; -import org.hyperledger.besu.plugin.services.storage.DataStorageFormat; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class EthSimulateV1JsonRpcHttpBySpecTest extends AbstractJsonRpcHttpBySpecTest { - - @Override - @BeforeEach - public void setup() throws Exception { - setupBonsaiBlockchain(); - startService(); - } - - @Override - protected BlockchainSetupUtil getBlockchainSetupUtil(final DataStorageFormat dataStorageFormat) { - return createBlockchainSetupUtil( - "eth/simulateV1/chain-data/genesis.json", - "eth/simulateV1/chain-data/blocks.bin", - dataStorageFormat); - } - - public static Object[][] specs() { - return findSpecFiles(new String[] {"eth/simulateV1/specs"}); - } - - @Test - void dryRunDetector() { - assertThat(true) - .withFailMessage("This test is here so gradle --dry-run executes this class") - .isTrue(); - } -} diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/blocks.bin b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/blocks.bin deleted file mode 100644 index 57c416125a98e4d0c3becd849ec4417631f39768..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23075 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 diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json deleted file mode 100644 index 96e91f7111e..00000000000 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/chain-data/genesis.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "config": { - "chainId": 3503995874084926, - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "muirGlacierBlock": 0, - "berlinBlock": 0, - "londonBlock": 0, - "arrowGlacierBlock": 0, - "grayGlacierBlock": 0, - "mergeNetsplitBlock": 0, - "shanghaiTime": 0, - "cancunTime": 0, - "terminalTotalDifficulty": 131072, - "terminalTotalDifficultyPassed": true, - "ethash": {} - }, - "nonce": "0x0", - "timestamp": "0x0", - "extraData": "0x68697665636861696e", - "gasLimit": "0x23f3e20", - "difficulty": "0x20000", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "coinbase": "0x0000000000000000000000000000000000000000", - "alloc": { - "000f3df6d732807ef1319fb7b8bb8522d0beac02": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", - "balance": "0x2a" - }, - "0c2c51a0990aee1d73c1228de158688341557508": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "14e46043e63d0e3cdcf2530519f4cfaf35058cb2": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "16c57edf7fa9d9525378b0b81bf8a3ced0620c1c": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "1f4924b14f34e24159387c0a4cdbaa32f3ddb0cf": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "1f5bde34b4afc686f136c7a3cb6ec376f7357759": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "2d389075be5be9f2246ad654ce152cf05990b209": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "3ae75c08b4c907eb63a8960c45b86e1e9ab6123c": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "4340ee1b812acb40a1eb561c019c327b243b92df": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "4a0f1452281bcec5bd90c3dce6162a5995bfe9df": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "4dde844b71bcdf95512fb4dc94e84fb67b512ed8": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "5f552da00dfb4d3749d9e62dcee3c918855a86a0": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "654aa64f5fbefb84c270ec74211b81ca8c44a72e": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "717f8aa2b982bee0e29f573d31df288663e1ce16": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "7435ed30a8b4aeb0877cef0c6e8cffe834eb865f": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "7dcd17433742f4c0ca53122ab541d0ba67fc27df": { - "code": "0x3680600080376000206000548082558060010160005560005263656d697460206000a2", - "balance": "0x0" - }, - "83c7e323d189f18725ac510004fdc2941f8c4a78": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "84e75c28348fb86acea1a93a39426d7d60f4cc46": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "8bebc8ba651aee624937e7d897853ac30c95a067": { - "storage": { - "0x0000000000000000000000000000000000000000000000000000000000000001": "0x0000000000000000000000000000000000000000000000000000000000000001", - "0x0000000000000000000000000000000000000000000000000000000000000002": "0x0000000000000000000000000000000000000000000000000000000000000002", - "0x0000000000000000000000000000000000000000000000000000000000000003": "0x0000000000000000000000000000000000000000000000000000000000000003" - }, - "balance": "0x1", - "nonce": "0x1" - }, - "c7b99a164efd027a93f147376cc7da7c67c6bbe0": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "d803681e487e6ac18053afc5a6cd813c86ec3e4d": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "e7d13f7aa2a838d24c59b40186a0aca1e21cffcc": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - }, - "eda8645ba6948855e3b3cd596bbb07596d59c603": { - "balance": "0xc097ce7bc90715b34b9f1000000000" - } - }, - "number": "0x0", - "gasUsed": "0x0", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "baseFeePerGas": "0x3b9aca00", - "excessBlobGas": null, - "blobGasUsed": null -} \ No newline at end of file diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json deleted file mode 100644 index 31cd1cff3c7..00000000000 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/simulateV1/specs/eth_simulateV1.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "id": 1, - "method": "eth_simulateV1", - "params": [ - { - "blockStateCalls": [ - { - "stateOverrides": { - "0xc000000000000000000000000000000000000000": { - "balance": "0x3e8" - } - }, - "calls": [ - { - "from": "0xc000000000000000000000000000000000000000", - "to": "0xc100000000000000000000000000000000000000", - "value": "0x3e8" - }, - { - "from": "0xc100000000000000000000000000000000000000", - "to": "0xc200000000000000000000000000000000000000", - "value": "0x3e8" - } - ] - } - ] - }, - "0x3" - ] - }, - "response": { - "jsonrpc": "2.0", - "id": 1, - "result": [ - { - "jsonrpc": "2.0", - "id": 1, - "result": [ - { - "number": "0x4", - "hash": "0x43554dd08fc12190549d7946b63288982fec040efad79dc69c4ef96c7a734375", - "timestamp": "0x1f", - "gasLimit": "0x4c4b40", - "gasUsed": "0xa410", - "feeRecipient": "0x0000000000000000000000000000000000000000", - "baseFeePerGas": "0x2310a91d", - "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", - "calls": [ - { - "returnData": "0x", - "logs": [], - "gasUsed": "0x5208", - "status": "0x1" - }, - { - "returnData": "0x", - "logs": [], - "gasUsed": "0x5208", - "status": "0x1" - } - ] - } - ] - } - ] - }, - "statusCode": 200 -} - - From 3ee61a4d9522c36ed2bf08aa22c44ca0476a6eea Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 9 Dec 2024 14:53:17 +1100 Subject: [PATCH 24/38] Refactoring Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 33 +++++++++---------- .../besu/datatypes/BlockOverrides.java | 27 +-------------- .../ethereum/transaction/BlockSimulator.java | 30 +++++------------ .../services/BlockSimulationService.java | 6 ++-- 4 files changed, 27 insertions(+), 69 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index c42db8610b6..85107bfd662 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -64,14 +64,12 @@ public BlockSimulationResult simulate( BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; - var result = blockSimulator.process(headerCore, blockStateCall); - return response(result); + var result = blockSimulator.process(headerCore, List.of(blockStateCall)); + return response(result.getFirst()); } /** - * NOTE: This method is experimental and should be used with caution. It may result in database - * inconsistencies if not used properly. Use only in specific scenarios where its behavior is well - * understood. + * This method is experimental and should be used with caution * * @param header the block header * @param transactions the transactions to include in the block @@ -80,15 +78,24 @@ public BlockSimulationResult simulate( */ @Unstable @Override - public BlockSimulationResult simulateAndPersist( + public BlockSimulationResult importBlockUnsafe( final BlockHeader header, final List transactions, final BlockOverrides blockOverrides) { BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; - try (final MutableWorldState ws = getWorldState(headerCore)) { - var result = blockSimulator.processWithMutableWorldState(headerCore, blockStateCall, ws); + try (final MutableWorldState ws = + worldStateArchive + .getMutable(headerCore, true) + .orElseThrow( + () -> + new IllegalArgumentException( + "Public world state not available for block " + + headerCore.toLogString()))) { + var results = + blockSimulator.processWithMutableWorldState(headerCore, List.of(blockStateCall), ws); + var result = results.getFirst(); ws.persist(result.getBlock().getHeader()); return response(result); } catch (final Exception e) { @@ -96,16 +103,6 @@ public BlockSimulationResult simulateAndPersist( } } - private MutableWorldState getWorldState( - final org.hyperledger.besu.ethereum.core.BlockHeader header) { - return worldStateArchive - .getMutable(header, true) - .orElseThrow( - () -> - new IllegalArgumentException( - "Public world state not available for block " + header.toLogString())); - } - private BlockStateCall createBlockStateCall( final List transactions, final BlockOverrides blockOverrides) { var callParameters = transactions.stream().map(CallParameter::fromTransaction).toList(); diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java index 00383d08f7c..e884e73ea09 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.datatypes; -import static com.google.common.base.Preconditions.checkArgument; +import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter; import java.math.BigInteger; import java.util.Optional; @@ -23,7 +23,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.checkerframework.checker.signedness.qual.Unsigned; public class BlockOverrides { private final Optional timestamp; @@ -212,28 +211,4 @@ public BlockOverrides build() { return new BlockOverrides(this); } } - - private static class UnsignedLongParameter { - - @Unsigned private final long value; - - @JsonCreator - public UnsignedLongParameter(final String value) { - checkArgument(value != null); - if (value.startsWith("0x")) { - this.value = Long.parseUnsignedLong(value.substring(2), 16); - } else { - this.value = Long.parseUnsignedLong(value, 16); - } - } - - @JsonCreator - public UnsignedLongParameter(final @Unsigned long value) { - this.value = value; - } - - public @Unsigned long getValue() { - return value; - } - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 1cbaab69fd0..4113ddcf1a3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -76,22 +76,19 @@ public BlockSimulator( public List process( final BlockHeader header, final List blockStateCalls) { - try (final MutableWorldState ws = getWorldState(header)) { + try (final MutableWorldState ws = + worldStateArchive + .getMutable(header, false) + .orElseThrow( + () -> + new IllegalArgumentException( + "Public world state not available for block " + header.toLogString()))) { return processWithMutableWorldState(header, blockStateCalls, ws); } catch (final Exception e) { throw new RuntimeException("Error simulating block", e); } } - public BlockSimulationResult process( - final BlockHeader header, final BlockStateCall blockStateCall) { - try (final MutableWorldState ws = getWorldState(header)) { - return processWithMutableWorldState(header, blockStateCall, ws); - } catch (final Exception e) { - throw new RuntimeException("Error simulating block", e); - } - } - /** * Processes a list of BlockStateCalls sequentially, collecting the results. * @@ -100,7 +97,7 @@ public BlockSimulationResult process( * @param worldState The initial MutableWorldState to start with. * @return A list of BlockSimulationResult objects from processing each BlockStateCall. */ - private List processWithMutableWorldState( + public List processWithMutableWorldState( final BlockHeader header, final List blockStateCalls, final MutableWorldState worldState) { @@ -113,7 +110,7 @@ private List processWithMutableWorldState( return simulationResults; } - public BlockSimulationResult processWithMutableWorldState( + private BlockSimulationResult processWithMutableWorldState( final BlockHeader header, final BlockStateCall blockStateCall, final MutableWorldState ws) { BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); @@ -272,15 +269,6 @@ private BlockHeader createFinalBlockHeader( .buildBlockHeader(); } - private MutableWorldState getWorldState(final BlockHeader header) { - return worldStateArchive - .getMutable(header, false) - .orElseThrow( - () -> - new IllegalArgumentException( - "Public world state not available for block " + header.toLogString())); - } - private ImmutableTransactionValidationParams buildTransactionValidationParams( final boolean shouldValidate) { diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 61e375e9f1a..7ecbd7deca2 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -37,9 +37,7 @@ BlockSimulationResult simulate( final BlockOverrides blockOverrides); /** - * NOTE: This method is experimental and should be used with caution. It may result in database - * inconsistencies if not used properly. Use only in specific scenarios where its behavior is well - * understood. + * This method is experimental and should be used with caution * * @param header the block header * @param transactions the transactions to include in the block @@ -47,6 +45,6 @@ BlockSimulationResult simulate( * @return the block context */ @Unstable - BlockSimulationResult simulateAndPersist( + BlockSimulationResult importBlockUnsafe( BlockHeader header, List transactions, BlockOverrides blockOverrides); } From 9f0e6108e2e5f818fac3637956d325c09c4d2a4c Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Mon, 9 Dec 2024 16:30:47 +1100 Subject: [PATCH 25/38] Refactoring Signed-off-by: Gabriel-Trintinalia --- .../ethereum/transaction/BlockSimulator.java | 62 ++++++++++++++++--- .../transaction/TransactionSimulator.java | 25 -------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 4113ddcf1a3..0bfb8727ba3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -74,6 +74,13 @@ public BlockSimulator( this.transactionSimulator = transactionSimulator; } + /** + * Processes a list of BlockStateCalls sequentially, collecting the results. + * + * @param header The block header for all simulations. + * @param blockStateCalls The list of BlockStateCalls to process. + * @return A list of BlockSimulationResult objects from processing each BlockStateCall. + */ public List process( final BlockHeader header, final List blockStateCalls) { try (final MutableWorldState ws = @@ -110,6 +117,14 @@ public List processWithMutableWorldState( return simulationResults; } + /** + * Processes a single BlockStateCall, simulating the block execution. + * + * @param header The block header for the simulation. + * @param blockStateCall The BlockStateCall to process. + * @param ws The MutableWorldState to use for the simulation. + * @return A BlockSimulationResult from processing the BlockStateCall. + */ private BlockSimulationResult processWithMutableWorldState( final BlockHeader header, final BlockStateCall blockStateCall, final MutableWorldState ws) { BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); @@ -121,14 +136,7 @@ private BlockSimulationResult processWithMutableWorldState( BlockHeader blockHeader = applyBlockHeaderOverrides(header, newProtocolSpec, blockOverrides); // Apply state overrides - blockStateCall - .getAccountOverrides() - .ifPresent( - overrides -> { - var updater = ws.updater(); - applyStateOverrides(overrides, updater); - updater.commit(); - }); + blockStateCall.getAccountOverrides().ifPresent(overrides -> applyStateOverrides(overrides, ws)); long currentGasUsed = 0; final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); @@ -145,7 +153,7 @@ private BlockSimulationResult processWithMutableWorldState( final Optional transactionSimulatorResult = transactionSimulator.processWithWorldUpdater( callParameter, - Optional.empty(), + Optional.empty(), // We have already applied state overrides on block level buildTransactionValidationParams(blockStateCall.isValidate()), OperationTracer.NO_TRACING, blockHeader, @@ -191,9 +199,17 @@ private BlockSimulationResult processWithMutableWorldState( return new BlockSimulationResult(block, receipts, transactionSimulations); } + /** + * Applies state overrides to the world state. + * + * @param accountOverrideMap The AccountOverrideMap containing the state overrides. + * @param ws The MutableWorldState to apply the overrides to. + */ private void applyStateOverrides( - final AccountOverrideMap accountOverrideMap, final WorldUpdater updater) { + final AccountOverrideMap accountOverrideMap, final MutableWorldState ws) { + var updater = ws.updater(); for (Address accountToOverride : accountOverrideMap.keySet()) { + final AccountOverride override = accountOverrideMap.get(accountToOverride); MutableAccount account = updater.getOrCreate(accountToOverride); override.getNonce().ifPresent(account::setNonce); @@ -210,8 +226,17 @@ private void applyStateOverrides( account.setStorageValue( UInt256.fromHexString(key), UInt256.fromHexString(value)))); } + updater.commit(); } + /** + * Applies block header overrides to the block header. + * + * @param header The original block header. + * @param newProtocolSpec The ProtocolSpec for the block. + * @param blockOverrides The BlockOverrides to apply. + * @return The modified block header. + */ private BlockHeader applyBlockHeaderOverrides( final BlockHeader header, final ProtocolSpec newProtocolSpec, @@ -245,6 +270,17 @@ private BlockHeader applyBlockHeaderOverrides( .buildBlockHeader(); } + /** + * Creates the final block header after applying state changes and transaction processing. + * + * @param blockHeader The original block header. + * @param ws The MutableWorldState after applying state overrides. + * @param transactions The list of transactions in the block. + * @param blockOverrides The BlockOverrides to apply. + * @param receipts The list of transaction receipts. + * @param currentGasUsed The total gas used in the block. + * @return The final block header. + */ private BlockHeader createFinalBlockHeader( final BlockHeader blockHeader, final MutableWorldState ws, @@ -269,6 +305,12 @@ private BlockHeader createFinalBlockHeader( .buildBlockHeader(); } + /** + * Builds the TransactionValidationParams for the block simulation. + * + * @param shouldValidate Whether to validate transactions. + * @return The TransactionValidationParams for the block simulation. + */ private ImmutableTransactionValidationParams buildTransactionValidationParams( final boolean shouldValidate) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index d3929eb37cb..1a38c02c0b7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -341,31 +341,6 @@ private MutableWorldState getWorldState(final BlockHeader header) { "Public world state not available for block " + header.toLogString())); } - @Nonnull - public Optional processWithWorldUpdater( - final CallParameter callParams, - final Optional maybeStateOverrides, - final TransactionValidationParams transactionValidationParams, - final OperationTracer operationTracer, - final BlockHeader header, - final WorldUpdater updater) { - - Address miningBeneficiary = - protocolSchedule - .getByBlockHeader(header) - .getMiningBeneficiaryCalculator() - .calculateBeneficiary(header); - - return processWithWorldUpdater( - callParams, - maybeStateOverrides, - transactionValidationParams, - operationTracer, - header, - updater, - miningBeneficiary); - } - @Nonnull public Optional processWithWorldUpdater( final CallParameter callParams, From a3c3a202281333d258fd067b519777ce1258bbc6 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 10 Dec 2024 13:24:42 +1100 Subject: [PATCH 26/38] Add tests Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 3 +- .../transaction/BlockSimulationException.java | 11 + .../ethereum/transaction/BlockSimulator.java | 126 +++++--- .../transaction/BlockSimulatorTest.java | 294 ++++++++++++++++++ 4 files changed, 388 insertions(+), 46 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 85107bfd662..4673b9c3588 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -93,8 +93,7 @@ public BlockSimulationResult importBlockUnsafe( new IllegalArgumentException( "Public world state not available for block " + headerCore.toLogString()))) { - var results = - blockSimulator.processWithMutableWorldState(headerCore, List.of(blockStateCall), ws); + var results = blockSimulator.process(headerCore, List.of(blockStateCall), ws); var result = results.getFirst(); ws.persist(result.getBlock().getHeader()); return response(result); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java new file mode 100644 index 00000000000..9874fbd9322 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java @@ -0,0 +1,11 @@ +package org.hyperledger.besu.ethereum.transaction; + +public class BlockSimulationException extends RuntimeException { + public BlockSimulationException(final String message) { + super(message); + } + + public BlockSimulationException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index 0bfb8727ba3..bb30672b224 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -50,12 +50,18 @@ import java.util.List; import java.util.Optional; +import com.google.common.annotations.VisibleForTesting; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; /** - * BlockSimulator is responsible for simulating the execution of a block. It processes transactions - * and applies state overrides to simulate the block execution. + * Simulates the execution of a block, processing transactions and applying state overrides. This + * class is responsible for simulating the execution of a block, which involves processing + * transactions and applying state overrides. It provides a way to test and validate the behavior of + * a block without actually executing it on the blockchain. The simulator takes into account various + * factors, such as the block header, transaction calls, and state overrides, to simulate the + * execution of the block. It returns a list of simulation results, which include the final block + * header, transaction receipts, and other relevant information. */ public class BlockSimulator { private final TransactionSimulator transactionSimulator; @@ -90,7 +96,9 @@ public List process( () -> new IllegalArgumentException( "Public world state not available for block " + header.toLogString()))) { - return processWithMutableWorldState(header, blockStateCalls, ws); + return process(header, blockStateCalls, ws); + } catch (IllegalArgumentException e) { + throw e; } catch (final Exception e) { throw new RuntimeException("Error simulating block", e); } @@ -104,14 +112,14 @@ public List process( * @param worldState The initial MutableWorldState to start with. * @return A list of BlockSimulationResult objects from processing each BlockStateCall. */ - public List processWithMutableWorldState( + public List process( final BlockHeader header, final List blockStateCalls, final MutableWorldState worldState) { List simulationResults = new ArrayList<>(); for (BlockStateCall blockStateCall : blockStateCalls) { BlockSimulationResult simulationResult = - processWithMutableWorldState(header, blockStateCall, worldState); + processSingleBlockStateCall(header, blockStateCall, worldState); simulationResults.add(simulationResult); } return simulationResults; @@ -125,28 +133,37 @@ public List processWithMutableWorldState( * @param ws The MutableWorldState to use for the simulation. * @return A BlockSimulationResult from processing the BlockStateCall. */ - private BlockSimulationResult processWithMutableWorldState( + private BlockSimulationResult processSingleBlockStateCall( final BlockHeader header, final BlockStateCall blockStateCall, final MutableWorldState ws) { BlockOverrides blockOverrides = blockStateCall.getBlockOverrides(); long timestamp = blockOverrides.getTimestamp().orElse(header.getTimestamp() + 1); - ProtocolSpec newProtocolSpec = protocolSchedule.getForNextBlockHeader(header, timestamp); - // Apply block header overrides + // Apply block header overrides and state overrides BlockHeader blockHeader = applyBlockHeaderOverrides(header, newProtocolSpec, blockOverrides); - - // Apply state overrides blockStateCall.getAccountOverrides().ifPresent(overrides -> applyStateOverrides(overrides, ws)); - long currentGasUsed = 0; - final var transactionReceiptFactory = newProtocolSpec.getTransactionReceiptFactory(); - final List receipts = new ArrayList<>(); - final List transactions = new ArrayList<>(); - List transactionSimulations = new ArrayList<>(); - + // Override the mining beneficiary calculator if a fee recipient is specified, otherwise use the + // default MiningBeneficiaryCalculator miningBeneficiaryCalculator = getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec); + List transactionSimulatorResults = + processTransactions(blockHeader, blockStateCall, ws, miningBeneficiaryCalculator); + + return finalizeBlock( + blockHeader, blockStateCall, ws, newProtocolSpec, transactionSimulatorResults); + } + + @VisibleForTesting + protected List processTransactions( + final BlockHeader blockHeader, + final BlockStateCall blockStateCall, + final MutableWorldState ws, + final MiningBeneficiaryCalculator miningBeneficiaryCalculator) { + + List transactionSimulations = new ArrayList<>(); + for (CallParameter callParameter : blockStateCall.getCalls()) { final WorldUpdater transactionUpdater = ws.updater(); @@ -161,21 +178,38 @@ private BlockSimulationResult processWithMutableWorldState( miningBeneficiaryCalculator); if (transactionSimulatorResult.isEmpty()) { - throw new RuntimeException("Transaction simulator result is empty"); + throw new BlockSimulationException("Transaction simulator result is empty"); } TransactionSimulatorResult result = transactionSimulatorResult.get(); - if (result.result().isInvalid()) { - throw new RuntimeException( - "Transaction simulator result is invalid: " + result.result().getValidationResult()); + if (result.isInvalid()) { + throw new BlockSimulationException( + "Transaction simulator result is invalid: " + result.result().getInvalidReason()); } transactionSimulations.add(transactionSimulatorResult.get()); - transactionUpdater.commit(); + } + return transactionSimulations; + } + + @VisibleForTesting + protected BlockSimulationResult finalizeBlock( + final BlockHeader blockHeader, + final BlockStateCall blockStateCall, + final MutableWorldState ws, + final ProtocolSpec protocolSpec, + final List transactionSimulations) { - TransactionProcessingResult transactionProcessingResult = - transactionSimulatorResult.get().result(); - final Transaction transaction = transactionSimulatorResult.get().transaction(); + long currentGasUsed = 0; + final var transactionReceiptFactory = protocolSpec.getTransactionReceiptFactory(); + + final List receipts = new ArrayList<>(); + final List transactions = new ArrayList<>(); + + for (TransactionSimulatorResult transactionSimulatorResult : transactionSimulations) { + + TransactionProcessingResult transactionProcessingResult = transactionSimulatorResult.result(); + final Transaction transaction = transactionSimulatorResult.transaction(); currentGasUsed += transaction.getGasLimit() - transactionProcessingResult.getGasRemaining(); @@ -205,11 +239,11 @@ private BlockSimulationResult processWithMutableWorldState( * @param accountOverrideMap The AccountOverrideMap containing the state overrides. * @param ws The MutableWorldState to apply the overrides to. */ - private void applyStateOverrides( + @VisibleForTesting + protected void applyStateOverrides( final AccountOverrideMap accountOverrideMap, final MutableWorldState ws) { var updater = ws.updater(); for (Address accountToOverride : accountOverrideMap.keySet()) { - final AccountOverride override = accountOverrideMap.get(accountToOverride); MutableAccount account = updater.getOrCreate(accountToOverride); override.getNonce().ifPresent(account::setNonce); @@ -237,7 +271,8 @@ private void applyStateOverrides( * @param blockOverrides The BlockOverrides to apply. * @return The modified block header. */ - private BlockHeader applyBlockHeaderOverrides( + @VisibleForTesting + protected BlockHeader applyBlockHeaderOverrides( final BlockHeader header, final ProtocolSpec newProtocolSpec, final BlockOverrides blockOverrides) { @@ -251,7 +286,7 @@ private BlockHeader applyBlockHeaderOverrides( .coinbase( blockOverrides .getFeeRecipient() - .orElse(miningConfiguration.getCoinbase().orElseThrow())) + .orElseGet(() -> miningConfiguration.getCoinbase().orElseThrow())) .difficulty( blockOverrides.getDifficulty().isPresent() ? Difficulty.of(blockOverrides.getDifficulty().get()) @@ -259,11 +294,11 @@ private BlockHeader applyBlockHeaderOverrides( .gasLimit( blockOverrides .getGasLimit() - .orElse(getNextGasLimit(newProtocolSpec, header, blockNumber))) + .orElseGet(()-> getNextGasLimit(newProtocolSpec, header, blockNumber))) .baseFee( blockOverrides .getBaseFeePerGas() - .orElse(getNextBaseFee(newProtocolSpec, header, blockNumber))) + .orElseGet(()-> getNextBaseFee(newProtocolSpec, header, blockNumber))) .mixHash(blockOverrides.getMixHashOrPrevRandao().orElse(Hash.EMPTY)) .extraData(blockOverrides.getExtraData().orElse(Bytes.EMPTY)) .blockHeaderFunctions(new SimulatorBlockHeaderFunctions(blockOverrides)) @@ -311,7 +346,8 @@ private BlockHeader createFinalBlockHeader( * @param shouldValidate Whether to validate transactions. * @return The TransactionValidationParams for the block simulation. */ - private ImmutableTransactionValidationParams buildTransactionValidationParams( + @VisibleForTesting + ImmutableTransactionValidationParams buildTransactionValidationParams( final boolean shouldValidate) { if (shouldValidate) { @@ -336,6 +372,10 @@ private long getNextGasLimit( blockNumber); } + /** + * Override the mining beneficiary calculator if a fee recipient is specified, otherwise use the + * default + */ private MiningBeneficiaryCalculator getMiningBeneficiaryCalculator( final BlockOverrides blockOverrides, final ProtocolSpec newProtocolSpec) { if (blockOverrides.getFeeRecipient().isPresent()) { @@ -347,19 +387,17 @@ private MiningBeneficiaryCalculator getMiningBeneficiaryCalculator( private Wei getNextBaseFee( final ProtocolSpec protocolSpec, final BlockHeader parentHeader, final long blockNumber) { - final Wei baseFee = - Optional.of(protocolSpec.getFeeMarket()) - .filter(FeeMarket::implementsBaseFee) - .map(BaseFeeMarket.class::cast) - .map( - feeMarket -> - feeMarket.computeBaseFee( - blockNumber, - parentHeader.getBaseFee().orElse(Wei.ZERO), - parentHeader.getGasUsed(), - feeMarket.targetGasUsed(parentHeader))) - .orElse(null); - return baseFee; + return Optional.of(protocolSpec.getFeeMarket()) + .filter(FeeMarket::implementsBaseFee) + .map(BaseFeeMarket.class::cast) + .map( + feeMarket -> + feeMarket.computeBaseFee( + blockNumber, + parentHeader.getBaseFee().orElse(Wei.ZERO), + parentHeader.getGasUsed(), + feeMarket.targetGasUsed(parentHeader))) + .orElse(null); } private static class SimulatorBlockHeaderFunctions implements BlockHeaderFunctions { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java new file mode 100644 index 00000000000..387c839c38a --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java @@ -0,0 +1,294 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.transaction; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.apache.tuweni.bytes.Bytes32; +import org.assertj.core.internal.Diff; +import org.hyperledger.besu.datatypes.AccountOverride; +import org.hyperledger.besu.datatypes.AccountOverrideMap; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.BlockOverrides; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder; +import org.hyperledger.besu.ethereum.core.Difficulty; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; +import org.hyperledger.besu.ethereum.core.MutableWorldState; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; +import org.hyperledger.besu.evm.account.MutableAccount; +import org.hyperledger.besu.evm.tracing.OperationTracer; +import org.hyperledger.besu.evm.worldstate.WorldUpdater; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.units.bigints.UInt256; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@SuppressWarnings("AlmostJavadoc") +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +public class BlockSimulatorTest { + + @Mock private WorldStateArchive worldStateArchive; + @Mock private ProtocolSchedule protocolSchedule; + @Mock private TransactionSimulator transactionSimulator; + @Mock private MiningConfiguration miningConfiguration; + @Mock private MutableWorldState mutableWorldState; + @Mock private BlockHeader blockHeader; + + private BlockSimulator blockSimulator; + + @BeforeEach + public void setUp() { + blockSimulator = + new BlockSimulator( + worldStateArchive, protocolSchedule, transactionSimulator, miningConfiguration); + blockHeader = BlockHeaderBuilder.createDefault().buildBlockHeader(); + ProtocolSpec protocolSpec = mock(ProtocolSpec.class); + when(miningConfiguration.getCoinbase()).thenReturn(Optional.ofNullable(Address.fromHexString("0x1"))); + when(protocolSchedule.getForNextBlockHeader(any(), anyLong())).thenReturn(protocolSpec); + when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(mock(MiningBeneficiaryCalculator.class)); + GasLimitCalculator gasLimitCalculator = mock(GasLimitCalculator.class); + when(protocolSpec.getGasLimitCalculator()).thenReturn(gasLimitCalculator); + when(gasLimitCalculator.nextGasLimit( anyLong(), anyLong(), anyLong())).thenReturn(1L); + when(protocolSpec.getFeeMarket()).thenReturn(mock(FeeMarket.class)); + } + + @Test + public void testProcessWithValidWorldState() { + when(worldStateArchive.getMutable(any(BlockHeader.class), eq(false))) + .thenReturn(Optional.of(mutableWorldState)); + + List results = + blockSimulator.process(blockHeader, Collections.emptyList()); + + assertNotNull(results); + verify(worldStateArchive).getMutable(any(BlockHeader.class), eq(false)); + } + + @Test + public void testProcessWithInvalidWorldState() { + when(worldStateArchive.getMutable(any(BlockHeader.class), eq(false))) + .thenReturn(Optional.empty()); + when(blockHeader.toLogString()).thenReturn("1"); + + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> blockSimulator.process(blockHeader, Collections.emptyList())); + + assertEquals("Public world state not available for block 1", exception.getMessage()); + } + + + @Test + public void shouldStopBlockSimulationWhenTransactionSimulationIsInvalid() { + + CallParameter callParameter = mock(CallParameter.class); + BlockStateCall blockStateCall = new BlockStateCall(List.of(callParameter), null, null, true); + + TransactionSimulatorResult transactionSimulatorResult = mock(TransactionSimulatorResult.class); + + TransactionProcessingResult transactionProcessingResult = mock(TransactionProcessingResult.class); + when(transactionSimulatorResult.result()).thenReturn(transactionProcessingResult); + when(transactionProcessingResult.isInvalid()).thenReturn(true); + when(transactionSimulatorResult.getValidationResult()).thenReturn(ValidationResult.invalid()); + + when(worldStateArchive.getMutable(any(BlockHeader.class), eq(false))) + .thenReturn(Optional.of(mutableWorldState)); + when(transactionSimulator.processWithWorldUpdater( + any(), + any(), + any(), + any(), + any(), + any(), + any(MiningBeneficiaryCalculator.class))) + .thenReturn(Optional.of(transactionSimulatorResult)); + + when(transactionSimulator.processWithWorldUpdater( + any(), + any(), + any(), + any(), + any(), + any(), + any(MiningBeneficiaryCalculator.class))) + .thenReturn(Optional.of(transactionSimulatorResult)); + + BlockSimulationException exception = + assertThrows( + BlockSimulationException.class, + () -> + blockSimulator.process(blockHeader, List.of(blockStateCall), mutableWorldState) + ); + + assertEquals("Public world state not available for block 1", exception.getMessage()); + } + + + @Test + public void testApplyStateOverrides() { + AccountOverrideMap accountOverrideMap = mock(AccountOverrideMap.class); + Address address = mock(Address.class); + AccountOverride accountOverride = mock(AccountOverride.class); + MutableAccount mutableAccount = mock(MutableAccount.class); + + when(accountOverrideMap.keySet()).thenReturn(Set.of(address)); + when(accountOverrideMap.get(address)).thenReturn(accountOverride); + + WorldUpdater worldUpdater = mock(WorldUpdater.class); + when(mutableWorldState.updater()).thenReturn(worldUpdater); + + when(worldUpdater.getOrCreate(address)).thenReturn(mutableAccount); + + when(accountOverride.getNonce()).thenReturn(Optional.of(123L)); + when(accountOverride.getBalance()).thenReturn(Optional.of(Wei.of(456L))); + when(accountOverride.getCode()).thenReturn(Optional.of("")); + when(accountOverride.getStateDiff()) + .thenReturn(Optional.of(new HashMap<>(Map.of("0x0", "0x1")))); + + blockSimulator.applyStateOverrides(accountOverrideMap, mutableWorldState); + + verify(mutableAccount).setNonce(anyLong()); + verify(mutableAccount).setBalance(any(Wei.class)); + verify(mutableAccount).setCode(any(Bytes.class)); + verify(mutableAccount).setStorageValue(any(UInt256.class), any(UInt256.class)); + } + + @Test + public void testApplyBlockHeaderOverrides() { + BlockOverrides blockOverrides = mock(BlockOverrides.class); + ProtocolSpec protocolSpec = mock(ProtocolSpec.class); + + var expectedTimestamp = Optional.of(1L); + var expectedBlockNumber = Optional.of(2L); + var expectedFeeRecipient = Optional.of(Address.fromHexString("0x1")); + var expectedBaseFeePerGas = Optional.of(Wei.of(7L)); + var expectedGasLimit = Optional.of(5L); + var expectedDifficulty = Optional.of(BigInteger.ONE); + var expectedMixHashOrPrevRandao = Optional.of(Hash.hash( Bytes.fromHexString("0x01"))); + var expectedExtraData = Optional.of(Bytes.fromHexString("0x02")); + + when(blockOverrides.getTimestamp()).thenReturn(expectedTimestamp); + when(blockOverrides.getBlockNumber()).thenReturn(expectedBlockNumber); + when(blockOverrides.getFeeRecipient()).thenReturn(expectedFeeRecipient); + when(blockOverrides.getBaseFeePerGas()).thenReturn(expectedBaseFeePerGas); + when(blockOverrides.getGasLimit()).thenReturn(expectedGasLimit); + when(blockOverrides.getDifficulty()).thenReturn(expectedDifficulty); + when(blockOverrides.getMixHashOrPrevRandao()).thenReturn(expectedMixHashOrPrevRandao); + when(blockOverrides.getExtraData()).thenReturn(expectedExtraData); + + BlockHeader result = + blockSimulator.applyBlockHeaderOverrides(blockHeader, protocolSpec, blockOverrides); + + assertNotNull(result); + assertEquals(expectedTimestamp.get(), result.getTimestamp()); + assertEquals(expectedBlockNumber.get(), result.getNumber()); + assertEquals(expectedFeeRecipient.get(), result.getCoinbase()); + assertEquals(expectedBaseFeePerGas, result.getBaseFee()); + assertEquals(expectedGasLimit.get(), result.getGasLimit()); + assertThat(result.getDifficulty()).isEqualTo(Difficulty.of(expectedDifficulty.get())); + assertEquals(expectedMixHashOrPrevRandao.get(), result.getMixHash()); + assertEquals(expectedExtraData.get(), result.getExtraData()); + } + + /* @Test + public void testProcessTransactions() { + + BlockStateCall blockStateCall = mock(BlockStateCall.class); + CallParameter callParameter = mock(CallParameter.class); + TransactionSimulatorResult transactionSimulatorResult = mock(TransactionSimulatorResult.class); + TransactionProcessingResult transactionProcessingResult = mock(TransactionProcessingResult.class); + MiningBeneficiaryCalculator miningBeneficiaryCalculator = mock(MiningBeneficiaryCalculator.class); + WorldUpdater worldUpdater = mock(WorldUpdater.class); + + when(blockStateCall.getCalls()).thenReturn(List.of(callParameter)); + when(transactionSimulator.processWithWorldUpdater( + eq(callParameter), + eq(Optional.empty()), + any(TransactionValidationParams.class), + eq(OperationTracer.NO_TRACING), + eq(blockHeader), + any(WorldUpdater.class), + eq(miningBeneficiaryCalculator))) + .thenReturn(Optional.of(transactionSimulatorResult)); + when(transactionSimulatorResult.result()).thenReturn(transactionProcessingResult); + when(transactionProcessingResult.isInvalid()).thenReturn(false); + when(mutableWorldState.updater()).thenReturn(worldUpdater); + + List results = blockSimulator.processTransactions( + blockHeader, blockStateCall, mutableWorldState, miningBeneficiaryCalculator); + + assertNotNull(results); + assertEquals(1, results.size()); + verify(worldUpdater).commit(); + }*/ + + + @Test + public void testBuildTransactionValidationParams() { + var configWhenValidate = + ImmutableTransactionValidationParams.builder() + .from(TransactionValidationParams.processingBlock()) + .build(); + + ImmutableTransactionValidationParams params = + blockSimulator.buildTransactionValidationParams(true); + assertThat(params).isEqualTo(configWhenValidate); + assertThat(params.isAllowExceedingBalance()).isFalse(); + + params = blockSimulator.buildTransactionValidationParams(false); + assertThat(params.isAllowExceedingBalance()).isTrue(); + } +} From 40db4213714a7a12214d0b91e2aad24dda619cf0 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 10 Dec 2024 14:19:03 +1100 Subject: [PATCH 27/38] Add tests Signed-off-by: Gabriel-Trintinalia --- .../transaction/BlockSimulationException.java | 18 ++- .../ethereum/transaction/BlockSimulator.java | 6 +- .../TransactionSimulatorResult.java | 6 + .../transaction/BlockSimulatorTest.java | 125 ++++++------------ plugin-api/build.gradle | 2 +- 5 files changed, 64 insertions(+), 93 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java index 9874fbd9322..c304ed9ae1a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationException.java @@ -1,11 +1,21 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ package org.hyperledger.besu.ethereum.transaction; public class BlockSimulationException extends RuntimeException { public BlockSimulationException(final String message) { super(message); } - - public BlockSimulationException(final String message, final Throwable cause) { - super(message, cause); - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index bb30672b224..ad50d313e91 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -184,7 +184,7 @@ protected List processTransactions( TransactionSimulatorResult result = transactionSimulatorResult.get(); if (result.isInvalid()) { throw new BlockSimulationException( - "Transaction simulator result is invalid: " + result.result().getInvalidReason()); + "Transaction simulator result is invalid: " + result.getInvalidReason().orElse(null)); } transactionSimulations.add(transactionSimulatorResult.get()); transactionUpdater.commit(); @@ -294,11 +294,11 @@ protected BlockHeader applyBlockHeaderOverrides( .gasLimit( blockOverrides .getGasLimit() - .orElseGet(()-> getNextGasLimit(newProtocolSpec, header, blockNumber))) + .orElseGet(() -> getNextGasLimit(newProtocolSpec, header, blockNumber))) .baseFee( blockOverrides .getBaseFeePerGas() - .orElseGet(()-> getNextBaseFee(newProtocolSpec, header, blockNumber))) + .orElseGet(() -> getNextBaseFee(newProtocolSpec, header, blockNumber))) .mixHash(blockOverrides.getMixHashOrPrevRandao().orElse(Hash.EMPTY)) .extraData(blockOverrides.getExtraData().orElse(Bytes.EMPTY)) .blockHeaderFunctions(new SimulatorBlockHeaderFunctions(blockOverrides)) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResult.java index 853bc4611a3..d06c6722505 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorResult.java @@ -18,6 +18,8 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import java.util.Optional; + import org.apache.tuweni.bytes.Bytes; public record TransactionSimulatorResult( @@ -42,4 +44,8 @@ public Bytes getOutput() { public ValidationResult getValidationResult() { return result.getValidationResult(); } + + public Optional getInvalidReason() { + return result.getInvalidReason(); + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java index 387c839c38a..a47018f57d5 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java @@ -18,17 +18,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.apache.tuweni.bytes.Bytes32; -import org.assertj.core.internal.Diff; import org.hyperledger.besu.datatypes.AccountOverride; import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.Address; @@ -41,22 +37,17 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MutableWorldState; -import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; -import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; -import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.account.MutableAccount; -import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import java.math.BigInteger; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -84,7 +75,7 @@ public class BlockSimulatorTest { @Mock private TransactionSimulator transactionSimulator; @Mock private MiningConfiguration miningConfiguration; @Mock private MutableWorldState mutableWorldState; - @Mock private BlockHeader blockHeader; + private BlockHeader blockHeader; private BlockSimulator blockSimulator; @@ -95,17 +86,19 @@ public void setUp() { worldStateArchive, protocolSchedule, transactionSimulator, miningConfiguration); blockHeader = BlockHeaderBuilder.createDefault().buildBlockHeader(); ProtocolSpec protocolSpec = mock(ProtocolSpec.class); - when(miningConfiguration.getCoinbase()).thenReturn(Optional.ofNullable(Address.fromHexString("0x1"))); + when(miningConfiguration.getCoinbase()) + .thenReturn(Optional.ofNullable(Address.fromHexString("0x1"))); when(protocolSchedule.getForNextBlockHeader(any(), anyLong())).thenReturn(protocolSpec); - when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(mock(MiningBeneficiaryCalculator.class)); + when(protocolSpec.getMiningBeneficiaryCalculator()) + .thenReturn(mock(MiningBeneficiaryCalculator.class)); GasLimitCalculator gasLimitCalculator = mock(GasLimitCalculator.class); when(protocolSpec.getGasLimitCalculator()).thenReturn(gasLimitCalculator); - when(gasLimitCalculator.nextGasLimit( anyLong(), anyLong(), anyLong())).thenReturn(1L); + when(gasLimitCalculator.nextGasLimit(anyLong(), anyLong(), anyLong())).thenReturn(1L); when(protocolSpec.getFeeMarket()).thenReturn(mock(FeeMarket.class)); } @Test - public void testProcessWithValidWorldState() { + public void shouldProcessWithValidWorldState() { when(worldStateArchive.getMutable(any(BlockHeader.class), eq(false))) .thenReturn(Optional.of(mutableWorldState)); @@ -117,68 +110,63 @@ public void testProcessWithValidWorldState() { } @Test - public void testProcessWithInvalidWorldState() { + public void shouldNotProcessWithInvalidWorldState() { when(worldStateArchive.getMutable(any(BlockHeader.class), eq(false))) .thenReturn(Optional.empty()); - when(blockHeader.toLogString()).thenReturn("1"); IllegalArgumentException exception = assertThrows( IllegalArgumentException.class, () -> blockSimulator.process(blockHeader, Collections.emptyList())); - assertEquals("Public world state not available for block 1", exception.getMessage()); + assertEquals( + String.format("Public world state not available for block %s", blockHeader.toLogString()), exception.getMessage()); } - @Test - public void shouldStopBlockSimulationWhenTransactionSimulationIsInvalid() { + public void shouldStopWhenTransactionSimulationIsInvalid() { CallParameter callParameter = mock(CallParameter.class); BlockStateCall blockStateCall = new BlockStateCall(List.of(callParameter), null, null, true); TransactionSimulatorResult transactionSimulatorResult = mock(TransactionSimulatorResult.class); + when(transactionSimulatorResult.isInvalid()).thenReturn(true); + when(transactionSimulatorResult.getInvalidReason()) + .thenReturn(Optional.of("Invalid Transaction")); - TransactionProcessingResult transactionProcessingResult = mock(TransactionProcessingResult.class); - when(transactionSimulatorResult.result()).thenReturn(transactionProcessingResult); - when(transactionProcessingResult.isInvalid()).thenReturn(true); - when(transactionSimulatorResult.getValidationResult()).thenReturn(ValidationResult.invalid()); - - when(worldStateArchive.getMutable(any(BlockHeader.class), eq(false))) - .thenReturn(Optional.of(mutableWorldState)); when(transactionSimulator.processWithWorldUpdater( - any(), - any(), - any(), - any(), - any(), - any(), - any(MiningBeneficiaryCalculator.class))) - .thenReturn(Optional.of(transactionSimulatorResult)); + any(), any(), any(), any(), any(), any(), any(MiningBeneficiaryCalculator.class))) + .thenReturn(Optional.of(transactionSimulatorResult)); + + BlockSimulationException exception = + assertThrows( + BlockSimulationException.class, + () -> blockSimulator.process(blockHeader, List.of(blockStateCall), mutableWorldState)); + + assertEquals( + "Transaction simulator result is invalid: Invalid Transaction", exception.getMessage()); + } + + @Test + public void shouldStopWhenTransactionSimulationIsEmpty() { + + CallParameter callParameter = mock(CallParameter.class); + BlockStateCall blockStateCall = new BlockStateCall(List.of(callParameter), null, null, true); when(transactionSimulator.processWithWorldUpdater( - any(), - any(), - any(), - any(), - any(), - any(), - any(MiningBeneficiaryCalculator.class))) - .thenReturn(Optional.of(transactionSimulatorResult)); + any(), any(), any(), any(), any(), any(), any(MiningBeneficiaryCalculator.class))) + .thenReturn(Optional.empty()); BlockSimulationException exception = - assertThrows( - BlockSimulationException.class, - () -> - blockSimulator.process(blockHeader, List.of(blockStateCall), mutableWorldState) - ); + assertThrows( + BlockSimulationException.class, + () -> blockSimulator.process(blockHeader, List.of(blockStateCall), mutableWorldState)); - assertEquals("Public world state not available for block 1", exception.getMessage()); + assertEquals("Transaction simulator result is empty", exception.getMessage()); } - @Test - public void testApplyStateOverrides() { + public void shouldApplyStateOverridesCorrectly() { AccountOverrideMap accountOverrideMap = mock(AccountOverrideMap.class); Address address = mock(Address.class); AccountOverride accountOverride = mock(AccountOverride.class); @@ -207,7 +195,7 @@ public void testApplyStateOverrides() { } @Test - public void testApplyBlockHeaderOverrides() { + public void shouldApplyBlockHeaderOverridesCorrectly() { BlockOverrides blockOverrides = mock(BlockOverrides.class); ProtocolSpec protocolSpec = mock(ProtocolSpec.class); @@ -217,7 +205,7 @@ public void testApplyBlockHeaderOverrides() { var expectedBaseFeePerGas = Optional.of(Wei.of(7L)); var expectedGasLimit = Optional.of(5L); var expectedDifficulty = Optional.of(BigInteger.ONE); - var expectedMixHashOrPrevRandao = Optional.of(Hash.hash( Bytes.fromHexString("0x01"))); + var expectedMixHashOrPrevRandao = Optional.of(Hash.hash(Bytes.fromHexString("0x01"))); var expectedExtraData = Optional.of(Bytes.fromHexString("0x02")); when(blockOverrides.getTimestamp()).thenReturn(expectedTimestamp); @@ -243,39 +231,6 @@ public void testApplyBlockHeaderOverrides() { assertEquals(expectedExtraData.get(), result.getExtraData()); } - /* @Test - public void testProcessTransactions() { - - BlockStateCall blockStateCall = mock(BlockStateCall.class); - CallParameter callParameter = mock(CallParameter.class); - TransactionSimulatorResult transactionSimulatorResult = mock(TransactionSimulatorResult.class); - TransactionProcessingResult transactionProcessingResult = mock(TransactionProcessingResult.class); - MiningBeneficiaryCalculator miningBeneficiaryCalculator = mock(MiningBeneficiaryCalculator.class); - WorldUpdater worldUpdater = mock(WorldUpdater.class); - - when(blockStateCall.getCalls()).thenReturn(List.of(callParameter)); - when(transactionSimulator.processWithWorldUpdater( - eq(callParameter), - eq(Optional.empty()), - any(TransactionValidationParams.class), - eq(OperationTracer.NO_TRACING), - eq(blockHeader), - any(WorldUpdater.class), - eq(miningBeneficiaryCalculator))) - .thenReturn(Optional.of(transactionSimulatorResult)); - when(transactionSimulatorResult.result()).thenReturn(transactionProcessingResult); - when(transactionProcessingResult.isInvalid()).thenReturn(false); - when(mutableWorldState.updater()).thenReturn(worldUpdater); - - List results = blockSimulator.processTransactions( - blockHeader, blockStateCall, mutableWorldState, miningBeneficiaryCalculator); - - assertNotNull(results); - assertEquals(1, results.size()); - verify(worldUpdater).commit(); - }*/ - - @Test public void testBuildTransactionValidationParams() { var configWhenValidate = diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index f8608f89325..750cf5bc888 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'TPCo4SZ61OrJxRAa2SIcAIOAOjVTdRw+UOeHMuiJP84=' + knownHash = 'XD0SpeqP/JVLGzoCXJyWTK5gtxbS9juXegr+xTeiZrw=' } check.dependsOn('checkAPIChanges') From e1a1967d3a5d562fb5f84b028a240d0f9bcfeef0 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 10 Dec 2024 14:29:52 +1100 Subject: [PATCH 28/38] Remove unused files Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 2 +- .../parameters/BlockStateCallsParameter.java | 43 ------------------- .../parameters/JsonBlockStateCall.java | 37 ---------------- .../jsonrpc/internal/results/BlockResult.java | 10 ++--- ...gResult.java => CallProcessingResult.java} | 4 +- .../transaction/BlockSimulatorTest.java | 3 +- .../services/BlockSimulationService.java | 2 +- 7 files changed, 11 insertions(+), 90 deletions(-) delete mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java delete mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java rename ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/{TransactionProcessingResult.java => CallProcessingResult.java} (96%) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 4673b9c3588..f6bda8aeee4 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -49,7 +49,7 @@ public BlockSimulatorServiceImpl( } /** - * Simulate the creation of a block given header, a list of transactions, and blockOverrides. + * Simulate the processing of a block given a header, a list of transactions, and blockOverrides. * * @param header the header * @param transactions the transactions to include in the block diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java deleted file mode 100644 index 3d9493e84be..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockStateCallsParameter.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright contributors to Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; - -import java.util.ArrayList; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class BlockStateCallsParameter { - @JsonProperty("blockStateCalls") - private final List blockStateCalls = new ArrayList<>(); - - @JsonProperty("validation") - private boolean validation; - - @JsonProperty("traceTransfers") - private boolean traceTransfers; - - public List getBlockStateCalls() { - return blockStateCalls; - } - - public boolean isValidation() { - return validation; - } - - public boolean isTraceTransfers() { - return traceTransfers; - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java deleted file mode 100644 index e18178fba50..00000000000 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonBlockStateCall.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright contributors to Besu. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; - -import org.hyperledger.besu.datatypes.AccountOverrideMap; -import org.hyperledger.besu.datatypes.BlockOverrides; -import org.hyperledger.besu.ethereum.transaction.BlockStateCall; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class JsonBlockStateCall extends BlockStateCall { - @JsonCreator - public JsonBlockStateCall( - @JsonProperty("calls") final List calls, - @JsonProperty("blockOverrides") final BlockOverrides blockOverrides, - @JsonProperty("stateOverrides") final AccountOverrideMap stateOverrides, - @JsonProperty("validation") final boolean validation) { - super(calls, blockOverrides, stateOverrides, validation); - } -} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java index 238f82dc574..e74cf2f4e0a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResult.java @@ -89,7 +89,7 @@ public class BlockResult implements JsonRpcResult { private final String excessBlobGas; private final String parentBeaconBlockRoot; private final String targetBlobsPerBlock; - private final List transactionProcessingResults; + private final List callProcessingResults; public BlockResult( final BlockHeader header, @@ -115,7 +115,7 @@ public BlockResult( final BlockHeader header, final List transactions, final List ommers, - final List transactionProcessingResults, + final List callProcessingResults, final Difficulty totalDifficulty, final int size, final boolean includeCoinbase, @@ -141,7 +141,7 @@ public BlockResult( this.timestamp = Quantity.create(header.getTimestamp()); this.ommers = ommers; this.transactions = transactions; - this.transactionProcessingResults = transactionProcessingResults; + this.callProcessingResults = callProcessingResults; this.coinbase = includeCoinbase ? header.getCoinbase().toString() : null; this.withdrawalsRoot = header.getWithdrawalsRoot().map(Hash::toString).orElse(null); this.withdrawals = @@ -298,7 +298,7 @@ public String getTargetBlobsPerBlock() { } @JsonGetter(value = "calls") - public List getTransactionProcessingResults() { - return transactionProcessingResults; + public List getTransactionProcessingResults() { + return callProcessingResults; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/CallProcessingResult.java similarity index 96% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java rename to ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/CallProcessingResult.java index b1473f3beef..9015a61c854 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionProcessingResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/CallProcessingResult.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.tuweni.bytes.Bytes; -public class TransactionProcessingResult { +public class CallProcessingResult { @JsonProperty("status") private final String status; @@ -36,7 +36,7 @@ public class TransactionProcessingResult { @JsonProperty("logs") private final List logs; - public TransactionProcessingResult( + public CallProcessingResult( @JsonProperty("status") final int status, @JsonProperty("returnData") final Bytes returnData, @JsonProperty("gasUsed") final long gasUsed, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java index a47018f57d5..313719c7890 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java @@ -120,7 +120,8 @@ public void shouldNotProcessWithInvalidWorldState() { () -> blockSimulator.process(blockHeader, Collections.emptyList())); assertEquals( - String.format("Public world state not available for block %s", blockHeader.toLogString()), exception.getMessage()); + String.format("Public world state not available for block %s", blockHeader.toLogString()), + exception.getMessage()); } @Test diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 7ecbd7deca2..4cf7285f3e5 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -24,7 +24,7 @@ public interface BlockSimulationService extends BesuService { /** - * Simulate the creation of a block given header, a list of transactions, and blockOverrides. + * Simulate the processing of a block given header, a list of transactions, and blockOverrides. * * @param header the header * @param transactions the transactions to include in the block From 8b97440825e6b9aabbce4c2887c8086511237aab Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 10 Dec 2024 15:45:42 +1100 Subject: [PATCH 29/38] Fix javadoc Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 9 + .../besu/datatypes/BlockOverrides.java | 168 ++++++++++++++++++ plugin-api/build.gradle | 2 +- .../plugin/data/BlockSimulationResult.java | 29 +++ .../services/BlockSimulationService.java | 1 + 5 files changed, 208 insertions(+), 1 deletion(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index f6bda8aeee4..6f9b0d80725 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -33,10 +33,19 @@ import java.util.List; +/** This class is a service that simulates the processing of a block */ public class BlockSimulatorServiceImpl implements BlockSimulationService { private final BlockSimulator blockSimulator; private final WorldStateArchive worldStateArchive; + /** + * This constructor creates a BlockSimulatorServiceImpl object + * + * @param worldStateArchive the world state archive + * @param miningConfiguration the mining configuration + * @param transactionSimulator the transaction simulator + * @param protocolSchedule the protocol schedule + */ public BlockSimulatorServiceImpl( final WorldStateArchive worldStateArchive, final MiningConfiguration miningConfiguration, diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java index e884e73ea09..83778caec26 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -24,6 +24,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; +/** BlockOverrides represents the block overrides for a block. */ public class BlockOverrides { private final Optional timestamp; private final Optional blockNumber; @@ -38,6 +39,22 @@ public class BlockOverrides { private final Optional extraData; private final Optional mixHashOrPrevRandao; + /** + * Constructs a new BlockOverrides instance. + * + * @param timestamp the optional timestamp + * @param blockNumber the optional block number + * @param blockHash the optional block hash + * @param prevRandao the optional previous Randao + * @param gasLimit the optional gas limit + * @param feeRecipient the optional fee recipient + * @param baseFeePerGas the optional base fee per gas + * @param blobBaseFee the optional blob base fee + * @param stateRoot the optional state root + * @param difficulty the optional difficulty + * @param extraData the optional extra data + * @param mixHashOrPrevRandao the optional mix hash or previous Randao + */ @JsonCreator public BlockOverrides( @JsonProperty("timestamp") final Optional timestamp, @@ -66,6 +83,11 @@ public BlockOverrides( this.mixHashOrPrevRandao = mixHashOrPrevRandao; } + /** + * Constructs a new BlockOverrides instance from a Builder. + * + * @param builder the builder to construct from + */ private BlockOverrides(final Builder builder) { this.blockNumber = Optional.ofNullable(builder.blockNumber); this.blockHash = Optional.ofNullable(builder.blockHash); @@ -81,58 +103,124 @@ private BlockOverrides(final Builder builder) { this.mixHashOrPrevRandao = Optional.ofNullable(builder.mixHashOrPrevRandao); } + /** + * Gets the block number. + * + * @return the optional block number + */ public Optional getBlockNumber() { return blockNumber; } + /** + * Gets the block hash. + * + * @return the optional block hash + */ public Optional getBlockHash() { return blockHash; } + /** + * Gets the previous Randao. + * + * @return the optional previous Randao + */ public Optional getPrevRandao() { return prevRandao; } + /** + * Gets the timestamp. + * + * @return the optional timestamp + */ public Optional getTimestamp() { return timestamp; } + /** + * Gets the gas limit. + * + * @return the optional gas limit + */ public Optional getGasLimit() { return gasLimit; } + /** + * Gets the fee recipient. + * + * @return the optional fee recipient + */ public Optional
getFeeRecipient() { return feeRecipient; } + /** + * Gets the base fee per gas. + * + * @return the optional base fee per gas + */ public Optional getBaseFeePerGas() { return baseFeePerGas; } + /** + * Gets the blob base fee. + * + * @return the optional blob base fee + */ public Optional getBlobBaseFee() { return blobBaseFee; } + /** + * Gets the state root. + * + * @return the optional state root + */ public Optional getStateRoot() { return stateRoot; } + /** + * Gets the difficulty. + * + * @return the optional difficulty + */ public Optional getDifficulty() { return difficulty; } + /** + * Gets the extra data. + * + * @return the optional extra data + */ public Optional getExtraData() { return extraData; } + /** + * Gets the mix hash or previous Randao. + * + * @return the optional mix hash or previous Randao + */ public Optional getMixHashOrPrevRandao() { return mixHashOrPrevRandao; } + /** + * Creates a new Builder instance. + * + * @return a new Builder + */ public static Builder builder() { return new Builder(); } + /** Builder for BlockOverrides. */ public static class Builder { private Long timestamp; private Long blockNumber; @@ -147,66 +235,146 @@ public static class Builder { private Bytes extraData; private Hash mixHashOrPrevRandao; + /** Constructs a new Builder instance. */ + public Builder() {} + + /** + * Sets the timestamp. + * + * @param timestamp the timestamp to set + * @return the builder instance + */ public Builder timestamp(final Long timestamp) { this.timestamp = timestamp; return this; } + /** + * Sets the block number. + * + * @param blockNumber the block number to set + * @return the builder instance + */ public Builder blockNumber(final Long blockNumber) { this.blockNumber = blockNumber; return this; } + /** + * Sets the block hash. + * + * @param blockHash the block hash to set + * @return the builder instance + */ public Builder blockHash(final Hash blockHash) { this.blockHash = blockHash; return this; } + /** + * Sets the previous Randao. + * + * @param prevRandao the previous Randao to set + * @return the builder instance + */ public Builder prevRandao(final Bytes32 prevRandao) { this.prevRandao = prevRandao; return this; } + /** + * Sets the gas limit. + * + * @param gasLimit the gas limit to set + * @return the builder instance + */ public Builder gasLimit(final Long gasLimit) { this.gasLimit = gasLimit; return this; } + /** + * Sets the fee recipient. + * + * @param feeRecipient the fee recipient to set + * @return the builder instance + */ public Builder feeRecipient(final Address feeRecipient) { this.feeRecipient = feeRecipient; return this; } + /** + * Sets the base fee per gas. + * + * @param baseFeePerGas the base fee per gas to set + * @return the builder instance + */ public Builder baseFeePerGas(final Wei baseFeePerGas) { this.baseFeePerGas = baseFeePerGas; return this; } + /** + * Sets the blob base fee. + * + * @param blobBaseFee the blob base fee to set + * @return the builder instance + */ public Builder blobBaseFee(final Long blobBaseFee) { this.blobBaseFee = blobBaseFee; return this; } + /** + * Sets the state root. + * + * @param stateRoot the state root to set + * @return the builder instance + */ public Builder stateRoot(final Hash stateRoot) { this.stateRoot = stateRoot; return this; } + /** + * Sets the difficulty. + * + * @param difficulty the difficulty to set + * @return the builder instance + */ public Builder difficulty(final BigInteger difficulty) { this.difficulty = difficulty; return this; } + /** + * Sets the extra data. + * + * @param extraData the extra data to set + * @return the builder instance + */ public Builder extraData(final Bytes extraData) { this.extraData = extraData; return this; } + /** + * Sets the mix hash or previous Randao. + * + * @param mixHashOrPrevRandao the mix hash or previous Randao to set + * @return the builder instance + */ public Builder mixHashOrPrevRandao(final Hash mixHashOrPrevRandao) { this.mixHashOrPrevRandao = mixHashOrPrevRandao; return this; } + /** + * Builds a new BlockOverrides instance. + * + * @return the new BlockOverrides instance + */ public BlockOverrides build() { return new BlockOverrides(this); } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 750cf5bc888..eec5c5b414c 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'XD0SpeqP/JVLGzoCXJyWTK5gtxbS9juXegr+xTeiZrw=' + knownHash = 'np8ChmBg/Fc8DiWlTn5PgRJbnuHtjbJGNIfaQgXv/tM=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java index 603aaf53627..d8cda478ff0 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java @@ -16,6 +16,7 @@ import java.util.List; +/** This class represents the result of simulating the processing of a block. */ public class BlockSimulationResult { final BlockHeader blockHeader; @@ -23,6 +24,14 @@ public class BlockSimulationResult { final List receipts; final List transactionSimulationResults; + /** + * Constructs a new BlockSimulationResult instance. + * + * @param blockHeader the block header + * @param blockBody the block body + * @param receipts the list of transaction receipts + * @param transactionSimulationResults the list of transaction simulation results + */ public BlockSimulationResult( final BlockHeader blockHeader, final BlockBody blockBody, @@ -34,18 +43,38 @@ public BlockSimulationResult( this.transactionSimulationResults = transactionSimulationResults; } + /** + * Gets the block header. + * + * @return the block header + */ public BlockHeader getBlockHeader() { return blockHeader; } + /** + * Gets the block body. + * + * @return the block body + */ public BlockBody getBlockBody() { return blockBody; } + /** + * Gets the list of transaction receipts. + * + * @return the list of transaction receipts + */ public List getReceipts() { return receipts; } + /** + * Gets the list of transaction simulation results. + * + * @return the list of transaction simulation results + */ public List getTransactionSimulationResults() { return transactionSimulationResults; } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 4cf7285f3e5..baf61b43471 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -22,6 +22,7 @@ import java.util.List; +/** This class is a service that simulates the processing of a block */ public interface BlockSimulationService extends BesuService { /** * Simulate the processing of a block given header, a list of transactions, and blockOverrides. From d026c0c97b86ee4f641d323ee539fad35ea4833f Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 13:52:08 +1100 Subject: [PATCH 30/38] Update besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Gabriel-Trintinalia --- .../hyperledger/besu/services/BlockSimulatorServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index 6f9b0d80725..ce2e16598d2 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -100,7 +100,7 @@ public BlockSimulationResult importBlockUnsafe( .orElseThrow( () -> new IllegalArgumentException( - "Public world state not available for block " + "World state not available for block number (block hash): " + headerCore.toLogString()))) { var results = blockSimulator.process(headerCore, List.of(blockStateCall), ws); var result = results.getFirst(); From 7ab57c6c677a40104f49156187c56552a1e8e25d Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 13:52:16 +1100 Subject: [PATCH 31/38] Update ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Gabriel-Trintinalia --- .../besu/ethereum/transaction/BlockSimulationResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 5cebf1128ad..501b5002d16 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -25,7 +25,7 @@ public class BlockSimulationResult { final Block block; final List receipts; - List transactionSimulations; + List transactionSimulationResults; public BlockSimulationResult( final Block block, From a6b45974af99f277420421e63450b4cac70ad5b2 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 13:52:24 +1100 Subject: [PATCH 32/38] Update ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Gabriel-Trintinalia --- .../besu/ethereum/transaction/BlockSimulationResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 501b5002d16..275503781a2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -33,7 +33,7 @@ public BlockSimulationResult( final List transactionSimulations) { this.block = block; this.receipts = new ArrayList<>(receipts); - this.transactionSimulations = transactionSimulations; + this.transactionSimulationResults = transactionSimulationResults; } public BlockHeader getBlockHeader() { From 9de954d647e63ab962be8b08414be62184cf2e39 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 13:52:31 +1100 Subject: [PATCH 33/38] Update ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java Co-authored-by: Stefan Pingel <16143240+pinges@users.noreply.github.com> Signed-off-by: Gabriel-Trintinalia --- .../besu/ethereum/transaction/BlockSimulationResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 275503781a2..15fe6a63971 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -30,7 +30,7 @@ public class BlockSimulationResult { public BlockSimulationResult( final Block block, final List receipts, - final List transactionSimulations) { + final List transactionSimulationResults) { this.block = block; this.receipts = new ArrayList<>(receipts); this.transactionSimulationResults = transactionSimulationResults; From f516105686ab0b17f9c1afad158b3fa8bbf4393c Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 10:56:43 +0800 Subject: [PATCH 34/38] Fix missing rename Signed-off-by: Gabriel-Trintinalia --- .../besu/ethereum/transaction/BlockSimulationResult.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java index 15fe6a63971..da0846890f6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulationResult.java @@ -49,7 +49,7 @@ public List getReceipts() { } public List getTransactionSimulations() { - return transactionSimulations; + return transactionSimulationResults; } public Block getBlock() { From 52a6d22aeb6672ecdf9bd1f28902f4a8a10ec4c5 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 12:45:30 +0800 Subject: [PATCH 35/38] Fix wrong json properties Signed-off-by: Gabriel-Trintinalia --- .../java/org/hyperledger/besu/datatypes/BlockOverrides.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java index 83778caec26..c2015e90221 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java @@ -57,7 +57,7 @@ public class BlockOverrides { */ @JsonCreator public BlockOverrides( - @JsonProperty("timestamp") final Optional timestamp, + @JsonProperty("time") final Optional timestamp, @JsonProperty("number") final Optional blockNumber, @JsonProperty("hash") final Optional blockHash, @JsonProperty("prevRandao") final Optional prevRandao, @@ -66,7 +66,7 @@ public BlockOverrides( @JsonProperty("baseFeePerGas") final Optional baseFeePerGas, @JsonProperty("blobBaseFee") final Optional blobBaseFee, @JsonProperty("stateRoot") final Optional stateRoot, - @JsonProperty("difficult") final Optional difficulty, + @JsonProperty("difficulty") final Optional difficulty, @JsonProperty("extraData") final Optional extraData, @JsonProperty("mixHashOrPrevRandao") final Optional mixHashOrPrevRandao) { this.timestamp = timestamp.map(UnsignedLongParameter::getValue); From 74a9fb02ad1bb397f3576256d90c922f5b448eee Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 15:47:43 +0800 Subject: [PATCH 36/38] Simplify simulator service impl Signed-off-by: Gabriel-Trintinalia --- .../org/hyperledger/besu/cli/BesuCommand.java | 3 +- .../services/BlockSimulatorServiceImpl.java | 103 +++++++++++------- ....java => PluginBlockSimulationResult.java} | 5 +- .../services/BlockSimulationService.java | 36 +++--- 4 files changed, 90 insertions(+), 57 deletions(-) rename plugin-api/src/main/java/org/hyperledger/besu/plugin/data/{BlockSimulationResult.java => PluginBlockSimulationResult.java} (96%) 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 323ecfda592..cd61d7c2fe8 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1304,7 +1304,8 @@ private void startPlugins(final Runner runner) { besuController.getProtocolContext().getWorldStateArchive(), miningParametersSupplier.get(), besuController.getTransactionSimulator(), - besuController.getProtocolSchedule())); + besuController.getProtocolSchedule(), + besuController.getProtocolContext().getBlockchain())); besuController.getAdditionalPluginServices().appendPluginServices(besuPluginContext); besuPluginContext.startPlugins(); diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index ce2e16598d2..f7d8bf7435b 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -17,17 +17,19 @@ import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; +import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.transaction.BlockSimulationResult; import org.hyperledger.besu.ethereum.transaction.BlockSimulator; import org.hyperledger.besu.ethereum.transaction.BlockStateCall; import org.hyperledger.besu.ethereum.transaction.CallParameter; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.Unstable; -import org.hyperledger.besu.plugin.data.BlockHeader; -import org.hyperledger.besu.plugin.data.BlockSimulationResult; +import org.hyperledger.besu.plugin.data.PluginBlockSimulationResult; import org.hyperledger.besu.plugin.data.TransactionSimulationResult; import org.hyperledger.besu.plugin.services.BlockSimulationService; @@ -37,6 +39,7 @@ public class BlockSimulatorServiceImpl implements BlockSimulationService { private final BlockSimulator blockSimulator; private final WorldStateArchive worldStateArchive; + private final Blockchain blockchain; /** * This constructor creates a BlockSimulatorServiceImpl object @@ -50,7 +53,9 @@ public BlockSimulatorServiceImpl( final WorldStateArchive worldStateArchive, final MiningConfiguration miningConfiguration, final TransactionSimulator transactionSimulator, - final ProtocolSchedule protocolSchedule) { + final ProtocolSchedule protocolSchedule, + final Blockchain blockchain) { + this.blockchain = blockchain; blockSimulator = new BlockSimulator( worldStateArchive, protocolSchedule, transactionSimulator, miningConfiguration); @@ -60,66 +65,86 @@ public BlockSimulatorServiceImpl( /** * Simulate the processing of a block given a header, a list of transactions, and blockOverrides. * - * @param header the header + * @param blockNumber the block number * @param transactions the transactions to include in the block * @param blockOverrides the blockSimulationOverride of the block + * @param accountOverrides state overrides of the block * @return the block context */ @Override - public BlockSimulationResult simulate( - final BlockHeader header, + public PluginBlockSimulationResult simulate( + final long blockNumber, final List transactions, - final BlockOverrides blockOverrides) { - BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); - var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; - - var result = blockSimulator.process(headerCore, List.of(blockStateCall)); - return response(result.getFirst()); + final BlockOverrides blockOverrides, + final AccountOverrideMap accountOverrides) { + return processSimulation(blockNumber, transactions, blockOverrides, accountOverrides, false); } /** - * This method is experimental and should be used with caution + * This method is experimental and should be used with caution. Simulate the processing of a block + * given a header, a list of transactions, and blockOverrides and persist the WorldState * - * @param header the block header + * @param blockNumber the block number * @param transactions the transactions to include in the block - * @param blockOverrides the blockSimulationOverride of the block - * @return the block context + * @param blockOverrides block overrides for the block + * @param accountOverrides state overrides of the block + * @return the PluginBlockSimulationResult */ @Unstable @Override - public BlockSimulationResult importBlockUnsafe( - final BlockHeader header, + public PluginBlockSimulationResult simulateAndPersistWorldState( + final long blockNumber, final List transactions, - final BlockOverrides blockOverrides) { + final BlockOverrides blockOverrides, + final AccountOverrideMap accountOverrides) { + return processSimulation(blockNumber, transactions, blockOverrides, accountOverrides, true); + } - BlockStateCall blockStateCall = createBlockStateCall(transactions, blockOverrides); - var headerCore = (org.hyperledger.besu.ethereum.core.BlockHeader) header; - try (final MutableWorldState ws = - worldStateArchive - .getMutable(headerCore, true) - .orElseThrow( - () -> - new IllegalArgumentException( - "World state not available for block number (block hash): " - + headerCore.toLogString()))) { - var results = blockSimulator.process(headerCore, List.of(blockStateCall), ws); - var result = results.getFirst(); - ws.persist(result.getBlock().getHeader()); + private PluginBlockSimulationResult processSimulation( + final long blockNumber, + final List transactions, + final BlockOverrides blockOverrides, + final AccountOverrideMap accountOverrides, + final boolean persistWorldState) { + BlockHeader header = getBlockHeader(blockNumber); + List callParameters = + transactions.stream().map(CallParameter::fromTransaction).toList(); + BlockStateCall blockStateCall = + new BlockStateCall(callParameters, blockOverrides, accountOverrides, true); + try (final MutableWorldState ws = getWorldState(header, persistWorldState)) { + List results = + blockSimulator.process(header, List.of(blockStateCall), ws); + BlockSimulationResult result = results.getFirst(); + if (persistWorldState) { + ws.persist(result.getBlock().getHeader()); + } return response(result); } catch (final Exception e) { throw new RuntimeException("Error simulating block", e); } } - private BlockStateCall createBlockStateCall( - final List transactions, final BlockOverrides blockOverrides) { - var callParameters = transactions.stream().map(CallParameter::fromTransaction).toList(); - return new BlockStateCall(callParameters, blockOverrides, new AccountOverrideMap(), true); + private BlockHeader getBlockHeader(final long blockNumber) { + return blockchain + .getBlockHeader(blockNumber) + .orElseThrow( + () -> + new IllegalArgumentException( + "Block header not found for block number: " + blockNumber)); + } + + private MutableWorldState getWorldState(final BlockHeader header, final boolean isPersisting) { + return worldStateArchive + .getMutable(header, isPersisting) + .orElseThrow( + () -> + new IllegalArgumentException( + "World state not available for block number (block hash): " + + header.toLogString())); } - private BlockSimulationResult response( - final org.hyperledger.besu.ethereum.transaction.BlockSimulationResult result) { - return new BlockSimulationResult( + private PluginBlockSimulationResult response(final BlockSimulationResult result) { + return new PluginBlockSimulationResult( result.getBlockHeader(), result.getBlockBody(), result.getReceipts(), diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/PluginBlockSimulationResult.java similarity index 96% rename from plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java rename to plugin-api/src/main/java/org/hyperledger/besu/plugin/data/PluginBlockSimulationResult.java index d8cda478ff0..b2b2ab0e7be 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockSimulationResult.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/PluginBlockSimulationResult.java @@ -17,8 +17,7 @@ import java.util.List; /** This class represents the result of simulating the processing of a block. */ -public class BlockSimulationResult { - +public class PluginBlockSimulationResult { final BlockHeader blockHeader; final BlockBody blockBody; final List receipts; @@ -32,7 +31,7 @@ public class BlockSimulationResult { * @param receipts the list of transaction receipts * @param transactionSimulationResults the list of transaction simulation results */ - public BlockSimulationResult( + public PluginBlockSimulationResult( final BlockHeader blockHeader, final BlockBody blockBody, final List receipts, diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index baf61b43471..292193e1f80 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -14,38 +14,46 @@ */ package org.hyperledger.besu.plugin.services; +import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.Unstable; -import org.hyperledger.besu.plugin.data.BlockHeader; -import org.hyperledger.besu.plugin.data.BlockSimulationResult; +import org.hyperledger.besu.plugin.data.PluginBlockSimulationResult; import java.util.List; /** This class is a service that simulates the processing of a block */ public interface BlockSimulationService extends BesuService { + /** - * Simulate the processing of a block given header, a list of transactions, and blockOverrides. + * Simulate the processing of a block given a header, a list of transactions, and blockOverrides. * - * @param header the header + * @param blockNumber the block number * @param transactions the transactions to include in the block * @param blockOverrides the blockSimulationOverride of the block + * @param accountOverrides state overrides of the block * @return the block context */ - BlockSimulationResult simulate( - final BlockHeader header, - final List transactions, - final BlockOverrides blockOverrides); + PluginBlockSimulationResult simulate( + long blockNumber, + List transactions, + BlockOverrides blockOverrides, + AccountOverrideMap accountOverrides); /** - * This method is experimental and should be used with caution + * This method is experimental and should be used with caution. Simulate the processing of a block + * given a header, a list of transactions, and blockOverrides and persist the WorldState * - * @param header the block header + * @param blockNumber the block number * @param transactions the transactions to include in the block - * @param blockOverrides the blockSimulationOverride of the block - * @return the block context + * @param blockOverrides block overrides for the block + * @param accountOverrides state overrides of the block + * @return the PluginBlockSimulationResult */ @Unstable - BlockSimulationResult importBlockUnsafe( - BlockHeader header, List transactions, BlockOverrides blockOverrides); + PluginBlockSimulationResult simulateAndPersistWorldState( + long blockNumber, + List transactions, + BlockOverrides blockOverrides, + AccountOverrideMap accountOverrides); } From cc0bcca3cc750f10843a44b5d885c2c50dc7754c Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 13 Dec 2024 16:09:02 +0800 Subject: [PATCH 37/38] Move BlockOverrides to plugin Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 2 +- .../parameters/BlockOverridesParameter.java | 76 +++++++++++++++++++ .../ethereum/transaction/BlockSimulator.java | 2 +- .../ethereum/transaction/BlockStateCall.java | 2 +- .../transaction/BlockSimulatorTest.java | 3 +- .../besu/plugin/data}/BlockOverrides.java | 32 ++++---- .../services/BlockSimulationService.java | 2 +- 7 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockOverridesParameter.java rename {datatypes/src/main/java/org/hyperledger/besu/datatypes => plugin-api/src/main/java/org/hyperledger/besu/plugin/data}/BlockOverrides.java (90%) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index f7d8bf7435b..ecd6eb2d38d 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.services; import org.hyperledger.besu.datatypes.AccountOverrideMap; -import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -29,6 +28,7 @@ import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.BlockOverrides; import org.hyperledger.besu.plugin.data.PluginBlockSimulationResult; import org.hyperledger.besu.plugin.data.TransactionSimulationResult; import org.hyperledger.besu.plugin.services.BlockSimulationService; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockOverridesParameter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockOverridesParameter.java new file mode 100644 index 00000000000..9cd6e880b42 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/BlockOverridesParameter.java @@ -0,0 +1,76 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters; + +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter; +import org.hyperledger.besu.plugin.data.BlockOverrides; + +import java.math.BigInteger; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +public class BlockOverridesParameter extends BlockOverrides { + /** + * Constructs a new BlockOverrides instance. + * + * @param timestamp the optional timestamp + * @param blockNumber the optional block number + * @param blockHash the optional block hash + * @param prevRandao the optional previous Randao + * @param gasLimit the optional gas limit + * @param feeRecipient the optional fee recipient + * @param baseFeePerGas the optional base fee per gas + * @param blobBaseFee the optional blob base fee + * @param stateRoot the optional state root + * @param difficulty the optional difficulty + * @param extraData the optional extra data + * @param mixHashOrPrevRandao the optional mix hash or previous Randao + */ + @JsonCreator + public BlockOverridesParameter( + @JsonProperty("time") final Optional timestamp, + @JsonProperty("number") final Optional blockNumber, + @JsonProperty("hash") final Optional blockHash, + @JsonProperty("prevRandao") final Optional prevRandao, + @JsonProperty("gasLimit") final Optional gasLimit, + @JsonProperty("feeRecipient") final Optional
feeRecipient, + @JsonProperty("baseFeePerGas") final Optional baseFeePerGas, + @JsonProperty("blobBaseFee") final Optional blobBaseFee, + @JsonProperty("stateRoot") final Optional stateRoot, + @JsonProperty("difficulty") final Optional difficulty, + @JsonProperty("extraData") final Optional extraData, + @JsonProperty("mixHashOrPrevRandao") final Optional mixHashOrPrevRandao) { + super( + timestamp, + blockNumber, + blockHash, + prevRandao, + gasLimit, + feeRecipient, + baseFeePerGas, + blobBaseFee, + stateRoot, + difficulty, + extraData, + mixHashOrPrevRandao); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java index ad50d313e91..018ce76ca7b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockSimulator.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.datatypes.AccountOverride; import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Block; @@ -45,6 +44,7 @@ import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.data.BlockOverrides; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java index 0ea8dc6cc9f..5db5faee23c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/BlockStateCall.java @@ -15,7 +15,7 @@ package org.hyperledger.besu.ethereum.transaction; import org.hyperledger.besu.datatypes.AccountOverrideMap; -import org.hyperledger.besu.datatypes.BlockOverrides; +import org.hyperledger.besu.plugin.data.BlockOverrides; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java index 313719c7890..1acc658862e 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java @@ -28,7 +28,6 @@ import org.hyperledger.besu.datatypes.AccountOverride; import org.hyperledger.besu.datatypes.AccountOverrideMap; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; @@ -46,6 +45,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.evm.account.MutableAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.data.BlockOverrides; import java.math.BigInteger; import java.util.Collections; @@ -65,7 +65,6 @@ import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; -@SuppressWarnings("AlmostJavadoc") @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) public class BlockSimulatorTest { diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockOverrides.java similarity index 90% rename from datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java rename to plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockOverrides.java index c2015e90221..703bb64b373 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/BlockOverrides.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/data/BlockOverrides.java @@ -12,15 +12,16 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.datatypes; +package org.hyperledger.besu.plugin.data; +import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter; import java.math.BigInteger; import java.util.Optional; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; @@ -55,20 +56,19 @@ public class BlockOverrides { * @param extraData the optional extra data * @param mixHashOrPrevRandao the optional mix hash or previous Randao */ - @JsonCreator public BlockOverrides( - @JsonProperty("time") final Optional timestamp, - @JsonProperty("number") final Optional blockNumber, - @JsonProperty("hash") final Optional blockHash, - @JsonProperty("prevRandao") final Optional prevRandao, - @JsonProperty("gasLimit") final Optional gasLimit, - @JsonProperty("feeRecipient") final Optional
feeRecipient, - @JsonProperty("baseFeePerGas") final Optional baseFeePerGas, - @JsonProperty("blobBaseFee") final Optional blobBaseFee, - @JsonProperty("stateRoot") final Optional stateRoot, - @JsonProperty("difficulty") final Optional difficulty, - @JsonProperty("extraData") final Optional extraData, - @JsonProperty("mixHashOrPrevRandao") final Optional mixHashOrPrevRandao) { + final Optional timestamp, + final Optional blockNumber, + final Optional blockHash, + final Optional prevRandao, + final Optional gasLimit, + final Optional
feeRecipient, + final Optional baseFeePerGas, + final Optional blobBaseFee, + final Optional stateRoot, + final Optional difficulty, + final Optional extraData, + final Optional mixHashOrPrevRandao) { this.timestamp = timestamp.map(UnsignedLongParameter::getValue); this.blockNumber = blockNumber.map(UnsignedLongParameter::getValue); this.blockHash = blockHash; diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java index 292193e1f80..f0253186daf 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BlockSimulationService.java @@ -15,9 +15,9 @@ package org.hyperledger.besu.plugin.services; import org.hyperledger.besu.datatypes.AccountOverrideMap; -import org.hyperledger.besu.datatypes.BlockOverrides; import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.BlockOverrides; import org.hyperledger.besu.plugin.data.PluginBlockSimulationResult; import java.util.List; From 6c6276fefd073dd531ea98a14d490e621d1223ea Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Tue, 17 Dec 2024 23:36:39 +1100 Subject: [PATCH 38/38] Accept PR suggestions Signed-off-by: Gabriel-Trintinalia --- .../services/BlockSimulatorServiceImpl.java | 1 + .../transaction/BlockSimulatorTest.java | 54 ++++++++++--------- plugin-api/build.gradle | 2 +- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java index ecd6eb2d38d..f840cd30273 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BlockSimulatorServiceImpl.java @@ -48,6 +48,7 @@ public class BlockSimulatorServiceImpl implements BlockSimulationService { * @param miningConfiguration the mining configuration * @param transactionSimulator the transaction simulator * @param protocolSchedule the protocol schedule + * @param blockchain the blockchain */ public BlockSimulatorServiceImpl( final WorldStateArchive worldStateArchive, diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java index 1acc658862e..bb1225107ec 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/BlockSimulatorTest.java @@ -196,39 +196,41 @@ public void shouldApplyStateOverridesCorrectly() { @Test public void shouldApplyBlockHeaderOverridesCorrectly() { - BlockOverrides blockOverrides = mock(BlockOverrides.class); ProtocolSpec protocolSpec = mock(ProtocolSpec.class); - var expectedTimestamp = Optional.of(1L); - var expectedBlockNumber = Optional.of(2L); - var expectedFeeRecipient = Optional.of(Address.fromHexString("0x1")); - var expectedBaseFeePerGas = Optional.of(Wei.of(7L)); - var expectedGasLimit = Optional.of(5L); - var expectedDifficulty = Optional.of(BigInteger.ONE); - var expectedMixHashOrPrevRandao = Optional.of(Hash.hash(Bytes.fromHexString("0x01"))); - var expectedExtraData = Optional.of(Bytes.fromHexString("0x02")); - - when(blockOverrides.getTimestamp()).thenReturn(expectedTimestamp); - when(blockOverrides.getBlockNumber()).thenReturn(expectedBlockNumber); - when(blockOverrides.getFeeRecipient()).thenReturn(expectedFeeRecipient); - when(blockOverrides.getBaseFeePerGas()).thenReturn(expectedBaseFeePerGas); - when(blockOverrides.getGasLimit()).thenReturn(expectedGasLimit); - when(blockOverrides.getDifficulty()).thenReturn(expectedDifficulty); - when(blockOverrides.getMixHashOrPrevRandao()).thenReturn(expectedMixHashOrPrevRandao); - when(blockOverrides.getExtraData()).thenReturn(expectedExtraData); + var expectedTimestamp = 1L; + var expectedBlockNumber = 2L; + var expectedFeeRecipient = Address.fromHexString("0x1"); + var expectedBaseFeePerGas = Wei.of(7L); + var expectedGasLimit = 5L; + var expectedDifficulty = BigInteger.ONE; + var expectedMixHashOrPrevRandao = Hash.hash(Bytes.fromHexString("0x01")); + var expectedExtraData = Bytes.fromHexString("0x02"); + + BlockOverrides blockOverrides = + BlockOverrides.builder() + .timestamp(expectedTimestamp) + .blockNumber(expectedBlockNumber) + .feeRecipient(expectedFeeRecipient) + .baseFeePerGas(expectedBaseFeePerGas) + .gasLimit(expectedGasLimit) + .difficulty(expectedDifficulty) + .mixHashOrPrevRandao(expectedMixHashOrPrevRandao) + .extraData(expectedExtraData) + .build(); BlockHeader result = blockSimulator.applyBlockHeaderOverrides(blockHeader, protocolSpec, blockOverrides); assertNotNull(result); - assertEquals(expectedTimestamp.get(), result.getTimestamp()); - assertEquals(expectedBlockNumber.get(), result.getNumber()); - assertEquals(expectedFeeRecipient.get(), result.getCoinbase()); - assertEquals(expectedBaseFeePerGas, result.getBaseFee()); - assertEquals(expectedGasLimit.get(), result.getGasLimit()); - assertThat(result.getDifficulty()).isEqualTo(Difficulty.of(expectedDifficulty.get())); - assertEquals(expectedMixHashOrPrevRandao.get(), result.getMixHash()); - assertEquals(expectedExtraData.get(), result.getExtraData()); + assertEquals(expectedTimestamp, result.getTimestamp()); + assertEquals(expectedBlockNumber, result.getNumber()); + assertEquals(expectedFeeRecipient, result.getCoinbase()); + assertEquals(Optional.of(expectedBaseFeePerGas), result.getBaseFee()); + assertEquals(expectedGasLimit, result.getGasLimit()); + assertThat(result.getDifficulty()).isEqualTo(Difficulty.of(expectedDifficulty)); + assertEquals(expectedMixHashOrPrevRandao, result.getMixHash()); + assertEquals(expectedExtraData, result.getExtraData()); } @Test diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index eec5c5b414c..070313150eb 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'np8ChmBg/Fc8DiWlTn5PgRJbnuHtjbJGNIfaQgXv/tM=' + knownHash = '+YR9PYN+gPCvXzK2w52ypz9dZ0FOy0G3I1PljZasOkU=' } check.dependsOn('checkAPIChanges')