diff --git a/CHANGELOG.md b/CHANGELOG.md index 08e4a572870..d95d1f332c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ - Extend simulate transaction on pending block plugin API [#8174](https://github.com/hyperledger/besu/pull/8174) ### Bug fixes - +- Fix the simulation of txs with a future nonce [#8215](https://github.com/hyperledger/besu/pull/8215) ## 25.1.0 diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java index 73e0d4cb570..654282f3522 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java @@ -21,7 +21,6 @@ import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; -import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams; import org.hyperledger.besu.ethereum.transaction.CallParameter; @@ -163,14 +162,9 @@ public Optional getCall(final DataFetchingEnvironment environment) { final CallParameter param = new CallParameter(from, to, gasParam, gasPriceParam, valueParam, data); - ImmutableTransactionValidationParams.Builder transactionValidationParams = - ImmutableTransactionValidationParams.builder() - .from(TransactionValidationParams.transactionSimulator()); - transactionValidationParams.isAllowExceedingBalance(true); - return transactionSimulator.process( param, - transactionValidationParams.build(), + TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce(), OperationTracer.NO_TRACING, (mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult.map( diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java index 9e380a4c17b..931a06c0fe7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/AbstractEstimateGas.java @@ -210,8 +210,8 @@ protected static TransactionValidationParams getTransactionValidationParams( final boolean isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE); return isAllowExceedingBalance - ? TransactionValidationParams.transactionSimulatorAllowExceedingBalance() - : TransactionValidationParams.transactionSimulator(); + ? TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce() + : TransactionValidationParams.transactionSimulatorAllowFutureNonce(); } @VisibleForTesting diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java index 45b06ce6910..4bfe4f18b47 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugTraceCall.java @@ -39,6 +39,13 @@ import java.util.Optional; public class DebugTraceCall extends AbstractTraceCall { + private static final TransactionValidationParams TRANSACTION_VALIDATION_PARAMS = + ImmutableTransactionValidationParams.builder() + .from(TransactionValidationParams.transactionSimulator()) + .isAllowFutureNonce(true) + .isAllowExceedingBalance(true) + .allowUnderpriced(true) + .build(); public DebugTraceCall( final BlockchainQueries blockchainQueries, @@ -103,10 +110,6 @@ protected PreCloseStateHandler getSimulatorResultHandler( @Override protected TransactionValidationParams buildTransactionValidationParams() { - return ImmutableTransactionValidationParams.builder() - .from(TransactionValidationParams.transactionSimulator()) - .isAllowExceedingBalance(true) - .allowUnderpriced(true) - .build(); + return TRANSACTION_VALIDATION_PARAMS; } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java index bec46f33d86..4424c6aa642 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java @@ -169,8 +169,8 @@ private TransactionValidationParams buildTransactionValidationParams( isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE); } return isAllowExceedingBalance - ? TransactionValidationParams.transactionSimulatorAllowExceedingBalance() - : TransactionValidationParams.transactionSimulator(); + ? TransactionValidationParams.transactionSimulatorAllowExceedingBalanceAndFutureNonce() + : TransactionValidationParams.transactionSimulatorAllowFutureNonce(); } private boolean isAllowExceedingBalanceAutoSelection( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java index 8f1e3d07ab8..697f31458d1 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java @@ -514,6 +514,7 @@ private void internalAutoSelectIsAllowedExceedingBalance( ImmutableTransactionValidationParams.builder() .from(TransactionValidationParams.transactionSimulator()) .isAllowExceedingBalance(isAllowedExceedingBalance) + .isAllowFutureNonce(true) .build(); verify(transactionSimulator) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java index 3fedb9b4532..c0d1b38e4d6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java @@ -140,7 +140,7 @@ public void shouldReturnErrorWhenTransientLegacyTransactionProcessorReturnsEmpty final JsonRpcRequestContext request = ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO)); when(transactionSimulator.process( - eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)), + eq(modifiedLegacyTransactionCallParameter(Wei.ZERO, Optional.empty())), eq(Optional.empty()), // no account overrides any(TransactionValidationParams.class), any(OperationTracer.class), @@ -193,11 +193,26 @@ public void shouldUseGasPriceParameterWhenIsPresent() { assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse); } + @Test + public void shouldUseNonceParameterWhenIsPresent() { + final Wei gasPrice = Wei.of(1000); + final long nonce = 0L; + final JsonRpcRequestContext request = + ethEstimateGasRequest( + eip1559TransactionCallParameter(Optional.of(gasPrice), Optional.of(nonce))); + getMockTransactionSimulatorResult( + true, 1L, gasPrice, Optional.empty(), latestBlockHeader, Optional.of(nonce)); + + final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, Quantity.create(1L)); + assertThat(method.response(request)).usingRecursiveComparison().isEqualTo(expectedResponse); + } + @Test public void shouldNotErrorWhenGasPricePresentForEip1559Transaction() { final Wei gasPrice = Wei.of(1000); final JsonRpcRequestContext request = - ethEstimateGasRequest(eip1559TransactionCallParameter(Optional.of(gasPrice))); + ethEstimateGasRequest( + eip1559TransactionCallParameter(Optional.of(gasPrice), Optional.empty())); mockTransientProcessorResultGasEstimate( 1L, true, gasPrice, Optional.empty(), latestBlockHeader); @@ -379,9 +394,11 @@ public void shouldIgnoreSenderBalanceAccountWhenStrictModeDisabled() { verify(transactionSimulator) .process( - eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)), + eq(modifiedLegacyTransactionCallParameter(Wei.ZERO, Optional.empty())), eq(Optional.empty()), // no account overrides - eq(TransactionValidationParams.transactionSimulatorAllowExceedingBalance()), + eq( + TransactionValidationParams + .transactionSimulatorAllowExceedingBalanceAndFutureNonceParams), any(OperationTracer.class), eq(latestBlockHeader)); } @@ -396,9 +413,9 @@ public void shouldNotIgnoreSenderBalanceAccountWhenStrictModeEnabled() { verify(transactionSimulator) .process( - eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)), + eq(modifiedLegacyTransactionCallParameter(Wei.ZERO, Optional.empty())), eq(Optional.empty()), // no account overrides - eq(TransactionValidationParams.transactionSimulator()), + eq(TransactionValidationParams.transactionSimulatorAllowFutureNonce()), any(OperationTracer.class), eq(latestBlockHeader)); } @@ -456,7 +473,8 @@ private void mockTransientProcessorResultTxInvalidReason( final String validationFailedErrorMessage, final BlockHeader blockHeader) { final TransactionSimulatorResult mockTxSimResult = - getMockTransactionSimulatorResult(false, 0, Wei.ZERO, Optional.empty(), blockHeader); + getMockTransactionSimulatorResult( + false, 0, Wei.ZERO, Optional.empty(), blockHeader, Optional.empty()); when(mockTxSimResult.getValidationResult()) .thenReturn( validationFailedErrorMessage == null @@ -493,7 +511,7 @@ private void mockTransientProcessorResultGasEstimate( final Optional revertReason, final BlockHeader blockHeader) { getMockTransactionSimulatorResult( - isSuccessful, estimateGas, gasPrice, revertReason, blockHeader); + isSuccessful, estimateGas, gasPrice, revertReason, blockHeader, Optional.empty()); } @SuppressWarnings("ReferenceEquality") @@ -502,11 +520,12 @@ private TransactionSimulatorResult getMockTransactionSimulatorResult( final long estimateGas, final Wei gasPrice, final Optional revertReason, - final BlockHeader blockHeader) { + final BlockHeader blockHeader, + final Optional maybeNonce) { final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class); if (blockHeader == pendingBlockHeader) { when(transactionSimulator.processOnPending( - eq(modifiedLegacyTransactionCallParameter(gasPrice)), + eq(modifiedLegacyTransactionCallParameter(gasPrice, maybeNonce)), eq(Optional.empty()), // no account overrides any(TransactionValidationParams.class), any(OperationTracer.class), @@ -521,7 +540,7 @@ private TransactionSimulatorResult getMockTransactionSimulatorResult( .thenReturn(Optional.of(mockTxSimResult)); } else { when(transactionSimulator.process( - eq(modifiedLegacyTransactionCallParameter(gasPrice)), + eq(modifiedLegacyTransactionCallParameter(gasPrice, maybeNonce)), eq(Optional.empty()), // no account overrides any(TransactionValidationParams.class), any(OperationTracer.class), @@ -536,7 +555,7 @@ private TransactionSimulatorResult getMockTransactionSimulatorResult( .thenReturn(Optional.of(mockTxSimResult)); // for testing different combination of gasPrice params when(transactionSimulator.process( - eq(modifiedEip1559TransactionCallParameter(Optional.of(gasPrice))), + eq(modifiedEip1559TransactionCallParameter(Optional.of(gasPrice), maybeNonce)), eq(Optional.empty()), // no account overrides any(TransactionValidationParams.class), any(OperationTracer.class), @@ -569,7 +588,8 @@ private JsonCallParameter legacyTransactionCallParameter( .build(); } - private CallParameter modifiedLegacyTransactionCallParameter(final Wei gasPrice) { + private CallParameter modifiedLegacyTransactionCallParameter( + final Wei gasPrice, final Optional maybeNonce) { return new CallParameter( Address.fromHexString("0x0"), Address.fromHexString("0x0"), @@ -580,14 +600,15 @@ private CallParameter modifiedLegacyTransactionCallParameter(final Wei gasPrice) Wei.ZERO, Bytes.EMPTY, Optional.empty(), - Optional.empty()); + maybeNonce); } private CallParameter eip1559TransactionCallParameter() { - return eip1559TransactionCallParameter(Optional.empty()); + return eip1559TransactionCallParameter(Optional.empty(), Optional.empty()); } - private JsonCallParameter eip1559TransactionCallParameter(final Optional maybeGasPrice) { + private JsonCallParameter eip1559TransactionCallParameter( + final Optional maybeGasPrice, final Optional maybeNonce) { return new JsonCallParameter.JsonCallParameterBuilder() .withFrom(Address.fromHexString("0x0")) .withTo(Address.fromHexString("0x0")) @@ -597,14 +618,16 @@ private JsonCallParameter eip1559TransactionCallParameter(final Optional ma .withValue(Wei.ZERO) .withInput(Bytes.EMPTY) .withStrict(false) + .withNonce(maybeNonce.map(UnsignedLongParameter::new).orElse(null)) .build(); } private CallParameter modifiedEip1559TransactionCallParameter() { - return modifiedEip1559TransactionCallParameter(Optional.empty()); + return modifiedEip1559TransactionCallParameter(Optional.empty(), Optional.empty()); } - private CallParameter modifiedEip1559TransactionCallParameter(final Optional gasPrice) { + private CallParameter modifiedEip1559TransactionCallParameter( + final Optional gasPrice, final Optional maybeNonce) { return new CallParameter( Address.fromHexString("0x0"), Address.fromHexString("0x0"), @@ -615,7 +638,7 @@ private CallParameter modifiedEip1559TransactionCallParameter(final Optional