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 }