github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/eth/filters/filter_system.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // package filters implements an ethereum filtering system for block,
    18  // transactions and log events.
    19  package filters
    20  
    21  import (
    22  	"fmt"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/ethereumproject/go-ethereum/core"
    27  	"github.com/ethereumproject/go-ethereum/core/vm"
    28  	"github.com/ethereumproject/go-ethereum/event"
    29  )
    30  
    31  // FilterType determines the type of filter and is used to put the filter in to
    32  // the correct bucket when added.
    33  type FilterType byte
    34  
    35  const (
    36  	ChainFilter      FilterType = iota // new block events filter
    37  	PendingTxFilter                    // pending transaction filter
    38  	LogFilter                          // new or removed log filter
    39  	PendingLogFilter                   // pending log filter
    40  )
    41  
    42  // FilterSystem manages filters that filter specific events such as
    43  // block, transaction and log events. The Filtering system can be used to listen
    44  // for specific LOG events fired by the EVM (Ethereum Virtual Machine).
    45  type FilterSystem struct {
    46  	filterMu sync.RWMutex
    47  	filterId int
    48  
    49  	chainFilters      map[int]*Filter
    50  	pendingTxFilters  map[int]*Filter
    51  	logFilters        map[int]*Filter
    52  	pendingLogFilters map[int]*Filter
    53  
    54  	// generic is an ugly hack for Get
    55  	generic map[int]*Filter
    56  
    57  	sub event.Subscription
    58  }
    59  
    60  // NewFilterSystem returns a newly allocated filter manager
    61  func NewFilterSystem(mux *event.TypeMux) *FilterSystem {
    62  	fs := &FilterSystem{
    63  		chainFilters:      make(map[int]*Filter),
    64  		pendingTxFilters:  make(map[int]*Filter),
    65  		logFilters:        make(map[int]*Filter),
    66  		pendingLogFilters: make(map[int]*Filter),
    67  		generic:           make(map[int]*Filter),
    68  	}
    69  	fs.sub = mux.Subscribe(
    70  		core.PendingLogsEvent{},
    71  		core.RemovedLogsEvent{},
    72  		core.ChainEvent{},
    73  		core.TxPreEvent{},
    74  		vm.Logs(nil),
    75  	)
    76  	go fs.filterLoop()
    77  	return fs
    78  }
    79  
    80  // Stop quits the filter loop required for polling events
    81  func (fs *FilterSystem) Stop() {
    82  	fs.sub.Unsubscribe()
    83  }
    84  
    85  // Acquire filter system maps lock, required to force lock acquisition
    86  // sequence with filterMu acquired first to avoid deadlocks by callbacks
    87  func (fs *FilterSystem) Lock() {
    88  	fs.filterMu.Lock()
    89  }
    90  
    91  // Release filter system maps lock
    92  func (fs *FilterSystem) Unlock() {
    93  	fs.filterMu.Unlock()
    94  }
    95  
    96  // Add adds a filter to the filter manager
    97  // Expects filterMu to be locked.
    98  func (fs *FilterSystem) Add(filter *Filter, filterType FilterType) (int, error) {
    99  	// protocol version eth/61
   100  	//fs.filterMu.Lock()
   101  	//defer fs.filterMu.Unlock()
   102  	id := fs.filterId
   103  	filter.created = time.Now()
   104  
   105  	switch filterType {
   106  	case ChainFilter:
   107  		fs.chainFilters[id] = filter
   108  	case PendingTxFilter:
   109  		fs.pendingTxFilters[id] = filter
   110  	case LogFilter:
   111  		fs.logFilters[id] = filter
   112  	case PendingLogFilter:
   113  		fs.pendingLogFilters[id] = filter
   114  	default:
   115  		return 0, fmt.Errorf("unknown filter type %v", filterType)
   116  	}
   117  	fs.generic[id] = filter
   118  
   119  	fs.filterId++
   120  
   121  	return id, nil
   122  }
   123  
   124  // Remove removes a filter by filter id
   125  // Expects filterMu to be locked.
   126  func (fs *FilterSystem) Remove(id int) {
   127  	delete(fs.chainFilters, id)
   128  	delete(fs.pendingTxFilters, id)
   129  	delete(fs.logFilters, id)
   130  	delete(fs.pendingLogFilters, id)
   131  	delete(fs.generic, id)
   132  }
   133  
   134  func (fs *FilterSystem) Get(id int) *Filter {
   135  	fs.filterMu.RLock()
   136  	defer fs.filterMu.RUnlock()
   137  
   138  	return fs.generic[id]
   139  }
   140  
   141  // filterLoop waits for specific events from ethereum and fires their handlers
   142  // when the filter matches the requirements.
   143  func (fs *FilterSystem) filterLoop() {
   144  	for event := range fs.sub.Chan() {
   145  		switch ev := event.Data.(type) {
   146  		case core.ChainEvent:
   147  			fs.filterMu.RLock()
   148  			for _, filter := range fs.chainFilters {
   149  				if filter.BlockCallback != nil && !filter.created.After(event.Time) {
   150  					filter.BlockCallback(ev.Block, ev.Logs)
   151  				}
   152  			}
   153  			fs.filterMu.RUnlock()
   154  		case core.TxPreEvent:
   155  			fs.filterMu.RLock()
   156  			for _, filter := range fs.pendingTxFilters {
   157  				if filter.TransactionCallback != nil && !filter.created.After(event.Time) {
   158  					filter.TransactionCallback(ev.Tx)
   159  				}
   160  			}
   161  			fs.filterMu.RUnlock()
   162  
   163  		case vm.Logs:
   164  			fs.filterMu.RLock()
   165  			for _, filter := range fs.logFilters {
   166  				if filter.LogCallback != nil && !filter.created.After(event.Time) {
   167  					for _, log := range filter.FilterLogs(ev) {
   168  						filter.LogCallback(log, false)
   169  					}
   170  				}
   171  			}
   172  			fs.filterMu.RUnlock()
   173  		case core.RemovedLogsEvent:
   174  			fs.filterMu.RLock()
   175  			for _, filter := range fs.logFilters {
   176  				if filter.LogCallback != nil && !filter.created.After(event.Time) {
   177  					for _, removedLog := range filter.FilterLogs(ev.Logs) {
   178  						filter.LogCallback(removedLog, true)
   179  					}
   180  				}
   181  			}
   182  			fs.filterMu.RUnlock()
   183  		case core.PendingLogsEvent:
   184  			fs.filterMu.RLock()
   185  			for _, filter := range fs.pendingLogFilters {
   186  				if filter.LogCallback != nil && !filter.created.After(event.Time) {
   187  					for _, pendingLog := range ev.Logs {
   188  						filter.LogCallback(pendingLog, false)
   189  					}
   190  				}
   191  			}
   192  			fs.filterMu.RUnlock()
   193  		}
   194  	}
   195  }