Add `rpc-gas-cap` via transaction simulator (#6156)

* Add `rpc-gas-cap` to enable user to cap gasLimit of certain RPC methods
Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>

---------

Signed-off-by: Gabriel Fukushima <gabrielfukushima@gmail.com>
pull/6194/head
Gabriel Fukushima 11 months ago committed by GitHub
parent 569ef931ff
commit a5d5af0d32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 17
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  3. 7
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 2
      besu/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java
  5. 6
      besu/src/test/java/org/hyperledger/besu/RunnerBuilderTest.java
  6. 3
      besu/src/test/java/org/hyperledger/besu/RunnerTest.java
  7. 14
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  8. 2
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  9. 1
      besu/src/test/resources/everything_config.toml
  10. 2
      consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContextBuilder.java
  11. 1
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java
  12. 3
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLContextType.java
  13. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java
  14. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/PendingStateAdapter.java
  15. 10
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/DebugJsonRpcMethods.java
  16. 14
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java
  17. 11
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java
  18. 17
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/TraceJsonRpcMethods.java
  19. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/graphql/AbstractEthGraphQLHttpServiceTest.java
  20. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java
  21. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java
  22. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java
  23. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  24. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java
  25. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java
  26. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java
  27. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java
  28. 1
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java
  29. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  30. 102
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
  31. 3
      ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/NodeSmartContractPermissioningControllerTest.java
  32. 3
      ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/TransactionSmartContractPermissioningControllerTest.java

@ -11,6 +11,8 @@
- Transactions that takes too long to evaluate, during block creation, are dropped from the txpool [#6163](https://github.com/hyperledger/besu/pull/6163)
- New option `tx-pool-min-gas-price` to set a lower bound when accepting txs to the pool [#6098](https://github.com/hyperledger/besu/pull/6098)
- Allow a transaction selection plugin to specify custom selection results [#6190](https://github.com/hyperledger/besu/pull/6190)
- Add `rpc-gas-cap` to allow users to set gas limit to the RPC methods used to simulate transactions[#6156](https://github.com/hyperledger/besu/pull/6156)
## 23.10.2

@ -192,6 +192,7 @@ public class RunnerBuilder {
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration;
private boolean legacyForkIdEnabled;
private Optional<Long> rpcMaxLogsRange;
private Optional<Long> rpcGasCap;
private Optional<EnodeDnsConfiguration> enodeDnsConfiguration;
/**
@ -585,6 +586,16 @@ public class RunnerBuilder {
this.rpcMaxLogsRange = rpcMaxLogsRange > 0 ? Optional.of(rpcMaxLogsRange) : Optional.empty();
return this;
}
/**
* Add Rpc gasLimit cap .
*
* @param rpcGasCap the rpc gas limit cap for transaction simulation methods
* @return the runner builder
*/
public RunnerBuilder rpcGasCap(final Long rpcGasCap) {
this.rpcGasCap = rpcGasCap > 0 ? Optional.of(rpcGasCap) : Optional.empty();
return this;
}
/**
* Add enode DNS configuration
@ -661,7 +672,7 @@ public class RunnerBuilder {
final TransactionSimulator transactionSimulator =
new TransactionSimulator(
context.getBlockchain(), context.getWorldStateArchive(), protocolSchedule);
context.getBlockchain(), context.getWorldStateArchive(), protocolSchedule, rpcGasCap);
final Bytes localNodeId = nodeKey.getPublicKey().getEncodedBytes();
final Optional<NodePermissioningController> nodePermissioningController =
@ -910,6 +921,7 @@ public class RunnerBuilder {
graphQlContextMap.putIfAbsent(GraphQLContextType.SYNCHRONIZER, synchronizer);
graphQlContextMap.putIfAbsent(
GraphQLContextType.CHAIN_ID, protocolSchedule.getChainId().map(UInt256::valueOf));
graphQlContextMap.putIfAbsent(GraphQLContextType.GAS_CAP, rpcGasCap);
final GraphQL graphQL;
try {
graphQL = GraphQLProvider.buildGraphQL(fetchers);
@ -1240,7 +1252,8 @@ public class RunnerBuilder {
besuController.getProtocolManager().ethContext().getEthPeers(),
consensusEngineServer,
rpcMaxLogsRange,
enodeDnsConfiguration);
enodeDnsConfiguration,
rpcGasCap);
methods.putAll(besuController.getAdditionalJsonRpcMethods(jsonRpcApis));
final var pluginMethods =

@ -1230,6 +1230,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"Specifies the maximum number of blocks to retrieve logs from via RPC. Must be >=0. 0 specifies no limit (default: ${DEFAULT-VALUE})")
private final Long rpcMaxLogsRange = 5000L;
@CommandLine.Option(
names = {"--rpc-gas-cap"},
description =
"Specifies the gasLimit cap for transaction simulation RPC methods. Must be >=0. 0 specifies no limit (default: ${DEFAULT-VALUE})")
private final Long rpcGasCap = 0L;
@CommandLine.Option(
names = {"--cache-last-blocks"},
description = "Specifies the number of last blocks to cache (default: ${DEFAULT-VALUE})")
@ -2948,6 +2954,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.storageProvider(keyValueStorageProvider(keyValueStorageName))
.rpcEndpointService(rpcEndpointServiceImpl)
.rpcMaxLogsRange(rpcMaxLogsRange)
.rpcGasCap(rpcGasCap)
.enodeDnsConfiguration(getEnodeDnsConfiguration())
.build();

@ -367,7 +367,7 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
blockchain, epochManager, bftBlockInterface().get(), validatorOverrides);
final TransactionSimulator transactionSimulator =
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule);
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, Optional.empty());
transactionValidatorProvider =
new TransactionValidatorProvider(
blockchain, new ValidatorContractController(transactionSimulator), qbftForksSchedule);

@ -167,6 +167,7 @@ public final class RunnerBuilderTest {
.dataDir(dataDir.getRoot())
.storageProvider(mock(KeyValueStorageProvider.class, RETURNS_DEEP_STUBS))
.rpcEndpointService(new RpcEndpointServiceImpl())
.rpcGasCap(50_000_000L)
.build();
runner.startEthereumMainLoop();
@ -211,6 +212,7 @@ public final class RunnerBuilderTest {
.dataDir(dataDir.getRoot())
.storageProvider(storageProvider)
.rpcEndpointService(new RpcEndpointServiceImpl())
.rpcGasCap(50_000_000L)
.build();
runner.startEthereumMainLoop();
@ -270,6 +272,7 @@ public final class RunnerBuilderTest {
.storageProvider(mock(KeyValueStorageProvider.class, RETURNS_DEEP_STUBS))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.rpcGasCap(50_000_000L)
.build();
assertThat(runner.getJsonRpcPort()).isPresent();
@ -312,6 +315,7 @@ public final class RunnerBuilderTest {
.storageProvider(mock(KeyValueStorageProvider.class, RETURNS_DEEP_STUBS))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.rpcGasCap(50_000_000L)
.build();
assertThat(runner.getEngineJsonRpcPort()).isPresent();
@ -353,6 +357,7 @@ public final class RunnerBuilderTest {
.storageProvider(mock(KeyValueStorageProvider.class, RETURNS_DEEP_STUBS))
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.rpcGasCap(50_000_000L)
.build();
assertThat(runner.getEngineJsonRpcPort()).isPresent();
@ -396,6 +401,7 @@ public final class RunnerBuilderTest {
.rpcEndpointService(new RpcEndpointServiceImpl())
.besuPluginContext(mock(BesuPluginContextImpl.class))
.networkingConfiguration(NetworkingConfiguration.create())
.rpcGasCap(50_000_000L)
.build();
assertThat(runner.getJsonRpcPort()).isPresent();

@ -192,7 +192,8 @@ public final class RunnerTest {
.permissioningService(new PermissioningServiceImpl())
.staticNodes(emptySet())
.storageProvider(new InMemoryKeyValueStorageProvider())
.rpcEndpointService(new RpcEndpointServiceImpl());
.rpcEndpointService(new RpcEndpointServiceImpl())
.rpcGasCap(50_000_000L);
Runner runnerBehind = null;
final Runner runnerAhead =

@ -1587,6 +1587,20 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void rpcGasCapOptionMustBeUsed() {
final long rpcGasCap = 150L;
parseCommand("--rpc-gas-cap", Long.toString(rpcGasCap));
verify(mockRunnerBuilder).rpcGasCap(longArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(longArgumentCaptor.getValue()).isEqualTo(rpcGasCap);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void p2pPeerUpperBound_without_p2pPeerLowerBound_shouldSetLowerBoundEqualToUpperBound() {

@ -197,7 +197,6 @@ public abstract class CommandTestAbstract {
@Captor protected ArgumentCaptor<String> stringArgumentCaptor;
@Captor protected ArgumentCaptor<Integer> intArgumentCaptor;
@Captor protected ArgumentCaptor<Long> longArgumentCaptor;
@Captor protected ArgumentCaptor<Float> floatCaptor;
@Captor protected ArgumentCaptor<EthNetworkConfig> ethNetworkConfigArgumentCaptor;
@Captor protected ArgumentCaptor<SynchronizerConfiguration> syncConfigurationCaptor;
@Captor protected ArgumentCaptor<JsonRpcConfiguration> jsonRpcConfigArgumentCaptor;
@ -315,6 +314,7 @@ public abstract class CommandTestAbstract {
when(mockRunnerBuilder.legacyForkId(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.rpcMaxLogsRange(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.enodeDnsConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.rpcGasCap(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();

@ -89,6 +89,7 @@ rpc-http-max-request-content-length = 5242880
rpc-max-logs-range=100
json-pretty-print-enabled=false
cache-last-blocks=512
rpc-gas-cap = 50000000
# PRIVACY TLS
privacy-tls-enabled=false

@ -414,7 +414,7 @@ public class TestContextBuilder {
final BftValidatorOverrides validatorOverrides = convertBftForks(qbftForks);
final TransactionSimulator transactionSimulator =
new TransactionSimulator(blockChain, worldStateArchive, protocolSchedule);
new TransactionSimulator(blockChain, worldStateArchive, protocolSchedule, Optional.empty());
final BlockValidatorProvider blockValidatorProvider =
BlockValidatorProvider.forkingValidatorProvider(

@ -188,6 +188,7 @@ public class JsonRpcTestMethodsFactory {
ethPeers,
Vertx.vertx(new VertxOptions().setWorkerPoolSize(1)),
Optional.empty(),
Optional.empty(),
Optional.empty());
}
}

@ -22,5 +22,6 @@ public enum GraphQLContextType {
MINING_COORDINATOR,
SYNCHRONIZER,
IS_ALIVE_HANDLER,
CHAIN_ID
CHAIN_ID,
GAS_CAP
}

@ -209,10 +209,10 @@ public class BlockAdapterBase extends AdapterBase {
final ProtocolSchedule protocolSchedule =
environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE);
final long bn = header.getNumber();
final Optional<Long> gasCap = environment.getGraphQlContext().get(GraphQLContextType.GAS_CAP);
final TransactionSimulator transactionSimulator =
new TransactionSimulator(
query.getBlockchain(), query.getWorldStateArchive(), protocolSchedule);
query.getBlockchain(), query.getWorldStateArchive(), protocolSchedule, gasCap);
long gasParam = -1;
Wei gasPriceParam = null;

@ -92,10 +92,10 @@ public class PendingStateAdapter extends AdapterBase {
final BlockchainQueries query = getBlockchainQueries(environment);
final ProtocolSchedule protocolSchedule =
environment.getGraphQlContext().get(GraphQLContextType.PROTOCOL_SCHEDULE);
final Optional<Long> gasCap = environment.getGraphQlContext().get(GraphQLContextType.GAS_CAP);
final TransactionSimulator transactionSimulator =
new TransactionSimulator(
query.getBlockchain(), query.getWorldStateArchive(), protocolSchedule);
query.getBlockchain(), query.getWorldStateArchive(), protocolSchedule, gasCap);
long gasParam = -1;
Wei gasPriceParam = null;

@ -51,6 +51,7 @@ import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
@ -64,6 +65,8 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final Synchronizer synchronizer;
private final Path dataDir;
private final Optional<Long> gasCap;
DebugJsonRpcMethods(
final BlockchainQueries blockchainQueries,
final ProtocolContext protocolContext,
@ -71,7 +74,8 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
final ObservableMetricsSystem metricsSystem,
final TransactionPool transactionPool,
final Synchronizer synchronizer,
final Path dataDir) {
final Path dataDir,
final Optional<Long> gasCap) {
this.blockchainQueries = blockchainQueries;
this.protocolContext = protocolContext;
this.protocolSchedule = protocolSchedule;
@ -79,6 +83,7 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
this.transactionPool = transactionPool;
this.synchronizer = synchronizer;
this.dataDir = dataDir;
this.gasCap = gasCap;
}
@Override
@ -122,6 +127,7 @@ public class DebugJsonRpcMethods extends ApiGroupJsonRpcMethods {
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)));
protocolSchedule,
gasCap)));
}
}

@ -87,6 +87,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final MiningCoordinator miningCoordinator;
private final Set<Capability> supportedCapabilities;
private final Optional<Long> maxLogRange;
private final Optional<Long> gasCap;
public EthJsonRpcMethods(
final BlockchainQueries blockchainQueries,
@ -96,7 +97,8 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
final TransactionPool transactionPool,
final MiningCoordinator miningCoordinator,
final Set<Capability> supportedCapabilities,
final Optional<Long> maxLogRange) {
final Optional<Long> maxLogRange,
final Optional<Long> gasCap) {
this.blockchainQueries = blockchainQueries;
this.synchronizer = synchronizer;
this.protocolSchedule = protocolSchedule;
@ -105,6 +107,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
this.miningCoordinator = miningCoordinator;
this.supportedCapabilities = supportedCapabilities;
this.maxLogRange = maxLogRange;
this.gasCap = gasCap;
}
@Override
@ -128,7 +131,8 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)),
protocolSchedule,
gasCap)),
new EthFeeHistory(protocolSchedule, blockchainQueries.getBlockchain()),
new EthGetCode(blockchainQueries),
new EthGetLogs(blockchainQueries, maxLogRange),
@ -157,13 +161,15 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)),
protocolSchedule,
gasCap)),
new EthCreateAccessList(
blockchainQueries,
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)),
protocolSchedule,
gasCap)),
new EthMining(miningCoordinator),
new EthCoinbase(miningCoordinator),
new EthProtocolVersion(supportedCapabilities),

@ -80,7 +80,8 @@ public class JsonRpcMethodsFactory {
final EthPeers ethPeers,
final Vertx consensusEngineServer,
final Optional<Long> maxLogRange,
final Optional<EnodeDnsConfiguration> enodeDnsConfiguration) {
final Optional<EnodeDnsConfiguration> enodeDnsConfiguration,
final Optional<Long> gasCap) {
final Map<String, JsonRpcMethod> enabled = new HashMap<>();
if (!rpcApis.isEmpty()) {
final JsonRpcMethod modules = new RpcModules(rpcApis);
@ -104,7 +105,8 @@ public class JsonRpcMethodsFactory {
metricsSystem,
transactionPool,
synchronizer,
dataDir),
dataDir,
gasCap),
new EeaJsonRpcMethods(
blockchainQueries, protocolSchedule, transactionPool, privacyParameters),
new ExecutionEngineJsonRpcMethods(
@ -121,7 +123,8 @@ public class JsonRpcMethodsFactory {
transactionPool,
miningCoordinator,
supportedCapabilities,
maxLogRange),
maxLogRange,
gasCap),
new NetJsonRpcMethods(
p2pNetwork,
networkId,
@ -139,7 +142,7 @@ public class JsonRpcMethodsFactory {
new PrivxJsonRpcMethods(
blockchainQueries, protocolSchedule, transactionPool, privacyParameters),
new Web3JsonRpcMethods(clientVersion),
new TraceJsonRpcMethods(blockchainQueries, protocolSchedule),
new TraceJsonRpcMethods(blockchainQueries, protocolSchedule, gasCap),
new TxPoolJsonRpcMethods(transactionPool),
new PluginsJsonRpcMethods(namedPlugins));

@ -31,16 +31,22 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import java.util.Map;
import java.util.Optional;
public class TraceJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final BlockchainQueries blockchainQueries;
private final ProtocolSchedule protocolSchedule;
private final Optional<Long> gasCap;
TraceJsonRpcMethods(
final BlockchainQueries blockchainQueries, final ProtocolSchedule protocolSchedule) {
final BlockchainQueries blockchainQueries,
final ProtocolSchedule protocolSchedule,
final Optional<Long> gasCap) {
this.blockchainQueries = blockchainQueries;
this.protocolSchedule = protocolSchedule;
this.gasCap = gasCap;
}
@Override
@ -65,20 +71,23 @@ public class TraceJsonRpcMethods extends ApiGroupJsonRpcMethods {
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)),
protocolSchedule,
gasCap)),
new TraceCallMany(
blockchainQueries,
protocolSchedule,
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)),
protocolSchedule,
gasCap)),
new TraceRawTransaction(
protocolSchedule,
blockchainQueries,
new TransactionSimulator(
blockchainQueries.getBlockchain(),
blockchainQueries.getWorldStateArchive(),
protocolSchedule)));
protocolSchedule,
gasCap)));
}
}

@ -143,7 +143,9 @@ public abstract class AbstractEthGraphQLHttpServiceTest {
GraphQLContextType.MINING_COORDINATOR,
miningCoordinatorMock,
GraphQLContextType.SYNCHRONIZER,
synchronizerMock),
synchronizerMock,
GraphQLContextType.GAS_CAP,
Optional.empty()),
Mockito.mock(EthScheduler.class));
service.start().join();

@ -191,6 +191,7 @@ public abstract class AbstractJsonRpcHttpServiceTest {
mock(EthPeers.class),
syncVertx,
Optional.empty(),
Optional.empty(),
Optional.empty());
}

@ -128,6 +128,7 @@ public class JsonRpcHttpServiceHostAllowlistTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService();
service.start().join();

@ -157,6 +157,7 @@ public class JsonRpcHttpServiceLoginTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService();
jwtAuth = service.authenticationService.get().getJwtAuthProvider();

@ -230,6 +230,7 @@ public class JsonRpcHttpServiceRpcApisTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(
@ -340,6 +341,7 @@ public class JsonRpcHttpServiceRpcApisTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(

@ -136,6 +136,7 @@ public class JsonRpcHttpServiceTestBase {
ethPeersMock,
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService(createLimitedJsonRpcConfig());
service.start().join();

@ -141,6 +141,7 @@ public class JsonRpcHttpServiceTlsClientAuthTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
System.setProperty("javax.net.ssl.trustStore", CLIENT_AS_CA_CERT.getKeyStoreFile().toString());

@ -130,6 +130,7 @@ class JsonRpcHttpServiceTlsMisconfigurationTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
}

@ -131,6 +131,7 @@ public class JsonRpcHttpServiceTlsTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
service = createJsonRpcHttpService(createJsonRpcConfig());
service.start().join();

@ -192,6 +192,7 @@ public class WebSocketServiceLoginTest {
mock(EthPeers.class),
vertx,
Optional.empty(),
Optional.empty(),
Optional.empty()));
websocketMethods.putAll(rpcMethods);

@ -48,6 +48,8 @@ import javax.annotation.Nonnull;
import com.google.common.base.Suppliers;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* Used to process transactions for eth_call and eth_estimateGas.
@ -56,6 +58,7 @@ import org.apache.tuweni.bytes.Bytes;
* blockchain or to estimate the transaction gas cost.
*/
public class TransactionSimulator {
private static final Logger LOG = LoggerFactory.getLogger(TransactionSimulator.class);
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
@ -76,14 +79,17 @@ public class TransactionSimulator {
private final Blockchain blockchain;
private final WorldStateArchive worldStateArchive;
private final ProtocolSchedule protocolSchedule;
private final Optional<Long> rpcGasCap;
public TransactionSimulator(
final Blockchain blockchain,
final WorldStateArchive worldStateArchive,
final ProtocolSchedule protocolSchedule) {
final ProtocolSchedule protocolSchedule,
final Optional<Long> rpcGasCap) {
this.blockchain = blockchain;
this.worldStateArchive = worldStateArchive;
this.protocolSchedule = protocolSchedule;
this.rpcGasCap = rpcGasCap;
}
public Optional<TransactionSimulatorResult> process(
@ -207,10 +213,17 @@ public class TransactionSimulator {
final Account sender = updater.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L;
final long gasLimit =
long gasLimit =
callParams.getGasLimit() >= 0
? callParams.getGasLimit()
: blockHeaderToProcess.getGasLimit();
if (rpcGasCap.isPresent()) {
final long gasCap = rpcGasCap.get();
if (gasCap < gasLimit) {
gasLimit = gasCap;
LOG.info("Capping gasLimit to " + gasCap);
}
}
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;

@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParam
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult.Status;
@ -75,8 +76,9 @@ public class TransactionSimulatorTest {
private static final Address DEFAULT_FROM =
Address.fromHexString("0x0000000000000000000000000000000000000000");
private static final long GASCAP = 500L;
private TransactionSimulator transactionSimulator;
private TransactionSimulator cappedTransactionSimulator;
@Mock private Blockchain blockchain;
@Mock private WorldStateArchive worldStateArchive;
@ -84,13 +86,15 @@ public class TransactionSimulatorTest {
@Mock private ProtocolSchedule protocolSchedule;
@Mock private ProtocolSpec protocolSpec;
@Mock private MainnetTransactionProcessor transactionProcessor;
private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture();
@BeforeEach
public void setUp() {
this.transactionSimulator =
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule);
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, Optional.empty());
this.cappedTransactionSimulator =
new TransactionSimulator(
blockchain, worldStateArchive, protocolSchedule, Optional.of(GASCAP));
}
@Test
@ -156,7 +160,6 @@ public class TransactionSimulatorTest {
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.build();
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
transactionSimulator.process(
@ -260,7 +263,6 @@ public class TransactionSimulatorTest {
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.build();
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
transactionSimulator.process(
@ -523,6 +525,82 @@ public class TransactionSimulatorTest {
verifyTransactionWasProcessed(expectedTransaction);
}
@Test
public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP + 1);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
mockBlockchainForBlockHeader(blockHeader);
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);
final Transaction expectedTransaction =
Transaction.builder()
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(GASCAP)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.build();
mockProtocolSpecForProcessWithWorldUpdater();
// call process with original transaction
cappedTransactionSimulator.process(
callParameter,
TransactionValidationParams.transactionSimulator(),
OperationTracer.NO_TRACING,
1L);
// expect overwritten transaction to be processed
verifyTransactionWasProcessed(expectedTransaction);
}
@Test
public void shouldKeepOriginalGasLimitWhenCapIsHigherThanOriginalValue() {
// generate a transaction with a gas limit that is lower than the gas cap
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP - 1);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
mockBlockchainForBlockHeader(blockHeader);
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);
mockProtocolSpecForProcessWithWorldUpdater();
final Transaction expectedTransaction =
Transaction.builder()
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.build();
// call process with original transaction
cappedTransactionSimulator.process(
callParameter,
TransactionValidationParams.transactionSimulator(),
OperationTracer.NO_TRACING,
1L);
// expect transaction with the original gas limit to be processed
verifyTransactionWasProcessed(expectedTransaction);
}
private void mockWorldStateForAccount(
final BlockHeader blockHeader, final Address address, final long nonce) {
final Account account = mock(Account.class);
@ -558,8 +636,7 @@ public class TransactionSimulatorTest {
.thenReturn(Optional.of(blockHeader));
}
private void mockProcessorStatusForTransaction(
final Transaction transaction, final Status status) {
private void mockProtocolSpecForProcessWithWorldUpdater() {
final BlockHeaderFunctions blockHeaderFunctions = mock(BlockHeaderFunctions.class);
when(protocolSchedule.getChainId()).thenReturn(Optional.of(BigInteger.ONE));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
@ -567,7 +644,11 @@ public class TransactionSimulatorTest {
when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase);
when(protocolSpec.getBlockHeaderFunctions()).thenReturn(blockHeaderFunctions);
when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0));
}
private void mockProcessorStatusForTransaction(
final Transaction transaction, final Status status) {
mockProtocolSpecForProcessWithWorldUpdater();
final TransactionProcessingResult result = mock(TransactionProcessingResult.class);
switch (status) {
case SUCCESSFUL:
@ -628,10 +709,15 @@ public class TransactionSimulatorTest {
private CallParameter eip1559TransactionCallParameter(
final Wei maxFeePerGas, final Wei maxPriorityFeePerGas) {
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, 0L);
}
private CallParameter eip1559TransactionCallParameter(
final Wei maxFeePerGas, final Wei maxPriorityFeePerGas, final long gasLimit) {
return new CallParameter(
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
0,
gasLimit,
Wei.of(0),
Optional.of(maxFeePerGas),
Optional.of(maxPriorityFeePerGas),

@ -38,6 +38,7 @@ import org.hyperledger.besu.plugin.services.MetricsSystem;
import org.hyperledger.besu.plugin.services.metrics.Counter;
import java.io.IOException;
import java.util.Optional;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.io.Resources;
@ -70,7 +71,7 @@ public class NodeSmartContractPermissioningControllerTest {
genesisState.writeStateTo(worldArchive.getMutable());
final TransactionSimulator ts =
new TransactionSimulator(blockchain, worldArchive, protocolSchedule);
new TransactionSimulator(blockchain, worldArchive, protocolSchedule, Optional.empty());
final Address contractAddress = Address.fromHexString(contractAddressString);
when(metricsSystem.createCounter(

@ -41,6 +41,7 @@ import org.hyperledger.besu.plugin.services.metrics.Counter;
import java.io.IOException;
import java.math.BigInteger;
import java.util.Optional;
import com.google.common.io.Resources;
import org.apache.tuweni.bytes.Bytes;
@ -71,7 +72,7 @@ public class TransactionSmartContractPermissioningControllerTest {
genesisState.writeStateTo(worldArchive.getMutable());
final TransactionSimulator ts =
new TransactionSimulator(blockchain, worldArchive, protocolSchedule);
new TransactionSimulator(blockchain, worldArchive, protocolSchedule, Optional.empty());
final Address contractAddress = Address.fromHexString(contractAddressString);
when(metricsSystem.createCounter(

Loading…
Cancel
Save