mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 15:37:54 -05:00
eth_estimateGas state overrides (#7890)
* parse account overrides parameter for eth_estimateGas Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> * changelog Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com> --------- Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
This commit is contained in:
@@ -15,8 +15,8 @@
|
||||
- Update Java dependencies [#7786](https://github.com/hyperledger/besu/pull/7786)
|
||||
- Add a method to get all the transaction in the pool, to the `TransactionPoolService`, to easily access the transaction pool content from plugins [#7813](https://github.com/hyperledger/besu/pull/7813)
|
||||
- Add a method to check if a metric category is enabled to the plugin API [#7832](https://github.com/hyperledger/besu/pull/7832)
|
||||
- Add account and state overrides to `eth_call` and `eth_estimateGas` [#7801](https://github.com/hyperledger/besu/pull/7801)
|
||||
- Add a new metric collector for counters which get their value from suppliers [#7894](https://github.com/hyperledger/besu/pull/7894)
|
||||
- Add account and state overrides to `eth_call` [#7801](https://github.com/hyperledger/besu/pull/7801) and `eth_estimateGas` [#7890](https://github.com/hyperledger/besu/pull/7890)
|
||||
|
||||
### Bug fixes
|
||||
- Fix registering new metric categories from plugins [#7825](https://github.com/hyperledger/besu/pull/7825)
|
||||
|
||||
@@ -16,7 +16,9 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
||||
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
|
||||
@@ -27,10 +29,12 @@ import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
|
||||
import org.hyperledger.besu.ethereum.transaction.CallParameter;
|
||||
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
|
||||
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
|
||||
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
|
||||
import org.hyperledger.besu.evm.tracing.EstimateGasOperationTracer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -55,6 +59,8 @@ public class EthEstimateGas extends AbstractEstimateGas {
|
||||
|
||||
final CallParameter modifiedCallParams =
|
||||
overrideGasLimitAndPrice(callParams, blockHeader.getGasLimit());
|
||||
Optional<AccountOverrideMap> maybeStateOverrides = getAddressAccountOverrideMap(requestContext);
|
||||
// TODO implement for block overrides
|
||||
|
||||
final boolean isAllowExceedingBalance = !callParams.isMaybeStrict().orElse(Boolean.FALSE);
|
||||
|
||||
@@ -68,7 +74,11 @@ public class EthEstimateGas extends AbstractEstimateGas {
|
||||
LOG.debug("Processing transaction with params: {}", modifiedCallParams);
|
||||
final var maybeResult =
|
||||
transactionSimulator.process(
|
||||
modifiedCallParams, transactionValidationParams, operationTracer, blockHeader);
|
||||
modifiedCallParams,
|
||||
maybeStateOverrides,
|
||||
transactionValidationParams,
|
||||
operationTracer,
|
||||
blockHeader);
|
||||
|
||||
final Optional<JsonRpcErrorResponse> maybeErrorResponse =
|
||||
validateSimulationResult(requestContext, maybeResult);
|
||||
@@ -81,6 +91,7 @@ public class EthEstimateGas extends AbstractEstimateGas {
|
||||
final var lowResult =
|
||||
transactionSimulator.process(
|
||||
overrideGasLimitAndPrice(callParams, low),
|
||||
maybeStateOverrides,
|
||||
transactionValidationParams,
|
||||
operationTracer,
|
||||
blockHeader);
|
||||
@@ -97,6 +108,7 @@ public class EthEstimateGas extends AbstractEstimateGas {
|
||||
var binarySearchResult =
|
||||
transactionSimulator.process(
|
||||
overrideGasLimitAndPrice(callParams, mid),
|
||||
maybeStateOverrides,
|
||||
transactionValidationParams,
|
||||
operationTracer,
|
||||
blockHeader);
|
||||
@@ -127,4 +139,15 @@ public class EthEstimateGas extends AbstractEstimateGas {
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected Optional<AccountOverrideMap> getAddressAccountOverrideMap(
|
||||
final JsonRpcRequestContext request) {
|
||||
try {
|
||||
return request.getOptionalParameter(2, AccountOverrideMap.class);
|
||||
} catch (JsonRpcParameter.JsonRpcParameterException e) {
|
||||
throw new InvalidJsonRpcRequestException(
|
||||
"Invalid account overrides parameter (index 2)", RpcErrorType.INVALID_CALL_PARAMS, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +342,8 @@ public class EthCallTest {
|
||||
public void shouldUseCorrectBlockNumberWhenEarliest() {
|
||||
final JsonRpcRequestContext request = ethCallRequest(callParameter(), "earliest");
|
||||
when(blockchainQueries.getBlockHashByNumber(anyLong())).thenReturn(Optional.of(Hash.ZERO));
|
||||
when(transactionSimulator.process(any(), any(), any(), any(), any()))
|
||||
when(transactionSimulator.process(
|
||||
any(), any(), any(TransactionValidationParams.class), any(), any(BlockHeader.class)))
|
||||
.thenReturn(Optional.empty());
|
||||
when(blockchainQueries.getBlockHeaderByHash(Hash.ZERO))
|
||||
.thenReturn(Optional.of(mock(BlockHeader.class)));
|
||||
|
||||
@@ -44,6 +44,8 @@ import org.hyperledger.besu.ethereum.transaction.CallParameter;
|
||||
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
|
||||
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
|
||||
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
|
||||
import org.hyperledger.besu.ethereum.util.AccountOverride;
|
||||
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
|
||||
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
|
||||
import org.hyperledger.besu.evm.tracing.OperationTracer;
|
||||
|
||||
@@ -99,12 +101,44 @@ public class EthEstimateGasTest {
|
||||
assertThat(method.getName()).isEqualTo("eth_estimateGas");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noAccountOverrides() {
|
||||
final Wei gasPrice = Wei.of(1000);
|
||||
final JsonRpcRequestContext request =
|
||||
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(gasPrice), "latest");
|
||||
Optional<AccountOverrideMap> overrideMap = method.getAddressAccountOverrideMap(request);
|
||||
assertThat(overrideMap.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void someAccountOverrides() {
|
||||
AccountOverrideMap expectedOverrides = new AccountOverrideMap();
|
||||
AccountOverride override = new AccountOverride.Builder().withNonce(88L).build();
|
||||
final Address address = Address.fromHexString("0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3");
|
||||
expectedOverrides.put(address, override);
|
||||
|
||||
final Wei gasPrice = Wei.of(1000);
|
||||
final JsonRpcRequestContext request =
|
||||
ethEstimateGasRequestWithStateOverrides(
|
||||
defaultLegacyTransactionCallParameter(gasPrice), "latest", expectedOverrides);
|
||||
|
||||
Optional<AccountOverrideMap> maybeOverrideMap = method.getAddressAccountOverrideMap(request);
|
||||
assertThat(maybeOverrideMap.isPresent()).isTrue();
|
||||
AccountOverrideMap overrideMap = maybeOverrideMap.get();
|
||||
assertThat(overrideMap.keySet()).hasSize(1);
|
||||
assertThat(overrideMap.values()).hasSize(1);
|
||||
|
||||
assertThat(overrideMap).containsKey(address);
|
||||
assertThat(overrideMap).containsValue(override);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnErrorWhenTransientLegacyTransactionProcessorReturnsEmpty() {
|
||||
final JsonRpcRequestContext request =
|
||||
ethEstimateGasRequest(defaultLegacyTransactionCallParameter(Wei.ZERO));
|
||||
when(transactionSimulator.process(
|
||||
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
|
||||
eq(Optional.empty()), // no account overrides
|
||||
any(TransactionValidationParams.class),
|
||||
any(OperationTracer.class),
|
||||
eq(latestBlockHeader)))
|
||||
@@ -341,6 +375,7 @@ public class EthEstimateGasTest {
|
||||
verify(transactionSimulator)
|
||||
.process(
|
||||
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
|
||||
eq(Optional.empty()), // no account overrides
|
||||
eq(
|
||||
ImmutableTransactionValidationParams.builder()
|
||||
.from(TransactionValidationParams.transactionSimulator())
|
||||
@@ -361,6 +396,7 @@ public class EthEstimateGasTest {
|
||||
verify(transactionSimulator)
|
||||
.process(
|
||||
eq(modifiedLegacyTransactionCallParameter(Wei.ZERO)),
|
||||
eq(Optional.empty()), // no account overrides
|
||||
eq(
|
||||
ImmutableTransactionValidationParams.builder()
|
||||
.from(TransactionValidationParams.transactionSimulator())
|
||||
@@ -461,12 +497,14 @@ public class EthEstimateGasTest {
|
||||
final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class);
|
||||
when(transactionSimulator.process(
|
||||
eq(modifiedLegacyTransactionCallParameter(gasPrice)),
|
||||
eq(Optional.empty()), // no account overrides
|
||||
any(TransactionValidationParams.class),
|
||||
any(OperationTracer.class),
|
||||
eq(blockHeader)))
|
||||
.thenReturn(Optional.of(mockTxSimResult));
|
||||
when(transactionSimulator.process(
|
||||
eq(modifiedEip1559TransactionCallParameter()),
|
||||
eq(Optional.empty()), // no account overrides
|
||||
any(TransactionValidationParams.class),
|
||||
any(OperationTracer.class),
|
||||
eq(blockHeader)))
|
||||
@@ -551,4 +589,13 @@ public class EthEstimateGasTest {
|
||||
return new JsonRpcRequestContext(
|
||||
new JsonRpcRequest("2.0", "eth_estimateGas", new Object[] {callParameter, blockParam}));
|
||||
}
|
||||
|
||||
private JsonRpcRequestContext ethEstimateGasRequestWithStateOverrides(
|
||||
final CallParameter callParameter,
|
||||
final String blockParam,
|
||||
final AccountOverrideMap overrides) {
|
||||
return new JsonRpcRequestContext(
|
||||
new JsonRpcRequest(
|
||||
"2.0", "eth_estimateGas", new Object[] {callParameter, blockParam, overrides}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +124,21 @@ public class TransactionSimulator {
|
||||
blockHeader);
|
||||
}
|
||||
|
||||
public Optional<TransactionSimulatorResult> process(
|
||||
final CallParameter callParams,
|
||||
final Optional<AccountOverrideMap> maybeStateOverrides,
|
||||
final TransactionValidationParams transactionValidationParams,
|
||||
final OperationTracer operationTracer,
|
||||
final BlockHeader blockHeader) {
|
||||
return process(
|
||||
callParams,
|
||||
maybeStateOverrides,
|
||||
transactionValidationParams,
|
||||
operationTracer,
|
||||
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,
|
||||
blockHeader);
|
||||
}
|
||||
|
||||
public Optional<TransactionSimulatorResult> processAtHead(final CallParameter callParams) {
|
||||
final var chainHeadHash = blockchain.getChainHeadHash();
|
||||
return process(
|
||||
|
||||
Reference in New Issue
Block a user