Skip to content

Commit

Permalink
Enable limit on range Of JSON-RPC API trace_filter method (hyperledge…
Browse files Browse the repository at this point in the history
…r#5971) (hyperledger#6446)

* Enable limit on range of JSON-RPC API trace_filter method (hyperledger#5971)

Enable a limit on the range of blocks that can be supplied to the
JSON-RPC trace_filter method.

The limit has a default value and can be overridden with a command
line option at start up.

Signed-off-by: alyokaz <alyoshakaz@live.co.uk>

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

---------

Signed-off-by: alyokaz <alyoshakaz@live.co.uk>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>
  • Loading branch information
alyokaz and macfarla authored Jan 25, 2024
1 parent ed1480b commit a1a5b20
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 24.1.2-SNAPSHOT

### Breaking Changes
- The `trace-filter` method in JSON-RPC API now has a default block range limit of 1000, adjustable with `--rpc-max-trace-filter-range` [#6446](https://github.com/hyperledger/besu/pull/6446)

### Deprecations

Expand Down
9 changes: 8 additions & 1 deletion besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,12 @@ static class PermissionsOptionGroup {
description = "Specifies the number of last blocks to cache (default: ${DEFAULT-VALUE})")
private final Integer numberOfblocksToCache = 0;

@Option(
names = {"--rpc-max-trace-filter-range"},
description =
"Specifies the maximum number of blocks for the trace_filter method. Must be >=0. 0 specifies no limit (default: $DEFAULT-VALUE)")
private final Long maxTraceFilterRange = 1000L;

@Mixin private P2PTLSConfigOptions p2pTLSConfigOptions;

@Mixin private PkiBlockCreationOptions pkiBlockCreationOptions;
Expand Down Expand Up @@ -2534,7 +2540,8 @@ private ApiConfiguration apiConfiguration() {
.gasPriceMax(apiGasPriceMax)
.maxLogsRange(rpcMaxLogsRange)
.gasCap(rpcGasCap)
.isGasAndPriorityFeeLimitingEnabled(apiGasAndPriorityFeeLimitingEnabled);
.isGasAndPriorityFeeLimitingEnabled(apiGasAndPriorityFeeLimitingEnabled)
.maxTraceFilterRange(maxTraceFilterRange);
if (apiGasAndPriorityFeeLimitingEnabled) {
if (apiGasAndPriorityFeeLowerBoundCoefficient > apiGasAndPriorityFeeUpperBoundCoefficient) {
throw new ParameterException(
Expand Down
3 changes: 2 additions & 1 deletion besu/src/test/resources/everything_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ rpc-max-logs-range=100
json-pretty-print-enabled=false
cache-last-blocks=512
rpc-gas-cap = 50000000
rpc-max-trace-filter-range=100

# PRIVACY TLS
privacy-tls-enabled=false
Expand Down Expand Up @@ -232,4 +233,4 @@ Xp2p-tls-crl-file="none.file"
Xp2p-tls-clienthello-sni=false

#contracts
Xevm-jumpdest-cache-weight-kb=32000
Xevm-jumpdest-cache-weight-kb=32000
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,9 @@ public Long getLowerBoundGasAndPriorityFeeCoefficient() {
public Long getUpperBoundGasAndPriorityFeeCoefficient() {
return DEFAULT_UPPER_BOUND_GAS_AND_PRIORITY_FEE_COEFFICIENT;
}

@Value.Default
public Long getMaxTraceFilterRange() {
return 1000L;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockTracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.Tracer;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.TransactionTrace;
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;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.flat.FlatTrace;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.tracing.flat.RewardTraceGenerator;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
Expand Down Expand Up @@ -66,12 +68,15 @@
public class TraceFilter extends TraceBlock {

private static final Logger LOG = LoggerFactory.getLogger(TraceFilter.class);
private final Long maxRange;

public TraceFilter(
final Supplier<BlockTracer> blockTracerSupplier,
final ProtocolSchedule protocolSchedule,
final BlockchainQueries blockchainQueries) {
final BlockchainQueries blockchainQueries,
final Long maxRange) {
super(protocolSchedule, blockchainQueries);
this.maxRange = maxRange;
}

@Override
Expand All @@ -88,6 +93,17 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
final long toBlock = resolveBlockNumber(filterParameter.getToBlock());
LOG.trace("Received RPC rpcName={} fromBlock={} toBlock={}", getName(), fromBlock, toBlock);

if (maxRange > 0 && toBlock - fromBlock > maxRange) {
LOG.atDebug()
.setMessage("trace_filter request {} failed:")
.addArgument(requestContext.getRequest())
.setCause(
new IllegalArgumentException(RpcErrorType.EXCEEDS_RPC_MAX_BLOCK_RANGE.getMessage()))
.log();
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(), RpcErrorType.EXCEEDS_RPC_MAX_BLOCK_RANGE);
}

final ObjectMapper mapper = new ObjectMapper();
final ArrayNodeWrapper resultArrayNode =
new ArrayNodeWrapper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ protected Map<String, JsonRpcMethod> create() {
new BlockReplay(protocolSchedule, blockchainQueries.getBlockchain());
return mapOf(
new TraceReplayBlockTransactions(protocolSchedule, blockchainQueries),
new TraceFilter(() -> new BlockTracer(blockReplay), protocolSchedule, blockchainQueries),
new TraceFilter(
() -> new BlockTracer(blockReplay),
protocolSchedule,
blockchainQueries,
apiConfiguration.getMaxTraceFilterRange()),
new TraceGet(() -> new BlockTracer(blockReplay), blockchainQueries, protocolSchedule),
new TraceTransaction(
() -> new BlockTracer(blockReplay), protocolSchedule, blockchainQueries),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;

import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
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.processor.BlockTracer;
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.RpcErrorType;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;

import java.util.function.Supplier;

import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class TraceFilterTest {

private TraceFilter method;

@Mock Supplier<BlockTracer> blockTracerSupplier;
@Mock ProtocolSchedule protocolSchedule;
@Mock BlockchainQueries blockchainQueries;

@ParameterizedTest
@CsvSource({
"0, 1001, 1000", "0, 5000, 1000", "1, 1002, 1000", "1, 6002, 1000", "1000, 3000, 1000",
"0, 501, 500", "0, 5000, 500", "1, 502, 500", "1, 6002, 500", "1000, 3000, 500"
})
public void shouldFailIfParamsExceedMaxRange(
final long fromBlock, final long toBlock, final long maxFilterRange) {
final FilterParameter filterParameter =
new FilterParameter(
new BlockParameter(fromBlock),
new BlockParameter(toBlock),
null,
null,
null,
null,
null,
null,
null);

JsonRpcRequestContext request =
new JsonRpcRequestContext(
new JsonRpcRequest("2.0", "trace_filter", new Object[] {filterParameter}));

method =
new TraceFilter(blockTracerSupplier, protocolSchedule, blockchainQueries, maxFilterRange);

final JsonRpcResponse response = method.response(request);
assertThat(response).isInstanceOf(JsonRpcErrorResponse.class);

final JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) response;
assertThat(errorResponse.getErrorType()).isEqualTo(RpcErrorType.EXCEEDS_RPC_MAX_BLOCK_RANGE);
}
}

0 comments on commit a1a5b20

Please sign in to comment.