github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/filters/filter_system.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  //版权所有2015 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  //包过滤器为块实现以太坊过滤系统,
    26  //事务和日志事件。
    27  package filters
    28  
    29  import (
    30  	"context"
    31  	"errors"
    32  	"fmt"
    33  	"sync"
    34  	"time"
    35  
    36  	ethereum "github.com/ethereum/go-ethereum"
    37  	"github.com/ethereum/go-ethereum/common"
    38  	"github.com/ethereum/go-ethereum/core"
    39  	"github.com/ethereum/go-ethereum/core/rawdb"
    40  	"github.com/ethereum/go-ethereum/core/types"
    41  	"github.com/ethereum/go-ethereum/event"
    42  	"github.com/ethereum/go-ethereum/log"
    43  	"github.com/ethereum/go-ethereum/rpc"
    44  )
    45  
    46  //类型确定筛选器的类型,并用于将筛选器放入
    47  //添加正确的桶。
    48  type Type byte
    49  
    50  const (
    51  //UnknownSubscription表示未知的订阅类型
    52  	UnknownSubscription Type = iota
    53  //新日志或已删除日志的日志订阅查询(chain reorg)
    54  	LogsSubscription
    55  //PendingLogs对挂起块中的日志的订阅查询
    56  	PendingLogsSubscription
    57  //MinedAndPendingLogs对挖掘和挂起块中的日志的订阅查询。
    58  	MinedAndPendingLogsSubscription
    59  //PendingtTransactionsSubscription查询待处理的Tx哈希
    60  //进入挂起状态的事务
    61  	PendingTransactionsSubscription
    62  //块订阅查询导入块的哈希
    63  	BlocksSubscription
    64  //LastSubscription跟踪最后一个索引
    65  	LastIndexSubscription
    66  )
    67  
    68  const (
    69  
    70  //txchanSize是侦听newtxSevent的频道的大小。
    71  //该数字是根据Tx池的大小引用的。
    72  	txChanSize = 4096
    73  //rmlogschansize是侦听removedlogsevent的通道的大小。
    74  	rmLogsChanSize = 10
    75  //logschansize是侦听logsevent的通道的大小。
    76  	logsChanSize = 10
    77  //ChainevChansize是侦听ChainEvent的通道的大小。
    78  	chainEvChanSize = 10
    79  )
    80  
    81  var (
    82  	ErrInvalidSubscriptionID = errors.New("invalid id")
    83  )
    84  
    85  type subscription struct {
    86  	id        rpc.ID
    87  	typ       Type
    88  	created   time.Time
    89  	logsCrit  ethereum.FilterQuery
    90  	logs      chan []*types.Log
    91  	hashes    chan []common.Hash
    92  	headers   chan *types.Header
    93  installed chan struct{} //安装过滤器时关闭
    94  err       chan error    //卸载筛选器时关闭
    95  }
    96  
    97  //EventSystem创建订阅、处理事件并将其广播到
    98  //符合订阅条件的订阅。
    99  type EventSystem struct {
   100  	mux       *event.TypeMux
   101  	backend   Backend
   102  	lightMode bool
   103  	lastHead  *types.Header
   104  
   105  //订阅
   106  txsSub        event.Subscription         //订阅新事务事件
   107  logsSub       event.Subscription         //订阅新日志事件
   108  rmLogsSub     event.Subscription         //已删除日志事件的订阅
   109  chainSub      event.Subscription         //订阅新的链事件
   110  pendingLogSub *event.TypeMuxSubscription //订阅挂起日志事件
   111  
   112  //渠道
   113  install   chan *subscription         //安装事件通知筛选器
   114  uninstall chan *subscription         //删除事件通知筛选器
   115  txsCh     chan core.NewTxsEvent      //接收新事务事件的通道
   116  logsCh    chan []*types.Log          //接收新日志事件的通道
   117  rmLogsCh  chan core.RemovedLogsEvent //接收已删除日志事件的通道
   118  chainCh   chan core.ChainEvent       //接收新链事件的通道
   119  }
   120  
   121  //newEventSystem创建一个新的管理器,用于侦听给定mux上的事件,
   122  //分析并过滤它们。它使用全部映射来检索过滤器更改。这个
   123  //工作循环保存自己的索引,用于将事件转发到筛选器。
   124  //
   125  //返回的管理器有一个需要用stop函数停止的循环
   126  //或者停止给定的多路复用器。
   127  func NewEventSystem(mux *event.TypeMux, backend Backend, lightMode bool) *EventSystem {
   128  	m := &EventSystem{
   129  		mux:       mux,
   130  		backend:   backend,
   131  		lightMode: lightMode,
   132  		install:   make(chan *subscription),
   133  		uninstall: make(chan *subscription),
   134  		txsCh:     make(chan core.NewTxsEvent, txChanSize),
   135  		logsCh:    make(chan []*types.Log, logsChanSize),
   136  		rmLogsCh:  make(chan core.RemovedLogsEvent, rmLogsChanSize),
   137  		chainCh:   make(chan core.ChainEvent, chainEvChanSize),
   138  	}
   139  
   140  //订阅事件
   141  	m.txsSub = m.backend.SubscribeNewTxsEvent(m.txsCh)
   142  	m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh)
   143  	m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh)
   144  	m.chainSub = m.backend.SubscribeChainEvent(m.chainCh)
   145  //TODO(RJL493456442):使用feed订阅挂起的日志事件
   146  	m.pendingLogSub = m.mux.Subscribe(core.PendingLogsEvent{})
   147  
   148  //确保所有订阅都不为空
   149  	if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil ||
   150  		m.pendingLogSub.Closed() {
   151  		log.Crit("Subscribe for event system failed")
   152  	}
   153  
   154  	go m.eventLoop()
   155  	return m
   156  }
   157  
   158  //订阅是在客户端为特定事件注册自身时创建的。
   159  type Subscription struct {
   160  	ID        rpc.ID
   161  	f         *subscription
   162  	es        *EventSystem
   163  	unsubOnce sync.Once
   164  }
   165  
   166  //err返回在取消订阅时关闭的通道。
   167  func (sub *Subscription) Err() <-chan error {
   168  	return sub.f.err
   169  }
   170  
   171  //取消订阅从事件广播循环中卸载订阅。
   172  func (sub *Subscription) Unsubscribe() {
   173  	sub.unsubOnce.Do(func() {
   174  	uninstallLoop:
   175  		for {
   176  //编写卸载请求并使用日志/哈希。这防止
   177  //写入时死锁的EventLoop广播方法
   178  //订阅循环等待时筛选事件通道
   179  //此方法返回(因此不读取这些事件)。
   180  			select {
   181  			case sub.es.uninstall <- sub.f:
   182  				break uninstallLoop
   183  			case <-sub.f.logs:
   184  			case <-sub.f.hashes:
   185  			case <-sub.f.headers:
   186  			}
   187  		}
   188  
   189  //在返回之前,请等待在工作循环中卸载筛选器
   190  //这样可以确保管理器不会使用
   191  //在该方法返回后,客户端可能会尽快关闭。
   192  		<-sub.Err()
   193  	})
   194  }
   195  
   196  //订阅在事件广播循环中安装订阅。
   197  func (es *EventSystem) subscribe(sub *subscription) *Subscription {
   198  	es.install <- sub
   199  	<-sub.installed
   200  	return &Subscription{ID: sub.id, f: sub, es: es}
   201  }
   202  
   203  //subscriptLogs创建一个订阅,该订阅将写入与
   204  //给定日志通道的给定条件。从和到的默认值
   205  //块为“最新”。如果FromBlock>ToBlock,则返回错误。
   206  func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) (*Subscription, error) {
   207  	var from, to rpc.BlockNumber
   208  	if crit.FromBlock == nil {
   209  		from = rpc.LatestBlockNumber
   210  	} else {
   211  		from = rpc.BlockNumber(crit.FromBlock.Int64())
   212  	}
   213  	if crit.ToBlock == nil {
   214  		to = rpc.LatestBlockNumber
   215  	} else {
   216  		to = rpc.BlockNumber(crit.ToBlock.Int64())
   217  	}
   218  
   219  //只对挂起的日志感兴趣
   220  	if from == rpc.PendingBlockNumber && to == rpc.PendingBlockNumber {
   221  		return es.subscribePendingLogs(crit, logs), nil
   222  	}
   223  //只对新开采的原木感兴趣
   224  	if from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber {
   225  		return es.subscribeLogs(crit, logs), nil
   226  	}
   227  //仅对特定区块范围内的开采原木感兴趣
   228  	if from >= 0 && to >= 0 && to >= from {
   229  		return es.subscribeLogs(crit, logs), nil
   230  	}
   231  //对特定块号、新日志和挂起日志中的挖掘日志感兴趣
   232  	if from >= rpc.LatestBlockNumber && to == rpc.PendingBlockNumber {
   233  		return es.subscribeMinedPendingLogs(crit, logs), nil
   234  	}
   235  //对从特定区块编号到新开采区块的原木感兴趣
   236  	if from >= 0 && to == rpc.LatestBlockNumber {
   237  		return es.subscribeLogs(crit, logs), nil
   238  	}
   239  	return nil, fmt.Errorf("invalid from and to block combination: from > to")
   240  }
   241  
   242  //subscripbeMinedPendingLogs创建一个返回已挖掘和
   243  //与给定条件匹配的挂起日志。
   244  func (es *EventSystem) subscribeMinedPendingLogs(crit ethereum.FilterQuery, logs chan []*types.Log) *Subscription {
   245  	sub := &subscription{
   246  		id:        rpc.NewID(),
   247  		typ:       MinedAndPendingLogsSubscription,
   248  		logsCrit:  crit,
   249  		created:   time.Now(),
   250  		logs:      logs,
   251  		hashes:    make(chan []common.Hash),
   252  		headers:   make(chan *types.Header),
   253  		installed: make(chan struct{}),
   254  		err:       make(chan error),
   255  	}
   256  	return es.subscribe(sub)
   257  }
   258  
   259  //subscriptLogs创建一个订阅,该订阅将写入与
   260  //给定日志通道的给定条件。
   261  func (es *EventSystem) subscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) *Subscription {
   262  	sub := &subscription{
   263  		id:        rpc.NewID(),
   264  		typ:       LogsSubscription,
   265  		logsCrit:  crit,
   266  		created:   time.Now(),
   267  		logs:      logs,
   268  		hashes:    make(chan []common.Hash),
   269  		headers:   make(chan *types.Header),
   270  		installed: make(chan struct{}),
   271  		err:       make(chan error),
   272  	}
   273  	return es.subscribe(sub)
   274  }
   275  
   276  //subscribePendingLogs创建一个订阅,该订阅为
   277  //进入事务池的事务。
   278  func (es *EventSystem) subscribePendingLogs(crit ethereum.FilterQuery, logs chan []*types.Log) *Subscription {
   279  	sub := &subscription{
   280  		id:        rpc.NewID(),
   281  		typ:       PendingLogsSubscription,
   282  		logsCrit:  crit,
   283  		created:   time.Now(),
   284  		logs:      logs,
   285  		hashes:    make(chan []common.Hash),
   286  		headers:   make(chan *types.Header),
   287  		installed: make(chan struct{}),
   288  		err:       make(chan error),
   289  	}
   290  	return es.subscribe(sub)
   291  }
   292  
   293  //SUBSCRIBENEWEADS创建一个订阅,该订阅写入的块头为
   294  //进口链。
   295  func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscription {
   296  	sub := &subscription{
   297  		id:        rpc.NewID(),
   298  		typ:       BlocksSubscription,
   299  		created:   time.Now(),
   300  		logs:      make(chan []*types.Log),
   301  		hashes:    make(chan []common.Hash),
   302  		headers:   headers,
   303  		installed: make(chan struct{}),
   304  		err:       make(chan error),
   305  	}
   306  	return es.subscribe(sub)
   307  }
   308  
   309  //订阅BuffixTxs创建一个订阅事务哈希的订阅。
   310  //进入事务池的事务。
   311  func (es *EventSystem) SubscribePendingTxs(hashes chan []common.Hash) *Subscription {
   312  	sub := &subscription{
   313  		id:        rpc.NewID(),
   314  		typ:       PendingTransactionsSubscription,
   315  		created:   time.Now(),
   316  		logs:      make(chan []*types.Log),
   317  		hashes:    hashes,
   318  		headers:   make(chan *types.Header),
   319  		installed: make(chan struct{}),
   320  		err:       make(chan error),
   321  	}
   322  	return es.subscribe(sub)
   323  }
   324  
   325  type filterIndex map[Type]map[rpc.ID]*subscription
   326  
   327  //将事件广播到符合条件的筛选器。
   328  func (es *EventSystem) broadcast(filters filterIndex, ev interface{}) {
   329  	if ev == nil {
   330  		return
   331  	}
   332  
   333  	switch e := ev.(type) {
   334  	case []*types.Log:
   335  		if len(e) > 0 {
   336  			for _, f := range filters[LogsSubscription] {
   337  				if matchedLogs := filterLogs(e, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 {
   338  					f.logs <- matchedLogs
   339  				}
   340  			}
   341  		}
   342  	case core.RemovedLogsEvent:
   343  		for _, f := range filters[LogsSubscription] {
   344  			if matchedLogs := filterLogs(e.Logs, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 {
   345  				f.logs <- matchedLogs
   346  			}
   347  		}
   348  	case *event.TypeMuxEvent:
   349  		if muxe, ok := e.Data.(core.PendingLogsEvent); ok {
   350  			for _, f := range filters[PendingLogsSubscription] {
   351  				if e.Time.After(f.created) {
   352  					if matchedLogs := filterLogs(muxe.Logs, nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics); len(matchedLogs) > 0 {
   353  						f.logs <- matchedLogs
   354  					}
   355  				}
   356  			}
   357  		}
   358  	case core.NewTxsEvent:
   359  		hashes := make([]common.Hash, 0, len(e.Txs))
   360  		for _, tx := range e.Txs {
   361  			hashes = append(hashes, tx.Hash())
   362  		}
   363  		for _, f := range filters[PendingTransactionsSubscription] {
   364  			f.hashes <- hashes
   365  		}
   366  	case core.ChainEvent:
   367  		for _, f := range filters[BlocksSubscription] {
   368  			f.headers <- e.Block.Header()
   369  		}
   370  		if es.lightMode && len(filters[LogsSubscription]) > 0 {
   371  			es.lightFilterNewHead(e.Block.Header(), func(header *types.Header, remove bool) {
   372  				for _, f := range filters[LogsSubscription] {
   373  					if matchedLogs := es.lightFilterLogs(header, f.logsCrit.Addresses, f.logsCrit.Topics, remove); len(matchedLogs) > 0 {
   374  						f.logs <- matchedLogs
   375  					}
   376  				}
   377  			})
   378  		}
   379  	}
   380  }
   381  
   382  func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) {
   383  	oldh := es.lastHead
   384  	es.lastHead = newHeader
   385  	if oldh == nil {
   386  		return
   387  	}
   388  	newh := newHeader
   389  //查找公共祖先,创建回滚和新块哈希的列表
   390  	var oldHeaders, newHeaders []*types.Header
   391  	for oldh.Hash() != newh.Hash() {
   392  		if oldh.Number.Uint64() >= newh.Number.Uint64() {
   393  			oldHeaders = append(oldHeaders, oldh)
   394  			oldh = rawdb.ReadHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1)
   395  		}
   396  		if oldh.Number.Uint64() < newh.Number.Uint64() {
   397  			newHeaders = append(newHeaders, newh)
   398  			newh = rawdb.ReadHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1)
   399  			if newh == nil {
   400  //当CHT同步时发生,无需执行任何操作
   401  				newh = oldh
   402  			}
   403  		}
   404  	}
   405  //回滚旧块
   406  	for _, h := range oldHeaders {
   407  		callBack(h, true)
   408  	}
   409  //检查新块(数组顺序相反)
   410  	for i := len(newHeaders) - 1; i >= 0; i-- {
   411  		callBack(newHeaders[i], false)
   412  	}
   413  }
   414  
   415  //在轻型客户端模式下筛选单个头的日志
   416  func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log {
   417  	if bloomFilter(header.Bloom, addresses, topics) {
   418  //获取块的日志
   419  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
   420  		defer cancel()
   421  		logsList, err := es.backend.GetLogs(ctx, header.Hash())
   422  		if err != nil {
   423  			return nil
   424  		}
   425  		var unfiltered []*types.Log
   426  		for _, logs := range logsList {
   427  			for _, log := range logs {
   428  				logcopy := *log
   429  				logcopy.Removed = remove
   430  				unfiltered = append(unfiltered, &logcopy)
   431  			}
   432  		}
   433  		logs := filterLogs(unfiltered, nil, nil, addresses, topics)
   434  		if len(logs) > 0 && logs[0].TxHash == (common.Hash{}) {
   435  //我们有匹配但非派生的日志
   436  			receipts, err := es.backend.GetReceipts(ctx, header.Hash())
   437  			if err != nil {
   438  				return nil
   439  			}
   440  			unfiltered = unfiltered[:0]
   441  			for _, receipt := range receipts {
   442  				for _, log := range receipt.Logs {
   443  					logcopy := *log
   444  					logcopy.Removed = remove
   445  					unfiltered = append(unfiltered, &logcopy)
   446  				}
   447  			}
   448  			logs = filterLogs(unfiltered, nil, nil, addresses, topics)
   449  		}
   450  		return logs
   451  	}
   452  	return nil
   453  }
   454  
   455  //EventLoop(un)安装过滤器并处理mux事件。
   456  func (es *EventSystem) eventLoop() {
   457  //确保清除所有订阅
   458  	defer func() {
   459  		es.pendingLogSub.Unsubscribe()
   460  		es.txsSub.Unsubscribe()
   461  		es.logsSub.Unsubscribe()
   462  		es.rmLogsSub.Unsubscribe()
   463  		es.chainSub.Unsubscribe()
   464  	}()
   465  
   466  	index := make(filterIndex)
   467  	for i := UnknownSubscription; i < LastIndexSubscription; i++ {
   468  		index[i] = make(map[rpc.ID]*subscription)
   469  	}
   470  
   471  	for {
   472  		select {
   473  //处理订阅的事件
   474  		case ev := <-es.txsCh:
   475  			es.broadcast(index, ev)
   476  		case ev := <-es.logsCh:
   477  			es.broadcast(index, ev)
   478  		case ev := <-es.rmLogsCh:
   479  			es.broadcast(index, ev)
   480  		case ev := <-es.chainCh:
   481  			es.broadcast(index, ev)
   482  		case ev, active := <-es.pendingLogSub.Chan():
   483  if !active { //系统停止
   484  				return
   485  			}
   486  			es.broadcast(index, ev)
   487  
   488  		case f := <-es.install:
   489  			if f.typ == MinedAndPendingLogsSubscription {
   490  //类型为日志和挂起的日志订阅
   491  				index[LogsSubscription][f.id] = f
   492  				index[PendingLogsSubscription][f.id] = f
   493  			} else {
   494  				index[f.typ][f.id] = f
   495  			}
   496  			close(f.installed)
   497  
   498  		case f := <-es.uninstall:
   499  			if f.typ == MinedAndPendingLogsSubscription {
   500  //类型为日志和挂起的日志订阅
   501  				delete(index[LogsSubscription], f.id)
   502  				delete(index[PendingLogsSubscription], f.id)
   503  			} else {
   504  				delete(index[f.typ], f.id)
   505  			}
   506  			close(f.err)
   507  
   508  //系统停止
   509  		case <-es.txsSub.Err():
   510  			return
   511  		case <-es.logsSub.Err():
   512  			return
   513  		case <-es.rmLogsSub.Err():
   514  			return
   515  		case <-es.chainSub.Err():
   516  			return
   517  		}
   518  	}
   519  }