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 }