Skip to content

Fix the simulation of txs with future nonce #8215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -163,14 +162,9 @@ public Optional<CallResult> 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -103,10 +110,6 @@ protected PreCloseStateHandler<Object> getSimulatorResultHandler(

@Override
protected TransactionValidationParams buildTransactionValidationParams() {
return ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(true)
.allowUnderpriced(true)
.build();
return TRANSACTION_VALIDATION_PARAMS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ private void internalAutoSelectIsAllowedExceedingBalance(
ImmutableTransactionValidationParams.builder()
.from(TransactionValidationParams.transactionSimulator())
.isAllowExceedingBalance(isAllowedExceedingBalance)
.isAllowFutureNonce(true)
.build();

verify(transactionSimulator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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));
}
Expand All @@ -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));
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -493,7 +511,7 @@ private void mockTransientProcessorResultGasEstimate(
final Optional<Bytes> revertReason,
final BlockHeader blockHeader) {
getMockTransactionSimulatorResult(
isSuccessful, estimateGas, gasPrice, revertReason, blockHeader);
isSuccessful, estimateGas, gasPrice, revertReason, blockHeader, Optional.empty());
}

@SuppressWarnings("ReferenceEquality")
Expand All @@ -502,11 +520,12 @@ private TransactionSimulatorResult getMockTransactionSimulatorResult(
final long estimateGas,
final Wei gasPrice,
final Optional<Bytes> revertReason,
final BlockHeader blockHeader) {
final BlockHeader blockHeader,
final Optional<Long> 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),
Expand All @@ -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),
Expand All @@ -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),
Expand Down Expand Up @@ -569,7 +588,8 @@ private JsonCallParameter legacyTransactionCallParameter(
.build();
}

private CallParameter modifiedLegacyTransactionCallParameter(final Wei gasPrice) {
private CallParameter modifiedLegacyTransactionCallParameter(
final Wei gasPrice, final Optional<Long> maybeNonce) {
return new CallParameter(
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
Expand All @@ -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<Wei> maybeGasPrice) {
private JsonCallParameter eip1559TransactionCallParameter(
final Optional<Wei> maybeGasPrice, final Optional<Long> maybeNonce) {
return new JsonCallParameter.JsonCallParameterBuilder()
.withFrom(Address.fromHexString("0x0"))
.withTo(Address.fromHexString("0x0"))
Expand All @@ -597,14 +618,16 @@ private JsonCallParameter eip1559TransactionCallParameter(final Optional<Wei> 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<Wei> gasPrice) {
private CallParameter modifiedEip1559TransactionCallParameter(
final Optional<Wei> gasPrice, final Optional<Long> maybeNonce) {
return new CallParameter(
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
Expand All @@ -615,7 +638,7 @@ private CallParameter modifiedEip1559TransactionCallParameter(final Optional<Wei
Wei.ZERO,
Bytes.EMPTY,
Optional.empty(),
Optional.empty());
maybeNonce);
}

private JsonRpcRequestContext ethEstimateGasRequest(final CallParameter callParameter) {
Expand Down
Loading