eth/filter, core/bloombits: pass begin, end, addresses and topics at create time

This commit is contained in:
Zsolt Felfoldi 2017-05-09 21:15:54 +02:00
parent c927db689f
commit 4f2b101d27
9 changed files with 48 additions and 92 deletions

View file

@ -164,13 +164,16 @@ type Matcher struct {
} }
// NewMatcher creates a new Matcher instance // NewMatcher creates a new Matcher instance
func NewMatcher(sectionSize uint64) *Matcher { func NewMatcher(sectionSize uint64, addresses []common.Address, topics [][]common.Hash) *Matcher {
return &Matcher{fetchers: make(map[uint]*fetcher), reqs: make(map[uint][]uint64), distCh: make(chan distReq, channelCap), sectionSize: sectionSize} m := &Matcher{fetchers: make(map[uint]*fetcher), reqs: make(map[uint][]uint64), distCh: make(chan distReq, channelCap), sectionSize: sectionSize}
m.setAddresses(addresses)
m.setTopics(topics)
return m
} }
// SetAddresses matches only logs that are generated from addresses that are included // setAddresses matches only logs that are generated from addresses that are included
// in the given addresses. // in the given addresses.
func (m *Matcher) SetAddresses(addr []common.Address) { func (m *Matcher) setAddresses(addr []common.Address) {
m.addresses = make([]types.BloomIndexList, len(addr)) m.addresses = make([]types.BloomIndexList, len(addr))
for i, b := range addr { for i, b := range addr {
m.addresses[i] = types.BloomIndexes(b.Bytes()) m.addresses[i] = types.BloomIndexes(b.Bytes())
@ -183,8 +186,8 @@ func (m *Matcher) SetAddresses(addr []common.Address) {
} }
} }
// SetTopics matches only logs that have topics matching the given topics. // setTopics matches only logs that have topics matching the given topics.
func (m *Matcher) SetTopics(topics [][]common.Hash) { func (m *Matcher) setTopics(topics [][]common.Hash) {
m.topics = nil m.topics = nil
loop: loop:
for _, topicList := range topics { for _, topicList := range topics {

View file

@ -94,7 +94,7 @@ func testServeMatcher(m *Matcher, stop chan struct{}, cnt *uint32) {
} }
func testMatcher(t *testing.T, idxs [][]types.BloomIndexList, cnt uint64, stopOnMatches bool, expCount uint32) uint32 { func testMatcher(t *testing.T, idxs [][]types.BloomIndexList, cnt uint64, stopOnMatches bool, expCount uint32) uint32 {
m := NewMatcher(testSectionSize) m := NewMatcher(testSectionSize, nil, nil)
for _, idxss := range idxs { for _, idxss := range idxs {
for _, idxs := range idxss { for _, idxs := range idxss {

View file

@ -213,6 +213,10 @@ func (b *EthApiBackend) GetBloomBits(ctx context.Context, bitIdx uint64, section
return results, nil return results, nil
} }
func (b *EthApiBackend) BloomBitsSectionSize() uint64 {
return bloomBitsSection
}
type EthApiState struct { type EthApiState struct {
state *state.StateDB state *state.StateDB
} }

View file

@ -333,11 +333,7 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
crit.ToBlock = big.NewInt(rpc.LatestBlockNumber.Int64()) crit.ToBlock = big.NewInt(rpc.LatestBlockNumber.Int64())
} }
filter := New(api.backend, api.bloomBitsSection) filter := New(api.backend, crit.FromBlock.Int64(), crit.ToBlock.Int64(), crit.Addresses, crit.Topics)
filter.SetBeginBlock(crit.FromBlock.Int64())
filter.SetEndBlock(crit.ToBlock.Int64())
filter.SetAddresses(crit.Addresses)
filter.SetTopics(crit.Topics)
logs, err := filter.Find(ctx) logs, err := filter.Find(ctx)
return returnLogs(logs), err return returnLogs(logs), err
@ -373,19 +369,18 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty
return nil, fmt.Errorf("filter not found") return nil, fmt.Errorf("filter not found")
} }
filter := New(api.backend, api.bloomBitsSection) var begin, end int64
if f.crit.FromBlock != nil { if f.crit.FromBlock != nil {
filter.SetBeginBlock(f.crit.FromBlock.Int64()) begin = f.crit.FromBlock.Int64()
} else { } else {
filter.SetBeginBlock(rpc.LatestBlockNumber.Int64()) begin = rpc.LatestBlockNumber.Int64()
} }
if f.crit.ToBlock != nil { if f.crit.ToBlock != nil {
filter.SetEndBlock(f.crit.ToBlock.Int64()) end = f.crit.ToBlock.Int64()
} else { } else {
filter.SetEndBlock(rpc.LatestBlockNumber.Int64()) end = rpc.LatestBlockNumber.Int64()
} }
filter.SetAddresses(f.crit.Addresses) filter := New(api.backend, begin, end, f.crit.Addresses, f.crit.Topics)
filter.SetTopics(f.crit.Topics)
logs, err := filter.Find(ctx) logs, err := filter.Find(ctx)
if err != nil { if err != nil {

View file

@ -167,14 +167,11 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64, comp int) {
db, _ = ethdb.NewLDBDatabase(benchDataDir, 128, 1024) db, _ = ethdb.NewLDBDatabase(benchDataDir, 128, 1024)
backend = &testBackend{mux, db} backend = &testBackend{mux, db}
} }
filter := New(backend, sectionSize)
filter.decompress = decompressFn
var addr common.Address var addr common.Address
addr[0] = byte(i) addr[0] = byte(i)
addr[1] = byte(i / 256) addr[1] = byte(i / 256)
filter.SetAddresses([]common.Address{addr}) filter := New(backend, 0, int64(cnt*sectionSize-1), []common.Address{addr}, nil)
filter.SetBeginBlock(0) filter.decompress = decompressFn
filter.SetEndBlock(int64(cnt*sectionSize - 1))
if _, err := filter.Find(context.Background()); err != nil { if _, err := filter.Find(context.Background()); err != nil {
b.Error("filter.Find error:", err) b.Error("filter.Find error:", err)
} }
@ -233,11 +230,7 @@ func BenchmarkNoBloomBits(b *testing.B) {
start := time.Now() start := time.Now()
mux := new(event.TypeMux) mux := new(event.TypeMux)
backend := &testBackend{mux, db} backend := &testBackend{mux, db}
filter := New(backend, 4096) // give any dummy section size, no bloombits data is available filter := New(backend, 0, int64(headNum), []common.Address{common.Address{}}, nil)
var addr common.Address
filter.SetAddresses([]common.Address{addr})
filter.SetBeginBlock(0)
filter.SetEndBlock(int64(headNum))
filter.Find(context.Background()) filter.Find(context.Background())
d := time.Since(start) d := time.Since(start)
fmt.Println("Finished running filter benchmarks") fmt.Println("Finished running filter benchmarks")

View file

@ -38,6 +38,7 @@ type Backend interface {
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetBloomBits(ctx context.Context, bitIdx uint64, sectionIdxList []uint64) ([][]byte, error) GetBloomBits(ctx context.Context, bitIdx uint64, sectionIdxList []uint64) ([][]byte, error)
BloomBitsSectionSize() uint64
} }
// Filter can be used to retrieve and filter logs. // Filter can be used to retrieve and filter logs.
@ -58,41 +59,20 @@ type Filter struct {
// New creates a new filter which uses a bloom filter on blocks to figure out whether // New creates a new filter which uses a bloom filter on blocks to figure out whether
// a particular block is interesting or not. // a particular block is interesting or not.
func New(backend Backend, bloomBitsSection uint64) *Filter { func New(backend Backend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
return &Filter{ return &Filter{
backend: backend, backend: backend,
bloomBitsSection: bloomBitsSection, begin: begin,
end: end,
addresses: addresses,
topics: topics,
bloomBitsSection: backend.BloomBitsSectionSize(),
db: backend.ChainDb(), db: backend.ChainDb(),
matcher: bloombits.NewMatcher(bloomBitsSection), matcher: bloombits.NewMatcher(backend.BloomBitsSectionSize(), addresses, topics),
decompress: bitutil.DecompressBytes, decompress: bitutil.DecompressBytes,
} }
} }
// SetBeginBlock sets the earliest block for filtering.
// -1 = latest block (i.e., the current block)
// hash = particular hash from-to
func (f *Filter) SetBeginBlock(begin int64) {
f.begin = begin
}
// SetEndBlock sets the latest block for filtering.
func (f *Filter) SetEndBlock(end int64) {
f.end = end
}
// SetAddresses matches only logs that are generated from addresses that are included
// in the given addresses.
func (f *Filter) SetAddresses(addr []common.Address) {
f.addresses = addr
f.matcher.SetAddresses(addr)
}
// SetTopics matches only logs that have topics matching the given topics.
func (f *Filter) SetTopics(topics [][]common.Hash) {
f.topics = topics
f.matcher.SetTopics(topics)
}
// FindOnce searches the blockchain for matching log entries, returning // FindOnce searches the blockchain for matching log entries, returning
// all matching entries from the first block that contains matches, // all matching entries from the first block that contains matches,
// updating the start point of the filter accordingly. If no results are // updating the start point of the filter accordingly. If no results are

View file

@ -75,6 +75,10 @@ func (b *testBackend) GetBloomBits(ctx context.Context, bitIdx uint64, sectionId
return results, nil return results, nil
} }
func (b *testBackend) BloomBitsSectionSize() uint64 {
return testBloomBitsSection
}
// TestBlockSubscription tests if a block subscription returns block hashes for posted chain events. // TestBlockSubscription tests if a block subscription returns block hashes for posted chain events.
// It creates multiple subscriptions: // It creates multiple subscriptions:
// - one at the start and should receive all posted chain events and a second (blockHashes) // - one at the start and should receive all posted chain events and a second (blockHashes)

View file

@ -105,10 +105,7 @@ func BenchmarkFilters(b *testing.B) {
} }
b.ResetTimer() b.ResetTimer()
filter := New(backend, testBloomBitsSection) filter := New(backend, 0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil)
filter.SetAddresses([]common.Address{addr1, addr2, addr3, addr4})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
logs, _ := filter.Find(context.Background()) logs, _ := filter.Find(context.Background())
@ -204,22 +201,14 @@ func TestFilters(t *testing.T) {
} }
} }
filter := New(backend, testBloomBitsSection) filter := New(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
filter.SetAddresses([]common.Address{addr})
filter.SetTopics([][]common.Hash{{hash1, hash2, hash3, hash4}})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
logs, _ := filter.Find(context.Background()) logs, _ := filter.Find(context.Background())
if len(logs) != 4 { if len(logs) != 4 {
t.Error("expected 4 log, got", len(logs)) t.Error("expected 4 log, got", len(logs))
} }
filter = New(backend, testBloomBitsSection) filter = New(backend, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
filter.SetAddresses([]common.Address{addr})
filter.SetTopics([][]common.Hash{{hash3}})
filter.SetBeginBlock(900)
filter.SetEndBlock(999)
logs, _ = filter.Find(context.Background()) logs, _ = filter.Find(context.Background())
if len(logs) != 1 { if len(logs) != 1 {
t.Error("expected 1 log, got", len(logs)) t.Error("expected 1 log, got", len(logs))
@ -228,11 +217,7 @@ func TestFilters(t *testing.T) {
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
} }
filter = New(backend, testBloomBitsSection) filter = New(backend, 990, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
filter.SetAddresses([]common.Address{addr})
filter.SetTopics([][]common.Hash{{hash3}})
filter.SetBeginBlock(990)
filter.SetEndBlock(-1)
logs, _ = filter.Find(context.Background()) logs, _ = filter.Find(context.Background())
if len(logs) != 1 { if len(logs) != 1 {
t.Error("expected 1 log, got", len(logs)) t.Error("expected 1 log, got", len(logs))
@ -241,10 +226,7 @@ func TestFilters(t *testing.T) {
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0]) t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
} }
filter = New(backend, testBloomBitsSection) filter = New(backend, 1, 10, nil, [][]common.Hash{{hash1, hash2}})
filter.SetTopics([][]common.Hash{{hash1, hash2}})
filter.SetBeginBlock(1)
filter.SetEndBlock(10)
logs, _ = filter.Find(context.Background()) logs, _ = filter.Find(context.Background())
if len(logs) != 2 { if len(logs) != 2 {
@ -252,10 +234,7 @@ func TestFilters(t *testing.T) {
} }
failHash := common.BytesToHash([]byte("fail")) failHash := common.BytesToHash([]byte("fail"))
filter = New(backend, testBloomBitsSection) filter = New(backend, 0, -1, nil, [][]common.Hash{{failHash}})
filter.SetTopics([][]common.Hash{{failHash}})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
logs, _ = filter.Find(context.Background()) logs, _ = filter.Find(context.Background())
if len(logs) != 0 { if len(logs) != 0 {
@ -263,20 +242,14 @@ func TestFilters(t *testing.T) {
} }
failAddr := common.BytesToAddress([]byte("failmenow")) failAddr := common.BytesToAddress([]byte("failmenow"))
filter = New(backend, testBloomBitsSection) filter = New(backend, 0, -1, []common.Address{failAddr}, nil)
filter.SetAddresses([]common.Address{failAddr})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
logs, _ = filter.Find(context.Background()) logs, _ = filter.Find(context.Background())
if len(logs) != 0 { if len(logs) != 0 {
t.Error("expected 0 log, got", len(logs)) t.Error("expected 0 log, got", len(logs))
} }
filter = New(backend, testBloomBitsSection) filter = New(backend, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
filter.SetTopics([][]common.Hash{{failHash}, {hash1}})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
logs, _ = filter.Find(context.Background()) logs, _ = filter.Find(context.Background())
if len(logs) != 0 { if len(logs) != 0 {

View file

@ -159,3 +159,7 @@ func (b *LesApiBackend) AccountManager() *accounts.Manager {
func (b *LesApiBackend) GetBloomBits(ctx context.Context, bitIdx uint64, sectionIdxList []uint64) ([][]byte, error) { func (b *LesApiBackend) GetBloomBits(ctx context.Context, bitIdx uint64, sectionIdxList []uint64) ([][]byte, error) {
return nil, nil // implemented in a subsequent PR return nil, nil // implemented in a subsequent PR
} }
func (b *LesApiBackend) BloomBitsSectionSize() uint64 {
return 0
}