Skip to content

Commit

Permalink
Simplify simulator service impl
Browse files Browse the repository at this point in the history
Signed-off-by: Gabriel-Trintinalia <[email protected]>
  • Loading branch information
Gabriel-Trintinalia committed Dec 13, 2024
1 parent 52a6d22 commit 74a9fb0
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 57 deletions.
3 changes: 2 additions & 1 deletion besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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<? extends Transaction> 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<? extends Transaction> 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<? extends Transaction> transactions,
final BlockOverrides blockOverrides,
final AccountOverrideMap accountOverrides,
final boolean persistWorldState) {
BlockHeader header = getBlockHeader(blockNumber);
List<CallParameter> callParameters =
transactions.stream().map(CallParameter::fromTransaction).toList();
BlockStateCall blockStateCall =
new BlockStateCall(callParameters, blockOverrides, accountOverrides, true);
try (final MutableWorldState ws = getWorldState(header, persistWorldState)) {
List<BlockSimulationResult> 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<? extends Transaction> 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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends TransactionReceipt> receipts;
Expand All @@ -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<? extends TransactionReceipt> receipts,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<? extends Transaction> transactions,
final BlockOverrides blockOverrides);
PluginBlockSimulationResult simulate(
long blockNumber,
List<? extends Transaction> 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<? extends Transaction> transactions, BlockOverrides blockOverrides);
PluginBlockSimulationResult simulateAndPersistWorldState(
long blockNumber,
List<? extends Transaction> transactions,
BlockOverrides blockOverrides,
AccountOverrideMap accountOverrides);
}

0 comments on commit 74a9fb0

Please sign in to comment.