mirror of
https://github.com/vacp2p/status-linea-besu.git
synced 2026-01-09 13:58:02 -05:00
Merge branch 'main' into zkbesu
This commit is contained in:
15
CHANGELOG.md
15
CHANGELOG.md
@@ -2,9 +2,22 @@
|
||||
|
||||
## Unreleased
|
||||
### Breaking Changes
|
||||
- `rpc-gas-cap` default value has changed from 0 (unlimited) to 50M. If you require `rpc-gas-cap` greater than 50M, you'll need to set that explicitly. [#8251](https://github.com/hyperledger/besu/issues/8251)
|
||||
### Upcoming Breaking Changes
|
||||
- `MetricSystem::createLabelledGauge` is deprecated and will be removed in a future release, replace it with `MetricSystem::createLabelledSuppliedGauge`
|
||||
- k8s (KUBERNETES) Nat method is now deprecated and will be removed in a future release. Use docker or none instead.
|
||||
- `--Xsnapsync-synchronizer-flat-db-healing-enabled` is deprecated, use `--Xbonsai-full-flat-db-enabled` instead.
|
||||
- `--Xbonsai-limit-trie-logs-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
|
||||
- `--Xbonsai-trie-log-pruning-enabled` is deprecated, use `--bonsai-limit-trie-logs-enabled` instead.
|
||||
- `--Xbonsai-trie-logs-pruning-window-size` is deprecated, use `--bonsai-trie-logs-pruning-window-size` instead.
|
||||
- Sunsetting features - for more context on the reasoning behind the deprecation of these features, including alternative options, read [this blog post](https://www.lfdecentralizedtrust.org/blog/sunsetting-tessera-and-simplifying-hyperledger-besu)
|
||||
- Tessera privacy
|
||||
- Smart-contract-based (onchain) permissioning
|
||||
- Proof of Work consensus
|
||||
- Fast Sync
|
||||
### Additions and Improvements
|
||||
- Add a tx selector to skip txs from the same sender after the first not selected [#8216](https://github.com/hyperledger/besu/pull/8216)
|
||||
- `rpc-gas-cap` default value has changed from 0 (unlimited) to 50M [#8251](https://github.com/hyperledger/besu/issues/8251)
|
||||
|
||||
#### Prague
|
||||
- Add timestamps to enable Prague hardfork on Sepolia and Holesky test networks [#8163](https://github.com/hyperledger/besu/pull/8163)
|
||||
@@ -20,7 +33,7 @@
|
||||
|
||||
### Breaking Changes
|
||||
- `--host-whitelist` has been deprecated since 2020 and this option is removed. Use the equivalent `--host-allowlist` instead.
|
||||
- Changed tracer API to include the mining beneficiary in BlockAwareOperationTracer::traceStartBlock [#8096](https://github.com/hyperledger/besu/pull/8096)
|
||||
- Change tracer API to include the mining beneficiary in BlockAwareOperationTracer::traceStartBlock [#8096](https://github.com/hyperledger/besu/pull/8096)
|
||||
- Change the input defaults on debug_trace* calls to not trace memory by default ("disableMemory": true, "disableStack": false, "disableStorage": false)
|
||||
- Change the output format of debug_trace* and trace_* calls to match Geth behaviour
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ApiConfigurationOptions {
|
||||
names = {"--rpc-gas-cap"},
|
||||
description =
|
||||
"Specifies the gasLimit cap for transaction simulation RPC methods. Must be >=0. 0 specifies no limit (default: ${DEFAULT-VALUE})")
|
||||
private final Long rpcGasCap = 0L;
|
||||
private final Long rpcGasCap = ApiConfiguration.DEFAULT_GAS_CAP;
|
||||
|
||||
@CommandLine.Option(
|
||||
names = {"--rpc-max-trace-filter-range"},
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.hyperledger.besu.cli.CommandTestAbstract;
|
||||
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
|
||||
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -111,7 +112,7 @@ public class ApiConfigurationOptionsTest extends CommandTestAbstract {
|
||||
verify(mockRunnerBuilder).build();
|
||||
|
||||
assertThat(apiConfigurationCaptor.getValue())
|
||||
.isEqualTo(ImmutableApiConfiguration.builder().maxLogsRange((rpcMaxLogsRange)).build());
|
||||
.isEqualTo(ImmutableApiConfiguration.builder().maxLogsRange(rpcMaxLogsRange).build());
|
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||
@@ -126,7 +127,37 @@ public class ApiConfigurationOptionsTest extends CommandTestAbstract {
|
||||
verify(mockRunnerBuilder).build();
|
||||
|
||||
assertThat(apiConfigurationCaptor.getValue())
|
||||
.isEqualTo(ImmutableApiConfiguration.builder().gasCap((rpcGasCap)).build());
|
||||
.isEqualTo(ImmutableApiConfiguration.builder().gasCap(rpcGasCap).build());
|
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rpcGasCapDefault() {
|
||||
parseCommand();
|
||||
|
||||
verify(mockRunnerBuilder).apiConfiguration(apiConfigurationCaptor.capture());
|
||||
verify(mockRunnerBuilder).build();
|
||||
|
||||
assertThat(apiConfigurationCaptor.getValue())
|
||||
.isEqualTo(
|
||||
ImmutableApiConfiguration.builder().gasCap(ApiConfiguration.DEFAULT_GAS_CAP).build());
|
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rpcGasCapAcceptsZero() {
|
||||
final long rpcGasCap = 0L;
|
||||
parseCommand("--rpc-gas-cap", Long.toString(rpcGasCap));
|
||||
|
||||
verify(mockRunnerBuilder).apiConfiguration(apiConfigurationCaptor.capture());
|
||||
verify(mockRunnerBuilder).build();
|
||||
|
||||
assertThat(apiConfigurationCaptor.getValue())
|
||||
.isEqualTo(ImmutableApiConfiguration.builder().gasCap(rpcGasCap).build());
|
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
|
||||
@@ -143,7 +174,7 @@ public class ApiConfigurationOptionsTest extends CommandTestAbstract {
|
||||
assertThat(apiConfigurationCaptor.getValue())
|
||||
.isEqualTo(
|
||||
ImmutableApiConfiguration.builder()
|
||||
.maxTraceFilterRange((rpcMaxTraceFilterOption))
|
||||
.maxTraceFilterRange(rpcMaxTraceFilterOption)
|
||||
.build());
|
||||
|
||||
assertThat(commandOutput.toString(UTF_8)).isEmpty();
|
||||
|
||||
@@ -43,4 +43,18 @@ public interface PendingTransaction {
|
||||
* @return timestamp
|
||||
*/
|
||||
long getAddedAt();
|
||||
|
||||
/**
|
||||
* Return the estimated amount memory that this pending transaction occupies
|
||||
*
|
||||
* @return the estimated memory size
|
||||
*/
|
||||
int memorySize();
|
||||
|
||||
/**
|
||||
* Formats a string with detailed information about the pending transaction for debug purposes
|
||||
*
|
||||
* @return a string
|
||||
*/
|
||||
String toTraceLog();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,9 @@ public abstract class ApiConfiguration {
|
||||
*/
|
||||
public static final long DEFAULT_UPPER_BOUND_GAS_AND_PRIORITY_FEE_COEFFICIENT = Long.MAX_VALUE;
|
||||
|
||||
/** The default gas cap used for transaction simulation */
|
||||
public static final long DEFAULT_GAS_CAP = 50_000_000L;
|
||||
|
||||
/** Constructs a new ApiConfiguration with default values. */
|
||||
protected ApiConfiguration() {}
|
||||
|
||||
@@ -93,13 +96,13 @@ public abstract class ApiConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gas cap. Default value is 0.
|
||||
* Returns the gas cap. Default value is 50M.
|
||||
*
|
||||
* @return the gas cap
|
||||
*/
|
||||
@Value.Default
|
||||
public Long getGasCap() {
|
||||
return 0L;
|
||||
return DEFAULT_GAS_CAP;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,8 +48,9 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
|
||||
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;
|
||||
@@ -210,10 +211,6 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
|
||||
|
||||
final List<BlockHeader> ommers = maybeOmmers.orElse(selectOmmers());
|
||||
|
||||
newProtocolSpec
|
||||
.getBlockHashProcessor()
|
||||
.processBlockHashes(disposableWorldState, processableBlockHeader);
|
||||
|
||||
throwIfStopped();
|
||||
|
||||
final PluginTransactionSelector pluginTransactionSelector =
|
||||
@@ -223,6 +220,17 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
|
||||
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(
|
||||
@@ -252,20 +260,11 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
|
||||
// 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();
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ public class BlockTransactionSelector {
|
||||
|
||||
final WorldUpdater txWorldStateUpdater = blockWorldStateUpdater.updater();
|
||||
final TransactionProcessingResult processingResult =
|
||||
processTransaction(pendingTransaction, txWorldStateUpdater);
|
||||
processTransaction(evaluationContext.getTransaction(), txWorldStateUpdater);
|
||||
|
||||
var postProcessingSelectionResult = evaluatePostProcessing(evaluationContext, processingResult);
|
||||
|
||||
@@ -370,12 +370,12 @@ public class BlockTransactionSelector {
|
||||
/**
|
||||
* Processes a transaction
|
||||
*
|
||||
* @param pendingTransaction The transaction to be processed.
|
||||
* @param transaction The transaction to be processed.
|
||||
* @param worldStateUpdater The world state updater.
|
||||
* @return The result of the transaction processing.
|
||||
*/
|
||||
private TransactionProcessingResult processTransaction(
|
||||
final PendingTransaction pendingTransaction, final WorldUpdater worldStateUpdater) {
|
||||
final Transaction transaction, final WorldUpdater worldStateUpdater) {
|
||||
final BlockHashLookup blockHashLookup =
|
||||
blockSelectionContext
|
||||
.blockHashProcessor()
|
||||
@@ -383,7 +383,7 @@ public class BlockTransactionSelector {
|
||||
return transactionProcessor.processTransaction(
|
||||
worldStateUpdater,
|
||||
blockSelectionContext.pendingBlockHeader(),
|
||||
pendingTransaction.getTransaction(),
|
||||
transaction,
|
||||
blockSelectionContext.miningBeneficiary(),
|
||||
operationTracer,
|
||||
blockHashLookup,
|
||||
@@ -528,7 +528,7 @@ public class BlockTransactionSelector {
|
||||
.setMessage(
|
||||
"Transaction {} is too late for inclusion, with result {}, evaluated in {} that is over the max limit of {}ms"
|
||||
+ ", {}")
|
||||
.addArgument(evaluationContext.getPendingTransaction()::getHash)
|
||||
.addArgument(evaluationContext.getTransaction()::getHash)
|
||||
.addArgument(selectionResult)
|
||||
.addArgument(evaluationTimer)
|
||||
.addArgument(blockTxsSelectionMaxTime)
|
||||
|
||||
@@ -14,16 +14,15 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.blockcreation.txselection;
|
||||
|
||||
import org.hyperledger.besu.datatypes.PendingTransaction;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
||||
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
public class TransactionEvaluationContext
|
||||
implements org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext<
|
||||
PendingTransaction> {
|
||||
implements org.hyperledger.besu.plugin.services.txselection.TransactionEvaluationContext {
|
||||
private final ProcessableBlockHeader pendingBlockHeader;
|
||||
private final PendingTransaction pendingTransaction;
|
||||
private final Stopwatch evaluationTimer;
|
||||
@@ -44,7 +43,9 @@ public class TransactionEvaluationContext
|
||||
}
|
||||
|
||||
public Transaction getTransaction() {
|
||||
return pendingTransaction.getTransaction();
|
||||
// ToDo: can we avoid this cast? either by always using the interface
|
||||
// or moving our Transaction implementation in the datatypes package
|
||||
return (Transaction) pendingTransaction.getTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionEvaluationContext;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
|
||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
||||
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
|
||||
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||
|
||||
@@ -47,7 +46,7 @@ public class MinPriorityFeePerGasTransactionSelector extends AbstractTransaction
|
||||
public TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||
final TransactionEvaluationContext evaluationContext,
|
||||
final TransactionSelectionResults transactionSelectionResults) {
|
||||
if (isPriorityFeePriceBelowMinimum(evaluationContext.getPendingTransaction())) {
|
||||
if (isPriorityFeePriceBelowMinimum(evaluationContext)) {
|
||||
return TransactionSelectionResult.PRIORITY_FEE_PER_GAS_BELOW_CURRENT_MIN;
|
||||
}
|
||||
return TransactionSelectionResult.SELECTED;
|
||||
@@ -56,17 +55,18 @@ public class MinPriorityFeePerGasTransactionSelector extends AbstractTransaction
|
||||
/**
|
||||
* Checks if the priority fee price is below the minimum.
|
||||
*
|
||||
* @param pendingTransaction The transaction to check.
|
||||
* @param evaluationContext The current selection session data.
|
||||
* @return boolean. Returns true if the minimum priority fee price is below the minimum, false
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean isPriorityFeePriceBelowMinimum(final PendingTransaction pendingTransaction) {
|
||||
private boolean isPriorityFeePriceBelowMinimum(
|
||||
final TransactionEvaluationContext evaluationContext) {
|
||||
// Priority txs are exempt from this check
|
||||
if (pendingTransaction.hasPriority()) {
|
||||
if (evaluationContext.getPendingTransaction().hasPriority()) {
|
||||
return false;
|
||||
}
|
||||
Wei priorityFeePerGas =
|
||||
pendingTransaction
|
||||
evaluationContext
|
||||
.getTransaction()
|
||||
.getEffectivePriorityFeePerGas(context.pendingBlockHeader().getBaseFee());
|
||||
return priorityFeePerGas.lessThan(context.miningConfiguration().getMinPriorityFeePerGas());
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.blockcreation.txselection.selectors;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.BlockSelectionContext;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionEvaluationContext;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
|
||||
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction;
|
||||
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
|
||||
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||
|
||||
@@ -71,7 +70,7 @@ public class PriceTransactionSelector extends AbstractTransactionSelector {
|
||||
*/
|
||||
private boolean transactionCurrentPriceBelowMin(
|
||||
final TransactionEvaluationContext evaluationContext) {
|
||||
final PendingTransaction pendingTransaction = evaluationContext.getPendingTransaction();
|
||||
final var pendingTransaction = evaluationContext.getPendingTransaction();
|
||||
// Priority txs are exempt from this check
|
||||
if (!pendingTransaction.hasPriority()) {
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ import org.hyperledger.besu.ethereum.mainnet.TransactionValidatorFactory;
|
||||
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;
|
||||
@@ -142,7 +143,9 @@ abstract class AbstractBlockCreatorTest {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -653,8 +653,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
new PluginTransactionSelector() {
|
||||
@Override
|
||||
public TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||
final TransactionEvaluationContext<? extends PendingTransaction>
|
||||
evaluationContext) {
|
||||
final TransactionEvaluationContext evaluationContext) {
|
||||
if (evaluationContext
|
||||
.getPendingTransaction()
|
||||
.getTransaction()
|
||||
@@ -670,8 +669,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
|
||||
@Override
|
||||
public TransactionSelectionResult evaluateTransactionPostProcessing(
|
||||
final TransactionEvaluationContext<? extends PendingTransaction>
|
||||
evaluationContext,
|
||||
final TransactionEvaluationContext evaluationContext,
|
||||
final org.hyperledger.besu.plugin.data.TransactionProcessingResult
|
||||
processingResult) {
|
||||
return SELECTED;
|
||||
@@ -727,15 +725,13 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
new PluginTransactionSelector() {
|
||||
@Override
|
||||
public TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||
final TransactionEvaluationContext<? extends PendingTransaction>
|
||||
evaluationContext) {
|
||||
final TransactionEvaluationContext evaluationContext) {
|
||||
return SELECTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionSelectionResult evaluateTransactionPostProcessing(
|
||||
final TransactionEvaluationContext<? extends PendingTransaction>
|
||||
evaluationContext,
|
||||
final TransactionEvaluationContext evaluationContext,
|
||||
final org.hyperledger.besu.plugin.data.TransactionProcessingResult
|
||||
processingResult) {
|
||||
// the transaction with max gas +1 should fail
|
||||
@@ -808,7 +804,7 @@ public abstract class AbstractBlockTransactionSelectorTest {
|
||||
selector.buildTransactionListForBlock();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArgumentCaptor<TransactionEvaluationContext<PendingTransaction>> argumentCaptor =
|
||||
ArgumentCaptor<TransactionEvaluationContext> argumentCaptor =
|
||||
ArgumentCaptor.forClass(TransactionEvaluationContext.class);
|
||||
|
||||
// selected transaction must be notified to the selector
|
||||
|
||||
@@ -30,8 +30,9 @@ import org.hyperledger.besu.ethereum.core.Transaction;
|
||||
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;
|
||||
@@ -126,10 +127,12 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
|
||||
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);
|
||||
|
||||
@@ -240,16 +243,9 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
|
||||
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()) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ public class Eip7709BlockHashProcessor extends PragueBlockHashProcessor {
|
||||
@Override
|
||||
public BlockHashLookup createBlockHashLookup(
|
||||
final Blockchain blockchain, final ProcessableBlockHeader blockHeader) {
|
||||
return new Eip7709BlockHashLookup(historyStorageAddress, historyServeWindow);
|
||||
return new Eip7709BlockHashLookup(historyStorageAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
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;
|
||||
@@ -24,9 +24,9 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,16 +15,11 @@
|
||||
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
|
||||
@@ -32,20 +27,14 @@ import org.slf4j.LoggerFactory;
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,53 +42,20 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
|
||||
* 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);
|
||||
public Void process(final BlockProcessingContext context) {
|
||||
super.process(context);
|
||||
SystemCallProcessor processor =
|
||||
new SystemCallProcessor(context.getProtocolSpec().getTransactionProcessor());
|
||||
|
||||
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);
|
||||
Bytes inputData = context.getBlockHeader().getParentHash();
|
||||
processor.process(historyStorageAddress, context, inputData);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class DepositRequestProcessor implements RequestProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request process(final ProcessRequestContext context) {
|
||||
public Request process(final RequestProcessingContext context) {
|
||||
if (depositContractAddress.isEmpty()) {
|
||||
return new Request(RequestType.DEPOSIT, Bytes.EMPTY);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,5 @@ package org.hyperledger.besu.ethereum.mainnet.requests;
|
||||
import org.hyperledger.besu.ethereum.core.Request;
|
||||
|
||||
public interface RequestProcessor {
|
||||
Request process(final ProcessRequestContext context);
|
||||
Request process(final RequestProcessingContext context);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class 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();
|
||||
|
||||
@@ -17,12 +17,14 @@ package org.hyperledger.besu.ethereum.mainnet.requests;
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.RequestType;
|
||||
import org.hyperledger.besu.ethereum.core.Request;
|
||||
import org.hyperledger.besu.ethereum.mainnet.SystemCallProcessor;
|
||||
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockContextProcessor;
|
||||
import org.hyperledger.besu.ethereum.mainnet.systemcall.SystemCallProcessor;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
|
||||
/** Processes system call requests. */
|
||||
public class SystemCallRequestProcessor implements RequestProcessor {
|
||||
public class SystemCallRequestProcessor
|
||||
implements RequestProcessor, BlockContextProcessor<Request, RequestProcessingContext> {
|
||||
|
||||
private final Address callAddress;
|
||||
private final RequestType requestType;
|
||||
@@ -39,18 +41,12 @@ public class SystemCallRequestProcessor implements RequestProcessor {
|
||||
* @return A {@link Request} request
|
||||
*/
|
||||
@Override
|
||||
public Request process(final ProcessRequestContext context) {
|
||||
public Request process(final RequestProcessingContext context) {
|
||||
|
||||
SystemCallProcessor systemCallProcessor =
|
||||
new SystemCallProcessor(context.protocolSpec().getTransactionProcessor());
|
||||
final SystemCallProcessor systemCallProcessor =
|
||||
new SystemCallProcessor(context.getProtocolSpec().getTransactionProcessor());
|
||||
|
||||
Bytes systemCallOutput =
|
||||
systemCallProcessor.process(
|
||||
callAddress,
|
||||
context.mutableWorldState().updater(),
|
||||
context.blockHeader(),
|
||||
context.operationTracer(),
|
||||
context.blockHashLookup());
|
||||
Bytes systemCallOutput = systemCallProcessor.process(callAddress, context, Bytes.EMPTY);
|
||||
|
||||
return new Request(requestType, systemCallOutput);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.mainnet.systemcall;
|
||||
|
||||
public interface BlockContextProcessor<T, C extends BlockProcessingContext> {
|
||||
T process(final C context);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.mainnet.systemcall;
|
||||
|
||||
import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
||||
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
|
||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
|
||||
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
||||
import org.hyperledger.besu.evm.tracing.OperationTracer;
|
||||
|
||||
public class BlockProcessingContext {
|
||||
|
||||
private final MutableWorldState worldState;
|
||||
private final ProcessableBlockHeader blockHeader;
|
||||
private final OperationTracer operationTracer;
|
||||
private final BlockHashLookup blockHashLookup;
|
||||
private final ProtocolSpec protocolSpec;
|
||||
|
||||
public BlockProcessingContext(
|
||||
final ProcessableBlockHeader blockHeader,
|
||||
final MutableWorldState worldState,
|
||||
final ProtocolSpec protocolSpec,
|
||||
final BlockHashLookup blockHashLookup,
|
||||
final OperationTracer operationTracer) {
|
||||
this.blockHeader = blockHeader;
|
||||
this.worldState = worldState;
|
||||
this.protocolSpec = protocolSpec;
|
||||
this.blockHashLookup = blockHashLookup;
|
||||
this.operationTracer = operationTracer;
|
||||
}
|
||||
|
||||
public MutableWorldState getWorldState() {
|
||||
return worldState;
|
||||
}
|
||||
|
||||
public ProcessableBlockHeader getBlockHeader() {
|
||||
return blockHeader;
|
||||
}
|
||||
|
||||
public OperationTracer getOperationTracer() {
|
||||
return operationTracer;
|
||||
}
|
||||
|
||||
public BlockHashLookup getBlockHashLookup() {
|
||||
return blockHashLookup;
|
||||
}
|
||||
|
||||
public ProtocolSpec getProtocolSpec() {
|
||||
return protocolSpec;
|
||||
}
|
||||
}
|
||||
@@ -12,19 +12,19 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.mainnet;
|
||||
package org.hyperledger.besu.ethereum.mainnet.systemcall;
|
||||
|
||||
import static org.hyperledger.besu.evm.frame.MessageFrame.DEFAULT_MAX_STACK_SIZE;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
|
||||
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
||||
import org.hyperledger.besu.evm.account.Account;
|
||||
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
||||
import org.hyperledger.besu.evm.code.CodeV0;
|
||||
import org.hyperledger.besu.evm.frame.MessageFrame;
|
||||
import org.hyperledger.besu.evm.processor.AbstractMessageProcessor;
|
||||
import org.hyperledger.besu.evm.tracing.OperationTracer;
|
||||
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
|
||||
|
||||
import java.util.Deque;
|
||||
@@ -48,44 +48,33 @@ public class SystemCallProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a system call to a specified address, using the provided world state, block header,
|
||||
* operation tracer, and block hash lookup.
|
||||
* Processes a system call.
|
||||
*
|
||||
* @param callAddress the address to call.
|
||||
* @param worldState the current world state.
|
||||
* @param blockHeader the current block header.
|
||||
* @param operationTracer the operation tracer for tracing EVM operations.
|
||||
* @param blockHashLookup the block hash lookup function.
|
||||
* @return the output data from the call. If no code exists at the callAddress then an empty Bytes
|
||||
* is returned.
|
||||
* @param callAddress The address to call.
|
||||
* @param context The system call context. The input data to the system call.
|
||||
* @param inputData The input data to the system call.
|
||||
* @return The output of the system call.
|
||||
*/
|
||||
public Bytes process(
|
||||
final Address callAddress,
|
||||
final WorldUpdater worldState,
|
||||
final ProcessableBlockHeader blockHeader,
|
||||
final OperationTracer operationTracer,
|
||||
final BlockHashLookup blockHashLookup) {
|
||||
final Address callAddress, final BlockProcessingContext context, final Bytes inputData) {
|
||||
WorldUpdater updater = context.getWorldState().updater();
|
||||
|
||||
// if no code exists at CALL_ADDRESS, the call must fail silently
|
||||
final Account maybeContract = worldState.get(callAddress);
|
||||
final Account maybeContract = updater.get(callAddress);
|
||||
if (maybeContract == null) {
|
||||
LOG.trace("System call address not found {}", callAddress);
|
||||
return Bytes.EMPTY;
|
||||
}
|
||||
|
||||
final AbstractMessageProcessor messageProcessor =
|
||||
final AbstractMessageProcessor processor =
|
||||
mainnetTransactionProcessor.getMessageProcessor(MessageFrame.Type.MESSAGE_CALL);
|
||||
final MessageFrame initialFrame =
|
||||
createCallFrame(callAddress, worldState, blockHeader, blockHashLookup);
|
||||
|
||||
return processFrame(initialFrame, messageProcessor, operationTracer, worldState);
|
||||
}
|
||||
|
||||
private Bytes processFrame(
|
||||
final MessageFrame frame,
|
||||
final AbstractMessageProcessor processor,
|
||||
final OperationTracer tracer,
|
||||
final WorldUpdater updater) {
|
||||
final MessageFrame frame =
|
||||
createMessageFrame(
|
||||
callAddress,
|
||||
updater,
|
||||
context.getBlockHeader(),
|
||||
context.getBlockHashLookup(),
|
||||
inputData);
|
||||
|
||||
if (!frame.getCode().isValid()) {
|
||||
throw new RuntimeException("System call did not execute to completion - opcode invalid");
|
||||
@@ -93,7 +82,7 @@ public class SystemCallProcessor {
|
||||
|
||||
Deque<MessageFrame> stack = frame.getMessageFrameStack();
|
||||
while (!stack.isEmpty()) {
|
||||
processor.process(stack.peekFirst(), tracer);
|
||||
processor.process(stack.peekFirst(), context.getOperationTracer());
|
||||
}
|
||||
|
||||
if (frame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
|
||||
@@ -105,11 +94,12 @@ public class SystemCallProcessor {
|
||||
throw new RuntimeException("System call did not execute to completion");
|
||||
}
|
||||
|
||||
private MessageFrame createCallFrame(
|
||||
private MessageFrame createMessageFrame(
|
||||
final Address callAddress,
|
||||
final WorldUpdater worldUpdater,
|
||||
final ProcessableBlockHeader blockHeader,
|
||||
final BlockHashLookup blockHashLookup) {
|
||||
final BlockHashLookup blockHashLookup,
|
||||
final Bytes inputData) {
|
||||
|
||||
final Optional<Account> maybeContract = Optional.ofNullable(worldUpdater.get(callAddress));
|
||||
final AbstractMessageProcessor processor =
|
||||
@@ -130,7 +120,7 @@ public class SystemCallProcessor {
|
||||
.type(MessageFrame.Type.MESSAGE_CALL)
|
||||
.address(callAddress)
|
||||
.contract(callAddress)
|
||||
.inputData(Bytes.EMPTY)
|
||||
.inputData(inputData)
|
||||
.sender(SYSTEM_ADDRESS)
|
||||
.blockHashLookup(blockHashLookup)
|
||||
.code(
|
||||
@@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory;
|
||||
public class Eip7709BlockHashLookup implements BlockHashLookup {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Eip7709BlockHashLookup.class);
|
||||
private static final long BLOCKHASH_SERVE_WINDOW = 256L;
|
||||
private static final long HISTORY_SERVE_WINDOW = 8191;
|
||||
|
||||
private final Address contractAddress;
|
||||
private final long historyServeWindow;
|
||||
@@ -47,10 +48,9 @@ public class Eip7709BlockHashLookup implements BlockHashLookup {
|
||||
* Constructs a Eip7709BlockHashLookup.
|
||||
*
|
||||
* @param contractAddress the address of the contract storing the history.
|
||||
* @param historyServeWindow the number of blocks for which history should be saved.
|
||||
*/
|
||||
public Eip7709BlockHashLookup(final Address contractAddress, final long historyServeWindow) {
|
||||
this(contractAddress, historyServeWindow, BLOCKHASH_SERVE_WINDOW);
|
||||
public Eip7709BlockHashLookup(final Address contractAddress) {
|
||||
this(contractAddress, HISTORY_SERVE_WINDOW, BLOCKHASH_SERVE_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,9 +22,12 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider;
|
||||
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.mainnet.systemcall.SystemCallProcessor;
|
||||
import org.hyperledger.besu.evm.blockhash.BlockHashLookup;
|
||||
import org.hyperledger.besu.evm.frame.MessageFrame;
|
||||
import org.hyperledger.besu.evm.processor.AbstractMessageProcessor;
|
||||
@@ -36,7 +39,7 @@ import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SystemCallProcessorTest {
|
||||
public class MainnetBlockContextProcessorTest {
|
||||
private static final Address CALL_ADDRESS = Address.fromHexString("0x1");
|
||||
private static final Bytes EXPECTED_OUTPUT = Bytes.fromHexString("0x01");
|
||||
private ProcessableBlockHeader mockBlockHeader;
|
||||
@@ -95,12 +98,17 @@ public class SystemCallProcessorTest {
|
||||
|
||||
Bytes processSystemCall(final MutableWorldState worldState) {
|
||||
SystemCallProcessor systemCallProcessor = new SystemCallProcessor(mockTransactionProcessor);
|
||||
return systemCallProcessor.process(
|
||||
CALL_ADDRESS,
|
||||
worldState.updater(),
|
||||
mockBlockHeader,
|
||||
OperationTracer.NO_TRACING,
|
||||
mockBlockHashLookup);
|
||||
|
||||
BlockProcessingContext blockProcessingContext =
|
||||
new BlockProcessingContext(
|
||||
mockBlockHeader,
|
||||
worldState,
|
||||
mock(ProtocolSpec.class),
|
||||
mockBlockHashLookup,
|
||||
OperationTracer.NO_TRACING);
|
||||
|
||||
when(mockBlockHashLookup.apply(any(), any())).thenReturn(Hash.EMPTY);
|
||||
return systemCallProcessor.process(CALL_ADDRESS, blockProcessingContext, Bytes.EMPTY);
|
||||
}
|
||||
|
||||
private MutableWorldState createWorldState(final Address address) {
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright contributors to Hyperledger Besu.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.mainnet.blockhash;
|
||||
|
||||
import static org.hyperledger.besu.datatypes.Hash.fromHexStringLenient;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
import org.hyperledger.besu.ethereum.core.MutableWorldState;
|
||||
import org.hyperledger.besu.evm.account.MutableAccount;
|
||||
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
|
||||
|
||||
import org.apache.tuweni.units.bigints.UInt256;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class BlockHashProcessorTest {
|
||||
private WorldUpdater worldUpdater;
|
||||
private MutableWorldState mutableWorldState;
|
||||
private MutableAccount account;
|
||||
private BlockHashProcessor processor;
|
||||
|
||||
private final long historicalWindow = 255;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mutableWorldState = mock(MutableWorldState.class);
|
||||
worldUpdater = mock(WorldUpdater.class);
|
||||
account = mock(MutableAccount.class);
|
||||
when(account.getNonce()).thenReturn(1L);
|
||||
when(mutableWorldState.updater()).thenReturn(worldUpdater);
|
||||
when(worldUpdater.getAccount(PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS))
|
||||
.thenReturn(account);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldStoreParentBlockHash() {
|
||||
long currentBlock = 3;
|
||||
processor = new PragueBlockHashProcessor();
|
||||
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
|
||||
mockAncestorHeaders(currentBlockHeader, 3);
|
||||
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||
// only parent slot number must be set
|
||||
verify(account, times(1)).setStorageValue(any(), any());
|
||||
verifyAccount(currentBlock - 1, historicalWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotStoreBlockHashForGenesisBlock() {
|
||||
// For the fork to be activated at genesis, no history is written to the genesis state, and at
|
||||
// the start of block 1, genesis hash will be written as a normal operation to slot 0.
|
||||
long currentBlock = 0;
|
||||
processor = new PragueBlockHashProcessor();
|
||||
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
|
||||
mockAncestorHeaders(currentBlockHeader, 0);
|
||||
|
||||
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||
verify(account, times(0)).setStorageValue(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldStoreAncestorBlockHashesAtForkCorrectlyParentIsGenesis() {
|
||||
// for activation at block 1, only genesis hash will be written at slot 0 as there is no
|
||||
// additional history that needs to be persisted.
|
||||
long currentBlock = 1;
|
||||
processor = new PragueBlockHashProcessor();
|
||||
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
|
||||
mockAncestorHeaders(currentBlockHeader, 10);
|
||||
|
||||
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||
verify(account, times(1)).setStorageValue(any(), any());
|
||||
verifyAccount(0, historicalWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotStoreBlockHashIfContractIsNotDeployed() {
|
||||
when(worldUpdater.getAccount(PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS))
|
||||
.thenReturn(null);
|
||||
|
||||
long currentBlock = 1;
|
||||
processor = new PragueBlockHashProcessor();
|
||||
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
|
||||
mockAncestorHeaders(currentBlockHeader, 0);
|
||||
|
||||
processor.processBlockHashes(mutableWorldState, currentBlockHeader);
|
||||
verifyNoInteractions(account);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldWriteGenesisHashAtSlot0() {
|
||||
processor = new PragueBlockHashProcessor();
|
||||
BlockHeader header = mockBlockHeader(1);
|
||||
mockAncestorHeaders(header, 1);
|
||||
processor.processBlockHashes(mutableWorldState, header);
|
||||
verify(account)
|
||||
.setStorageValue(UInt256.valueOf(0), UInt256.fromHexString(Hash.ZERO.toHexString()));
|
||||
}
|
||||
|
||||
private void verifyAccount(final long number, final long historicalWindow) {
|
||||
verify(account)
|
||||
.setStorageValue(UInt256.valueOf(number % historicalWindow), UInt256.valueOf(number));
|
||||
}
|
||||
|
||||
private void mockAncestorHeaders(final BlockHeader blockHeader, final int count) {
|
||||
long firstAncestor = Math.max(blockHeader.getNumber() - count, 0);
|
||||
var block = blockHeader;
|
||||
for (long i = blockHeader.getNumber(); i > firstAncestor; i--) {
|
||||
long parentNumber = block.getNumber() - 1;
|
||||
block = mockBlockHeader(parentNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private BlockHeader mockBlockHeader(final long currentNumber) {
|
||||
BlockHeader blockHeader = mock(BlockHeader.class);
|
||||
when(blockHeader.getNumber()).thenReturn(currentNumber);
|
||||
Hash hash = fromHexStringLenient("0x" + Long.toHexString(currentNumber));
|
||||
Hash parentHash = fromHexStringLenient("0x" + Long.toHexString(currentNumber - 1));
|
||||
when(blockHeader.getHash()).thenReturn(hash);
|
||||
when(blockHeader.getTimestamp()).thenReturn(currentNumber);
|
||||
when(blockHeader.getParentHash()).thenReturn(parentHash);
|
||||
return blockHeader;
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import org.hyperledger.besu.datatypes.TransactionType;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.datatypes.parameters.UnsignedLongParameter;
|
||||
import org.hyperledger.besu.ethereum.GasLimitCalculator;
|
||||
import org.hyperledger.besu.ethereum.api.ApiConfiguration;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter.JsonCallParameterBuilder;
|
||||
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
||||
import org.hyperledger.besu.ethereum.core.BlobTestFixture;
|
||||
@@ -93,8 +94,9 @@ public class TransactionSimulatorTest {
|
||||
Address.fromHexString("0x0000000000000000000000000000000000000000");
|
||||
private static final long GAS_CAP = 500000L;
|
||||
private static final long TRANSFER_GAS_LIMIT = 21000L;
|
||||
private TransactionSimulator transactionSimulator;
|
||||
private TransactionSimulator uncappedTransactionSimulator;
|
||||
private TransactionSimulator cappedTransactionSimulator;
|
||||
private TransactionSimulator defaultCappedTransactionSimulator;
|
||||
|
||||
@Mock private Blockchain blockchain;
|
||||
@Mock private WorldStateArchive worldStateArchive;
|
||||
@@ -107,12 +109,22 @@ public class TransactionSimulatorTest {
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
final var miningConfiguration = MiningConfiguration.newDefault().setCoinbase(Address.ZERO);
|
||||
this.transactionSimulator =
|
||||
// rpc gas cap 0 means unlimited
|
||||
this.uncappedTransactionSimulator =
|
||||
new TransactionSimulator(
|
||||
blockchain, worldStateArchive, protocolSchedule, miningConfiguration, 0);
|
||||
// capped at a lower limit
|
||||
this.cappedTransactionSimulator =
|
||||
new TransactionSimulator(
|
||||
blockchain, worldStateArchive, protocolSchedule, miningConfiguration, GAS_CAP);
|
||||
// capped at default limit
|
||||
this.defaultCappedTransactionSimulator =
|
||||
new TransactionSimulator(
|
||||
blockchain,
|
||||
worldStateArchive,
|
||||
protocolSchedule,
|
||||
miningConfiguration,
|
||||
ApiConfiguration.DEFAULT_GAS_CAP);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -174,7 +186,7 @@ public class TransactionSimulatorTest {
|
||||
when(blockchain.getBlockHeader(eq(1L))).thenReturn(Optional.empty());
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(legacyTransactionCallParameterBuilder().build(), 1L);
|
||||
uncappedTransactionSimulator.process(legacyTransactionCallParameterBuilder().build(), 1L);
|
||||
|
||||
assertThat(result.isPresent()).isFalse();
|
||||
}
|
||||
@@ -203,7 +215,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
assertThat(result.get().isSuccessful()).isTrue();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -234,12 +246,12 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.processOnPending(
|
||||
uncappedTransactionSimulator.processOnPending(
|
||||
callParameter,
|
||||
Optional.empty(),
|
||||
TransactionValidationParams.transactionSimulator(),
|
||||
NO_TRACING,
|
||||
transactionSimulator.simulatePendingBlockHeader());
|
||||
uncappedTransactionSimulator.simulatePendingBlockHeader());
|
||||
|
||||
assertThat(result.get().isSuccessful()).isTrue();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -269,7 +281,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(
|
||||
uncappedTransactionSimulator.process(
|
||||
callParameter,
|
||||
ImmutableTransactionValidationParams.builder().isAllowExceedingBalance(true).build(),
|
||||
NO_TRACING,
|
||||
@@ -306,7 +318,7 @@ public class TransactionSimulatorTest {
|
||||
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(
|
||||
uncappedTransactionSimulator.process(
|
||||
callParameter,
|
||||
ImmutableTransactionValidationParams.builder().isAllowExceedingBalance(true).build(),
|
||||
NO_TRACING,
|
||||
@@ -340,7 +352,7 @@ public class TransactionSimulatorTest {
|
||||
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(
|
||||
uncappedTransactionSimulator.process(
|
||||
callParameter,
|
||||
ImmutableTransactionValidationParams.builder().isAllowExceedingBalance(false).build(),
|
||||
NO_TRACING,
|
||||
@@ -376,7 +388,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(
|
||||
uncappedTransactionSimulator.process(
|
||||
callParameter,
|
||||
ImmutableTransactionValidationParams.builder().isAllowExceedingBalance(false).build(),
|
||||
NO_TRACING,
|
||||
@@ -409,7 +421,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
@@ -438,7 +450,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
@@ -472,7 +484,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
|
||||
@@ -501,7 +513,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.FAILED);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
assertThat(result.get().isSuccessful()).isFalse();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -512,7 +524,8 @@ public class TransactionSimulatorTest {
|
||||
when(blockchain.getBlockHeader(eq(Hash.ZERO))).thenReturn(Optional.empty());
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(legacyTransactionCallParameterBuilder().build(), Hash.ZERO);
|
||||
uncappedTransactionSimulator.process(
|
||||
legacyTransactionCallParameterBuilder().build(), Hash.ZERO);
|
||||
|
||||
assertThat(result.isPresent()).isFalse();
|
||||
}
|
||||
@@ -542,7 +555,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
uncappedTransactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
|
||||
assertThat(result.get().isSuccessful()).isTrue();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -572,7 +585,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
uncappedTransactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
@@ -601,7 +614,7 @@ public class TransactionSimulatorTest {
|
||||
.build();
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
transactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
uncappedTransactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
@@ -631,7 +644,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.FAILED);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
uncappedTransactionSimulator.process(callParameter, blockHeader.getBlockHash());
|
||||
|
||||
assertThat(result.get().isSuccessful()).isFalse();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -662,7 +675,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
assertThat(result.get().isSuccessful()).isTrue();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -735,7 +748,7 @@ public class TransactionSimulatorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUseRpcGasCapWhenGasLimitNoPresent() {
|
||||
public void shouldUseRpcGasCapWhenGasLimitNotPresent() {
|
||||
// generate call parameters that do not specify a gas limit,
|
||||
// expect the rpc gas cap to be used for simulation
|
||||
|
||||
@@ -769,6 +782,41 @@ public class TransactionSimulatorTest {
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUseDefaultRpcGasCapWhenGasLimitNotPresent() {
|
||||
// generate call parameters that do not specify a gas limit,
|
||||
// expect the default rpc gas cap to be used for simulation
|
||||
|
||||
final CallParameter callParameter =
|
||||
eip1559TransactionCallParameterBuilder().withGas(-1L).build();
|
||||
|
||||
mockBlockchainAndWorldState(callParameter);
|
||||
mockProtocolSpecForProcessWithWorldUpdater();
|
||||
|
||||
final Transaction expectedTransaction =
|
||||
Transaction.builder()
|
||||
.type(TransactionType.EIP1559)
|
||||
.chainId(BigInteger.ONE)
|
||||
.nonce(1L)
|
||||
.gasLimit(callParameter.getGasLimit())
|
||||
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
|
||||
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
|
||||
.to(callParameter.getTo())
|
||||
.sender(callParameter.getFrom())
|
||||
.value(callParameter.getValue())
|
||||
.payload(callParameter.getPayload())
|
||||
.signature(FAKE_SIGNATURE)
|
||||
.gasLimit(ApiConfiguration.DEFAULT_GAS_CAP)
|
||||
.build();
|
||||
|
||||
// call process with original transaction
|
||||
defaultCappedTransactionSimulator.process(
|
||||
callParameter, TransactionValidationParams.transactionSimulator(), NO_TRACING, 1L);
|
||||
|
||||
// expect transaction with the original gas limit to be processed
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnSuccessfulResultWhenBlobTransactionProcessingIsSuccessful() {
|
||||
final CallParameter callParameter = blobTransactionCallParameter();
|
||||
@@ -780,7 +828,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
assertThat(result.get().isSuccessful()).isTrue();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -797,7 +845,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.FAILED);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
assertThat(result.get().isSuccessful()).isFalse();
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
@@ -980,7 +1028,7 @@ public class TransactionSimulatorTest {
|
||||
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
|
||||
|
||||
final Optional<TransactionSimulatorResult> result =
|
||||
transactionSimulator.process(callParameter, 1L);
|
||||
uncappedTransactionSimulator.process(callParameter, 1L);
|
||||
|
||||
verifyTransactionWasProcessed(expectedTransaction);
|
||||
assertThat(result.get().isSuccessful()).isTrue();
|
||||
|
||||
@@ -121,6 +121,7 @@ public abstract class PendingTransaction
|
||||
return addedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int memorySize() {
|
||||
if (memorySize == NOT_INITIALIZED) {
|
||||
memorySize = computeMemorySize();
|
||||
@@ -291,6 +292,7 @@ public abstract class PendingTransaction
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toTraceLog() {
|
||||
return "{sequence: "
|
||||
+ sequence
|
||||
|
||||
@@ -43,7 +43,8 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
|
||||
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.requests.ProcessRequestContext;
|
||||
import org.hyperledger.besu.ethereum.mainnet.requests.RequestProcessingContext;
|
||||
import org.hyperledger.besu.ethereum.mainnet.systemcall.BlockProcessingContext;
|
||||
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
|
||||
import org.hyperledger.besu.ethereum.referencetests.BonsaiReferenceTestWorldState;
|
||||
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv;
|
||||
@@ -356,9 +357,18 @@ public class T8nExecutor {
|
||||
.orElse(blockHeader.getExcessBlobGas().orElse(BlobGas.ZERO)); // state-test
|
||||
final Wei blobGasPrice = protocolSpec.getFeeMarket().blobGasPricePerGas(excessBlobGas);
|
||||
long blobGasLimit = protocolSpec.getGasLimitCalculator().currentBlobGasLimit();
|
||||
BlockProcessingContext blockProcessingContext =
|
||||
new BlockProcessingContext(
|
||||
referenceTestEnv,
|
||||
worldState,
|
||||
protocolSpec,
|
||||
protocolSpec
|
||||
.getBlockHashProcessor()
|
||||
.createBlockHashLookup(blockchain, referenceTestEnv),
|
||||
OperationTracer.NO_TRACING);
|
||||
|
||||
if (!referenceTestEnv.isStateTest()) {
|
||||
protocolSpec.getBlockHashProcessor().processBlockHashes(worldState, referenceTestEnv);
|
||||
protocolSpec.getBlockHashProcessor().process(blockProcessingContext);
|
||||
}
|
||||
|
||||
final WorldUpdater rootWorldStateUpdater = worldState.updater();
|
||||
@@ -535,15 +545,10 @@ public class T8nExecutor {
|
||||
var requestProcessorCoordinator = protocolSpec.getRequestProcessorCoordinator();
|
||||
if (requestProcessorCoordinator.isPresent()) {
|
||||
var rpc = requestProcessorCoordinator.get();
|
||||
ProcessRequestContext context =
|
||||
new ProcessRequestContext(
|
||||
blockHeader,
|
||||
worldState,
|
||||
protocolSpec,
|
||||
receipts,
|
||||
protocolSpec.getBlockHashProcessor().createBlockHashLookup(blockchain, blockHeader),
|
||||
OperationTracer.NO_TRACING);
|
||||
Optional<List<Request>> maybeRequests = Optional.of(rpc.process(context));
|
||||
|
||||
RequestProcessingContext requestContext =
|
||||
new RequestProcessingContext(blockProcessingContext, receipts);
|
||||
Optional<List<Request>> maybeRequests = Optional.of(rpc.process(requestContext));
|
||||
Hash requestsHash = BodyValidation.requestsHash(maybeRequests.orElse(List.of()));
|
||||
|
||||
resultObject.put("requestsHash", requestsHash.toHexString());
|
||||
|
||||
@@ -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 = 'FEieWer0x6AdCmvf02G7yGQxS5JRxsIYrRDpqsNgQ+0='
|
||||
knownHash = 'U/zVfjqq/stLY920xHh1N26KU+KoAdgEiV2nPWIFRIs='
|
||||
}
|
||||
check.dependsOn('checkAPIChanges')
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ package org.hyperledger.besu.plugin.services.txselection;
|
||||
|
||||
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
|
||||
|
||||
import org.hyperledger.besu.datatypes.PendingTransaction;
|
||||
import org.hyperledger.besu.plugin.Unstable;
|
||||
import org.hyperledger.besu.plugin.data.TransactionProcessingResult;
|
||||
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
|
||||
@@ -30,13 +29,13 @@ public interface PluginTransactionSelector {
|
||||
new PluginTransactionSelector() {
|
||||
@Override
|
||||
public TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||
TransactionEvaluationContext<? extends PendingTransaction> evaluationContext) {
|
||||
TransactionEvaluationContext evaluationContext) {
|
||||
return SELECTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionSelectionResult evaluateTransactionPostProcessing(
|
||||
TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
|
||||
TransactionEvaluationContext evaluationContext,
|
||||
TransactionProcessingResult processingResult) {
|
||||
return SELECTED;
|
||||
}
|
||||
@@ -60,7 +59,7 @@ public interface PluginTransactionSelector {
|
||||
* @return TransactionSelectionResult that indicates whether to include the transaction
|
||||
*/
|
||||
TransactionSelectionResult evaluateTransactionPreProcessing(
|
||||
TransactionEvaluationContext<? extends PendingTransaction> evaluationContext);
|
||||
TransactionEvaluationContext evaluationContext);
|
||||
|
||||
/**
|
||||
* Method called to decide whether a processed transaction is added to a block. The result can
|
||||
@@ -71,8 +70,7 @@ public interface PluginTransactionSelector {
|
||||
* @return TransactionSelectionResult that indicates whether to include the transaction
|
||||
*/
|
||||
TransactionSelectionResult evaluateTransactionPostProcessing(
|
||||
TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
|
||||
TransactionProcessingResult processingResult);
|
||||
TransactionEvaluationContext evaluationContext, TransactionProcessingResult processingResult);
|
||||
|
||||
/**
|
||||
* Method called when a transaction is selected to be added to a block.
|
||||
@@ -81,7 +79,7 @@ public interface PluginTransactionSelector {
|
||||
* @param processingResult The result of processing the selected transaction.
|
||||
*/
|
||||
default void onTransactionSelected(
|
||||
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
|
||||
final TransactionEvaluationContext evaluationContext,
|
||||
final TransactionProcessingResult processingResult) {}
|
||||
|
||||
/**
|
||||
@@ -91,6 +89,6 @@ public interface PluginTransactionSelector {
|
||||
* @param transactionSelectionResult The transaction selection result
|
||||
*/
|
||||
default void onTransactionNotSelected(
|
||||
final TransactionEvaluationContext<? extends PendingTransaction> evaluationContext,
|
||||
final TransactionEvaluationContext evaluationContext,
|
||||
final TransactionSelectionResult transactionSelectionResult) {}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,8 @@ import com.google.common.base.Stopwatch;
|
||||
/**
|
||||
* This interface defines the context for evaluating a transaction. It provides methods to get the
|
||||
* pending transaction, the evaluation timer, and the transaction gas price.
|
||||
*
|
||||
* @param <PT> the type of the pending transaction
|
||||
*/
|
||||
public interface TransactionEvaluationContext<PT extends PendingTransaction> {
|
||||
public interface TransactionEvaluationContext {
|
||||
|
||||
/**
|
||||
* Gets the pending block header
|
||||
@@ -40,7 +38,7 @@ public interface TransactionEvaluationContext<PT extends PendingTransaction> {
|
||||
*
|
||||
* @return the pending transaction
|
||||
*/
|
||||
PT getPendingTransaction();
|
||||
PendingTransaction getPendingTransaction();
|
||||
|
||||
/**
|
||||
* Gets the stopwatch used for timing the evaluation.
|
||||
|
||||
Reference in New Issue
Block a user