feat: add eth_getLogs block range limit (#576)

* update cmd/geth/main.go

* update `eth/ethconfig` package

* update `eth/filters` package

* update cmd/utils/flags.go

* fix cmd/utils/flags.go

* fix eth/filters/filter.go
This commit is contained in:
HAOYUatHZ 2023-11-23 14:38:28 +08:00 committed by GitHub
parent fccf142288
commit fc8e8622d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 14 deletions

View file

@ -176,6 +176,7 @@ var (
utils.AllowUnprotectedTxs,
utils.BatchRequestLimit,
utils.BatchResponseMaxSize,
utils.MaxBlockRangeFlag,
}
metricsFlags = []cli.Flag{

View file

@ -944,6 +944,13 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: metrics.DefaultConfig.InfluxDBOrganization,
Category: flags.MetricsCategory,
}
// Max block range for `eth_getLogs` method
MaxBlockRangeFlag = &cli.Int64Flag{
Name: "rpc.getlogs.maxrange",
Usage: "Limit max fetched block range for `eth_getLogs` method",
}
)
var (
@ -1605,6 +1612,14 @@ func setRequiredBlocks(ctx *cli.Context, cfg *ethconfig.Config) {
}
}
func setMaxBlockRange(ctx *cli.Context, cfg *ethconfig.Config) {
if ctx.IsSet(MaxBlockRangeFlag.Name) {
cfg.MaxBlockRange = ctx.Int64(MaxBlockRangeFlag.Name)
} else {
cfg.MaxBlockRange = -1
}
}
// CheckExclusive verifies that only a single instance of the provided flags was
// set by the user. Each flag might optionally be followed by a string type to
// specialize it further.
@ -1660,6 +1675,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
setMiner(ctx, &cfg.Miner)
setRequiredBlocks(ctx, cfg)
setLes(ctx, cfg)
setMaxBlockRange(ctx, cfg)
// Cap the cache allowance and tune the garbage collector
mem, err := gopsutil.VirtualMemory()
@ -1956,7 +1972,7 @@ func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconf
})
stack.RegisterAPIs([]rpc.API{{
Namespace: "eth",
Service: filters.NewFilterAPI(filterSystem, isLightClient),
Service: filters.NewFilterAPI(filterSystem, isLightClient, ethcfg.MaxBlockRange),
}})
return filterSystem
}

View file

@ -77,6 +77,7 @@ var Defaults = Config{
RPCEVMTimeout: 5 * time.Second,
GPO: FullNodeGPO,
RPCTxFeeCap: 1, // 1 ether
MaxBlockRange: -1, // Default unconfigured value: no block range limit for backward compatibility
}
//go:generate go run github.com/fjl/gencodec -type Config -formats toml -out gen_config.go
@ -168,6 +169,9 @@ type Config struct {
// OverrideVerkle (TODO: remove after the fork)
OverrideVerkle *uint64 `toml:",omitempty"`
// Max block range for eth_getLogs api method
MaxBlockRange int64
}
// CreateConsensusEngine creates a consensus engine for the given chain config.

View file

@ -56,6 +56,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
RPCTxFeeCap float64
OverrideCancun *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"`
MaxBlockRange int64
}
var enc Config
enc.Genesis = c.Genesis
@ -97,6 +98,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.RPCTxFeeCap = c.RPCTxFeeCap
enc.OverrideCancun = c.OverrideCancun
enc.OverrideVerkle = c.OverrideVerkle
enc.MaxBlockRange = c.MaxBlockRange
return &enc, nil
}
@ -142,6 +144,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
RPCTxFeeCap *float64
OverrideCancun *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"`
MaxBlockRange *int64
}
var dec Config
if err := unmarshal(&dec); err != nil {
@ -264,5 +267,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.OverrideVerkle != nil {
c.OverrideVerkle = dec.OverrideVerkle
}
if dec.MaxBlockRange != nil {
c.MaxBlockRange = *dec.MaxBlockRange
}
return nil
}

View file

@ -59,15 +59,17 @@ type FilterAPI struct {
filtersMu sync.Mutex
filters map[rpc.ID]*filter
timeout time.Duration
maxBlockRange int64
}
// NewFilterAPI returns a new FilterAPI instance.
func NewFilterAPI(system *FilterSystem, lightMode bool) *FilterAPI {
func NewFilterAPI(system *FilterSystem, lightMode bool, maxBlockRange int64) *FilterAPI {
api := &FilterAPI{
sys: system,
events: NewEventSystem(system, lightMode),
filters: make(map[rpc.ID]*filter),
timeout: system.cfg.Timeout,
maxBlockRange: maxBlockRange,
}
go api.timeoutLoop(system.cfg.Timeout)
@ -348,7 +350,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type
end = crit.ToBlock.Int64()
}
// Construct the range filter
filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics)
filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics, api.maxBlockRange)
}
// Run the filter and return all the logs
logs, err := filter.Logs(ctx)

View file

@ -19,6 +19,7 @@ package filters
import (
"context"
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@ -38,11 +39,13 @@ type Filter struct {
begin, end int64 // Range interval if filtering multiple blocks
matcher *bloombits.Matcher
maxBlockRange int64
}
// NewRangeFilter creates a new filter which uses a bloom filter on blocks to
// figure out whether a particular block is interesting or not.
func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash, maxBlockRange ...int64) *Filter {
// Flatten the address and topic filter clauses into a single bloombits filter
// system. Since the bloombits are not positional, nil topics are permitted,
// which get flattened into a nil byte slice.
@ -70,6 +73,12 @@ func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Add
filter.begin = begin
filter.end = end
if len(maxBlockRange) > 0 {
filter.maxBlockRange = maxBlockRange[0]
} else {
filter.maxBlockRange = -1
}
return filter
}
@ -157,6 +166,11 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
return nil, err
}
// if maxBlockRange configured then check for it
if f.maxBlockRange != -1 && f.end-f.begin+1 > f.maxBlockRange {
return nil, fmt.Errorf("block range is larger than max block range, block range = %d, max block range = %d", f.end-f.begin+1, f.maxBlockRange)
}
logChan, errChan := f.rangeLogsAsync(ctx)
var logs []*types.Log
for {