mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
configurable address limit
This commit is contained in:
parent
b340103e9d
commit
22580d2237
8 changed files with 89 additions and 31 deletions
|
|
@ -180,6 +180,7 @@ var (
|
|||
utils.RPCGlobalGasCapFlag,
|
||||
utils.RPCGlobalEVMTimeoutFlag,
|
||||
utils.RPCGlobalTxFeeCapFlag,
|
||||
utils.EthGetLogMaxAddressFlag,
|
||||
utils.AllowUnprotectedTxs,
|
||||
utils.BatchRequestLimit,
|
||||
utils.BatchResponseMaxSize,
|
||||
|
|
|
|||
|
|
@ -590,6 +590,12 @@ var (
|
|||
Value: ethconfig.Defaults.RPCTxFeeCap,
|
||||
Category: flags.APICategory,
|
||||
}
|
||||
EthGetLogMaxAddressFlag = &cli.Uint64Flag{
|
||||
Name: "rpc.getlogmaxaddrs",
|
||||
Usage: "Maximum number of addresses allowed in eth_getLogs filter criteria",
|
||||
Value: 1000,
|
||||
Category: flags.APICategory,
|
||||
}
|
||||
// Authenticated RPC HTTP settings
|
||||
AuthListenFlag = &cli.StringFlag{
|
||||
Name: "authrpc.addr",
|
||||
|
|
@ -1689,6 +1695,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||
if ctx.IsSet(CacheLogSizeFlag.Name) {
|
||||
cfg.FilterLogCacheSize = ctx.Int(CacheLogSizeFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(EthGetLogMaxAddressFlag.Name) {
|
||||
cfg.FilterMaxAddresses = int(ctx.Uint64(EthGetLogMaxAddressFlag.Name))
|
||||
}
|
||||
if !ctx.Bool(SnapshotFlag.Name) || cfg.SnapshotCache == 0 {
|
||||
// If snap-sync is requested, this flag is also required
|
||||
if cfg.SyncMode == ethconfig.SnapSync {
|
||||
|
|
@ -1998,6 +2007,7 @@ func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, filterSyst
|
|||
func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconfig.Config) *filters.FilterSystem {
|
||||
filterSystem := filters.NewFilterSystem(backend, filters.Config{
|
||||
LogCacheSize: ethcfg.FilterLogCacheSize,
|
||||
MaxAddresses: ethcfg.FilterMaxAddresses,
|
||||
})
|
||||
stack.RegisterAPIs([]rpc.API{{
|
||||
Namespace: "eth",
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ var Defaults = Config{
|
|||
TrieTimeout: 60 * time.Minute,
|
||||
SnapshotCache: 102,
|
||||
FilterLogCacheSize: 32,
|
||||
FilterMaxAddresses: 1000,
|
||||
Miner: miner.DefaultConfig,
|
||||
TxPool: legacypool.DefaultConfig,
|
||||
BlobPool: blobpool.DefaultConfig,
|
||||
|
|
@ -131,6 +132,9 @@ type Config struct {
|
|||
// This is the number of blocks for which logs will be cached in the filter system.
|
||||
FilterLogCacheSize int
|
||||
|
||||
// This is the maximum number of addresses allowed in filter criteria for eth_getLogs.
|
||||
FilterMaxAddresses int
|
||||
|
||||
// Mining options
|
||||
Miner miner.Config
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
SnapshotCache int
|
||||
Preimages bool
|
||||
FilterLogCacheSize int
|
||||
FilterMaxAddresses int
|
||||
Miner miner.Config
|
||||
TxPool legacypool.Config
|
||||
BlobPool blobpool.Config
|
||||
|
|
@ -86,6 +87,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
enc.SnapshotCache = c.SnapshotCache
|
||||
enc.Preimages = c.Preimages
|
||||
enc.FilterLogCacheSize = c.FilterLogCacheSize
|
||||
enc.FilterMaxAddresses = c.FilterMaxAddresses
|
||||
enc.Miner = c.Miner
|
||||
enc.TxPool = c.TxPool
|
||||
enc.BlobPool = c.BlobPool
|
||||
|
|
@ -132,6 +134,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
SnapshotCache *int
|
||||
Preimages *bool
|
||||
FilterLogCacheSize *int
|
||||
FilterMaxAddresses *int
|
||||
Miner *miner.Config
|
||||
TxPool *legacypool.Config
|
||||
BlobPool *blobpool.Config
|
||||
|
|
@ -231,6 +234,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.FilterLogCacheSize != nil {
|
||||
c.FilterLogCacheSize = *dec.FilterLogCacheSize
|
||||
}
|
||||
if dec.FilterMaxAddresses != nil {
|
||||
c.FilterMaxAddresses = *dec.FilterMaxAddresses
|
||||
}
|
||||
if dec.Miner != nil {
|
||||
c.Miner = *dec.Miner
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
// The maximum number of addresses allowed in a filter criteria
|
||||
maxAddresses = 1000
|
||||
// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
|
||||
maxTopics = 4
|
||||
// The maximum number of allowed topics within a topic criteria
|
||||
|
|
@ -70,20 +68,22 @@ type filter struct {
|
|||
// FilterAPI offers support to create and manage filters. This will allow external clients to retrieve various
|
||||
// information related to the Ethereum protocol such as blocks, transactions and logs.
|
||||
type FilterAPI struct {
|
||||
sys *FilterSystem
|
||||
events *EventSystem
|
||||
filtersMu sync.Mutex
|
||||
filters map[rpc.ID]*filter
|
||||
timeout time.Duration
|
||||
sys *FilterSystem
|
||||
events *EventSystem
|
||||
filtersMu sync.Mutex
|
||||
filters map[rpc.ID]*filter
|
||||
timeout time.Duration
|
||||
maxAddresses int
|
||||
}
|
||||
|
||||
// NewFilterAPI returns a new FilterAPI instance.
|
||||
func NewFilterAPI(system *FilterSystem) *FilterAPI {
|
||||
api := &FilterAPI{
|
||||
sys: system,
|
||||
events: NewEventSystem(system),
|
||||
filters: make(map[rpc.ID]*filter),
|
||||
timeout: system.cfg.Timeout,
|
||||
sys: system,
|
||||
events: NewEventSystem(system),
|
||||
filters: make(map[rpc.ID]*filter),
|
||||
timeout: system.cfg.Timeout,
|
||||
maxAddresses: system.cfg.MaxAddresses,
|
||||
}
|
||||
go api.timeoutLoop(system.cfg.Timeout)
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type
|
|||
if len(crit.Topics) > maxTopics {
|
||||
return nil, errExceedMaxTopics
|
||||
}
|
||||
if len(crit.Addresses) > maxAddresses {
|
||||
if len(crit.Addresses) > api.maxAddresses {
|
||||
return nil, errExceedMaxAddresses
|
||||
}
|
||||
|
||||
|
|
@ -545,9 +545,6 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
|||
// raw.Address can contain a single address or an array of addresses
|
||||
switch rawAddr := raw.Addresses.(type) {
|
||||
case []interface{}:
|
||||
if len(rawAddr) > maxAddresses {
|
||||
return errExceedMaxAddresses
|
||||
}
|
||||
for i, addr := range rawAddr {
|
||||
if strAddr, ok := addr.(string); ok {
|
||||
addr, err := decodeAddress(strAddr)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package filters
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -183,15 +182,4 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) {
|
|||
if len(test7.Topics[2]) != 0 {
|
||||
t.Fatalf("expected 0 topics, got %d topics", len(test7.Topics[2]))
|
||||
}
|
||||
|
||||
// multiple address exceeding max
|
||||
var test8 FilterCriteria
|
||||
addresses := make([]string, maxAddresses+1)
|
||||
for i := 0; i < maxAddresses+1; i++ {
|
||||
addresses[i] = fmt.Sprintf(`"%s"`, common.HexToAddress(fmt.Sprintf("0x%x", i)).Hex())
|
||||
}
|
||||
vector = fmt.Sprintf(`{"address": [%s]}`, strings.Join(addresses, ", "))
|
||||
if err := json.Unmarshal([]byte(vector), &test8); err != errExceedMaxAddresses {
|
||||
t.Fatal("expected errExceedMaxAddresses, got", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import (
|
|||
type Config struct {
|
||||
LogCacheSize int // maximum number of cached blocks (default: 32)
|
||||
Timeout time.Duration // how long filters stay active (default: 5min)
|
||||
MaxAddresses int // maximum number of addresses allowed in filter criteria (default: 1000)
|
||||
}
|
||||
|
||||
func (cfg Config) withDefaults() Config {
|
||||
|
|
@ -52,6 +53,9 @@ func (cfg Config) withDefaults() Config {
|
|||
if cfg.LogCacheSize == 0 {
|
||||
cfg.LogCacheSize = 32
|
||||
}
|
||||
if cfg.MaxAddresses == 0 {
|
||||
cfg.MaxAddresses = 1000
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
|
|
@ -291,7 +295,7 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
|
|||
if len(crit.Topics) > maxTopics {
|
||||
return nil, errExceedMaxTopics
|
||||
}
|
||||
if len(crit.Addresses) > maxAddresses {
|
||||
if len(crit.Addresses) > es.sys.cfg.MaxAddresses {
|
||||
return nil, errExceedMaxAddresses
|
||||
}
|
||||
var from, to rpc.BlockNumber
|
||||
|
|
|
|||
|
|
@ -435,7 +435,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
|
|||
1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)},
|
||||
2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)},
|
||||
3: {Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
|
||||
4: {Addresses: make([]common.Address, maxAddresses+1)},
|
||||
4: {Addresses: make([]common.Address, api.maxAddresses+1)},
|
||||
}
|
||||
|
||||
for i, test := range testCases {
|
||||
|
|
@ -500,8 +500,8 @@ func TestInvalidGetLogsRequest(t *testing.T) {
|
|||
err: errExceedMaxTopics,
|
||||
},
|
||||
{
|
||||
f: FilterCriteria{BlockHash: &blockHash, Addresses: make([]common.Address, maxAddresses+1)},
|
||||
err: errExceedMaxAddresses,
|
||||
f: FilterCriteria{BlockHash: &blockHash, Addresses: make([]common.Address, api.logQueryLimit+1)},
|
||||
err: errExceedLogQueryLimit,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -528,6 +528,54 @@ func TestInvalidGetRangeLogsRequest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestInvalidAddressLengthRequest tests getLogs with too many addresses
|
||||
func TestInvalidAddressLengthRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Test with custom config (MaxAddresses = 5 for easier testing)
|
||||
var (
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
_, sys = newTestFilterSystem(db, Config{MaxAddresses: 5})
|
||||
api = NewFilterAPI(sys)
|
||||
)
|
||||
|
||||
// Test that 6 addresses fails with correct error
|
||||
invalidAddresses := make([]common.Address, 6)
|
||||
for i := range invalidAddresses {
|
||||
invalidAddresses[i] = common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||
}
|
||||
|
||||
// Add FromBlock and ToBlock to make it similar to other invalid tests
|
||||
if _, err := api.GetLogs(context.Background(), FilterCriteria{
|
||||
FromBlock: big.NewInt(0),
|
||||
ToBlock: big.NewInt(100),
|
||||
Addresses: invalidAddresses,
|
||||
}); err != errExceedMaxAddresses {
|
||||
t.Errorf("Expected GetLogs with 6 addresses to return errExceedMaxAddresses, but got: %v", err)
|
||||
}
|
||||
|
||||
// Test with default config should reject 1001 addresses
|
||||
var (
|
||||
db2 = rawdb.NewMemoryDatabase()
|
||||
_, sys2 = newTestFilterSystem(db2, Config{}) // Uses default MaxAddresses = 1000
|
||||
api2 = NewFilterAPI(sys2)
|
||||
)
|
||||
|
||||
// Test that 1001 addresses fails with correct error
|
||||
tooManyAddresses := make([]common.Address, 1001)
|
||||
for i := range tooManyAddresses {
|
||||
tooManyAddresses[i] = common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||
}
|
||||
|
||||
if _, err := api2.GetLogs(context.Background(), FilterCriteria{
|
||||
FromBlock: big.NewInt(0),
|
||||
ToBlock: big.NewInt(100),
|
||||
Addresses: tooManyAddresses,
|
||||
}); err != errExceedMaxAddresses {
|
||||
t.Errorf("Expected GetLogs with 1001 addresses to return errExceedMaxAddresses, but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestLogFilter tests whether log filters match the correct logs that are posted to the event feed.
|
||||
func TestLogFilter(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
|
|
|||
Loading…
Reference in a new issue