github.com/MetalBlockchain/subnet-evm@v0.4.9/eth/filters/filter_system.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2015 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  // Package filters implements an ethereum filtering system for block,
    28  // transactions and log events.
    29  package filters
    30  
    31  import (
    32  	"context"
    33  	"fmt"
    34  	"sync"
    35  	"time"
    36  
    37  	"github.com/MetalBlockchain/subnet-evm/core"
    38  	"github.com/MetalBlockchain/subnet-evm/core/bloombits"
    39  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    40  	"github.com/MetalBlockchain/subnet-evm/core/types"
    41  	"github.com/MetalBlockchain/subnet-evm/core/vm"
    42  	"github.com/MetalBlockchain/subnet-evm/ethdb"
    43  	"github.com/MetalBlockchain/subnet-evm/interfaces"
    44  	"github.com/MetalBlockchain/subnet-evm/rpc"
    45  	"github.com/ethereum/go-ethereum/common"
    46  	"github.com/ethereum/go-ethereum/event"
    47  	"github.com/ethereum/go-ethereum/log"
    48  )
    49  
    50  // Config represents the configuration of the filter system.
    51  type Config struct {
    52  	Timeout time.Duration // how long filters stay active (default: 5min)
    53  }
    54  
    55  func (cfg Config) withDefaults() Config {
    56  	if cfg.Timeout == 0 {
    57  		cfg.Timeout = 5 * time.Minute
    58  	}
    59  	return cfg
    60  }
    61  
    62  type Backend interface {
    63  	ChainDb() ethdb.Database
    64  	HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
    65  	HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
    66  	GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error)
    67  	GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error)
    68  
    69  	SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
    70  	SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
    71  	SubscribeChainAcceptedEvent(ch chan<- core.ChainEvent) event.Subscription
    72  	SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
    73  	SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
    74  	SubscribeAcceptedLogsEvent(ch chan<- []*types.Log) event.Subscription
    75  
    76  	SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription
    77  
    78  	SubscribeAcceptedTransactionEvent(ch chan<- core.NewTxsEvent) event.Subscription
    79  
    80  	BloomStatus() (uint64, uint64)
    81  	ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
    82  
    83  	// Added to the backend interface to support limiting of logs requests
    84  	GetVMConfig() *vm.Config
    85  	LastAcceptedBlock() *types.Block
    86  	GetMaxBlocksPerRequest() int64
    87  }
    88  
    89  // FilterSystem holds resources shared by all filters.
    90  type FilterSystem struct {
    91  	backend Backend
    92  	cfg     *Config
    93  }
    94  
    95  // NewFilterSystem creates a filter system.
    96  func NewFilterSystem(backend Backend, config Config) *FilterSystem {
    97  	config = config.withDefaults()
    98  	return &FilterSystem{
    99  		backend: backend,
   100  		cfg:     &config,
   101  	}
   102  }
   103  
   104  // getLogs loads block logs from the backend. The backend is responsible for
   105  // performing any log caching.
   106  func (sys *FilterSystem) getLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
   107  	logs, err := sys.backend.GetLogs(ctx, blockHash, number)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	if logs == nil {
   112  		return nil, fmt.Errorf("failed to get logs for block #%d (0x%s)", number, blockHash.TerminalString())
   113  	}
   114  	return logs, nil
   115  }
   116  
   117  // Type determines the kind of filter and is used to put the filter in to
   118  // the correct bucket when added.
   119  type Type byte
   120  
   121  const (
   122  	// UnknownSubscription indicates an unknown subscription type
   123  	UnknownSubscription Type = iota
   124  	// LogsSubscription queries for new or removed (chain reorg) logs
   125  	LogsSubscription
   126  	// AcceptedLogsSubscription queries for new or removed (chain reorg) logs
   127  	AcceptedLogsSubscription
   128  	// PendingLogsSubscription queries for logs in pending blocks
   129  	PendingLogsSubscription
   130  	// MinedAndPendingLogsSubscription queries for logs in mined and pending blocks.
   131  	MinedAndPendingLogsSubscription
   132  	// PendingTransactionsSubscription queries tx hashes for pending
   133  	// transactions entering the pending state
   134  	PendingTransactionsSubscription
   135  	// AcceptedTransactionsSubscription queries tx hashes for accepted transactions
   136  	AcceptedTransactionsSubscription
   137  	// BlocksSubscription queries hashes for blocks that are imported
   138  	BlocksSubscription
   139  	// AcceptedBlocksSubscription queries hashes for blocks that are accepted
   140  	AcceptedBlocksSubscription
   141  	// LastSubscription keeps track of the last index
   142  	LastIndexSubscription
   143  )
   144  
   145  const (
   146  	// txChanSize is the size of channel listening to NewTxsEvent.
   147  	// The number is referenced from the size of tx pool.
   148  	txChanSize = 4096
   149  	// rmLogsChanSize is the size of channel listening to RemovedLogsEvent.
   150  	rmLogsChanSize = 10
   151  	// logsChanSize is the size of channel listening to LogsEvent.
   152  	logsChanSize = 10
   153  	// chainEvChanSize is the size of channel listening to ChainEvent.
   154  	chainEvChanSize = 10
   155  )
   156  
   157  type subscription struct {
   158  	id        rpc.ID
   159  	typ       Type
   160  	created   time.Time
   161  	logsCrit  interfaces.FilterQuery
   162  	logs      chan []*types.Log
   163  	hashes    chan []common.Hash
   164  	headers   chan *types.Header
   165  	installed chan struct{} // closed when the filter is installed
   166  	err       chan error    // closed when the filter is uninstalled
   167  }
   168  
   169  // EventSystem creates subscriptions, processes events and broadcasts them to the
   170  // subscription which match the subscription criteria.
   171  type EventSystem struct {
   172  	backend   Backend
   173  	sys       *FilterSystem
   174  	lightMode bool
   175  	lastHead  *types.Header
   176  
   177  	// Subscriptions
   178  	txsSub           event.Subscription // Subscription for new transaction event
   179  	logsSub          event.Subscription // Subscription for new log event
   180  	logsAcceptedSub  event.Subscription // Subscription for new accepted log event
   181  	rmLogsSub        event.Subscription // Subscription for removed log event
   182  	pendingLogsSub   event.Subscription // Subscription for pending log event
   183  	chainSub         event.Subscription // Subscription for new chain event
   184  	chainAcceptedSub event.Subscription // Subscription for new chain accepted event
   185  	txsAcceptedSub   event.Subscription // Subscription for new accepted txs
   186  
   187  	// Channels
   188  	install         chan *subscription         // install filter for event notification
   189  	uninstall       chan *subscription         // remove filter for event notification
   190  	txsCh           chan core.NewTxsEvent      // Channel to receive new transactions event
   191  	logsCh          chan []*types.Log          // Channel to receive new log event
   192  	logsAcceptedCh  chan []*types.Log          // Channel to receive new accepted log event
   193  	pendingLogsCh   chan []*types.Log          // Channel to receive new log event
   194  	rmLogsCh        chan core.RemovedLogsEvent // Channel to receive removed log event
   195  	chainCh         chan core.ChainEvent       // Channel to receive new chain event
   196  	chainAcceptedCh chan core.ChainEvent       // Channel to receive new chain accepted event
   197  	txsAcceptedCh   chan core.NewTxsEvent      // Channel to receive new accepted txs
   198  }
   199  
   200  // NewEventSystem creates a new manager that listens for event on the given mux,
   201  // parses and filters them. It uses the all map to retrieve filter changes. The
   202  // work loop holds its own index that is used to forward events to filters.
   203  //
   204  // The returned manager has a loop that needs to be stopped with the Stop function
   205  // or by stopping the given mux.
   206  func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem {
   207  	m := &EventSystem{
   208  		sys:             sys,
   209  		backend:         sys.backend,
   210  		lightMode:       lightMode,
   211  		install:         make(chan *subscription),
   212  		uninstall:       make(chan *subscription),
   213  		txsCh:           make(chan core.NewTxsEvent, txChanSize),
   214  		logsCh:          make(chan []*types.Log, logsChanSize),
   215  		logsAcceptedCh:  make(chan []*types.Log, logsChanSize),
   216  		rmLogsCh:        make(chan core.RemovedLogsEvent, rmLogsChanSize),
   217  		pendingLogsCh:   make(chan []*types.Log, logsChanSize),
   218  		chainCh:         make(chan core.ChainEvent, chainEvChanSize),
   219  		chainAcceptedCh: make(chan core.ChainEvent, chainEvChanSize),
   220  		txsAcceptedCh:   make(chan core.NewTxsEvent, txChanSize),
   221  	}
   222  
   223  	// Subscribe events
   224  	m.txsSub = m.backend.SubscribeNewTxsEvent(m.txsCh)
   225  	m.logsSub = m.backend.SubscribeLogsEvent(m.logsCh)
   226  	m.logsAcceptedSub = m.backend.SubscribeAcceptedLogsEvent(m.logsAcceptedCh)
   227  	m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh)
   228  	m.chainSub = m.backend.SubscribeChainEvent(m.chainCh)
   229  	m.chainAcceptedSub = m.backend.SubscribeChainAcceptedEvent(m.chainAcceptedCh)
   230  	m.pendingLogsSub = m.backend.SubscribePendingLogsEvent(m.pendingLogsCh)
   231  	m.txsAcceptedSub = m.backend.SubscribeAcceptedTransactionEvent(m.txsAcceptedCh)
   232  
   233  	// Make sure none of the subscriptions are empty
   234  	if m.txsSub == nil || m.logsSub == nil || m.logsAcceptedSub == nil || m.rmLogsSub == nil || m.chainSub == nil || m.chainAcceptedSub == nil || m.pendingLogsSub == nil || m.txsAcceptedSub == nil {
   235  		log.Crit("Subscribe for event system failed")
   236  	}
   237  
   238  	go m.eventLoop()
   239  	return m
   240  }
   241  
   242  // Subscription is created when the client registers itself for a particular event.
   243  type Subscription struct {
   244  	ID        rpc.ID
   245  	f         *subscription
   246  	es        *EventSystem
   247  	unsubOnce sync.Once
   248  }
   249  
   250  // Err returns a channel that is closed when unsubscribed.
   251  func (sub *Subscription) Err() <-chan error {
   252  	return sub.f.err
   253  }
   254  
   255  // Unsubscribe uninstalls the subscription from the event broadcast loop.
   256  func (sub *Subscription) Unsubscribe() {
   257  	sub.unsubOnce.Do(func() {
   258  	uninstallLoop:
   259  		for {
   260  			// write uninstall request and consume logs/hashes. This prevents
   261  			// the eventLoop broadcast method to deadlock when writing to the
   262  			// filter event channel while the subscription loop is waiting for
   263  			// this method to return (and thus not reading these events).
   264  			select {
   265  			case sub.es.uninstall <- sub.f:
   266  				break uninstallLoop
   267  			case <-sub.f.logs:
   268  			case <-sub.f.hashes:
   269  			case <-sub.f.headers:
   270  			}
   271  		}
   272  
   273  		// wait for filter to be uninstalled in work loop before returning
   274  		// this ensures that the manager won't use the event channel which
   275  		// will probably be closed by the client asap after this method returns.
   276  		<-sub.Err()
   277  	})
   278  }
   279  
   280  // subscribe installs the subscription in the event broadcast loop.
   281  func (es *EventSystem) subscribe(sub *subscription) *Subscription {
   282  	es.install <- sub
   283  	<-sub.installed
   284  	return &Subscription{ID: sub.id, f: sub, es: es}
   285  }
   286  
   287  // SubscribeLogs creates a subscription that will write all logs matching the
   288  // given criteria to the given logs channel. Default value for the from and to
   289  // block is "latest". If the fromBlock > toBlock an error is returned.
   290  func (es *EventSystem) SubscribeLogs(crit interfaces.FilterQuery, logs chan []*types.Log) (*Subscription, error) {
   291  	var from, to rpc.BlockNumber
   292  	if crit.FromBlock == nil {
   293  		from = rpc.LatestBlockNumber
   294  	} else {
   295  		from = rpc.BlockNumber(crit.FromBlock.Int64())
   296  	}
   297  	if crit.ToBlock == nil {
   298  		to = rpc.LatestBlockNumber
   299  	} else {
   300  		to = rpc.BlockNumber(crit.ToBlock.Int64())
   301  	}
   302  
   303  	// only interested in pending logs
   304  	if from == rpc.PendingBlockNumber && to == rpc.PendingBlockNumber {
   305  		return es.subscribePendingLogs(crit, logs), nil
   306  	}
   307  	// only interested in new mined logs
   308  	if from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber {
   309  		return es.subscribeLogs(crit, logs), nil
   310  	}
   311  	// only interested in mined logs within a specific block range
   312  	if from >= 0 && to >= 0 && to >= from {
   313  		return es.subscribeLogs(crit, logs), nil
   314  	}
   315  	// interested in mined logs from a specific block number, new logs and pending logs
   316  	if from >= rpc.LatestBlockNumber && to == rpc.PendingBlockNumber {
   317  		return es.subscribeMinedPendingLogs(crit, logs), nil
   318  	}
   319  	// interested in logs from a specific block number to new mined blocks
   320  	if from >= 0 && to == rpc.LatestBlockNumber {
   321  		return es.subscribeLogs(crit, logs), nil
   322  	}
   323  	return nil, fmt.Errorf("invalid from and to block combination: from > to")
   324  }
   325  
   326  func (es *EventSystem) SubscribeAcceptedLogs(crit interfaces.FilterQuery, logs chan []*types.Log) (*Subscription, error) {
   327  	var from, to rpc.BlockNumber
   328  	if crit.FromBlock == nil {
   329  		from = rpc.LatestBlockNumber
   330  	} else {
   331  		from = rpc.BlockNumber(crit.FromBlock.Int64())
   332  	}
   333  	if crit.ToBlock == nil {
   334  		to = rpc.LatestBlockNumber
   335  	} else {
   336  		to = rpc.BlockNumber(crit.ToBlock.Int64())
   337  	}
   338  
   339  	// subscribeAcceptedLogs if filter is valid (from SubscribeLogs)
   340  	if from == rpc.PendingBlockNumber && to == rpc.PendingBlockNumber ||
   341  		from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber ||
   342  		from >= 0 && to >= 0 && to >= from ||
   343  		from >= rpc.LatestBlockNumber && to == rpc.PendingBlockNumber ||
   344  		from >= 0 && to == rpc.LatestBlockNumber {
   345  		return es.subscribeAcceptedLogs(crit, logs), nil
   346  	}
   347  
   348  	return nil, fmt.Errorf("invalid from and to block combination: from > to")
   349  }
   350  
   351  func (es *EventSystem) subscribeAcceptedLogs(crit interfaces.FilterQuery, logs chan []*types.Log) *Subscription {
   352  	sub := &subscription{
   353  		id:        rpc.NewID(),
   354  		typ:       AcceptedLogsSubscription,
   355  		logsCrit:  crit,
   356  		created:   time.Now(),
   357  		logs:      logs,
   358  		hashes:    make(chan []common.Hash),
   359  		headers:   make(chan *types.Header),
   360  		installed: make(chan struct{}),
   361  		err:       make(chan error),
   362  	}
   363  	return es.subscribe(sub)
   364  }
   365  
   366  // subscribeMinedPendingLogs creates a subscription that returned mined and
   367  // pending logs that match the given criteria.
   368  func (es *EventSystem) subscribeMinedPendingLogs(crit interfaces.FilterQuery, logs chan []*types.Log) *Subscription {
   369  	sub := &subscription{
   370  		id:        rpc.NewID(),
   371  		typ:       MinedAndPendingLogsSubscription,
   372  		logsCrit:  crit,
   373  		created:   time.Now(),
   374  		logs:      logs,
   375  		hashes:    make(chan []common.Hash),
   376  		headers:   make(chan *types.Header),
   377  		installed: make(chan struct{}),
   378  		err:       make(chan error),
   379  	}
   380  	return es.subscribe(sub)
   381  }
   382  
   383  // subscribeLogs creates a subscription that will write all logs matching the
   384  // given criteria to the given logs channel.
   385  func (es *EventSystem) subscribeLogs(crit interfaces.FilterQuery, logs chan []*types.Log) *Subscription {
   386  	sub := &subscription{
   387  		id:        rpc.NewID(),
   388  		typ:       LogsSubscription,
   389  		logsCrit:  crit,
   390  		created:   time.Now(),
   391  		logs:      logs,
   392  		hashes:    make(chan []common.Hash),
   393  		headers:   make(chan *types.Header),
   394  		installed: make(chan struct{}),
   395  		err:       make(chan error),
   396  	}
   397  	return es.subscribe(sub)
   398  }
   399  
   400  // subscribePendingLogs creates a subscription that writes contract event logs for
   401  // transactions that enter the transaction pool.
   402  func (es *EventSystem) subscribePendingLogs(crit interfaces.FilterQuery, logs chan []*types.Log) *Subscription {
   403  	sub := &subscription{
   404  		id:        rpc.NewID(),
   405  		typ:       PendingLogsSubscription,
   406  		logsCrit:  crit,
   407  		created:   time.Now(),
   408  		logs:      logs,
   409  		hashes:    make(chan []common.Hash),
   410  		headers:   make(chan *types.Header),
   411  		installed: make(chan struct{}),
   412  		err:       make(chan error),
   413  	}
   414  	return es.subscribe(sub)
   415  }
   416  
   417  // SubscribeNewHeads creates a subscription that writes the header of a block that is
   418  // imported in the chain.
   419  func (es *EventSystem) SubscribeNewHeads(headers chan *types.Header) *Subscription {
   420  	sub := &subscription{
   421  		id:        rpc.NewID(),
   422  		typ:       BlocksSubscription,
   423  		created:   time.Now(),
   424  		logs:      make(chan []*types.Log),
   425  		hashes:    make(chan []common.Hash),
   426  		headers:   headers,
   427  		installed: make(chan struct{}),
   428  		err:       make(chan error),
   429  	}
   430  	return es.subscribe(sub)
   431  }
   432  
   433  // SubscribeAcceptedHeads creates a subscription that writes the header of an accepted block that is
   434  // imported in the chain.
   435  func (es *EventSystem) SubscribeAcceptedHeads(headers chan *types.Header) *Subscription {
   436  	sub := &subscription{
   437  		id:        rpc.NewID(),
   438  		typ:       AcceptedBlocksSubscription,
   439  		created:   time.Now(),
   440  		logs:      make(chan []*types.Log),
   441  		hashes:    make(chan []common.Hash),
   442  		headers:   headers,
   443  		installed: make(chan struct{}),
   444  		err:       make(chan error),
   445  	}
   446  	return es.subscribe(sub)
   447  }
   448  
   449  // SubscribePendingTxs creates a subscription that writes transaction hashes for
   450  // transactions that enter the transaction pool.
   451  func (es *EventSystem) SubscribePendingTxs(hashes chan []common.Hash) *Subscription {
   452  	sub := &subscription{
   453  		id:        rpc.NewID(),
   454  		typ:       PendingTransactionsSubscription,
   455  		created:   time.Now(),
   456  		logs:      make(chan []*types.Log),
   457  		hashes:    hashes,
   458  		headers:   make(chan *types.Header),
   459  		installed: make(chan struct{}),
   460  		err:       make(chan error),
   461  	}
   462  	return es.subscribe(sub)
   463  }
   464  
   465  // SubscribeAcceptedTxs creates a subscription that writes transaction hashes for
   466  // transactions have been accepted.
   467  func (es *EventSystem) SubscribeAcceptedTxs(hashes chan []common.Hash) *Subscription {
   468  	sub := &subscription{
   469  		id:        rpc.NewID(),
   470  		typ:       AcceptedTransactionsSubscription,
   471  		created:   time.Now(),
   472  		logs:      make(chan []*types.Log),
   473  		hashes:    hashes,
   474  		headers:   make(chan *types.Header),
   475  		installed: make(chan struct{}),
   476  		err:       make(chan error),
   477  	}
   478  	return es.subscribe(sub)
   479  }
   480  
   481  type filterIndex map[Type]map[rpc.ID]*subscription
   482  
   483  func (es *EventSystem) handleLogs(filters filterIndex, ev []*types.Log) {
   484  	if len(ev) == 0 {
   485  		return
   486  	}
   487  	for _, f := range filters[LogsSubscription] {
   488  		matchedLogs := filterLogs(ev, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics)
   489  		if len(matchedLogs) > 0 {
   490  			f.logs <- matchedLogs
   491  		}
   492  	}
   493  }
   494  
   495  func (es *EventSystem) handleAcceptedLogs(filters filterIndex, ev []*types.Log) {
   496  	if len(ev) == 0 {
   497  		return
   498  	}
   499  	for _, f := range filters[AcceptedLogsSubscription] {
   500  		matchedLogs := filterLogs(ev, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics)
   501  		if len(matchedLogs) > 0 {
   502  			f.logs <- matchedLogs
   503  		}
   504  	}
   505  }
   506  
   507  func (es *EventSystem) handlePendingLogs(filters filterIndex, ev []*types.Log) {
   508  	if len(ev) == 0 {
   509  		return
   510  	}
   511  	for _, f := range filters[PendingLogsSubscription] {
   512  		matchedLogs := filterLogs(ev, nil, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics)
   513  		if len(matchedLogs) > 0 {
   514  			f.logs <- matchedLogs
   515  		}
   516  	}
   517  }
   518  
   519  func (es *EventSystem) handleRemovedLogs(filters filterIndex, ev core.RemovedLogsEvent) {
   520  	for _, f := range filters[LogsSubscription] {
   521  		matchedLogs := filterLogs(ev.Logs, f.logsCrit.FromBlock, f.logsCrit.ToBlock, f.logsCrit.Addresses, f.logsCrit.Topics)
   522  		if len(matchedLogs) > 0 {
   523  			f.logs <- matchedLogs
   524  		}
   525  	}
   526  }
   527  
   528  func (es *EventSystem) handleTxsEvent(filters filterIndex, ev core.NewTxsEvent, accepted bool) {
   529  	hashes := make([]common.Hash, 0, len(ev.Txs))
   530  	for _, tx := range ev.Txs {
   531  		hashes = append(hashes, tx.Hash())
   532  	}
   533  	for _, f := range filters[PendingTransactionsSubscription] {
   534  		f.hashes <- hashes
   535  	}
   536  	if accepted {
   537  		for _, f := range filters[AcceptedTransactionsSubscription] {
   538  			f.hashes <- hashes
   539  		}
   540  	}
   541  }
   542  
   543  func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent) {
   544  	for _, f := range filters[BlocksSubscription] {
   545  		f.headers <- ev.Block.Header()
   546  	}
   547  	if es.lightMode && len(filters[LogsSubscription]) > 0 {
   548  		es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) {
   549  			for _, f := range filters[LogsSubscription] {
   550  				if matchedLogs := es.lightFilterLogs(header, f.logsCrit.Addresses, f.logsCrit.Topics, remove); len(matchedLogs) > 0 {
   551  					f.logs <- matchedLogs
   552  				}
   553  			}
   554  		})
   555  	}
   556  }
   557  
   558  func (es *EventSystem) handleChainAcceptedEvent(filters filterIndex, ev core.ChainEvent) {
   559  	for _, f := range filters[AcceptedBlocksSubscription] {
   560  		f.headers <- ev.Block.Header()
   561  	}
   562  	if es.lightMode && len(filters[LogsSubscription]) > 0 {
   563  		es.lightFilterNewHead(ev.Block.Header(), func(header *types.Header, remove bool) {
   564  			for _, f := range filters[LogsSubscription] {
   565  				if matchedLogs := es.lightFilterLogs(header, f.logsCrit.Addresses, f.logsCrit.Topics, remove); len(matchedLogs) > 0 {
   566  					f.logs <- matchedLogs
   567  				}
   568  			}
   569  		})
   570  	}
   571  }
   572  
   573  func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) {
   574  	oldh := es.lastHead
   575  	es.lastHead = newHeader
   576  	if oldh == nil {
   577  		return
   578  	}
   579  	newh := newHeader
   580  	// find common ancestor, create list of rolled back and new block hashes
   581  	var oldHeaders, newHeaders []*types.Header
   582  	for oldh.Hash() != newh.Hash() {
   583  		if oldh.Number.Uint64() >= newh.Number.Uint64() {
   584  			oldHeaders = append(oldHeaders, oldh)
   585  			oldh = rawdb.ReadHeader(es.backend.ChainDb(), oldh.ParentHash, oldh.Number.Uint64()-1)
   586  		}
   587  		if oldh.Number.Uint64() < newh.Number.Uint64() {
   588  			newHeaders = append(newHeaders, newh)
   589  			newh = rawdb.ReadHeader(es.backend.ChainDb(), newh.ParentHash, newh.Number.Uint64()-1)
   590  			if newh == nil {
   591  				// happens when CHT syncing, nothing to do
   592  				newh = oldh
   593  			}
   594  		}
   595  	}
   596  	// roll back old blocks
   597  	for _, h := range oldHeaders {
   598  		callBack(h, true)
   599  	}
   600  	// check new blocks (array is in reverse order)
   601  	for i := len(newHeaders) - 1; i >= 0; i-- {
   602  		callBack(newHeaders[i], false)
   603  	}
   604  }
   605  
   606  // filter logs of a single header in light client mode
   607  func (es *EventSystem) lightFilterLogs(header *types.Header, addresses []common.Address, topics [][]common.Hash, remove bool) []*types.Log {
   608  	if bloomFilter(header.Bloom, addresses, topics) {
   609  		// Get the logs of the block
   610  		ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
   611  		defer cancel()
   612  		logsList, err := es.sys.getLogs(ctx, header.Hash(), header.Number.Uint64())
   613  		if err != nil {
   614  			return nil
   615  		}
   616  		var unfiltered []*types.Log
   617  		for _, logs := range logsList {
   618  			for _, log := range logs {
   619  				logcopy := *log
   620  				logcopy.Removed = remove
   621  				unfiltered = append(unfiltered, &logcopy)
   622  			}
   623  		}
   624  		logs := filterLogs(unfiltered, nil, nil, addresses, topics)
   625  		if len(logs) > 0 && logs[0].TxHash == (common.Hash{}) {
   626  			// We have matching but non-derived logs
   627  			receipts, err := es.backend.GetReceipts(ctx, header.Hash())
   628  			if err != nil {
   629  				return nil
   630  			}
   631  			unfiltered = unfiltered[:0]
   632  			for _, receipt := range receipts {
   633  				for _, log := range receipt.Logs {
   634  					logcopy := *log
   635  					logcopy.Removed = remove
   636  					unfiltered = append(unfiltered, &logcopy)
   637  				}
   638  			}
   639  			logs = filterLogs(unfiltered, nil, nil, addresses, topics)
   640  		}
   641  		return logs
   642  	}
   643  	return nil
   644  }
   645  
   646  // eventLoop (un)installs filters and processes mux events.
   647  func (es *EventSystem) eventLoop() {
   648  	// Ensure all subscriptions get cleaned up
   649  	defer func() {
   650  		es.txsSub.Unsubscribe()
   651  		es.logsSub.Unsubscribe()
   652  		es.logsAcceptedSub.Unsubscribe()
   653  		es.rmLogsSub.Unsubscribe()
   654  		es.pendingLogsSub.Unsubscribe()
   655  		es.chainSub.Unsubscribe()
   656  		es.chainAcceptedSub.Unsubscribe()
   657  		es.txsAcceptedSub.Unsubscribe()
   658  	}()
   659  
   660  	index := make(filterIndex)
   661  	for i := UnknownSubscription; i < LastIndexSubscription; i++ {
   662  		index[i] = make(map[rpc.ID]*subscription)
   663  	}
   664  
   665  	for {
   666  		select {
   667  		case ev := <-es.txsCh:
   668  			es.handleTxsEvent(index, ev, false)
   669  		case ev := <-es.logsCh:
   670  			es.handleLogs(index, ev)
   671  		case ev := <-es.logsAcceptedCh:
   672  			es.handleAcceptedLogs(index, ev)
   673  		case ev := <-es.rmLogsCh:
   674  			es.handleRemovedLogs(index, ev)
   675  		case ev := <-es.pendingLogsCh:
   676  			es.handlePendingLogs(index, ev)
   677  		case ev := <-es.chainCh:
   678  			es.handleChainEvent(index, ev)
   679  		case ev := <-es.chainAcceptedCh:
   680  			es.handleChainAcceptedEvent(index, ev)
   681  		case ev := <-es.txsAcceptedCh:
   682  			es.handleTxsEvent(index, ev, true)
   683  
   684  		case f := <-es.install:
   685  			if f.typ == MinedAndPendingLogsSubscription {
   686  				// the type are logs and pending logs subscriptions
   687  				index[LogsSubscription][f.id] = f
   688  				index[PendingLogsSubscription][f.id] = f
   689  			} else {
   690  				index[f.typ][f.id] = f
   691  			}
   692  			close(f.installed)
   693  
   694  		case f := <-es.uninstall:
   695  			if f.typ == MinedAndPendingLogsSubscription {
   696  				// the type are logs and pending logs subscriptions
   697  				delete(index[LogsSubscription], f.id)
   698  				delete(index[PendingLogsSubscription], f.id)
   699  			} else {
   700  				delete(index[f.typ], f.id)
   701  			}
   702  			close(f.err)
   703  
   704  		// System stopped
   705  		case <-es.txsSub.Err():
   706  			return
   707  		case <-es.logsSub.Err():
   708  			return
   709  		case <-es.logsAcceptedSub.Err():
   710  			return
   711  		case <-es.rmLogsSub.Err():
   712  			return
   713  		case <-es.chainSub.Err():
   714  			return
   715  		case <-es.chainAcceptedSub.Err():
   716  			return
   717  		case <-es.txsAcceptedSub.Err():
   718  			return
   719  		}
   720  	}
   721  }