From 7a37179a61a99bf718af1df38b193cb70299efe8 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio <fabio.difabio@consensys.net> Date: Mon, 27 Jan 2025 15:24:58 +0100 Subject: [PATCH] Extend simulate transaction on pending block plugin API Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net> --- .../TransactionSimulationServiceImpl.java | 68 +++++++++------ .../mainnet/TransactionValidationParams.java | 14 ++++ .../transaction/TransactionSimulator.java | 2 +- plugin-api/build.gradle | 2 +- .../TransactionSimulationService.java | 82 +++++-------------- 5 files changed, 79 insertions(+), 89 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/services/TransactionSimulationServiceImpl.java b/besu/src/main/java/org/hyperledger/besu/services/TransactionSimulationServiceImpl.java index d8e12a2be7f5..bac48cb47db6 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/TransactionSimulationServiceImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/TransactionSimulationServiceImpl.java @@ -26,11 +26,17 @@ import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; import org.hyperledger.besu.plugin.data.TransactionSimulationResult; import org.hyperledger.besu.plugin.services.TransactionSimulationService; import java.util.Optional; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionSimulator; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionSimulatorAllowExceedingBalance; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce; +import static org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams.transactionSimulatorAllowFutureNonce; + /** TransactionSimulationServiceImpl */ @Unstable public class TransactionSimulationServiceImpl implements TransactionSimulationService { @@ -51,50 +57,62 @@ public void init(final Blockchain blockchain, final TransactionSimulator transac this.transactionSimulator = transactionSimulator; } + @Override + public ProcessableBlockHeader simulatePendingBlockHeader() { + return transactionSimulator.simulatePendingBlockHeader(); + } + @Override public Optional<TransactionSimulationResult> simulate( final Transaction transaction, final Optional<StateOverrideMap> maybeStateOverrides, - final Optional<Hash> maybeBlockHash, + final Hash blockHash, final OperationTracer operationTracer, final boolean isAllowExceedingBalance) { final CallParameter callParameter = CallParameter.fromTransaction(transaction); - if (maybeBlockHash.isPresent()) { - final Hash blockHash = maybeBlockHash.get(); + final var maybeBlockHeader = + blockchain.getBlockHeader(blockHash).or(() -> blockchain.getBlockHeaderSafe(blockHash)); - final var maybeBlockHeader = - blockchain.getBlockHeader(blockHash).or(() -> blockchain.getBlockHeaderSafe(blockHash)); + if (maybeBlockHeader.isEmpty()) { + return Optional.of( + new TransactionSimulationResult( + transaction, + TransactionProcessingResult.invalid( + ValidationResult.invalid(TransactionInvalidReason.BLOCK_NOT_FOUND)))); + } - if (maybeBlockHeader.isEmpty()) { - return Optional.of( - new TransactionSimulationResult( - transaction, - TransactionProcessingResult.invalid( - ValidationResult.invalid(TransactionInvalidReason.BLOCK_NOT_FOUND)))); - } + return transactionSimulator + .process( + callParameter, + isAllowExceedingBalance + ? transactionSimulatorAllowExceedingBalance() + : transactionSimulator(), + operationTracer, + maybeBlockHeader.get()) + .map(res -> new TransactionSimulationResult(transaction, res.result())); + } - return transactionSimulator - .process( - callParameter, - isAllowExceedingBalance - ? TransactionValidationParams.transactionSimulatorAllowExceedingBalance() - : TransactionValidationParams.transactionSimulator(), - operationTracer, - maybeBlockHeader.get()) - .map(res -> new TransactionSimulationResult(transaction, res.result())); - } + @Override + public Optional<TransactionSimulationResult> simulate( + final Transaction transaction, + final Optional<StateOverrideMap> maybeStateOverrides, + final ProcessableBlockHeader pendingBlockHeader, + final OperationTracer operationTracer, + final boolean isAllowExceedingBalance, final boolean isAllowFutureNonce) { + + final CallParameter callParameter = CallParameter.fromTransaction(transaction); return transactionSimulator .processOnPending( callParameter, maybeStateOverrides, isAllowExceedingBalance - ? TransactionValidationParams.transactionSimulatorAllowExceedingBalance() - : TransactionValidationParams.transactionSimulator(), + ? isAllowFutureNonce ? transactionSimulatorAllowExceedingBalanceAndFutureNonce() : transactionSimulatorAllowExceedingBalance() + : isAllowFutureNonce ? transactionSimulatorAllowFutureNonce(): transactionSimulator(), operationTracer, - transactionSimulator.simulatePendingBlockHeader()) + (org.hyperledger.besu.ethereum.core.ProcessableBlockHeader) pendingBlockHeader) .map(res -> new TransactionSimulationResult(transaction, res.result())); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java index 78d6497335ab..c0ca00f8b9c1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionValidationParams.java @@ -35,9 +35,15 @@ public interface TransactionValidationParams { TransactionValidationParams transactionSimulatorParams = ImmutableTransactionValidationParams.of(false, false, false, false, false, true); + TransactionValidationParams transactionSimulatorParamsAllowFutureNonce = + ImmutableTransactionValidationParams.of(true, false, false, false, false, true); + TransactionValidationParams transactionSimulatorAllowExceedingBalanceParams = ImmutableTransactionValidationParams.of(false, true, false, false, false, true); + TransactionValidationParams transactionSimulatorAllowExceedingBalanceAndFutureNonceParams = + ImmutableTransactionValidationParams.of(true, true, false, false, false, true); + @Value.Default default boolean isAllowFutureNonce() { return false; @@ -72,10 +78,18 @@ static TransactionValidationParams transactionSimulator() { return transactionSimulatorParams; } + static TransactionValidationParams transactionSimulatorAllowFutureNonce() { + return transactionSimulatorParamsAllowFutureNonce; + } + static TransactionValidationParams transactionSimulatorAllowExceedingBalance() { return transactionSimulatorAllowExceedingBalanceParams; } + static TransactionValidationParams transactionSimulatorAllowExceedingBalanceAndFutureNonce() { + return transactionSimulatorAllowExceedingBalanceAndFutureNonceParams; + } + static TransactionValidationParams processingBlock() { return processingBlockParams; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index bf8c966f8c9f..7c089c5aa8be 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -174,7 +174,7 @@ public Optional<TransactionSimulatorResult> processOnPending( operationTracer, pendingBlockHeader, updater, - Address.ZERO); + pendingBlockHeader.getCoinbase()); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/plugin-api/build.gradle b/plugin-api/build.gradle index 3844f76480ec..a2e9d320e5d2 100644 --- a/plugin-api/build.gradle +++ b/plugin-api/build.gradle @@ -71,7 +71,7 @@ Calculated : ${currentHash} tasks.register('checkAPIChanges', FileStateChecker) { description = "Checks that the API for the Plugin-API project does not change without deliberate thought" files = sourceSets.main.allJava.files - knownHash = 'E2b/W+IKnNxo6L7cHuijBMBUewHHRrkQ8dEVlcql5KE=' + knownHash = 'iy+e0qmPmjT+hD0LI39QnlXJzreSUjKgCj1tlNqIUzQ=' } check.dependsOn('checkAPIChanges') diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TransactionSimulationService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TransactionSimulationService.java index 508e6eeff7d1..6b60f9c6c24d 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TransactionSimulationService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TransactionSimulationService.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.datatypes.Transaction; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.plugin.Unstable; +import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; import org.hyperledger.besu.plugin.data.TransactionSimulationResult; import java.util.Optional; @@ -27,13 +28,21 @@ @Unstable public interface TransactionSimulationService extends BesuService { + /** + * Return a simulation of what could be current pending block, it can also be passed to {@link + * #simulate(Transaction, Optional, ProcessableBlockHeader, OperationTracer, boolean, boolean)} + * + * @return the simulated pending block header + */ + ProcessableBlockHeader simulatePendingBlockHeader(); + /** * Simulate transaction execution at the block identified by the hash if present, otherwise on the * pending block, with optional state overrides that can be applied before the simulation. * * @param transaction tx * @param stateOverrides state overrides to apply to this simulation - * @param maybeBlockHash optional hash of the block, empty to simulate on pending block + * @param blockHash hash of the block * @param operationTracer the tracer * @param isAllowExceedingBalance should ignore the sender balance during the simulation? * @return the result of the simulation @@ -41,77 +50,26 @@ public interface TransactionSimulationService extends BesuService { Optional<TransactionSimulationResult> simulate( Transaction transaction, Optional<StateOverrideMap> stateOverrides, - Optional<Hash> maybeBlockHash, + Hash blockHash, OperationTracer operationTracer, boolean isAllowExceedingBalance); /** * Simulate transaction execution at the block identified by the hash if present, otherwise on the - * pending block - * - * @param transaction tx - * @param maybeBlockHash optional hash of the block, empty to simulate on pending block - * @param operationTracer the tracer - * @param isAllowExceedingBalance should ignore the sender balance during the simulation? - * @return the result of the simulation - */ - default Optional<TransactionSimulationResult> simulate( - final Transaction transaction, - final Optional<Hash> maybeBlockHash, - final OperationTracer operationTracer, - final boolean isAllowExceedingBalance) { - return simulate( - transaction, Optional.empty(), maybeBlockHash, operationTracer, isAllowExceedingBalance); - } - - /** - * Simulate transaction execution at the block identified by the hash - * - * @param transaction tx - * @param blockHash then hash of the block - * @param operationTracer the tracer - * @param isAllowExceedingBalance should ignore the sender balance during the simulation? - * @return the result of the simulation - * @deprecated use {@link #simulate(Transaction, Optional, OperationTracer, boolean)} - */ - @Deprecated(since = "24.12", forRemoval = true) - default Optional<TransactionSimulationResult> simulate( - final Transaction transaction, - final Hash blockHash, - final OperationTracer operationTracer, - final boolean isAllowExceedingBalance) { - return simulate( - transaction, - Optional.empty(), - Optional.of(blockHash), - operationTracer, - isAllowExceedingBalance); - } - - /** - * Simulate transaction execution at the block identified by the hash, with optional state - * overrides that can be applied before the simulation. + * pending block, with optional state overrides that can be applied before the simulation. * * @param transaction tx * @param stateOverrides state overrides to apply to this simulation - * @param blockHash the hash of the block + * @param processableBlockHeader block header to simulate on pending block * @param operationTracer the tracer * @param isAllowExceedingBalance should ignore the sender balance during the simulation? + * @param isAllowFutureNonce should skip strict check on sequential nonce? * @return the result of the simulation - * @deprecated use {@link #simulate(Transaction, Optional, Optional, OperationTracer, boolean)} */ - @Deprecated(since = "24.12", forRemoval = true) - default Optional<TransactionSimulationResult> simulate( - final Transaction transaction, - final Optional<StateOverrideMap> stateOverrides, - final Hash blockHash, - final OperationTracer operationTracer, - final boolean isAllowExceedingBalance) { - return simulate( - transaction, - stateOverrides, - Optional.of(blockHash), - operationTracer, - isAllowExceedingBalance); - } + Optional<TransactionSimulationResult> simulate( + Transaction transaction, + Optional<StateOverrideMap> stateOverrides, + ProcessableBlockHeader processableBlockHeader, + OperationTracer operationTracer, + boolean isAllowExceedingBalance, boolean isAllowFutureNonce); }