github.com/yuanzimu/bsc@v1.1.4/eth/handler.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 eth 18 19 import ( 20 "errors" 21 "math" 22 "math/big" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/core" 29 "github.com/ethereum/go-ethereum/core/forkid" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/eth/downloader" 32 "github.com/ethereum/go-ethereum/eth/fetcher" 33 "github.com/ethereum/go-ethereum/eth/protocols/diff" 34 "github.com/ethereum/go-ethereum/eth/protocols/eth" 35 "github.com/ethereum/go-ethereum/eth/protocols/snap" 36 "github.com/ethereum/go-ethereum/ethdb" 37 "github.com/ethereum/go-ethereum/event" 38 "github.com/ethereum/go-ethereum/log" 39 "github.com/ethereum/go-ethereum/p2p" 40 "github.com/ethereum/go-ethereum/params" 41 "github.com/ethereum/go-ethereum/rlp" 42 "github.com/ethereum/go-ethereum/trie" 43 ) 44 45 const ( 46 // txChanSize is the size of channel listening to NewTxsEvent. 47 // The number is referenced from the size of tx pool. 48 txChanSize = 4096 49 ) 50 51 var ( 52 syncChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the sync progress challenge 53 ) 54 55 // txPool defines the methods needed from a transaction pool implementation to 56 // support all the operations needed by the Ethereum chain protocols. 57 type txPool interface { 58 // Has returns an indicator whether txpool has a transaction 59 // cached with the given hash. 60 Has(hash common.Hash) bool 61 62 // Get retrieves the transaction from local txpool with given 63 // tx hash. 64 Get(hash common.Hash) *types.Transaction 65 66 // AddRemotes should add the given transactions to the pool. 67 AddRemotes([]*types.Transaction) []error 68 69 // Pending should return pending transactions. 70 // The slice should be modifiable by the caller. 71 Pending() (map[common.Address]types.Transactions, error) 72 73 // SubscribeNewTxsEvent should return an event subscription of 74 // NewTxsEvent and send events to the given channel. 75 SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription 76 } 77 78 // handlerConfig is the collection of initialization parameters to create a full 79 // node network handler. 80 type handlerConfig struct { 81 Database ethdb.Database // Database for direct sync insertions 82 Chain *core.BlockChain // Blockchain to serve data from 83 TxPool txPool // Transaction pool to propagate from 84 Network uint64 // Network identifier to adfvertise 85 Sync downloader.SyncMode // Whether to fast or full sync 86 DiffSync bool // Whether to diff sync 87 BloomCache uint64 // Megabytes to alloc for fast sync bloom 88 EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` 89 Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges 90 Whitelist map[uint64]common.Hash // Hard coded whitelist for sync challenged 91 DirectBroadcast bool 92 DisablePeerTxBroadcast bool 93 } 94 95 type handler struct { 96 networkID uint64 97 forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node 98 disablePeerTxBroadcast bool 99 100 fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks) 101 snapSync uint32 // Flag whether fast sync should operate on top of the snap protocol 102 acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) 103 directBroadcast bool 104 diffSync bool // Flag whether diff sync should operate on top of the diff protocol 105 106 checkpointNumber uint64 // Block number for the sync progress validator to cross reference 107 checkpointHash common.Hash // Block hash for the sync progress validator to cross reference 108 109 database ethdb.Database 110 txpool txPool 111 chain *core.BlockChain 112 maxPeers int 113 114 downloader *downloader.Downloader 115 stateBloom *trie.SyncBloom 116 blockFetcher *fetcher.BlockFetcher 117 txFetcher *fetcher.TxFetcher 118 peers *peerSet 119 120 eventMux *event.TypeMux 121 txsCh chan core.NewTxsEvent 122 txsSub event.Subscription 123 minedBlockSub *event.TypeMuxSubscription 124 125 whitelist map[uint64]common.Hash 126 127 // channels for fetcher, syncer, txsyncLoop 128 txsyncCh chan *txsync 129 quitSync chan struct{} 130 131 chainSync *chainSyncer 132 wg sync.WaitGroup 133 peerWG sync.WaitGroup 134 } 135 136 // newHandler returns a handler for all Ethereum chain management protocol. 137 func newHandler(config *handlerConfig) (*handler, error) { 138 // Create the protocol manager with the base fields 139 if config.EventMux == nil { 140 config.EventMux = new(event.TypeMux) // Nicety initialization for tests 141 } 142 h := &handler{ 143 networkID: config.Network, 144 forkFilter: forkid.NewFilter(config.Chain), 145 disablePeerTxBroadcast: config.DisablePeerTxBroadcast, 146 eventMux: config.EventMux, 147 database: config.Database, 148 txpool: config.TxPool, 149 chain: config.Chain, 150 peers: newPeerSet(), 151 whitelist: config.Whitelist, 152 directBroadcast: config.DirectBroadcast, 153 diffSync: config.DiffSync, 154 txsyncCh: make(chan *txsync), 155 quitSync: make(chan struct{}), 156 } 157 if config.Sync == downloader.FullSync { 158 // The database seems empty as the current block is the genesis. Yet the fast 159 // block is ahead, so fast sync was enabled for this node at a certain point. 160 // The scenarios where this can happen is 161 // * if the user manually (or via a bad block) rolled back a fast sync node 162 // below the sync point. 163 // * the last fast sync is not finished while user specifies a full sync this 164 // time. But we don't have any recent state for full sync. 165 // In these cases however it's safe to reenable fast sync. 166 fullBlock, fastBlock := h.chain.CurrentBlock(), h.chain.CurrentFastBlock() 167 if fullBlock.NumberU64() == 0 && fastBlock.NumberU64() > 0 { 168 h.fastSync = uint32(1) 169 log.Warn("Switch sync mode from full sync to fast sync") 170 } 171 } else { 172 if h.chain.CurrentBlock().NumberU64() > 0 { 173 // Print warning log if database is not empty to run fast sync. 174 log.Warn("Switch sync mode from fast sync to full sync") 175 } else { 176 // If fast sync was requested and our database is empty, grant it 177 h.fastSync = uint32(1) 178 if config.Sync == downloader.SnapSync { 179 h.snapSync = uint32(1) 180 } 181 } 182 } 183 // If we have trusted checkpoints, enforce them on the chain 184 if config.Checkpoint != nil { 185 h.checkpointNumber = (config.Checkpoint.SectionIndex+1)*params.CHTFrequency - 1 186 h.checkpointHash = config.Checkpoint.SectionHead 187 } 188 // Construct the downloader (long sync) and its backing state bloom if fast 189 // sync is requested. The downloader is responsible for deallocating the state 190 // bloom when it's done. 191 // Note: we don't enable it if snap-sync is performed, since it's very heavy 192 // and the heal-portion of the snap sync is much lighter than fast. What we particularly 193 // want to avoid, is a 90%-finished (but restarted) snap-sync to begin 194 // indexing the entire trie 195 if atomic.LoadUint32(&h.fastSync) == 1 && atomic.LoadUint32(&h.snapSync) == 0 { 196 h.stateBloom = trie.NewSyncBloom(config.BloomCache, config.Database) 197 } 198 var downloadOptions []downloader.DownloadOption 199 if h.diffSync { 200 downloadOptions = append(downloadOptions, downloader.EnableDiffFetchOp(h.peers)) 201 } 202 h.downloader = downloader.New(h.checkpointNumber, config.Database, h.stateBloom, h.eventMux, h.chain, nil, h.removePeer, downloadOptions...) 203 204 // Construct the fetcher (short sync) 205 validator := func(header *types.Header) error { 206 return h.chain.Engine().VerifyHeader(h.chain, header, true) 207 } 208 heighter := func() uint64 { 209 return h.chain.CurrentBlock().NumberU64() 210 } 211 inserter := func(blocks types.Blocks) (int, error) { 212 // If sync hasn't reached the checkpoint yet, deny importing weird blocks. 213 // 214 // Ideally we would also compare the head block's timestamp and similarly reject 215 // the propagated block if the head is too old. Unfortunately there is a corner 216 // case when starting new networks, where the genesis might be ancient (0 unix) 217 // which would prevent full nodes from accepting it. 218 if h.chain.CurrentBlock().NumberU64() < h.checkpointNumber { 219 log.Warn("Unsynced yet, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) 220 return 0, nil 221 } 222 // If fast sync is running, deny importing weird blocks. This is a problematic 223 // clause when starting up a new network, because fast-syncing miners might not 224 // accept each others' blocks until a restart. Unfortunately we haven't figured 225 // out a way yet where nodes can decide unilaterally whether the network is new 226 // or not. This should be fixed if we figure out a solution. 227 if atomic.LoadUint32(&h.fastSync) == 1 { 228 log.Warn("Fast syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) 229 return 0, nil 230 } 231 n, err := h.chain.InsertChain(blocks) 232 if err == nil { 233 atomic.StoreUint32(&h.acceptTxs, 1) // Mark initial sync done on any fetcher import 234 } 235 return n, err 236 } 237 h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, h.BroadcastBlock, heighter, nil, inserter, h.removePeer) 238 239 fetchTx := func(peer string, hashes []common.Hash) error { 240 p := h.peers.peer(peer) 241 if p == nil { 242 return errors.New("unknown peer") 243 } 244 return p.RequestTxs(hashes) 245 } 246 h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, h.txpool.AddRemotes, fetchTx) 247 h.chainSync = newChainSyncer(h) 248 return h, nil 249 } 250 251 // runEthPeer registers an eth peer into the joint eth/snap peerset, adds it to 252 // various subsistems and starts handling messages. 253 func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { 254 // If the peer has a `snap` extension, wait for it to connect so we can have 255 // a uniform initialization/teardown mechanism 256 snap, err := h.peers.waitSnapExtension(peer) 257 if err != nil { 258 peer.Log().Error("Snapshot extension barrier failed", "err", err) 259 return err 260 } 261 diff, err := h.peers.waitDiffExtension(peer) 262 if err != nil { 263 peer.Log().Error("Diff extension barrier failed", "err", err) 264 return err 265 } 266 // TODO(karalabe): Not sure why this is needed 267 if !h.chainSync.handlePeerEvent(peer) { 268 return p2p.DiscQuitting 269 } 270 h.peerWG.Add(1) 271 defer h.peerWG.Done() 272 273 // Execute the Ethereum handshake 274 var ( 275 genesis = h.chain.Genesis() 276 head = h.chain.CurrentHeader() 277 hash = head.Hash() 278 number = head.Number.Uint64() 279 td = h.chain.GetTd(hash, number) 280 ) 281 forkID := forkid.NewID(h.chain.Config(), h.chain.Genesis().Hash(), h.chain.CurrentHeader().Number.Uint64()) 282 if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter, ð.UpgradeStatusExtension{DisablePeerTxBroadcast: h.disablePeerTxBroadcast}); err != nil { 283 peer.Log().Debug("Ethereum handshake failed", "err", err) 284 return err 285 } 286 reject := false // reserved peer slots 287 if atomic.LoadUint32(&h.snapSync) == 1 { 288 if snap == nil { 289 // If we are running snap-sync, we want to reserve roughly half the peer 290 // slots for peers supporting the snap protocol. 291 // The logic here is; we only allow up to 5 more non-snap peers than snap-peers. 292 if all, snp := h.peers.len(), h.peers.snapLen(); all-snp > snp+5 { 293 reject = true 294 } 295 } 296 } 297 // Ignore maxPeers if this is a trusted peer 298 if !peer.Peer.Info().Network.Trusted { 299 if reject || h.peers.len() >= h.maxPeers { 300 return p2p.DiscTooManyPeers 301 } 302 } 303 peer.Log().Debug("Ethereum peer connected", "name", peer.Name()) 304 305 // Register the peer locally 306 if err := h.peers.registerPeer(peer, snap, diff); err != nil { 307 peer.Log().Error("Ethereum peer registration failed", "err", err) 308 return err 309 } 310 defer h.removePeer(peer.ID()) 311 312 p := h.peers.peer(peer.ID()) 313 if p == nil { 314 return errors.New("peer dropped during handling") 315 } 316 // Register the peer in the downloader. If the downloader considers it banned, we disconnect 317 if err := h.downloader.RegisterPeer(peer.ID(), peer.Version(), peer); err != nil { 318 peer.Log().Error("Failed to register peer in eth syncer", "err", err) 319 return err 320 } 321 if snap != nil { 322 if err := h.downloader.SnapSyncer.Register(snap); err != nil { 323 peer.Log().Error("Failed to register peer in snap syncer", "err", err) 324 return err 325 } 326 } 327 h.chainSync.handlePeerEvent(peer) 328 329 // Propagate existing transactions. new transactions appearing 330 // after this will be sent via broadcasts. 331 h.syncTransactions(peer) 332 333 // If we have a trusted CHT, reject all peers below that (avoid fast sync eclipse) 334 if h.checkpointHash != (common.Hash{}) { 335 // Request the peer's checkpoint header for chain height/weight validation 336 if err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false); err != nil { 337 return err 338 } 339 // Start a timer to disconnect if the peer doesn't reply in time 340 p.syncDrop = time.AfterFunc(syncChallengeTimeout, func() { 341 peer.Log().Warn("Checkpoint challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) 342 h.removePeer(peer.ID()) 343 }) 344 // Make sure it's cleaned up if the peer dies off 345 defer func() { 346 if p.syncDrop != nil { 347 p.syncDrop.Stop() 348 p.syncDrop = nil 349 } 350 }() 351 } 352 // If we have any explicit whitelist block hashes, request them 353 for number := range h.whitelist { 354 if err := peer.RequestHeadersByNumber(number, 1, 0, false); err != nil { 355 return err 356 } 357 } 358 // Handle incoming messages until the connection is torn down 359 return handler(peer) 360 } 361 362 // runSnapExtension registers a `snap` peer into the joint eth/snap peerset and 363 // starts handling inbound messages. As `snap` is only a satellite protocol to 364 // `eth`, all subsystem registrations and lifecycle management will be done by 365 // the main `eth` handler to prevent strange races. 366 func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error { 367 h.peerWG.Add(1) 368 defer h.peerWG.Done() 369 370 if err := h.peers.registerSnapExtension(peer); err != nil { 371 peer.Log().Error("Snapshot extension registration failed", "err", err) 372 return err 373 } 374 return handler(peer) 375 } 376 377 // runDiffExtension registers a `diff` peer into the joint eth/diff peerset and 378 // starts handling inbound messages. As `diff` is only a satellite protocol to 379 // `eth`, all subsystem registrations and lifecycle management will be done by 380 // the main `eth` handler to prevent strange races. 381 func (h *handler) runDiffExtension(peer *diff.Peer, handler diff.Handler) error { 382 h.peerWG.Add(1) 383 defer h.peerWG.Done() 384 385 if err := h.peers.registerDiffExtension(peer); err != nil { 386 peer.Log().Error("Diff extension registration failed", "err", err) 387 return err 388 } 389 return handler(peer) 390 } 391 392 // removePeer unregisters a peer from the downloader and fetchers, removes it from 393 // the set of tracked peers and closes the network connection to it. 394 func (h *handler) removePeer(id string) { 395 // Create a custom logger to avoid printing the entire id 396 var logger log.Logger 397 if len(id) < 16 { 398 // Tests use short IDs, don't choke on them 399 logger = log.New("peer", id) 400 } else { 401 logger = log.New("peer", id[:8]) 402 } 403 // Abort if the peer does not exist 404 peer := h.peers.peer(id) 405 if peer == nil { 406 logger.Error("Ethereum peer removal failed", "err", errPeerNotRegistered) 407 return 408 } 409 // Remove the `eth` peer if it exists 410 logger.Debug("Removing Ethereum peer", "snap", peer.snapExt != nil) 411 412 // Remove the `snap` extension if it exists 413 if peer.snapExt != nil { 414 h.downloader.SnapSyncer.Unregister(id) 415 } 416 h.downloader.UnregisterPeer(id) 417 h.txFetcher.Drop(id) 418 419 if err := h.peers.unregisterPeer(id); err != nil { 420 logger.Error("Ethereum peer removal failed", "err", err) 421 } 422 // Hard disconnect at the networking layer 423 peer.Peer.Disconnect(p2p.DiscUselessPeer) 424 } 425 426 func (h *handler) Start(maxPeers int) { 427 h.maxPeers = maxPeers 428 429 // broadcast transactions 430 h.wg.Add(1) 431 h.txsCh = make(chan core.NewTxsEvent, txChanSize) 432 h.txsSub = h.txpool.SubscribeNewTxsEvent(h.txsCh) 433 go h.txBroadcastLoop() 434 435 // broadcast mined blocks 436 h.wg.Add(1) 437 h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}) 438 go h.minedBroadcastLoop() 439 440 // start sync handlers 441 h.wg.Add(2) 442 go h.chainSync.loop() 443 go h.txsyncLoop64() // TODO(karalabe): Legacy initial tx echange, drop with eth/64. 444 } 445 446 func (h *handler) Stop() { 447 h.txsSub.Unsubscribe() // quits txBroadcastLoop 448 h.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop 449 450 // Quit chainSync and txsync64. 451 // After this is done, no new peers will be accepted. 452 close(h.quitSync) 453 h.wg.Wait() 454 455 // Disconnect existing sessions. 456 // This also closes the gate for any new registrations on the peer set. 457 // sessions which are already established but not added to h.peers yet 458 // will exit when they try to register. 459 h.peers.close() 460 h.peerWG.Wait() 461 462 log.Info("Ethereum protocol stopped") 463 } 464 465 // BroadcastBlock will either propagate a block to a subset of its peers, or 466 // will only announce its availability (depending what's requested). 467 func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { 468 hash := block.Hash() 469 peers := h.peers.peersWithoutBlock(hash) 470 471 // If propagation is requested, send to a subset of the peer 472 if propagate { 473 // Calculate the TD of the block (it's not imported yet, so block.Td is not valid) 474 var td *big.Int 475 if parent := h.chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent != nil { 476 td = new(big.Int).Add(block.Difficulty(), h.chain.GetTd(block.ParentHash(), block.NumberU64()-1)) 477 } else { 478 log.Error("Propagating dangling block", "number", block.Number(), "hash", hash) 479 return 480 } 481 // Send the block to a subset of our peers 482 var transfer []*ethPeer 483 if h.directBroadcast { 484 transfer = peers[:] 485 } else { 486 transfer = peers[:int(math.Sqrt(float64(len(peers))))] 487 } 488 diff := h.chain.GetDiffLayerRLP(block.Hash()) 489 for _, peer := range transfer { 490 if len(diff) != 0 && peer.diffExt != nil { 491 // difflayer should send before block 492 peer.diffExt.SendDiffLayers([]rlp.RawValue{diff}) 493 } 494 peer.AsyncSendNewBlock(block, td) 495 } 496 497 log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) 498 return 499 } 500 // Otherwise if the block is indeed in out own chain, announce it 501 if h.chain.HasBlock(hash, block.NumberU64()) { 502 for _, peer := range peers { 503 peer.AsyncSendNewBlockHash(block) 504 } 505 log.Trace("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) 506 } 507 } 508 509 // BroadcastTransactions will propagate a batch of transactions 510 // - To a square root of all peers 511 // - And, separately, as announcements to all peers which are not known to 512 // already have the given transaction. 513 func (h *handler) BroadcastTransactions(txs types.Transactions) { 514 var ( 515 annoCount int // Count of announcements made 516 annoPeers int 517 directCount int // Count of the txs sent directly to peers 518 directPeers int // Count of the peers that were sent transactions directly 519 520 txset = make(map[*ethPeer][]common.Hash) // Set peer->hash to transfer directly 521 annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce 522 523 ) 524 // Broadcast transactions to a batch of peers not knowing about it 525 for _, tx := range txs { 526 peers := h.peers.peersWithoutTransaction(tx.Hash()) 527 // Send the tx unconditionally to a subset of our peers 528 numDirect := int(math.Sqrt(float64(len(peers)))) 529 for _, peer := range peers[:numDirect] { 530 txset[peer] = append(txset[peer], tx.Hash()) 531 } 532 // For the remaining peers, send announcement only 533 for _, peer := range peers[numDirect:] { 534 annos[peer] = append(annos[peer], tx.Hash()) 535 } 536 } 537 for peer, hashes := range txset { 538 directPeers++ 539 directCount += len(hashes) 540 peer.AsyncSendTransactions(hashes) 541 } 542 for peer, hashes := range annos { 543 annoPeers++ 544 annoCount += len(hashes) 545 peer.AsyncSendPooledTransactionHashes(hashes) 546 } 547 log.Debug("Transaction broadcast", "txs", len(txs), 548 "announce packs", annoPeers, "announced hashes", annoCount, 549 "tx packs", directPeers, "broadcast txs", directCount) 550 } 551 552 // minedBroadcastLoop sends mined blocks to connected peers. 553 func (h *handler) minedBroadcastLoop() { 554 defer h.wg.Done() 555 556 for obj := range h.minedBlockSub.Chan() { 557 if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok { 558 h.BroadcastBlock(ev.Block, true) // First propagate block to peers 559 h.BroadcastBlock(ev.Block, false) // Only then announce to the rest 560 } 561 } 562 } 563 564 // txBroadcastLoop announces new transactions to connected peers. 565 func (h *handler) txBroadcastLoop() { 566 defer h.wg.Done() 567 for { 568 select { 569 case event := <-h.txsCh: 570 h.BroadcastTransactions(event.Txs) 571 case <-h.txsSub.Err(): 572 return 573 } 574 } 575 }