Skip to content

Commit

Permalink
Fix the simulation of txs with future nonce (hyperledger#8215)
Browse files Browse the repository at this point in the history
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
  • Loading branch information
fab-10 authored Feb 3, 2025
1 parent 4fa9f0c commit 24e2895
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 36 deletions.
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

0 comments on commit 24e2895

Please sign in to comment.