Skip to content

Commit 10e5584

Browse files
authored
apply bloom filter in api.StreamLogs() (iotexproject#2409)
1 parent 56ac23b commit 10e5584

File tree

3 files changed

+59
-16
lines changed

3 files changed

+59
-16
lines changed

api/api.go

+12-13
Original file line numberDiff line numberDiff line change
@@ -653,19 +653,19 @@ func (api *Server) GetLogs(
653653
if in.GetFilter() == nil {
654654
return nil, status.Error(codes.InvalidArgument, "empty filter")
655655
}
656+
657+
var (
658+
startBlock, count uint64
659+
err error
660+
)
656661
switch {
657662
case in.GetByBlock() != nil:
663+
count = 1
658664
req := in.GetByBlock()
659-
h, err := api.dao.GetBlockHeight(hash.BytesToHash256(req.BlockHash))
665+
startBlock, err = api.dao.GetBlockHeight(hash.BytesToHash256(req.BlockHash))
660666
if err != nil {
661667
return nil, status.Error(codes.InvalidArgument, "invalid block hash")
662668
}
663-
filter, ok := NewLogFilter(in.GetFilter(), nil, nil).(*LogFilter)
664-
if !ok {
665-
return nil, status.Error(codes.Internal, "cannot convert to *LogFilter")
666-
}
667-
logs, err := api.getLogsInBlock(filter, h, 1)
668-
return &iotexapi.GetLogsResponse{Logs: logs}, err
669669
case in.GetByRange() != nil:
670670
req := in.GetByRange()
671671
if req.FromBlock > api.bc.TipHeight() {
@@ -674,15 +674,14 @@ func (api *Server) GetLogs(
674674
if req.Count > 1000 {
675675
return nil, status.Error(codes.InvalidArgument, "maximum query range is 1000 blocks")
676676
}
677-
filter, ok := NewLogFilter(in.GetFilter(), nil, nil).(*LogFilter)
678-
if !ok {
679-
return nil, status.Error(codes.Internal, "cannot convert to *LogFilter")
680-
}
681-
logs, err := api.getLogsInBlock(filter, req.FromBlock, req.Count)
682-
return &iotexapi.GetLogsResponse{Logs: logs}, err
677+
startBlock = req.FromBlock
678+
count = req.Count
683679
default:
684680
return nil, status.Error(codes.InvalidArgument, "invalid GetLogsRequest type")
685681
}
682+
683+
logs, err := api.getLogsInBlock(NewLogFilter(in.GetFilter(), nil, nil), startBlock, count)
684+
return &iotexapi.GetLogsResponse{Logs: logs}, err
686685
}
687686

688687
// StreamBlocks streams blocks

api/logfilter.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package api
33
import (
44
"bytes"
55

6+
"github.com/iotexproject/go-pkgs/bloom"
67
"github.com/iotexproject/iotex-proto/golang/iotexapi"
78
"github.com/iotexproject/iotex-proto/golang/iotextypes"
89
"go.uber.org/zap"
@@ -31,7 +32,7 @@ type LogFilter struct {
3132
}
3233

3334
// NewLogFilter returns a new log filter
34-
func NewLogFilter(in *iotexapi.LogsFilter, stream iotexapi.APIService_StreamLogsServer, errChan chan error) Responder {
35+
func NewLogFilter(in *iotexapi.LogsFilter, stream iotexapi.APIService_StreamLogsServer, errChan chan error) *LogFilter {
3536
return &LogFilter{
3637
stream: stream,
3738
errChan: errChan,
@@ -41,6 +42,9 @@ func NewLogFilter(in *iotexapi.LogsFilter, stream iotexapi.APIService_StreamLogs
4142

4243
// Respond to new block
4344
func (l *LogFilter) Respond(blk *block.Block) error {
45+
if !l.ExistInBloomFilter(blk.LogsBloomfilter()) {
46+
return nil
47+
}
4448
logs := l.MatchLogs(blk.Receipts)
4549
if len(logs) == 0 {
4650
return nil
@@ -117,3 +121,24 @@ func (l *LogFilter) match(log *iotextypes.Log) bool {
117121
}
118122
return true
119123
}
124+
125+
// ExistInBloomFilter returns true if topics of filter exist in the bloom filter
126+
func (l *LogFilter) ExistInBloomFilter(filter bloom.BloomFilter) bool {
127+
if filter == nil {
128+
return true
129+
}
130+
131+
for _, e := range l.pbFilter.Topics {
132+
if e == nil || len(e.Topic) == 0 {
133+
continue
134+
}
135+
136+
for _, v := range e.Topic {
137+
if filter.Exist(v) {
138+
return true
139+
}
140+
}
141+
}
142+
// {} or nil matches any address or topic list
143+
return len(l.pbFilter.Topics) == 0
144+
}

api/logfilter_test.go

+21-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package api
33
import (
44
"testing"
55

6+
"github.com/iotexproject/go-pkgs/bloom"
67
"github.com/iotexproject/go-pkgs/hash"
78
"github.com/iotexproject/iotex-proto/golang/iotexapi"
89
"github.com/stretchr/testify/require"
@@ -77,80 +78,98 @@ var (
7778
testData = []struct {
7879
log *action.Log
7980
match [5]bool
81+
exist [5]bool
8082
}{
8183
{
8284
&action.Log{
8385
Address: "topicN",
8486
Topics: []hash.Hash256{dataN}, // both address and topic not exist
8587
},
8688
[5]bool{true, false, false, false, false},
89+
[5]bool{true, true, false, false, false},
8790
},
8891
{
8992
&action.Log{
9093
Address: "topicN",
9194
Topics: []hash.Hash256{data1, data2, dataA}, // topic longer than log's topic list
9295
},
9396
[5]bool{true, false, false, false, false},
97+
[5]bool{true, true, true, true, true},
9498
},
9599
{
96100
&action.Log{
97101
Address: "topicN",
98102
Topics: []hash.Hash256{data1, dataN}, // topic not match
99103
},
100104
[5]bool{true, false, false, false, false},
105+
[5]bool{true, true, true, true, false},
101106
},
102107
{
103108
&action.Log{
104109
Address: "topic1",
105110
Topics: []hash.Hash256{dataN}, // topic not exist
106111
},
107112
[5]bool{true, true, false, false, false},
113+
[5]bool{true, true, false, false, false},
108114
},
109115
{
110116
&action.Log{
111117
Address: "topic2",
112118
Topics: []hash.Hash256{dataA, dataB}, // topic not match
113119
},
114120
[5]bool{true, true, false, false, false},
121+
[5]bool{true, true, true, false, true},
115122
},
116123
{
117124
&action.Log{
118125
Address: "topicN",
119126
Topics: []hash.Hash256{data1, dataB},
120127
},
121128
[5]bool{true, false, true, false, false},
129+
[5]bool{true, true, true, true, true},
122130
},
123131
{
124132
&action.Log{
125133
Address: "topicN",
126134
Topics: []hash.Hash256{data2, dataA},
127135
},
128136
[5]bool{true, false, true, false, false},
137+
[5]bool{true, true, true, true, true},
129138
},
130139
{
131140
&action.Log{
132141
Address: "topic1",
133142
Topics: []hash.Hash256{data1, dataN},
134143
},
135144
[5]bool{true, true, false, true, false},
145+
[5]bool{true, true, true, true, false},
136146
},
137147
{
138148
&action.Log{
139149
Address: "topicB",
140150
Topics: []hash.Hash256{dataN, dataA},
141151
},
142152
[5]bool{true, true, false, false, true},
153+
[5]bool{true, true, true, false, true},
143154
},
144155
}
145156
)
146157

147158
func TestLogFilter_MatchBlock(t *testing.T) {
148159
require := require.New(t)
149160

161+
f := NewLogFilter(testFilter[0], nil, nil)
162+
require.True(f.ExistInBloomFilter(nil))
163+
150164
for i, q := range testFilter {
151-
f, ok := NewLogFilter(q, nil, nil).(*LogFilter)
152-
require.True(ok)
165+
f = NewLogFilter(q, nil, nil)
153166
for _, v := range testData {
167+
bloom, err := bloom.NewBloomFilter(2048, 3)
168+
require.NoError(err)
169+
for _, topic := range v.log.Topics {
170+
bloom.Add(topic[:])
171+
}
172+
require.Equal(f.ExistInBloomFilter(bloom), v.exist[i])
154173
log := v.log.ConvertToLogPb()
155174
require.Equal(f.match(log), v.match[i])
156175
}

0 commit comments

Comments
 (0)