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 }