aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2017-09-27 18:14:52 +0800
committerFelix Lange <fjl@users.noreply.github.com>2017-09-27 18:14:52 +0800
commit2ab2a9f13116748ca343892f851e3632861c994e (patch)
tree97e5cc5dc3b07dbcdc6a73adfbfb07acf816d35f /core
parent860e697b00c25b8f47371f8b8c7342d0230cee84 (diff)
downloaddexon-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.go16
-rw-r--r--core/bloombits/matcher_test.go28
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)