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
func NewMatcher(sectionSize uint64) *Matcher {
return &Matcher{fetchers: make(map[uint]*fetcher), reqs: make(map[uint][]uint64), distCh: make(chan distReq, channelCap), sectionSize: sectionSize}
func NewMatcher(sectionSize uint64, addresses []common.Address, topics [][]common.Hash) *Matcher {
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.
func (m *Matcher) SetAddresses(addr []common.Address) {
func (m *Matcher) setAddresses(addr []common.Address) {
m.addresses = make([]types.BloomIndexList, len(addr))
for i, b := range addr {
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.
func (m *Matcher) SetTopics(topics [][]common.Hash) {
// setTopics matches only logs that have topics matching the given topics.
func (m *Matcher) setTopics(topics [][]common.Hash) {
m.topics = nil
loop:
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 {
m := NewMatcher(testSectionSize)
m := NewMatcher(testSectionSize, nil, nil)
for _, idxss := range idxs {
for _, idxs := range idxss {

View file

@ -213,6 +213,10 @@ func (b *EthApiBackend) GetBloomBits(ctx context.Context, bitIdx uint64, section
return results, nil
}
func (b *EthApiBackend) BloomBitsSectionSize() uint64 {
return bloomBitsSection
}
type EthApiState struct {
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())
}
filter := New(api.backend, api.bloomBitsSection)
filter.SetBeginBlock(crit.FromBlock.Int64())
filter.SetEndBlock(crit.ToBlock.Int64())
filter.SetAddresses(crit.Addresses)
filter.SetTopics(crit.Topics)
filter := New(api.backend, crit.FromBlock.Int64(), crit.ToBlock.Int64(), crit.Addresses, crit.Topics)
logs, err := filter.Find(ctx)
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")
}
filter := New(api.backend, api.bloomBitsSection)
var begin, end int64
if f.crit.FromBlock != nil {
filter.SetBeginBlock(f.crit.FromBlock.Int64())
begin = f.crit.FromBlock.Int64()
} else {
filter.SetBeginBlock(rpc.LatestBlockNumber.Int64())
begin = rpc.LatestBlockNumber.Int64()
}
if f.crit.ToBlock != nil {
filter.SetEndBlock(f.crit.ToBlock.Int64())
end = f.crit.ToBlock.Int64()
} else {
filter.SetEndBlock(rpc.LatestBlockNumber.Int64())
end = rpc.LatestBlockNumber.Int64()
}
filter.SetAddresses(f.crit.Addresses)
filter.SetTopics(f.crit.Topics)
filter := New(api.backend, begin, end, f.crit.Addresses, f.crit.Topics)
logs, err := filter.Find(ctx)
if err != nil {

View file

@ -167,14 +167,11 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64, comp int) {
db, _ = ethdb.NewLDBDatabase(benchDataDir, 128, 1024)
backend = &testBackend{mux, db}
}
filter := New(backend, sectionSize)
filter.decompress = decompressFn
var addr common.Address
addr[0] = byte(i)
addr[1] = byte(i / 256)
filter.SetAddresses([]common.Address{addr})
filter.SetBeginBlock(0)
filter.SetEndBlock(int64(cnt*sectionSize - 1))
filter := New(backend, 0, int64(cnt*sectionSize-1), []common.Address{addr}, nil)
filter.decompress = decompressFn
if _, err := filter.Find(context.Background()); err != nil {
b.Error("filter.Find error:", err)
}
@ -233,11 +230,7 @@ func BenchmarkNoBloomBits(b *testing.B) {
start := time.Now()
mux := new(event.TypeMux)
backend := &testBackend{mux, db}
filter := New(backend, 4096) // give any dummy section size, no bloombits data is available
var addr common.Address
filter.SetAddresses([]common.Address{addr})
filter.SetBeginBlock(0)
filter.SetEndBlock(int64(headNum))
filter := New(backend, 0, int64(headNum), []common.Address{common.Address{}}, nil)
filter.Find(context.Background())
d := time.Since(start)
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)
GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
GetBloomBits(ctx context.Context, bitIdx uint64, sectionIdxList []uint64) ([][]byte, error)
BloomBitsSectionSize() uint64
}
// 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
// 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{
backend: backend,
bloomBitsSection: bloomBitsSection,
begin: begin,
end: end,
addresses: addresses,
topics: topics,
bloomBitsSection: backend.BloomBitsSectionSize(),
db: backend.ChainDb(),
matcher: bloombits.NewMatcher(bloomBitsSection),
matcher: bloombits.NewMatcher(backend.BloomBitsSectionSize(), addresses, topics),
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
// all matching entries from the first block that contains matches,
// 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
}
func (b *testBackend) BloomBitsSectionSize() uint64 {
return testBloomBitsSection
}
// TestBlockSubscription tests if a block subscription returns block hashes for posted chain events.
// It creates multiple subscriptions:
// - 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()
filter := New(backend, testBloomBitsSection)
filter.SetAddresses([]common.Address{addr1, addr2, addr3, addr4})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
filter := New(backend, 0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil)
for i := 0; i < b.N; i++ {
logs, _ := filter.Find(context.Background())
@ -204,22 +201,14 @@ func TestFilters(t *testing.T) {
}
}
filter := New(backend, testBloomBitsSection)
filter.SetAddresses([]common.Address{addr})
filter.SetTopics([][]common.Hash{{hash1, hash2, hash3, hash4}})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
filter := New(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
logs, _ := filter.Find(context.Background())
if len(logs) != 4 {
t.Error("expected 4 log, got", len(logs))
}
filter = New(backend, testBloomBitsSection)
filter.SetAddresses([]common.Address{addr})
filter.SetTopics([][]common.Hash{{hash3}})
filter.SetBeginBlock(900)
filter.SetEndBlock(999)
filter = New(backend, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
logs, _ = filter.Find(context.Background())
if len(logs) != 1 {
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])
}
filter = New(backend, testBloomBitsSection)
filter.SetAddresses([]common.Address{addr})
filter.SetTopics([][]common.Hash{{hash3}})
filter.SetBeginBlock(990)
filter.SetEndBlock(-1)
filter = New(backend, 990, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
logs, _ = filter.Find(context.Background())
if len(logs) != 1 {
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])
}
filter = New(backend, testBloomBitsSection)
filter.SetTopics([][]common.Hash{{hash1, hash2}})
filter.SetBeginBlock(1)
filter.SetEndBlock(10)
filter = New(backend, 1, 10, nil, [][]common.Hash{{hash1, hash2}})
logs, _ = filter.Find(context.Background())
if len(logs) != 2 {
@ -252,10 +234,7 @@ func TestFilters(t *testing.T) {
}
failHash := common.BytesToHash([]byte("fail"))
filter = New(backend, testBloomBitsSection)
filter.SetTopics([][]common.Hash{{failHash}})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
filter = New(backend, 0, -1, nil, [][]common.Hash{{failHash}})
logs, _ = filter.Find(context.Background())
if len(logs) != 0 {
@ -263,20 +242,14 @@ func TestFilters(t *testing.T) {
}
failAddr := common.BytesToAddress([]byte("failmenow"))
filter = New(backend, testBloomBitsSection)
filter.SetAddresses([]common.Address{failAddr})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
filter = New(backend, 0, -1, []common.Address{failAddr}, nil)
logs, _ = filter.Find(context.Background())
if len(logs) != 0 {
t.Error("expected 0 log, got", len(logs))
}
filter = New(backend, testBloomBitsSection)
filter.SetTopics([][]common.Hash{{failHash}, {hash1}})
filter.SetBeginBlock(0)
filter.SetEndBlock(-1)
filter = New(backend, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
logs, _ = filter.Find(context.Background())
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) {
return nil, nil // implemented in a subsequent PR
}
func (b *LesApiBackend) BloomBitsSectionSize() uint64 {
return 0
}