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 }