| 
									
										
										
										
											2016-04-14 18:18:24 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-30 10:04:59 +02:00
										 |  |  | package filters | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-03-22 18:20:33 +01:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-11-28 14:59:06 +01:00
										 |  |  | 	"math/big" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-17 11:19:23 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2015-08-30 10:04:59 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/bloombits" | 
					
						
							| 
									
										
										
										
											2015-03-26 12:06:14 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2015-08-31 17:09:50 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rpc" | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | type Backend interface { | 
					
						
							|  |  |  | 	ChainDb() ethdb.Database | 
					
						
							|  |  |  | 	HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 	HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error) | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | 	GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription | 
					
						
							|  |  |  | 	SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription | 
					
						
							|  |  |  | 	SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription | 
					
						
							| 
									
										
										
										
											2019-12-10 12:39:14 +01:00
										 |  |  | 	SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	BloomStatus() (uint64, uint64) | 
					
						
							|  |  |  | 	ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 19:07:24 +01:00
										 |  |  | // Filter can be used to retrieve and filter logs. | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | type Filter struct { | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	backend Backend | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 	db        ethdb.Database | 
					
						
							|  |  |  | 	addresses []common.Address | 
					
						
							|  |  |  | 	topics    [][]common.Hash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	block      common.Hash // Block hash if filtering a single block | 
					
						
							|  |  |  | 	begin, end int64       // Range interval if filtering multiple blocks | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	matcher *bloombits.Matcher | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | // NewRangeFilter creates a new filter which uses a bloom filter on blocks to | 
					
						
							|  |  |  | // figure out whether a particular block is interesting or not. | 
					
						
							|  |  |  | func NewRangeFilter(backend Backend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter { | 
					
						
							| 
									
										
										
										
											2017-09-27 13:14:52 +03:00
										 |  |  | 	// Flatten the address and topic filter clauses into a single bloombits filter | 
					
						
							|  |  |  | 	// system. Since the bloombits are not positional, nil topics are permitted, | 
					
						
							|  |  |  | 	// which get flattened into a nil byte slice. | 
					
						
							| 
									
										
										
										
											2017-09-06 02:33:10 +02:00
										 |  |  | 	var filters [][][]byte | 
					
						
							|  |  |  | 	if len(addresses) > 0 { | 
					
						
							|  |  |  | 		filter := make([][]byte, len(addresses)) | 
					
						
							|  |  |  | 		for i, address := range addresses { | 
					
						
							|  |  |  | 			filter[i] = address.Bytes() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		filters = append(filters, filter) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, topicList := range topics { | 
					
						
							|  |  |  | 		filter := make([][]byte, len(topicList)) | 
					
						
							|  |  |  | 		for i, topic := range topicList { | 
					
						
							|  |  |  | 			filter[i] = topic.Bytes() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		filters = append(filters, filter) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	size, _ := backend.BloomStatus() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 	// Create a generic filter and convert it into a range filter | 
					
						
							|  |  |  | 	filter := newFilter(backend, addresses, topics) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	filter.matcher = bloombits.NewMatcher(size, filters) | 
					
						
							|  |  |  | 	filter.begin = begin | 
					
						
							|  |  |  | 	filter.end = end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return filter | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewBlockFilter creates a new filter which directly inspects the contents of | 
					
						
							|  |  |  | // a block to figure out whether it is interesting or not. | 
					
						
							|  |  |  | func NewBlockFilter(backend Backend, block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter { | 
					
						
							|  |  |  | 	// Create a generic filter and convert it into a block filter | 
					
						
							|  |  |  | 	filter := newFilter(backend, addresses, topics) | 
					
						
							|  |  |  | 	filter.block = block | 
					
						
							|  |  |  | 	return filter | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newFilter creates a generic filter that can either filter based on a block hash, | 
					
						
							|  |  |  | // or based on range queries. The search criteria needs to be explicitly set. | 
					
						
							|  |  |  | func newFilter(backend Backend, addresses []common.Address, topics [][]common.Hash) *Filter { | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | 	return &Filter{ | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 		backend:   backend, | 
					
						
							|  |  |  | 		addresses: addresses, | 
					
						
							|  |  |  | 		topics:    topics, | 
					
						
							|  |  |  | 		db:        backend.ChainDb(), | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | // Logs searches the blockchain for matching log entries, returning all from the | 
					
						
							|  |  |  | // first block that contains matches, updating the start of the filter accordingly. | 
					
						
							|  |  |  | func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) { | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 	// If we're doing singleton block filtering, execute and return | 
					
						
							|  |  |  | 	if f.block != (common.Hash{}) { | 
					
						
							|  |  |  | 		header, err := f.backend.HeaderByHash(ctx, f.block) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if header == nil { | 
					
						
							|  |  |  | 			return nil, errors.New("unknown block") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return f.blockLogs(ctx, header) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	// Figure out the limits of the filter range | 
					
						
							|  |  |  | 	header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber) | 
					
						
							|  |  |  | 	if header == nil { | 
					
						
							| 
									
										
										
										
											2016-01-13 19:35:48 +01:00
										 |  |  | 		return nil, nil | 
					
						
							| 
									
										
										
										
											2016-07-26 16:37:04 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	head := header.Number.Uint64() | 
					
						
							| 
									
										
										
										
											2016-07-27 17:47:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if f.begin == -1 { | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 		f.begin = int64(head) | 
					
						
							| 
									
										
										
										
											2014-09-26 13:32:54 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	end := uint64(f.end) | 
					
						
							| 
									
										
										
										
											2016-07-27 17:47:46 +02:00
										 |  |  | 	if f.end == -1 { | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 		end = head | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	// Gather all indexed logs, and finish with non indexed ones | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		logs []*types.Log | 
					
						
							|  |  |  | 		err  error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	size, sections := f.backend.BloomStatus() | 
					
						
							|  |  |  | 	if indexed := sections * size; indexed > uint64(f.begin) { | 
					
						
							|  |  |  | 		if indexed > end { | 
					
						
							|  |  |  | 			logs, err = f.indexedLogs(ctx, end) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			logs, err = f.indexedLogs(ctx, indexed-1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-12-20 01:00:03 +00:00
										 |  |  | 			return logs, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-31 17:09:50 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	rest, err := f.unindexedLogs(ctx, end) | 
					
						
							|  |  |  | 	logs = append(logs, rest...) | 
					
						
							|  |  |  | 	return logs, err | 
					
						
							| 
									
										
										
										
											2015-10-12 17:58:51 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-09 13:22:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | // indexedLogs returns the logs matching the filter criteria based on the bloom | 
					
						
							|  |  |  | // bits indexed available locally or via the network. | 
					
						
							|  |  |  | func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) { | 
					
						
							|  |  |  | 	// Create a matcher session and request servicing from the backend | 
					
						
							|  |  |  | 	matches := make(chan uint64, 64) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches) | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 	defer session.Close() | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	f.backend.ServiceFilter(ctx, session) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Iterate over the matches until exhausted or context closed | 
					
						
							|  |  |  | 	var logs []*types.Log | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case number, ok := <-matches: | 
					
						
							|  |  |  | 			// Abort if all matches have been fulfilled | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 				err := session.Error() | 
					
						
							|  |  |  | 				if err == nil { | 
					
						
							|  |  |  | 					f.begin = int64(end) + 1 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return logs, err | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-10-24 15:19:09 +02:00
										 |  |  | 			f.begin = int64(number) + 1 | 
					
						
							| 
									
										
										
										
											2017-11-15 13:54:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 			// Retrieve the suggested block and pull any truly matching logs | 
					
						
							|  |  |  | 			header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number)) | 
					
						
							|  |  |  | 			if header == nil || err != nil { | 
					
						
							|  |  |  | 				return logs, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			found, err := f.checkMatches(ctx, header) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return logs, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			logs = append(logs, found...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-ctx.Done(): | 
					
						
							|  |  |  | 			return logs, ctx.Err() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-27 22:33:14 +07:00
										 |  |  | // unindexedLogs returns the logs matching the filter criteria based on raw block | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | // iteration and bloom matching. | 
					
						
							|  |  |  | func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) { | 
					
						
							|  |  |  | 	var logs []*types.Log | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for ; f.begin <= int64(end); f.begin++ { | 
					
						
							|  |  |  | 		header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin)) | 
					
						
							|  |  |  | 		if header == nil || err != nil { | 
					
						
							|  |  |  | 			return logs, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 		found, err := f.blockLogs(ctx, header) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return logs, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		logs = append(logs, found...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return logs, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // blockLogs returns the logs matching the filter criteria within a single block. | 
					
						
							|  |  |  | func (f *Filter) blockLogs(ctx context.Context, header *types.Header) (logs []*types.Log, err error) { | 
					
						
							|  |  |  | 	if bloomFilter(header.Bloom, f.addresses, f.topics) { | 
					
						
							|  |  |  | 		found, err := f.checkMatches(ctx, header) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return logs, err | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-07-12 17:36:07 +03:00
										 |  |  | 		logs = append(logs, found...) | 
					
						
							| 
									
										
										
										
											2015-10-12 17:58:51 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-29 14:13:11 +03:00
										 |  |  | 	return logs, nil | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // checkMatches checks if the receipts belonging to the given header contain any log events that | 
					
						
							|  |  |  | // match the filter criteria. This function is called when the bloom filter signals a potential match. | 
					
						
							|  |  |  | func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) { | 
					
						
							|  |  |  | 	// Get the logs of the block | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	logsList, err := f.backend.GetLogs(ctx, header.Hash()) | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var unfiltered []*types.Log | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 	for _, logs := range logsList { | 
					
						
							|  |  |  | 		unfiltered = append(unfiltered, logs...) | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics) | 
					
						
							|  |  |  | 	if len(logs) > 0 { | 
					
						
							| 
									
										
										
										
											2018-02-22 12:48:14 +02:00
										 |  |  | 		// We have matching logs, check if we need to resolve full logs via the light client | 
					
						
							|  |  |  | 		if logs[0].TxHash == (common.Hash{}) { | 
					
						
							|  |  |  | 			receipts, err := f.backend.GetReceipts(ctx, header.Hash()) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			unfiltered = unfiltered[:0] | 
					
						
							|  |  |  | 			for _, receipt := range receipts { | 
					
						
							|  |  |  | 				unfiltered = append(unfiltered, receipt.Logs...) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-18 21:52:20 +02:00
										 |  |  | 		return logs, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, nil | 
					
						
							| 
									
										
										
										
											2015-10-12 17:58:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-17 11:19:23 +01:00
										 |  |  | func includes(addresses []common.Address, a common.Address) bool { | 
					
						
							| 
									
										
										
										
											2014-08-15 16:19:10 +02:00
										 |  |  | 	for _, addr := range addresses { | 
					
						
							| 
									
										
										
										
											2015-09-01 09:19:45 +02:00
										 |  |  | 		if addr == a { | 
					
						
							|  |  |  | 			return true | 
					
						
							| 
									
										
										
										
											2014-08-15 16:19:10 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 09:19:45 +02:00
										 |  |  | 	return false | 
					
						
							| 
									
										
										
										
											2014-08-15 16:19:10 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-04 19:07:24 +01:00
										 |  |  | // filterLogs creates a slice of logs matching the given criteria. | 
					
						
							| 
									
										
										
										
											2017-01-05 14:03:50 +01:00
										 |  |  | func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log { | 
					
						
							|  |  |  | 	var ret []*types.Log | 
					
						
							| 
									
										
										
										
											2015-02-04 17:28:54 -08:00
										 |  |  | Logs: | 
					
						
							| 
									
										
										
										
											2015-01-28 10:23:18 +01:00
										 |  |  | 	for _, log := range logs { | 
					
						
							| 
									
										
										
										
											2016-12-04 19:07:24 +01:00
										 |  |  | 		if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber { | 
					
						
							| 
									
										
										
										
											2016-11-28 14:59:06 +01:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-04 19:07:24 +01:00
										 |  |  | 		if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber { | 
					
						
							| 
									
										
										
										
											2016-11-28 14:59:06 +01:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-27 17:47:46 +02:00
										 |  |  | 		if len(addresses) > 0 && !includes(addresses, log.Address) { | 
					
						
							| 
									
										
										
										
											2014-08-15 00:24:37 +02:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-27 17:47:46 +02:00
										 |  |  | 		// If the to filtered topics is greater than the amount of topics in logs, skip. | 
					
						
							|  |  |  | 		if len(topics) > len(log.Topics) { | 
					
						
							| 
									
										
										
										
											2015-04-24 13:36:34 +02:00
										 |  |  | 			continue Logs | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-06-14 17:27:02 +08:00
										 |  |  | 		for i, sub := range topics { | 
					
						
							|  |  |  | 			match := len(sub) == 0 // empty rule set == wildcard | 
					
						
							|  |  |  | 			for _, topic := range sub { | 
					
						
							| 
									
										
										
										
											2017-09-27 13:14:52 +03:00
										 |  |  | 				if log.Topics[i] == topic { | 
					
						
							| 
									
										
										
										
											2015-03-01 19:08:26 +01:00
										 |  |  | 					match = true | 
					
						
							| 
									
										
										
										
											2015-04-24 13:36:34 +02:00
										 |  |  | 					break | 
					
						
							| 
									
										
										
										
											2015-03-01 19:08:26 +01:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2014-08-15 16:19:10 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-04-24 13:36:34 +02:00
										 |  |  | 			if !match { | 
					
						
							|  |  |  | 				continue Logs | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-08-15 16:19:10 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-01-28 10:23:18 +01:00
										 |  |  | 		ret = append(ret, log) | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-28 10:23:18 +01:00
										 |  |  | 	return ret | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-14 05:51:29 +02:00
										 |  |  | func bloomFilter(bloom types.Bloom, addresses []common.Address, topics [][]common.Hash) bool { | 
					
						
							|  |  |  | 	if len(addresses) > 0 { | 
					
						
							| 
									
										
										
										
											2015-02-17 16:12:55 +01:00
										 |  |  | 		var included bool | 
					
						
							| 
									
										
										
										
											2016-10-14 05:51:29 +02:00
										 |  |  | 		for _, addr := range addresses { | 
					
						
							|  |  |  | 			if types.BloomLookup(bloom, addr) { | 
					
						
							| 
									
										
										
										
											2015-02-17 16:12:55 +01:00
										 |  |  | 				included = true | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !included { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-14 05:51:29 +02:00
										 |  |  | 	for _, sub := range topics { | 
					
						
							| 
									
										
										
										
											2017-09-27 13:14:52 +03:00
										 |  |  | 		included := len(sub) == 0 // empty rule set == wildcard | 
					
						
							| 
									
										
										
										
											2015-03-01 19:08:26 +01:00
										 |  |  | 		for _, topic := range sub { | 
					
						
							| 
									
										
										
										
											2017-09-27 13:14:52 +03:00
										 |  |  | 			if types.BloomLookup(bloom, topic) { | 
					
						
							| 
									
										
										
										
											2015-03-01 19:08:26 +01:00
										 |  |  | 				included = true | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !included { | 
					
						
							| 
									
										
										
										
											2015-01-28 10:23:18 +01:00
										 |  |  | 			return false | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-01-28 10:23:18 +01:00
										 |  |  | 	return true | 
					
						
							| 
									
										
										
										
											2014-08-11 16:23:17 +02:00
										 |  |  | } |