github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/filters/filter.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2014 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package filters
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"math/big"
    31  
    32  	"github.com/ethereum/go-ethereum/common"
    33  	"github.com/ethereum/go-ethereum/core"
    34  	"github.com/ethereum/go-ethereum/core/bloombits"
    35  	"github.com/ethereum/go-ethereum/core/types"
    36  	"github.com/ethereum/go-ethereum/ethdb"
    37  	"github.com/ethereum/go-ethereum/event"
    38  	"github.com/ethereum/go-ethereum/rpc"
    39  )
    40  
    41  type Backend interface {
    42  	ChainDb() ethdb.Database
    43  	EventMux() *event.TypeMux
    44  	HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
    45  	HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
    46  	GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
    47  	GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
    48  
    49  	SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
    50  	SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
    51  	SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
    52  	SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
    53  
    54  	BloomStatus() (uint64, uint64)
    55  	ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
    56  }
    57  
    58  //筛选器可用于检索和筛选日志。
    59  type Filter struct {
    60  	backend Backend
    61  
    62  	db        ethdb.Database
    63  	addresses []common.Address
    64  	topics    [][]common.Hash
    65  
    66  block      common.Hash //如果筛选单个块,则阻止哈希
    67  begin, end int64       //过滤多个块时的范围间隔
    68  
    69  	matcher *bloombits.Matcher
    70  }
    71  
    72  //newrangefilter创建一个新的过滤器,它在块上使用bloom过滤器来
    73  //找出一个特定的块是否有趣。
    74  func NewRangeFilter(backend Backend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
    75  //将地址和主题筛选子句展平为单个bloombits筛选器
    76  //系统。因为bloombits不是位置的,所以不允许使用任何主题,
    77  //它被压扁成一个零字节的片。
    78  	var filters [][][]byte
    79  	if len(addresses) > 0 {
    80  		filter := make([][]byte, len(addresses))
    81  		for i, address := range addresses {
    82  			filter[i] = address.Bytes()
    83  		}
    84  		filters = append(filters, filter)
    85  	}
    86  	for _, topicList := range topics {
    87  		filter := make([][]byte, len(topicList))
    88  		for i, topic := range topicList {
    89  			filter[i] = topic.Bytes()
    90  		}
    91  		filters = append(filters, filter)
    92  	}
    93  	size, _ := backend.BloomStatus()
    94  
    95  //创建通用筛选器并将其转换为范围筛选器
    96  	filter := newFilter(backend, addresses, topics)
    97  
    98  	filter.matcher = bloombits.NewMatcher(size, filters)
    99  	filter.begin = begin
   100  	filter.end = end
   101  
   102  	return filter
   103  }
   104  
   105  //newblockfilter创建一个新的过滤器,它直接检查
   106  //用来判断它是否有趣的块。
   107  func NewBlockFilter(backend Backend, block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter {
   108  //创建通用筛选器并将其转换为块筛选器
   109  	filter := newFilter(backend, addresses, topics)
   110  	filter.block = block
   111  	return filter
   112  }
   113  
   114  //newfilter创建一个通用筛选器,该筛选器可以基于块哈希进行筛选,
   115  //或者基于范围查询。需要显式设置搜索条件。
   116  func newFilter(backend Backend, addresses []common.Address, topics [][]common.Hash) *Filter {
   117  	return &Filter{
   118  		backend:   backend,
   119  		addresses: addresses,
   120  		topics:    topics,
   121  		db:        backend.ChainDb(),
   122  	}
   123  }
   124  
   125  //日志在区块链中搜索匹配的日志条目,从
   126  //包含匹配项的第一个块,相应地更新筛选器的开头。
   127  func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
   128  //如果我们进行单例块过滤,执行并返回
   129  	if f.block != (common.Hash{}) {
   130  		header, err := f.backend.HeaderByHash(ctx, f.block)
   131  		if err != nil {
   132  			return nil, err
   133  		}
   134  		if header == nil {
   135  			return nil, errors.New("unknown block")
   136  		}
   137  		return f.blockLogs(ctx, header)
   138  	}
   139  //找出过滤范围的限制
   140  	header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
   141  	if header == nil {
   142  		return nil, nil
   143  	}
   144  	head := header.Number.Uint64()
   145  
   146  	if f.begin == -1 {
   147  		f.begin = int64(head)
   148  	}
   149  	end := uint64(f.end)
   150  	if f.end == -1 {
   151  		end = head
   152  	}
   153  //收集所有索引日志,并使用非索引日志完成
   154  	var (
   155  		logs []*types.Log
   156  		err  error
   157  	)
   158  	size, sections := f.backend.BloomStatus()
   159  	if indexed := sections * size; indexed > uint64(f.begin) {
   160  		if indexed > end {
   161  			logs, err = f.indexedLogs(ctx, end)
   162  		} else {
   163  			logs, err = f.indexedLogs(ctx, indexed-1)
   164  		}
   165  		if err != nil {
   166  			return logs, err
   167  		}
   168  	}
   169  	rest, err := f.unindexedLogs(ctx, end)
   170  	logs = append(logs, rest...)
   171  	return logs, err
   172  }
   173  
   174  //indexedlogs返回与基于bloom的筛选条件匹配的日志
   175  //在本地或通过网络可用的索引位。
   176  func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
   177  //创建Matcher会话并从后端请求服务
   178  	matches := make(chan uint64, 64)
   179  
   180  	session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	defer session.Close()
   185  
   186  	f.backend.ServiceFilter(ctx, session)
   187  
   188  //迭代匹配项,直到耗尽或上下文关闭
   189  	var logs []*types.Log
   190  
   191  	for {
   192  		select {
   193  		case number, ok := <-matches:
   194  //如果满足所有匹配,则中止
   195  			if !ok {
   196  				err := session.Error()
   197  				if err == nil {
   198  					f.begin = int64(end) + 1
   199  				}
   200  				return logs, err
   201  			}
   202  			f.begin = int64(number) + 1
   203  
   204  //检索建议的块并提取任何真正匹配的日志
   205  			header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number))
   206  			if header == nil || err != nil {
   207  				return logs, err
   208  			}
   209  			found, err := f.checkMatches(ctx, header)
   210  			if err != nil {
   211  				return logs, err
   212  			}
   213  			logs = append(logs, found...)
   214  
   215  		case <-ctx.Done():
   216  			return logs, ctx.Err()
   217  		}
   218  	}
   219  }
   220  
   221  //indexedlogs返回与基于原始块的筛选条件匹配的日志
   222  //迭代和开花匹配。
   223  func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
   224  	var logs []*types.Log
   225  
   226  	for ; f.begin <= int64(end); f.begin++ {
   227  		header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
   228  		if header == nil || err != nil {
   229  			return logs, err
   230  		}
   231  		found, err := f.blockLogs(ctx, header)
   232  		if err != nil {
   233  			return logs, err
   234  		}
   235  		logs = append(logs, found...)
   236  	}
   237  	return logs, nil
   238  }
   239  
   240  //block logs返回与单个块中的筛选条件匹配的日志。
   241  func (f *Filter) blockLogs(ctx context.Context, header *types.Header) (logs []*types.Log, err error) {
   242  	if bloomFilter(header.Bloom, f.addresses, f.topics) {
   243  		found, err := f.checkMatches(ctx, header)
   244  		if err != nil {
   245  			return logs, err
   246  		}
   247  		logs = append(logs, found...)
   248  	}
   249  	return logs, nil
   250  }
   251  
   252  //checkmatches检查属于给定头的收据是否包含
   253  //匹配筛选条件。当布卢姆滤波器发出潜在匹配信号时,调用此函数。
   254  func (f *Filter) checkMatches(ctx context.Context, header *types.Header) (logs []*types.Log, err error) {
   255  //获取块的日志
   256  	logsList, err := f.backend.GetLogs(ctx, header.Hash())
   257  	if err != nil {
   258  		return nil, err
   259  	}
   260  	var unfiltered []*types.Log
   261  	for _, logs := range logsList {
   262  		unfiltered = append(unfiltered, logs...)
   263  	}
   264  	logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
   265  	if len(logs) > 0 {
   266  //我们有匹配的日志,检查是否需要通过Light客户端解析完整的日志
   267  		if logs[0].TxHash == (common.Hash{}) {
   268  			receipts, err := f.backend.GetReceipts(ctx, header.Hash())
   269  			if err != nil {
   270  				return nil, err
   271  			}
   272  			unfiltered = unfiltered[:0]
   273  			for _, receipt := range receipts {
   274  				unfiltered = append(unfiltered, receipt.Logs...)
   275  			}
   276  			logs = filterLogs(unfiltered, nil, nil, f.addresses, f.topics)
   277  		}
   278  		return logs, nil
   279  	}
   280  	return nil, nil
   281  }
   282  
   283  func includes(addresses []common.Address, a common.Address) bool {
   284  	for _, addr := range addresses {
   285  		if addr == a {
   286  			return true
   287  		}
   288  	}
   289  
   290  	return false
   291  }
   292  
   293  //FieldLtG创建一个与给定标准匹配的日志片段。
   294  func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log {
   295  	var ret []*types.Log
   296  Logs:
   297  	for _, log := range logs {
   298  		if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber {
   299  			continue
   300  		}
   301  		if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber {
   302  			continue
   303  		}
   304  
   305  		if len(addresses) > 0 && !includes(addresses, log.Address) {
   306  			continue
   307  		}
   308  //如果到筛选的主题大于日志中的主题数量,则跳过。
   309  		if len(topics) > len(log.Topics) {
   310  			continue Logs
   311  		}
   312  		for i, sub := range topics {
   313  match := len(sub) == 0 //空规则集==通配符
   314  			for _, topic := range sub {
   315  				if log.Topics[i] == topic {
   316  					match = true
   317  					break
   318  				}
   319  			}
   320  			if !match {
   321  				continue Logs
   322  			}
   323  		}
   324  		ret = append(ret, log)
   325  	}
   326  	return ret
   327  }
   328  
   329  func bloomFilter(bloom types.Bloom, addresses []common.Address, topics [][]common.Hash) bool {
   330  	if len(addresses) > 0 {
   331  		var included bool
   332  		for _, addr := range addresses {
   333  			if types.BloomLookup(bloom, addr) {
   334  				included = true
   335  				break
   336  			}
   337  		}
   338  		if !included {
   339  			return false
   340  		}
   341  	}
   342  
   343  	for _, sub := range topics {
   344  included := len(sub) == 0 //空规则集==通配符
   345  		for _, topic := range sub {
   346  			if types.BloomLookup(bloom, topic) {
   347  				included = true
   348  				break
   349  			}
   350  		}
   351  		if !included {
   352  			return false
   353  		}
   354  	}
   355  	return true
   356  }