Added max range CLI option for eth_getLogs. (#4597)

* Added max range CLI option for eth_getLogs. Default value: 1000.

Signed-off-by: mark-terry <mark.terry@consensys.net>
Signed-off-by: mark-terry <36909937+mark-terry@users.noreply.github.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
pull/4782/head
mark-terry 2 years ago committed by GitHub
parent 01fcb42edd
commit 6973a07b72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 9
      besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
  3. 7
      besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
  4. 15
      besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
  5. 3
      besu/src/test/java/org/hyperledger/besu/cli/CommandTestAbstract.java
  6. 1
      besu/src/test/resources/everything_config.toml
  7. 3
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcTestMethodsFactory.java
  8. 16
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogs.java
  9. 1
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java
  10. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java
  11. 6
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactory.java
  12. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/AbstractJsonRpcHttpServiceTest.java
  13. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceHostAllowlistTest.java
  14. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceLoginTest.java
  15. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceRpcApisTest.java
  16. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTestBase.java
  17. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsClientAuthTest.java
  18. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsMisconfigurationTest.java
  19. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpServiceTlsTest.java
  20. 17
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetLogsTest.java
  21. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/WebSocketServiceLoginTest.java

@ -1,6 +1,9 @@
# Changelog
## 22.10.3
### Breaking Changes
- Added `--rpc-max-logs-range` CLI option to allow limiting the number of blocks queried by `eth_getLogs` RPC API. Default value: 1000 [#4597](https://github.com/hyperledger/besu/pull/4597)
### Bug Fixes
### Download Links

@ -193,6 +193,7 @@ public class RunnerBuilder {
private RpcEndpointServiceImpl rpcEndpointServiceImpl;
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration;
private boolean legacyForkIdEnabled;
private Optional<Long> rpcMaxLogsRange;
public RunnerBuilder vertx(final Vertx vertx) {
this.vertx = vertx;
@ -398,6 +399,11 @@ public class RunnerBuilder {
return this;
}
public RunnerBuilder rpcMaxLogsRange(final Long rpcMaxLogsRange) {
this.rpcMaxLogsRange = rpcMaxLogsRange > 0 ? Optional.of(rpcMaxLogsRange) : Optional.empty();
return this;
}
public Runner build() {
Preconditions.checkNotNull(besuController);
@ -1019,7 +1025,8 @@ public class RunnerBuilder {
namedPlugins,
dataDir,
besuController.getProtocolManager().ethContext().getEthPeers(),
consensusEngineServer);
consensusEngineServer,
rpcMaxLogsRange);
methods.putAll(besuController.getAdditionalJsonRpcMethods(jsonRpcApis));
final var pluginMethods =

@ -1286,6 +1286,12 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
"Specifies the static node file containing the static nodes for this node to connect to")
private final Path staticNodesFile = null;
@CommandLine.Option(
names = {"--rpc-max-logs-range"},
description =
"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 = 1000L;
@Mixin private P2PTLSConfigOptions p2pTLSConfigOptions;
@Mixin private PkiBlockCreationOptions pkiBlockCreationOptions;
@ -2905,6 +2911,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
.ethstatsContact(ethstatsOptions.getEthstatsContact())
.storageProvider(keyValueStorageProvider(keyValueStorageName))
.rpcEndpointService(rpcEndpointServiceImpl)
.rpcMaxLogsRange(rpcMaxLogsRange)
.build();
addShutdownHook(runner);

@ -255,6 +255,7 @@ public class BesuCommandTest extends CommandTestAbstract {
verify(mockRunnerBuilder).metricsConfiguration(eq(DEFAULT_METRICS_CONFIGURATION));
verify(mockRunnerBuilder).ethNetworkConfig(ethNetworkArg.capture());
verify(mockRunnerBuilder).autoLogBloomCaching(eq(true));
verify(mockRunnerBuilder).rpcMaxLogsRange(eq(1000L));
verify(mockRunnerBuilder).build();
verify(mockControllerBuilderFactory).fromEthNetworkConfig(ethNetworkArg.capture(), any());
@ -1565,6 +1566,20 @@ public class BesuCommandTest extends CommandTestAbstract {
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void rpcMaxLogsRangeOptionMustBeUsed() {
final long rpcMaxLogsRange = 150L;
parseCommand("--rpc-max-logs-range", Long.toString(rpcMaxLogsRange));
verify(mockRunnerBuilder).rpcMaxLogsRange(longArgumentCaptor.capture());
verify(mockRunnerBuilder).build();
assertThat(longArgumentCaptor.getValue()).isEqualTo(rpcMaxLogsRange);
assertThat(commandOutput.toString(UTF_8)).isEmpty();
assertThat(commandErrorOutput.toString(UTF_8)).isEmpty();
}
@Test
public void p2pPeerUpperBound_without_p2pPeerLowerBound_shouldSetLowerBoundEqualToUpperBound() {

@ -174,6 +174,7 @@ public abstract class CommandTestAbstract {
@Captor protected ArgumentCaptor<Path> pathArgumentCaptor;
@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;
@ -225,6 +226,7 @@ public abstract class CommandTestAbstract {
when(mockControllerBuilder.dataStorageConfiguration(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.evmConfiguration(any())).thenReturn(mockControllerBuilder);
when(mockControllerBuilder.maxPeers(anyInt())).thenReturn(mockControllerBuilder);
// doReturn used because of generic BesuController
doReturn(mockController).when(mockControllerBuilder).build();
lenient().when(mockController.getProtocolManager()).thenReturn(mockEthProtocolManager);
@ -282,6 +284,7 @@ public abstract class CommandTestAbstract {
when(mockRunnerBuilder.storageProvider(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.rpcEndpointService(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.legacyForkId(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.rpcMaxLogsRange(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);
final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance();

@ -83,6 +83,7 @@ rpc-http-authentication-jwt-algorithm="RS256"
rpc-ws-authentication-jwt-algorithm="RS256"
rpc-http-tls-protocols=["TLSv1.2,TlSv1.1"]
rpc-http-tls-cipher-suites=["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"]
rpc-max-logs-range=100
# PRIVACY TLS
privacy-tls-enabled=false

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

@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
@ -37,9 +38,11 @@ public class EthGetLogs implements JsonRpcMethod {
private static final Logger LOG = LoggerFactory.getLogger(EthGetLogs.class);
private final BlockchainQueries blockchain;
private final Optional<Long> maxLogRange;
public EthGetLogs(final BlockchainQueries blockchain) {
public EthGetLogs(final BlockchainQueries blockchain, final Optional<Long> maxLogRange) {
this.blockchain = blockchain;
this.maxLogRange = maxLogRange;
}
@Override
@ -82,6 +85,11 @@ public class EthGetLogs implements JsonRpcMethod {
.getBlockNumber(blockchain)
.orElseThrow(
() -> new Exception("toBlock not found: " + filter.getToBlock()));
if (maxLogRange.isPresent()
&& (toBlockNumber - fromBlockNumber) > maxLogRange.get()) {
throw new IllegalArgumentException(
"Requested range exceeds maximum range limit");
}
} catch (final Exception e) {
ex.set(e);
return Collections.emptyList();
@ -96,8 +104,12 @@ public class EthGetLogs implements JsonRpcMethod {
if (ex.get() != null) {
LOG.debug("eth_getLogs call failed: ", ex.get());
if (ex.get() instanceof IllegalArgumentException) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.EXCEEDS_RPC_MAX_BLOCK_RANGE);
}
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), JsonRpcError.INTERNAL_ERROR);
requestContext.getRequest().getId(), JsonRpcError.INVALID_PARAMS);
}
return new JsonRpcSuccessResponse(

@ -58,6 +58,7 @@ public enum JsonRpcError {
INTRINSIC_GAS_EXCEEDS_LIMIT(-32003, "Intrinsic gas exceeds gas limit"),
TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE(-32004, "Upfront cost exceeds account balance"),
EXCEEDS_BLOCK_GAS_LIMIT(-32005, "Transaction gas limit exceeds block gas limit"),
EXCEEDS_RPC_MAX_BLOCK_RANGE(-32005, "Requested range exceeds maximum RPC range limit"),
NONCE_TOO_HIGH(-32006, "Nonce too high"),
TX_SENDER_NOT_AUTHORIZED(-32007, "Sender account not authorized to send transactions"),
CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(-32008, "Initial sync is still in progress"),

@ -86,6 +86,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
private final MiningCoordinator miningCoordinator;
private final Set<Capability> supportedCapabilities;
private final PrivacyParameters privacyParameters;
private final Optional<Long> maxLogRange;
public EthJsonRpcMethods(
final BlockchainQueries blockchainQueries,
@ -95,7 +96,8 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
final TransactionPool transactionPool,
final MiningCoordinator miningCoordinator,
final Set<Capability> supportedCapabilities,
final PrivacyParameters privacyParameters) {
final PrivacyParameters privacyParameters,
final Optional<Long> maxLogRange) {
this.blockchainQueries = blockchainQueries;
this.synchronizer = synchronizer;
this.protocolSchedule = protocolSchedule;
@ -104,6 +106,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
this.miningCoordinator = miningCoordinator;
this.supportedCapabilities = supportedCapabilities;
this.privacyParameters = privacyParameters;
this.maxLogRange = maxLogRange;
}
@Override
@ -130,7 +133,7 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
privacyParameters)),
new EthFeeHistory(protocolSchedule, blockchainQueries.getBlockchain()),
new EthGetCode(blockchainQueries, Optional.of(privacyParameters)),
new EthGetLogs(blockchainQueries),
new EthGetLogs(blockchainQueries, maxLogRange),
new EthGetProof(blockchainQueries),
new EthGetUncleCountByBlockHash(blockchainQueries),
new EthGetUncleCountByBlockNumber(blockchainQueries),

@ -75,7 +75,8 @@ public class JsonRpcMethodsFactory {
final Map<String, BesuPlugin> namedPlugins,
final Path dataDir,
final EthPeers ethPeers,
final Vertx consensusEngineServer) {
final Vertx consensusEngineServer,
final Optional<Long> maxLogRange) {
final Map<String, JsonRpcMethod> enabled = new HashMap<>();
if (!rpcApis.isEmpty()) {
@ -114,7 +115,8 @@ public class JsonRpcMethodsFactory {
transactionPool,
miningCoordinator,
supportedCapabilities,
privacyParameters),
privacyParameters,
maxLogRange),
new NetJsonRpcMethods(
p2pNetwork,
networkId,

@ -191,7 +191,8 @@ public abstract class AbstractJsonRpcHttpServiceTest {
new HashMap<>(),
folder.getRoot().toPath(),
mock(EthPeers.class),
syncVertx);
syncVertx,
Optional.empty());
}
protected void startService() throws Exception {

@ -123,7 +123,8 @@ public class JsonRpcHttpServiceHostAllowlistTest {
new HashMap<>(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
service = createJsonRpcHttpService();
service.start().join();

@ -153,7 +153,8 @@ public class JsonRpcHttpServiceLoginTest {
new HashMap<>(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
service = createJsonRpcHttpService();
jwtAuth = service.authenticationService.get().getJwtAuthProvider();
service.start().join();

@ -225,7 +225,8 @@ public class JsonRpcHttpServiceRpcApisTest {
new HashMap<>(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(
vertx,
@ -329,7 +330,8 @@ public class JsonRpcHttpServiceRpcApisTest {
new HashMap<>(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
final JsonRpcHttpService jsonRpcHttpService =
new JsonRpcHttpService(
vertx,

@ -131,7 +131,8 @@ public class JsonRpcHttpServiceTestBase {
new HashMap<>(),
folder.getRoot().toPath(),
ethPeersMock,
vertx));
vertx,
Optional.empty()));
service = createJsonRpcHttpService(createLimitedJsonRpcConfig());
service.start().join();

@ -138,7 +138,8 @@ public class JsonRpcHttpServiceTlsClientAuthTest {
Collections.emptyMap(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
System.setProperty("javax.net.ssl.trustStore", CLIENT_AS_CA_CERT.getKeyStoreFile().toString());
System.setProperty(

@ -126,7 +126,8 @@ class JsonRpcHttpServiceTlsMisconfigurationTest {
Collections.emptyMap(),
tempDir.getRoot(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
}
@AfterEach

@ -128,7 +128,8 @@ public class JsonRpcHttpServiceTlsTest {
Collections.emptyMap(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
service = createJsonRpcHttpService(createJsonRpcConfig());
service.start().join();
baseUrl = service.url();

@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
@ -52,10 +53,11 @@ public class EthGetLogsTest {
private EthGetLogs method;
@Mock BlockchainQueries blockchainQueries;
@Mock Optional<Long> maxLogRange;
@Before
public void setUp() {
method = new EthGetLogs(blockchainQueries);
method = new EthGetLogs(blockchainQueries, maxLogRange);
}
@Test
@ -271,6 +273,19 @@ public class EthGetLogsTest {
assertThat(response).isInstanceOf(JsonRpcErrorResponse.class);
}
@Test
public void shouldFailIfParamsExceedMaxRange() {
final JsonRpcRequestContext request = buildRequest(0, 50);
when(maxLogRange.isPresent()).thenReturn(true);
when(maxLogRange.get()).thenReturn(20L);
final JsonRpcResponse response = method.response(request);
assertThat(response).isInstanceOf(JsonRpcErrorResponse.class);
final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response;
assertThat(errorResponse.getError()).isEqualTo(JsonRpcError.EXCEEDS_RPC_MAX_BLOCK_RANGE);
}
private JsonRpcRequestContext buildRequest(final long fromBlock, final long toBlock) {
final FilterParameter filterParameter =
buildFilterParameter(new BlockParameter(fromBlock), new BlockParameter(toBlock));

@ -185,7 +185,8 @@ public class WebSocketServiceLoginTest {
new HashMap<>(),
folder.getRoot().toPath(),
mock(EthPeers.class),
vertx));
vertx,
Optional.empty()));
websocketMethods.putAll(rpcMethods);
webSocketMessageHandlerSpy =

Loading…
Cancel
Save