Skip to content

Commit 1f4ea4d

Browse files
ceyonurzsfelfoldi
andauthored
eth/filters: add address limit to filters (#31876)
The address filter was never checked against a maximum limit, which can be somewhat abusive for API nodes. This PR adds a limit similar to topics ## Description (AI generated) This pull request introduces a new validation to enforce a maximum limit on the number of addresses allowed in filter criteria for Ethereum logs. It includes updates to the `FilterAPI` and `EventSystem` logic, as well as corresponding test cases to ensure the new constraint is properly enforced. ### Core functionality changes: * **Validation for maximum addresses in filter criteria**: - Added a new constant, `maxAddresses`, set to 100, to define the maximum allowable addresses in a filter. - Introduced a new error, `errExceedMaxAddresses`, to handle cases where the number of addresses exceeds the limit. - Updated the `GetLogs` method in `FilterAPI` to validate the number of addresses against `maxAddresses`. - Modified the `UnmarshalJSON` method to return an error if the number of addresses in the input JSON exceeds `maxAddresses`. - Added similar validation to the `SubscribeLogs` method in `EventSystem`. ### Test updates: * **New test cases for address limit validation**: - Added a test in `TestUnmarshalJSONNewFilterArgs` to verify that exceeding the maximum number of addresses triggers the `errExceedMaxAddresses` error. - Updated `TestInvalidLogFilterCreation` to include a test case for an invalid filter with more than `maxAddresses` addresses. - Updated `TestInvalidGetLogsRequest` to test for invalid log requests with excessive addresses. These changes ensure that the system enforces a reasonable limit on the number of addresses in filter criteria, improving robustness and preventing potential performance issues. --------- Co-authored-by: zsfelfoldi <zsfelfoldi@gmail.com>
1 parent c59c647 commit 1f4ea4d

File tree

4 files changed

+32
-5
lines changed

4 files changed

+32
-5
lines changed

eth/filters/api.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ var (
4040
errInvalidBlockRange = errors.New("invalid block range params")
4141
errPendingLogsUnsupported = errors.New("pending logs are not supported")
4242
errExceedMaxTopics = errors.New("exceed max topics")
43+
errExceedMaxAddresses = errors.New("exceed max addresses")
4344
)
4445

45-
// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
46-
const maxTopics = 4
47-
48-
// The maximum number of allowed topics within a topic criteria
49-
const maxSubTopics = 1000
46+
const (
47+
// The maximum number of addresses allowed in a filter criteria
48+
maxAddresses = 1000
49+
// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
50+
maxTopics = 4
51+
// The maximum number of allowed topics within a topic criteria
52+
maxSubTopics = 1000
53+
)
5054

5155
// filter is a helper struct that holds meta information over the filter type
5256
// and associated subscription in the event system.
@@ -341,6 +345,9 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type
341345
if len(crit.Topics) > maxTopics {
342346
return nil, errExceedMaxTopics
343347
}
348+
if len(crit.Addresses) > maxAddresses {
349+
return nil, errExceedMaxAddresses
350+
}
344351
var filter *Filter
345352
if crit.BlockHash != nil {
346353
// Block filter requested, construct a single-shot filter
@@ -530,6 +537,9 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
530537
// raw.Address can contain a single address or an array of addresses
531538
switch rawAddr := raw.Addresses.(type) {
532539
case []interface{}:
540+
if len(rawAddr) > maxAddresses {
541+
return errExceedMaxAddresses
542+
}
533543
for i, addr := range rawAddr {
534544
if strAddr, ok := addr.(string); ok {
535545
addr, err := decodeAddress(strAddr)

eth/filters/api_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package filters
1919
import (
2020
"encoding/json"
2121
"fmt"
22+
"strings"
2223
"testing"
2324

2425
"github.com/ethereum/go-ethereum/common"
@@ -182,4 +183,15 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) {
182183
if len(test7.Topics[2]) != 0 {
183184
t.Fatalf("expected 0 topics, got %d topics", len(test7.Topics[2]))
184185
}
186+
187+
// multiple address exceeding max
188+
var test8 FilterCriteria
189+
addresses := make([]string, maxAddresses+1)
190+
for i := 0; i < maxAddresses+1; i++ {
191+
addresses[i] = fmt.Sprintf(`"%s"`, common.HexToAddress(fmt.Sprintf("0x%x", i)).Hex())
192+
}
193+
vector = fmt.Sprintf(`{"address": [%s]}`, strings.Join(addresses, ", "))
194+
if err := json.Unmarshal([]byte(vector), &test8); err != errExceedMaxAddresses {
195+
t.Fatal("expected errExceedMaxAddresses, got", err)
196+
}
185197
}

eth/filters/filter_system.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
291291
if len(crit.Topics) > maxTopics {
292292
return nil, errExceedMaxTopics
293293
}
294+
if len(crit.Addresses) > maxAddresses {
295+
return nil, errExceedMaxAddresses
296+
}
294297
var from, to rpc.BlockNumber
295298
if crit.FromBlock == nil {
296299
from = rpc.LatestBlockNumber

eth/filters/filter_system_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
435435
1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)},
436436
2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)},
437437
3: {Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
438+
4: {Addresses: make([]common.Address, maxAddresses+1)},
438439
}
439440

440441
for i, test := range testCases {
@@ -461,6 +462,7 @@ func TestInvalidGetLogsRequest(t *testing.T) {
461462
1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)},
462463
2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
463464
3: {BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
465+
4: {BlockHash: &blockHash, Addresses: make([]common.Address, maxAddresses+1)},
464466
}
465467

466468
for i, test := range testCases {

0 commit comments

Comments
 (0)