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