Skip to content

Commit

Permalink
Simulation - Expose BlockHashLookup to BlockSimulatorService (hyperle…
Browse files Browse the repository at this point in the history
…dger#8267)

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
  • Loading branch information
Gabriel-Trintinalia authored Feb 8, 2025
1 parent cbabf87 commit 72a4e4a
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ public BlockSimulatorServiceImpl(
this.blockchain = blockchain;
blockSimulator =
new BlockSimulator(
worldStateArchive, protocolSchedule, transactionSimulator, miningConfiguration);
worldStateArchive,
protocolSchedule,
transactionSimulator,
miningConfiguration,
blockchain);
this.worldStateArchive = worldStateArchive;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.hyperledger.besu.datatypes.StateOverride;
import org.hyperledger.besu.datatypes.StateOverrideMap;
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;
Expand All @@ -44,6 +45,7 @@
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.blockhash.BlockHashLookup;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.BlockOverrides;
Expand All @@ -69,16 +71,19 @@ public class BlockSimulator {
private final WorldStateArchive worldStateArchive;
private final ProtocolSchedule protocolSchedule;
private final MiningConfiguration miningConfiguration;
private final Blockchain blockchain;

public BlockSimulator(
final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule,
final TransactionSimulator transactionSimulator,
final MiningConfiguration miningConfiguration) {
final MiningConfiguration miningConfiguration,
final Blockchain blockchain) {
this.worldStateArchive = worldStateArchive;
this.protocolSchedule = protocolSchedule;
this.miningConfiguration = miningConfiguration;
this.transactionSimulator = transactionSimulator;
this.blockchain = blockchain;
}

/**
Expand Down Expand Up @@ -149,8 +154,12 @@ private BlockSimulationResult processSingleBlockStateCall(
MiningBeneficiaryCalculator miningBeneficiaryCalculator =
getMiningBeneficiaryCalculator(blockOverrides, newProtocolSpec);

BlockHashLookup blockHashLookup =
createBlockHashLookup(blockOverrides, newProtocolSpec, blockHeader);

List<TransactionSimulatorResult> transactionSimulatorResults =
processTransactions(blockHeader, blockStateCall, ws, miningBeneficiaryCalculator);
processTransactions(
blockHeader, blockStateCall, ws, miningBeneficiaryCalculator, blockHashLookup);

return finalizeBlock(
blockHeader, blockStateCall, ws, newProtocolSpec, transactionSimulatorResults);
Expand All @@ -161,7 +170,8 @@ protected List<TransactionSimulatorResult> processTransactions(
final BlockHeader blockHeader,
final BlockStateCall blockStateCall,
final MutableWorldState ws,
final MiningBeneficiaryCalculator miningBeneficiaryCalculator) {
final MiningBeneficiaryCalculator miningBeneficiaryCalculator,
final BlockHashLookup blockHashLookup) {

List<TransactionSimulatorResult> transactionSimulations = new ArrayList<>();

Expand All @@ -176,7 +186,8 @@ protected List<TransactionSimulatorResult> processTransactions(
OperationTracer.NO_TRACING,
blockHeader,
transactionUpdater,
miningBeneficiaryCalculator);
miningBeneficiaryCalculator,
blockHashLookup);

if (transactionSimulatorResult.isEmpty()) {
throw new BlockSimulationException("Transaction simulator result is empty");
Expand Down Expand Up @@ -409,4 +420,28 @@ public ParsedExtraData parseExtraData(final BlockHeader header) {
return blockHeaderFunctions.parseExtraData(header);
}
}

/**
* Creates a BlockHashLookup for the block simulation. If a BlockHashLookup is provided in the
* BlockOverrides, it is used. Otherwise, the default BlockHashLookup is created.
*
* @param blockOverrides The BlockOverrides to use.
* @param newProtocolSpec The ProtocolSpec for the block.
* @param blockHeader The block header for the simulation.
* @return The BlockHashLookup for the block simulation.
*/
private BlockHashLookup createBlockHashLookup(
final BlockOverrides blockOverrides,
final ProtocolSpec newProtocolSpec,
final BlockHeader blockHeader) {
return blockOverrides
.getBlockHashLookup()
.<BlockHashLookup>map(
blockHashLookup -> (frame, blockNumber) -> blockHashLookup.apply(blockNumber))
.orElseGet(
() ->
newProtocolSpec
.getBlockHashProcessor()
.createBlockHashLookup(blockchain, blockHeader));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;

Expand Down Expand Up @@ -353,7 +354,8 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
final OperationTracer operationTracer,
final BlockHeader header,
final WorldUpdater updater,
final MiningBeneficiaryCalculator miningBeneficiaryCalculator) {
final MiningBeneficiaryCalculator miningBeneficiaryCalculator,
final BlockHashLookup blockHashLookup) {

final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(header);

Expand All @@ -364,7 +366,8 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
operationTracer,
header,
updater,
miningBeneficiary);
miningBeneficiary,
blockHashLookup);
}

@Nonnull
Expand All @@ -377,7 +380,31 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
final WorldUpdater updater,
final Address miningBeneficiary) {
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(processableHeader);
final BlockHashLookup blockHashLookup =
protocolSpec.getBlockHashProcessor().createBlockHashLookup(blockchain, processableHeader);
return processWithWorldUpdater(
callParams,
maybeStateOverrides,
transactionValidationParams,
operationTracer,
processableHeader,
updater,
miningBeneficiary,
blockHashLookup);
}

@Nonnull
public Optional<TransactionSimulatorResult> processWithWorldUpdater(
final CallParameter callParams,
final Optional<StateOverrideMap> maybeStateOverrides,
final TransactionValidationParams transactionValidationParams,
final OperationTracer operationTracer,
final ProcessableBlockHeader processableHeader,
final WorldUpdater updater,
final Address miningBeneficiary,
final BlockHashLookup blockHashLookup) {

final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(processableHeader);
final Address senderAddress =
callParams.getFrom() != null ? callParams.getFrom() : DEFAULT_FROM;

Expand Down Expand Up @@ -448,9 +475,7 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
blockHeaderToProcess,
transaction,
miningBeneficiary,
protocolSpec
.getBlockHashProcessor()
.createBlockHashLookup(blockchain, blockHeaderToProcess),
blockHashLookup,
false,
transactionValidationParams,
operationTracer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.Difficulty;
Expand All @@ -42,6 +43,7 @@
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.blockhash.BlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.trie.diffbased.common.provider.WorldStateQueryParams;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
Expand Down Expand Up @@ -74,6 +76,8 @@ public class BlockSimulatorTest {
@Mock private TransactionSimulator transactionSimulator;
@Mock private MiningConfiguration miningConfiguration;
@Mock private MutableWorldState mutableWorldState;
@Mock private Blockchain blockchain;

private BlockHeader blockHeader;

private BlockSimulator blockSimulator;
Expand All @@ -82,7 +86,11 @@ public class BlockSimulatorTest {
public void setUp() {
blockSimulator =
new BlockSimulator(
worldStateArchive, protocolSchedule, transactionSimulator, miningConfiguration);
worldStateArchive,
protocolSchedule,
transactionSimulator,
miningConfiguration,
blockchain);
blockHeader = BlockHeaderBuilder.createDefault().buildBlockHeader();
ProtocolSpec protocolSpec = mock(ProtocolSpec.class);
when(miningConfiguration.getCoinbase())
Expand All @@ -94,6 +102,7 @@ public void setUp() {
when(protocolSpec.getGasLimitCalculator()).thenReturn(gasLimitCalculator);
when(gasLimitCalculator.nextGasLimit(anyLong(), anyLong(), anyLong())).thenReturn(1L);
when(protocolSpec.getFeeMarket()).thenReturn(mock(FeeMarket.class));
when(protocolSpec.getBlockHashProcessor()).thenReturn(mock(BlockHashProcessor.class));
}

@Test
Expand Down Expand Up @@ -135,7 +144,14 @@ public void shouldStopWhenTransactionSimulationIsInvalid() {
.thenReturn(Optional.of("Invalid Transaction"));

when(transactionSimulator.processWithWorldUpdater(
any(), any(), any(), any(), any(), any(), any(MiningBeneficiaryCalculator.class)))
any(),
any(),
any(),
any(),
any(),
any(),
any(MiningBeneficiaryCalculator.class),
any()))
.thenReturn(Optional.of(transactionSimulatorResult));

BlockSimulationException exception =
Expand All @@ -154,7 +170,14 @@ public void shouldStopWhenTransactionSimulationIsEmpty() {
BlockStateCall blockStateCall = new BlockStateCall(List.of(callParameter), null, null, true);

when(transactionSimulator.processWithWorldUpdater(
any(), any(), any(), any(), any(), any(), any(MiningBeneficiaryCalculator.class)))
any(),
any(),
any(),
any(),
any(),
any(),
any(MiningBeneficiaryCalculator.class),
any()))
.thenReturn(Optional.empty());

BlockSimulationException exception =
Expand Down
2 changes: 1 addition & 1 deletion plugin-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 'U/zVfjqq/stLY920xHh1N26KU+KoAdgEiV2nPWIFRIs='
knownHash = 'I2IrN2aLU610031Vw8xNr3hcT8/wb25pDrclwZUggE4='
}
check.dependsOn('checkAPIChanges')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.math.BigInteger;
import java.util.Optional;
import java.util.function.Function;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
Expand All @@ -39,6 +40,7 @@ public class BlockOverrides {
private final Optional<BigInteger> difficulty;
private final Optional<Bytes> extraData;
private final Optional<Hash> mixHashOrPrevRandao;
private final Optional<Function<Long, Hash>> blockHashLookup;

/**
* Constructs a new BlockOverrides instance.
Expand Down Expand Up @@ -81,6 +83,7 @@ public BlockOverrides(
this.difficulty = difficulty;
this.extraData = extraData;
this.mixHashOrPrevRandao = mixHashOrPrevRandao;
this.blockHashLookup = Optional.empty();
}

/**
Expand All @@ -101,6 +104,7 @@ private BlockOverrides(final Builder builder) {
this.difficulty = Optional.ofNullable(builder.difficulty);
this.extraData = Optional.ofNullable(builder.extraData);
this.mixHashOrPrevRandao = Optional.ofNullable(builder.mixHashOrPrevRandao);
this.blockHashLookup = Optional.ofNullable(builder.blockHashLookup);
}

/**
Expand Down Expand Up @@ -211,6 +215,15 @@ public Optional<Hash> getMixHashOrPrevRandao() {
return mixHashOrPrevRandao;
}

/**
* Gets the block hash lookup.
*
* @return the optional block hash lookup
*/
public Optional<Function<Long, Hash>> getBlockHashLookup() {
return blockHashLookup;
}

/**
* Creates a new Builder instance.
*
Expand All @@ -234,6 +247,7 @@ public static class Builder {
private BigInteger difficulty;
private Bytes extraData;
private Hash mixHashOrPrevRandao;
private Function<Long, Hash> blockHashLookup;

/** Constructs a new Builder instance. */
public Builder() {}
Expand Down Expand Up @@ -370,6 +384,17 @@ public Builder mixHashOrPrevRandao(final Hash mixHashOrPrevRandao) {
return this;
}

/**
* Sets the block hash lookup.
*
* @param blockHashLookup the block hash lookup to set
* @return the builder instance
*/
public Builder blockHashLookup(final Function<Long, Hash> blockHashLookup) {
this.blockHashLookup = blockHashLookup;
return this;
}

/**
* Builds a new BlockOverrides instance.
*
Expand Down

0 comments on commit 72a4e4a

Please sign in to comment.