Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator;
import org.hyperledger.besu.ethereum.mainnet.requests.ProcessRequestContext;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessingContext;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.services.exception.StorageException;
Expand Down Expand Up @@ -210,10 +211,6 @@ protected BlockCreationResult createBlock(

final List<BlockHeader> ommers = maybeOmmers.orElse(selectOmmers());

newProtocolSpec
.getBlockHashProcessor()
.processBlockHashes(disposableWorldState, processableBlockHeader);

throwIfStopped();

final PluginTransactionSelector pluginTransactionSelector =
Expand All @@ -223,6 +220,17 @@ protected BlockCreationResult createBlock(
pluginTransactionSelector.getOperationTracer();

operationTracer.traceStartBlock(processableBlockHeader, miningBeneficiary);
BlockProcessingContext blockProcessingContext =
new BlockProcessingContext(
processableBlockHeader,
disposableWorldState,
newProtocolSpec,
newProtocolSpec
.getBlockHashProcessor()
.createBlockHashLookup(protocolContext.getBlockchain(), processableBlockHeader),
operationTracer);
newProtocolSpec.getBlockHashProcessor().process(blockProcessingContext);

timings.register("preTxsSelection");
final TransactionSelectionResults transactionResults =
selectTransactions(
Expand Down Expand Up @@ -252,20 +260,11 @@ protected BlockCreationResult createBlock(
// EIP-7685: process EL requests
final Optional<RequestProcessorCoordinator> requestProcessor =
newProtocolSpec.getRequestProcessorCoordinator();

ProcessRequestContext context =
new ProcessRequestContext(
processableBlockHeader,
disposableWorldState,
newProtocolSpec,
transactionResults.getReceipts(),
newProtocolSpec
.getBlockHashProcessor()
.createBlockHashLookup(protocolContext.getBlockchain(), processableBlockHeader),
operationTracer);
RequestProcessingContext requestProcessingContext =
new RequestProcessingContext(blockProcessingContext, transactionResults.getReceipts());

Optional<List<Request>> maybeRequests =
requestProcessor.map(processor -> processor.process(context));
requestProcessor.map(processor -> processor.process(requestProcessingContext));

throwIfStopped();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsProcessor;
import org.hyperledger.besu.ethereum.mainnet.requests.DepositRequestProcessor;
import org.hyperledger.besu.ethereum.mainnet.requests.ProcessRequestContext;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessingContext;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
Expand Down Expand Up @@ -142,7 +143,9 @@ void findDepositRequestsFromReceipts() {

var depositRequestsFromReceipts =
new DepositRequestProcessor(DEFAULT_DEPOSIT_CONTRACT_ADDRESS)
.process(new ProcessRequestContext(null, null, null, receipts, null, null));
.process(
new RequestProcessingContext(
new BlockProcessingContext(null, null, null, null, null), receipts));
assertThat(depositRequestsFromReceipts).isEqualTo(expectedDepositRequest);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor.PreprocessingFunction.NoPreprocessing;
import org.hyperledger.besu.ethereum.mainnet.requests.ProcessRequestContext;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessingContext;
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessorCoordinator;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
Expand Down Expand Up @@ -126,10 +127,12 @@ protected BlockProcessingResult processBlock(
long currentBlobGasUsed = 0;

final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader);

protocolSpec.getBlockHashProcessor().processBlockHashes(worldState, blockHeader);
final BlockHashLookup blockHashLookup =
protocolSpec.getBlockHashProcessor().createBlockHashLookup(blockchain, blockHeader);
final BlockProcessingContext blockProcessingContext =
new BlockProcessingContext(
blockHeader, worldState, protocolSpec, blockHashLookup, OperationTracer.NO_TRACING);
protocolSpec.getBlockHashProcessor().process(blockProcessingContext);

final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);

Expand Down Expand Up @@ -240,16 +243,9 @@ protected BlockProcessingResult processBlock(
protocolSpec.getRequestProcessorCoordinator();
Optional<List<Request>> maybeRequests = Optional.empty();
if (requestProcessor.isPresent()) {
ProcessRequestContext context =
new ProcessRequestContext(
blockHeader,
worldState,
protocolSpec,
receipts,
blockHashLookup,
OperationTracer.NO_TRACING);

maybeRequests = Optional.of(requestProcessor.get().process(context));
RequestProcessingContext requestProcessingContext =
new RequestProcessingContext(blockProcessingContext, receipts);
maybeRequests = Optional.of(requestProcessor.get().process(requestProcessingContext));
}

if (maybeRequests.isPresent() && blockHeader.getRequestsHash().isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
package org.hyperledger.besu.ethereum.mainnet.blockhash;

import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockContextProcessor;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;

public interface BlockHashProcessor {

void processBlockHashes(MutableWorldState worldState, ProcessableBlockHeader currentBlockHeader);
public interface BlockHashProcessor extends BlockContextProcessor<Void, BlockProcessingContext> {

BlockHashLookup createBlockHashLookup(Blockchain blockchain, ProcessableBlockHeader blockHeader);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,28 @@
*/
package org.hyperledger.besu.ethereum.mainnet.blockhash;

import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.mainnet.ParentBeaconBlockRootHelper;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;

/** Processes the beacon block storage if it is present in the block header. */
public class CancunBlockHashProcessor extends FrontierBlockHashProcessor {

@Override
public void processBlockHashes(
final MutableWorldState mutableWorldState, final ProcessableBlockHeader currentBlockHeader) {
public Void process(final BlockProcessingContext context) {
ProcessableBlockHeader currentBlockHeader = context.getBlockHeader();
currentBlockHeader
.getParentBeaconBlockRoot()
.ifPresent(
beaconBlockRoot -> {
if (!beaconBlockRoot.isEmpty()) {
WorldUpdater worldUpdater = mutableWorldState.updater();
WorldUpdater worldUpdater = context.getWorldState().updater();
ParentBeaconBlockRootHelper.storeParentBeaconBlockRoot(
worldUpdater, currentBlockHeader.getTimestamp(), beaconBlockRoot);
worldUpdater.commit();
}
});
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ public class Eip7709BlockHashProcessor extends PragueBlockHashProcessor {
@Override
public BlockHashLookup createBlockHashLookup(
final Blockchain blockchain, final ProcessableBlockHeader blockHeader) {
return new Eip7709BlockHashLookup(historyStorageAddress, historyServeWindow);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you think this could change in the future? Having the BlockHashProcessor have a handle on the window size makes it more extendable in another fork if the window changes

return new Eip7709BlockHashLookup(historyStorageAddress);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@
package org.hyperledger.besu.ethereum.mainnet.blockhash;

import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.ethereum.vm.BlockchainBasedBlockHashLookup;
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
import org.hyperledger.besu.evm.operation.BlockHashOperation;

public class FrontierBlockHashProcessor implements BlockHashProcessor {

@Override
public void processBlockHashes(
final MutableWorldState mutableWorldState, final ProcessableBlockHeader currentBlockHeader) {
public Void process(final BlockProcessingContext context) {
// do nothing
return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,91 +15,47 @@
package org.hyperledger.besu.ethereum.mainnet.blockhash;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
import org.hyperledger.besu.ethereum.mainnet.systemcall.SystemCallProcessor;

import com.google.common.annotations.VisibleForTesting;
import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.tuweni.bytes.Bytes;

/**
* Processes and stores historical block hashes in accordance with EIP-2935. This class is
* responsible for managing the storage of block hashes to support EIP-2935, which introduces
* historical block hash access in smart contracts.
*/
public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
private static final Logger LOG = LoggerFactory.getLogger(PragueBlockHashProcessor.class);

public static final Address HISTORY_STORAGE_ADDRESS =
private static final Address HISTORY_STORAGE_ADDRESS =
Address.fromHexString("0x0000f90827f1c53a10cb7a02335b175320002935");

/** The HISTORY_SERVE_WINDOW */
private static final long HISTORY_SERVE_WINDOW = 8191;

protected final long historyServeWindow;
protected final Address historyStorageAddress;

/** Constructs a BlockHashProcessor. */
public PragueBlockHashProcessor() {
this(HISTORY_STORAGE_ADDRESS, HISTORY_SERVE_WINDOW);
this(HISTORY_STORAGE_ADDRESS);
}

/**
* Constructs a BlockHashProcessor with a specified history save window. This constructor is
* primarily used for testing.
*
* @param historyStorageAddress the address of the contract storing the history
* @param historyServeWindow The number of blocks for which history should be saved.
*/
@VisibleForTesting
public PragueBlockHashProcessor(
final Address historyStorageAddress, final long historyServeWindow) {
public PragueBlockHashProcessor(final Address historyStorageAddress) {
this.historyStorageAddress = historyStorageAddress;
this.historyServeWindow = historyServeWindow;
}

@Override
public void processBlockHashes(
final MutableWorldState mutableWorldState, final ProcessableBlockHeader currentBlockHeader) {
super.processBlockHashes(mutableWorldState, currentBlockHeader);

WorldUpdater worldUpdater = mutableWorldState.updater();
final MutableAccount historyStorageAccount = worldUpdater.getAccount(historyStorageAddress);

if (historyStorageAccount != null
&& historyStorageAccount.getNonce() > 0
&& currentBlockHeader.getNumber() > 0) {
storeParentHash(historyStorageAccount, currentBlockHeader);
}
worldUpdater.commit();
}

/**
* Stores the hash of the parent block in the world state.
*
* @param account The account associated with the historical block hash storage.
* @param header The current block header being processed.
*/
private void storeParentHash(final MutableAccount account, final ProcessableBlockHeader header) {
storeHash(account, header.getNumber() - 1, header.getParentHash());
}

/**
* Stores the hash in the world state.
*
* @param account The account associated with the historical block hash storage.
* @param number The slot to store.
* @param hash The hash to be stored.
*/
private void storeHash(final MutableAccount account, final long number, final Hash hash) {
UInt256 slot = UInt256.valueOf(number % historyServeWindow);
UInt256 value = UInt256.fromBytes(hash);
LOG.trace(
"Writing to {} {}=%{}", account.getAddress(), slot.toDecimalString(), value.toHexString());
account.setStorageValue(slot, value);
public Void process(final BlockProcessingContext context) {
super.process(context);
SystemCallProcessor processor =
new SystemCallProcessor(context.getProtocolSpec().getTransactionProcessor());

Bytes inputData = context.getBlockHeader().getParentHash();
processor.process(historyStorageAddress, context, inputData);
return null;
Comment on lines +52 to +59
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the important change of this PR. The rest is refactoring.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public DepositRequestProcessor(final Address depositContractAddress) {
}

@Override
public Request process(final ProcessRequestContext context) {
public Request process(final RequestProcessingContext context) {
if (depositContractAddress.isEmpty()) {
return new Request(RequestType.DEPOSIT, Bytes.EMPTY);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,26 @@
*/
package org.hyperledger.besu.ethereum.mainnet.requests;

import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;

import java.util.List;

public record ProcessRequestContext(
ProcessableBlockHeader blockHeader,
MutableWorldState mutableWorldState,
ProtocolSpec protocolSpec,
List<TransactionReceipt> transactionReceipts,
BlockHashLookup blockHashLookup,
OperationTracer operationTracer) {}
public final class RequestProcessingContext extends BlockProcessingContext {
private final List<TransactionReceipt> transactionReceipts;

public RequestProcessingContext(
final BlockProcessingContext context, final List<TransactionReceipt> transactionReceipts) {
super(
context.getBlockHeader(),
context.getWorldState(),
context.getProtocolSpec(),
context.getBlockHashLookup(),
context.getOperationTracer());
this.transactionReceipts = transactionReceipts;
}

public List<TransactionReceipt> transactionReceipts() {
return transactionReceipts;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
import org.hyperledger.besu.ethereum.core.Request;

public interface RequestProcessor {
Request process(final ProcessRequestContext context);
Request process(final RequestProcessingContext context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private RequestProcessorCoordinator(
this.processors = processors;
}

public List<Request> process(final ProcessRequestContext context) {
public List<Request> process(final RequestProcessingContext context) {
return processors.values().stream()
.map(requestProcessor -> requestProcessor.process(context))
.toList();
Expand Down
Loading