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:
parent
f7dde2a96c
commit
e38b9f1830
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user