eth/filters: exit early if topics-filter has more than 4 topics (#28494)

Currently, geth's will return `[]` for any `len(topics) > 4` log filter. The EVM only supports up to four logs, via LOG4 opcode, so larger criterias fail. This change makes the filter query exit early in those cases.
This commit is contained in:
Delweng 2023-11-10 15:10:03 +08:00 committed by GitHub
parent f7dde2a96c
commit e38b9f1830
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 14 additions and 0 deletions

View File

@ -37,8 +37,12 @@ var (
errInvalidTopic = errors.New("invalid topic(s)") errInvalidTopic = errors.New("invalid topic(s)")
errFilterNotFound = errors.New("filter not found") errFilterNotFound = errors.New("filter not found")
errInvalidBlockRange = errors.New("invalid block range params") errInvalidBlockRange = errors.New("invalid block range params")
errExceedMaxTopics = errors.New("exceed max topics")
) )
// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
const maxTopics = 4
// filter is a helper struct that holds meta information over the filter type // filter is a helper struct that holds meta information over the filter type
// and associated subscription in the event system. // and associated subscription in the event system.
type filter struct { type filter struct {
@ -334,6 +338,9 @@ func (api *FilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
// GetLogs returns logs matching the given argument that are stored within the state. // GetLogs returns logs matching the given argument that are stored within the state.
func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) { func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*types.Log, error) {
if len(crit.Topics) > maxTopics {
return nil, errExceedMaxTopics
}
var filter *Filter var filter *Filter
if crit.BlockHash != nil { if crit.BlockHash != nil {
// Block filter requested, construct a single-shot filter // Block filter requested, construct a single-shot filter

View File

@ -299,6 +299,9 @@ func (es *EventSystem) subscribe(sub *subscription) *Subscription {
// given criteria to the given logs channel. Default value for the from and to // given criteria to the given logs channel. Default value for the from and to
// block is "latest". If the fromBlock > toBlock an error is returned. // block is "latest". If the fromBlock > toBlock an error is returned.
func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) (*Subscription, error) { func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) (*Subscription, error) {
if len(crit.Topics) > maxTopics {
return nil, errExceedMaxTopics
}
var from, to rpc.BlockNumber var from, to rpc.BlockNumber
if crit.FromBlock == nil { if crit.FromBlock == nil {
from = rpc.LatestBlockNumber from = rpc.LatestBlockNumber

View File

@ -386,6 +386,8 @@ func TestLogFilterCreation(t *testing.T) {
{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false}, {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, false},
// from block "higher" than to block // from block "higher" than to block
{FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false}, {FilterCriteria{FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, false},
// topics more then 4
{FilterCriteria{Topics: [][]common.Hash{{}, {}, {}, {}, {}}}, false},
} }
) )
@ -420,6 +422,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 0: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 1: {FromBlock: big.NewInt(rpc.PendingBlockNumber.Int64()), ToBlock: big.NewInt(100)},
2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)}, 2: {FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64()), ToBlock: big.NewInt(100)},
3: {Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
} }
for i, test := range testCases { for i, test := range testCases {
@ -445,6 +448,7 @@ func TestInvalidGetLogsRequest(t *testing.T) {
0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)}, 0: {BlockHash: &blockHash, FromBlock: big.NewInt(100)},
1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)}, 1: {BlockHash: &blockHash, ToBlock: big.NewInt(500)},
2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())}, 2: {BlockHash: &blockHash, FromBlock: big.NewInt(rpc.LatestBlockNumber.Int64())},
3: {BlockHash: &blockHash, Topics: [][]common.Hash{{}, {}, {}, {}, {}}},
} }
for i, test := range testCases { for i, test := range testCases {