diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-09-27 18:14:52 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2017-09-27 18:14:52 +0800 |
commit | 2ab2a9f13116748ca343892f851e3632861c994e (patch) | |
tree | 97e5cc5dc3b07dbcdc6a73adfbfb07acf816d35f /core | |
parent | 860e697b00c25b8f47371f8b8c7342d0230cee84 (diff) | |
download | dexon-2ab2a9f13116748ca343892f851e3632861c994e.tar dexon-2ab2a9f13116748ca343892f851e3632861c994e.tar.gz dexon-2ab2a9f13116748ca343892f851e3632861c994e.tar.bz2 dexon-2ab2a9f13116748ca343892f851e3632861c994e.tar.lz dexon-2ab2a9f13116748ca343892f851e3632861c994e.tar.xz dexon-2ab2a9f13116748ca343892f851e3632861c994e.tar.zst dexon-2ab2a9f13116748ca343892f851e3632861c994e.zip |
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.
Diffstat (limited to 'core')
-rw-r--r-- | core/bloombits/matcher.go | 16 | ||||
-rw-r--r-- | core/bloombits/matcher_test.go | 28 |
2 files changed, 42 insertions, 2 deletions
diff --git a/core/bloombits/matcher.go b/core/bloombits/matcher.go index f3ed405a6..e33de018a 100644 --- a/core/bloombits/matcher.go +++ b/core/bloombits/matcher.go @@ -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 { diff --git a/core/bloombits/matcher_test.go b/core/bloombits/matcher_test.go index f0198c4e3..f95d0ea9e 100644 --- a/core/bloombits/matcher_test.go +++ b/core/bloombits/matcher_test.go @@ -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) |