From 6c7ecbf2081da947bcc9e44b12238188c5f763e1 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Mon, 2 Dec 2024 18:15:04 +0100 Subject: [PATCH] Support state overrides in `linea_estimateGas` Signed-off-by: Fabio Di Fabio --- .../acc/test/rpc/linea/EstimateGasTest.java | 42 ++++++++++++++++++- .../linea/rpc/methods/LineaEstimateGas.java | 33 +++++++++++---- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java index f4e17cec..10963bd2 100644 --- a/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java +++ b/acceptance-tests/src/test/java/linea/plugin/acc/test/rpc/linea/EstimateGasTest.java @@ -24,6 +24,7 @@ import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Map; import linea.plugin.acc.test.LineaPluginTestBase; import linea.plugin.acc.test.TestCommandLineOptionsBuilder; @@ -122,6 +123,36 @@ public void passingGasPriceFieldWorks() { assertThat(respLinea.getResult()).isNotNull(); } + @Test + public void passingStateOverridesWorks() { + + final Account sender = accounts.getSecondaryBenefactor(); + + final var actualBalance = minerNode.execute(ethTransactions.getBalance(sender)); + + assertThat(actualBalance).isGreaterThan(BigInteger.ONE); + + final CallParams callParams = + new CallParams( + sender.getAddress(), + sender.getAddress(), + "1", + Bytes.EMPTY.toHexString(), + "0", + "0x1234"); + + final var zeroBalance = Map.of("balance", Wei.ZERO.toHexString()); + + final var stateOverrides = Map.of(accounts.getSecondaryBenefactor().getAddress(), zeroBalance); + + final var reqLinea = new LineaEstimateGasRequest(callParams, stateOverrides); + final var respLinea = reqLinea.execute(minerNode.nodeRequests()); + assertThat(respLinea.hasError()).isTrue(); + assertThat(respLinea.getError().getMessage()) + .isEqualTo( + "transaction up-front cost 0x208cbab601 exceeds transaction sender account balance 0x0"); + } + @Test public void lineaEstimateGasIsProfitable() { @@ -258,9 +289,16 @@ protected void assertMinGasPriceLowerBound(final Wei baseFee, final Wei estimate static class LineaEstimateGasRequest implements Transaction { private final CallParams callParams; + private final Map> stateOverrides; public LineaEstimateGasRequest(final CallParams callParams) { + this(callParams, null); + } + + public LineaEstimateGasRequest( + final CallParams callParams, final Map> stateOverrides) { this.callParams = callParams; + this.stateOverrides = stateOverrides; } @Override @@ -268,7 +306,7 @@ public LineaEstimateGasResponse execute(final NodeRequests nodeRequests) { try { return new Request<>( "linea_estimateGas", - List.of(callParams), + List.of(callParams, stateOverrides), nodeRequests.getWeb3jService(), LineaEstimateGasResponse.class) .send(); @@ -337,4 +375,6 @@ static class RawEstimateGasResponse extends org.web3j.protocol.core.Response maybeStateOverrides, + final Transaction transaction, + final long logId) { final var estimateGasTracer = new EstimateGasOperationTracer(); final var chainHeadHeader = blockchainService.getChainHeadHeader(); @@ -272,7 +279,8 @@ private Long estimateGasUsed( final var chainHeadHash = chainHeadHeader.getBlockHash(); final var maybeSimulationResults = - transactionSimulationService.simulate(transaction, chainHeadHash, zkAndGasTracer, false); + transactionSimulationService.simulate( + transaction, maybeStateOverrides, chainHeadHash, zkAndGasTracer, false); ModuleLimitsValidationResult moduleLimit = moduleLineCountValidator.validate(zkTracer.getModulesLineCount()); @@ -319,6 +327,7 @@ private Long estimateGasUsed( final var lowResult = transactionSimulationService.simulate( createTransactionForSimulation(callParameters, lowGasEstimation), + maybeStateOverrides, chainHeadHash, estimateGasTracer, true); @@ -354,6 +363,7 @@ private Long estimateGasUsed( final var binarySearchResult = transactionSimulationService.simulate( createTransactionForSimulation(callParameters, mid), + maybeStateOverrides, chainHeadHash, estimateGasTracer, true); @@ -409,7 +419,7 @@ private Long estimateGasUsed( RpcErrorType.PLUGIN_INTERNAL_ERROR, "Empty result from simulation")); } - private JsonCallParameter parseRequest(final Object[] params) { + private JsonCallParameter parseCallParameters(final Object[] params) { final JsonCallParameter callParameters; try { callParameters = parameterParser.required(params, 0, JsonCallParameter.class); @@ -417,11 +427,11 @@ private JsonCallParameter parseRequest(final Object[] params) { throw new InvalidJsonRpcParameters( "Invalid call parameters (index 0)", RpcErrorType.INVALID_CALL_PARAMS); } - validateParameters(callParameters); + validateCallParameters(callParameters); return callParameters; } - private void validateParameters(final JsonCallParameter callParameters) { + private void validateCallParameters(final JsonCallParameter callParameters) { if (callParameters.getGasPrice() != null && isBaseFeeTransaction(callParameters)) { throw new InvalidJsonRpcParameters( "gasPrice cannot be used with maxFeePerGas or maxPriorityFeePerGas or maxFeePerBlobGas"); @@ -434,6 +444,15 @@ private void validateParameters(final JsonCallParameter callParameters) { } } + protected Optional getAddressAccountOverrideMap(final Object[] params) { + try { + return parameterParser.optional(params, 1, AccountOverrideMap.class); + } catch (JsonRpcParameter.JsonRpcParameterException e) { + throw new InvalidJsonRpcRequestException( + "Invalid account overrides parameter (index 1)", RpcErrorType.INVALID_CALL_PARAMS, e); + } + } + private boolean isBaseFeeTransaction(final JsonCallParameter callParameters) { return (callParameters.getMaxFeePerGas().isPresent() || callParameters.getMaxPriorityFeePerGas().isPresent()