core/bloombits, eth/filters: handle null topics (#15195)
When implementing the new bloombits based filter, I've accidentally broke null topics by removing the special casing of common.Hash{} filter rules, which acted as the wildcard topic until now. This PR fixes the regression, but instead of using the magic hash common.Hash{} as the null wildcard, the PR reworks the code to handle nil topics during parsing, converting a JSON null into nil []common.Hash topic.
This commit is contained in:
committed by
Felix Lange
parent
860e697b00
commit
2ab2a9f131
@ -80,7 +80,8 @@ type Matcher struct {
|
||||
}
|
||||
|
||||
// NewMatcher creates a new pipeline for retrieving bloom bit streams and doing
|
||||
// address and topic filtering on them.
|
||||
// address and topic filtering on them. Setting a filter component to `nil` is
|
||||
// allowed and will result in that filter rule being skipped (OR 0x11...1).
|
||||
func NewMatcher(sectionSize uint64, filters [][][]byte) *Matcher {
|
||||
// Create the matcher instance
|
||||
m := &Matcher{
|
||||
@ -95,11 +96,22 @@ func NewMatcher(sectionSize uint64, filters [][][]byte) *Matcher {
|
||||
m.filters = nil
|
||||
|
||||
for _, filter := range filters {
|
||||
// Gather the bit indexes of the filter rule, special casing the nil filter
|
||||
if len(filter) == 0 {
|
||||
continue
|
||||
}
|
||||
bloomBits := make([]bloomIndexes, len(filter))
|
||||
for i, clause := range filter {
|
||||
if clause == nil {
|
||||
bloomBits = nil
|
||||
break
|
||||
}
|
||||
bloomBits[i] = calcBloomIndexes(clause)
|
||||
}
|
||||
m.filters = append(m.filters, bloomBits)
|
||||
// Accumulate the filter rules if no nil rule was within
|
||||
if bloomBits != nil {
|
||||
m.filters = append(m.filters, bloomBits)
|
||||
}
|
||||
}
|
||||
// For every bit, create a scheduler to load/download the bit vectors
|
||||
for _, bloomIndexLists := range m.filters {
|
||||
|
@ -21,10 +21,38 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
const testSectionSize = 4096
|
||||
|
||||
// Tests that wildcard filter rules (nil) can be specified and are handled well.
|
||||
func TestMatcherWildcards(t *testing.T) {
|
||||
matcher := NewMatcher(testSectionSize, [][][]byte{
|
||||
[][]byte{common.Address{}.Bytes(), common.Address{0x01}.Bytes()}, // Default address is not a wildcard
|
||||
[][]byte{common.Hash{}.Bytes(), common.Hash{0x01}.Bytes()}, // Default hash is not a wildcard
|
||||
[][]byte{common.Hash{0x01}.Bytes()}, // Plain rule, sanity check
|
||||
[][]byte{common.Hash{0x01}.Bytes(), nil}, // Wildcard suffix, drop rule
|
||||
[][]byte{nil, common.Hash{0x01}.Bytes()}, // Wildcard prefix, drop rule
|
||||
[][]byte{nil, nil}, // Wildcard combo, drop rule
|
||||
[][]byte{}, // Inited wildcard rule, drop rule
|
||||
nil, // Proper wildcard rule, drop rule
|
||||
})
|
||||
if len(matcher.filters) != 3 {
|
||||
t.Fatalf("filter system size mismatch: have %d, want %d", len(matcher.filters), 3)
|
||||
}
|
||||
if len(matcher.filters[0]) != 2 {
|
||||
t.Fatalf("address clause size mismatch: have %d, want %d", len(matcher.filters[0]), 2)
|
||||
}
|
||||
if len(matcher.filters[1]) != 2 {
|
||||
t.Fatalf("combo topic clause size mismatch: have %d, want %d", len(matcher.filters[1]), 2)
|
||||
}
|
||||
if len(matcher.filters[2]) != 1 {
|
||||
t.Fatalf("singletone topic clause size mismatch: have %d, want %d", len(matcher.filters[2]), 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests the matcher pipeline on a single continuous workflow without interrupts.
|
||||
func TestMatcherContinuous(t *testing.T) {
|
||||
testMatcherDiffBatches(t, [][]bloomIndexes{{{10, 20, 30}}}, 100000, false, 75)
|
||||
|
Reference in New Issue
Block a user