Skip to content

Commit 80ffd87

Browse files
serikssonnlupin012
andauthored
rpc: preserve topic wildcard positions in log subscriptions (#21067)
This fixes log subscription topic filtering to preserve wildcard positions, and adds regression tests for wildcard-only and positional matching. Co-authored-by: lupin012 <58134934+lupin012@users.noreply.github.com>
1 parent a3ee155 commit 80ffd87

3 files changed

Lines changed: 68 additions & 14 deletions

File tree

rpc/rpchelper/filters.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ func (ff *Filters) SubscribeLogs(size int, criteria filters.FilterCriteria) (<-c
567567
} else {
568568
// Limit the number of topics
569569
topicCount := 0
570-
allowedTopics := [][]common.Hash{}
570+
allowedTopics := make([][]common.Hash, 0, len(criteria.Topics))
571571
for _, topics := range criteria.Topics {
572572
allowedTopicsRow := []common.Hash{}
573573
for _, topic := range topics {
@@ -579,9 +579,8 @@ func (ff *Filters) SubscribeLogs(size int, criteria filters.FilterCriteria) (<-c
579579
break
580580
}
581581
}
582-
if len(allowedTopicsRow) > 0 {
583-
allowedTopics = append(allowedTopics, allowedTopicsRow)
584-
}
582+
// Preserve per-position wildcard slots (empty rows) for correct positional matching.
583+
allowedTopics = append(allowedTopics, allowedTopicsRow)
585584
}
586585
f.topicsOriginal = allowedTopics
587586
}

rpc/rpchelper/filters_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,71 @@ func TestFilters_SingleSubscription_EmptyTopicsInCriteria_OnlyTopicsSubscribedAr
139139
}
140140
}
141141

142+
func TestFilters_SingleSubscription_TopicPositionWildcardIsPreserved(t *testing.T) {
143+
t.Parallel()
144+
config := FiltersConfig{}
145+
f := New(t.Context(), config, nil, nil, nil, func() {}, log.New(), nil)
146+
147+
topic0 := common.BytesToHash([]byte{10, 20})
148+
topic2 := common.BytesToHash([]byte{30, 40})
149+
criteria := filters.FilterCriteria{
150+
Addresses: nil,
151+
Topics: [][]common.Hash{{topic0}, nil, {topic2}},
152+
}
153+
154+
outChan, _ := f.SubscribeLogs(10, criteria)
155+
156+
matchingLog := createLog()
157+
matchingLog.Topics = []*typesproto.H256{
158+
gointerfaces.ConvertHashToH256(topic0),
159+
gointerfaces.ConvertHashToH256(common.BytesToHash([]byte{50, 60})),
160+
gointerfaces.ConvertHashToH256(topic2),
161+
}
162+
f.OnNewLogs(matchingLog)
163+
164+
if len(outChan) != 1 {
165+
t.Error("expected wildcard middle topic to preserve positional matching")
166+
}
167+
168+
nonMatchingLog := createLog()
169+
nonMatchingLog.Topics = []*typesproto.H256{
170+
gointerfaces.ConvertHashToH256(topic0),
171+
gointerfaces.ConvertHashToH256(common.BytesToHash([]byte{50, 60})),
172+
gointerfaces.ConvertHashToH256(common.BytesToHash([]byte{70, 80})),
173+
}
174+
f.OnNewLogs(nonMatchingLog)
175+
176+
if len(outChan) != 1 {
177+
t.Error("expected non-matching topic at constrained position to be filtered out")
178+
}
179+
}
180+
181+
func TestFilters_SingleSubscription_WildcardOnlyTopicRowMatches(t *testing.T) {
182+
t.Parallel()
183+
config := FiltersConfig{}
184+
f := New(t.Context(), config, nil, nil, nil, func() {}, log.New(), nil)
185+
186+
criteria := filters.FilterCriteria{
187+
Addresses: nil,
188+
Topics: [][]common.Hash{nil},
189+
}
190+
191+
outChan, _ := f.SubscribeLogs(10, criteria)
192+
193+
log1 := createLog()
194+
f.OnNewLogs(log1)
195+
if len(outChan) != 1 {
196+
t.Error("expected wildcard-only topic row to match arbitrary topics")
197+
}
198+
199+
log2 := createLog()
200+
log2.Topics = []*typesproto.H256{gointerfaces.ConvertHashToH256(common.BytesToHash([]byte{1, 2, 3}))}
201+
f.OnNewLogs(log2)
202+
if len(outChan) != 2 {
203+
t.Error("expected wildcard-only topic row to continue matching subsequent logs")
204+
}
205+
}
206+
142207
func TestFilters_TwoSubscriptionsWithDifferentCriteria(t *testing.T) {
143208
t.Parallel()
144209
config := FiltersConfig{}

rpc/rpchelper/logsfilter.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -270,16 +270,6 @@ func (a *LogsFilterAggregator) distributeLog(eventLog *remoteproto.SubscribeLogs
270270
// chooseTopics checks if the log topics match the filter's topics.
271271
// It returns true if the log topics match the filter's topics, otherwise false.
272272
func (a *LogsFilterAggregator) chooseTopics(filter *LogsFilter, logTopics []common.Hash) bool {
273-
var found bool
274-
for _, logTopic := range logTopics {
275-
if _, ok := filter.topics.Get(logTopic); ok {
276-
found = true
277-
break
278-
}
279-
}
280-
if !found {
281-
return false
282-
}
283273
if len(filter.topicsOriginal) > len(logTopics) {
284274
return false
285275
}

0 commit comments

Comments
 (0)