github.com/alex403s/heco-chain@v1.2.3-0.20220611014610-f10f4107d8b9/eth/backend.go (about) 1 // Copyright 2014 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 implements the Ethereum protocol. 18 package eth 19 20 import ( 21 "errors" 22 "fmt" 23 "math/big" 24 "runtime" 25 "sync" 26 "sync/atomic" 27 "time" 28 29 "github.com/ethereum/go-ethereum/accounts" 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/common/hexutil" 32 "github.com/ethereum/go-ethereum/consensus" 33 "github.com/ethereum/go-ethereum/consensus/clique" 34 "github.com/ethereum/go-ethereum/consensus/congress" 35 "github.com/ethereum/go-ethereum/core" 36 "github.com/ethereum/go-ethereum/core/bloombits" 37 "github.com/ethereum/go-ethereum/core/rawdb" 38 "github.com/ethereum/go-ethereum/core/state/pruner" 39 "github.com/ethereum/go-ethereum/core/types" 40 "github.com/ethereum/go-ethereum/core/vm" 41 "github.com/ethereum/go-ethereum/eth/downloader" 42 "github.com/ethereum/go-ethereum/eth/ethconfig" 43 "github.com/ethereum/go-ethereum/eth/filters" 44 "github.com/ethereum/go-ethereum/eth/gasprice" 45 "github.com/ethereum/go-ethereum/eth/protocols/eth" 46 "github.com/ethereum/go-ethereum/eth/protocols/snap" 47 "github.com/ethereum/go-ethereum/ethdb" 48 "github.com/ethereum/go-ethereum/event" 49 "github.com/ethereum/go-ethereum/internal/ethapi" 50 "github.com/ethereum/go-ethereum/log" 51 "github.com/ethereum/go-ethereum/miner" 52 "github.com/ethereum/go-ethereum/node" 53 "github.com/ethereum/go-ethereum/p2p" 54 "github.com/ethereum/go-ethereum/p2p/dnsdisc" 55 "github.com/ethereum/go-ethereum/p2p/enode" 56 "github.com/ethereum/go-ethereum/params" 57 "github.com/ethereum/go-ethereum/rlp" 58 "github.com/ethereum/go-ethereum/rpc" 59 ) 60 61 // Config contains the configuration options of the ETH protocol. 62 // Deprecated: use ethconfig.Config instead. 63 type Config = ethconfig.Config 64 65 // Ethereum implements the Ethereum full node service. 66 type Ethereum struct { 67 config *ethconfig.Config 68 69 // Handlers 70 txPool *core.TxPool 71 blockchain *core.BlockChain 72 handler *handler 73 ethDialCandidates enode.Iterator 74 snapDialCandidates enode.Iterator 75 76 // DB interfaces 77 chainDb ethdb.Database // Block chain database 78 79 eventMux *event.TypeMux 80 engine consensus.Engine 81 accountManager *accounts.Manager 82 83 isPoSA bool 84 posa consensus.PoSA 85 86 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 87 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 88 closeBloomHandler chan struct{} 89 90 APIBackend *EthAPIBackend 91 92 miner *miner.Miner 93 gasPrice *big.Int 94 etherbase common.Address 95 96 networkID uint64 97 netRPCService *ethapi.PublicNetAPI 98 99 p2pServer *p2p.Server 100 101 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 102 } 103 104 // New creates a new Ethereum object (including the 105 // initialisation of the common Ethereum object) 106 func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { 107 // Ensure configuration values are compatible and sane 108 if config.SyncMode == downloader.LightSync { 109 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 110 } 111 if !config.SyncMode.IsValid() { 112 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 113 } 114 if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { 115 log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) 116 config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) 117 } 118 if config.NoPruning && config.TrieDirtyCache > 0 { 119 if config.SnapshotCache > 0 { 120 config.TrieCleanCache += config.TrieDirtyCache * 3 / 5 121 config.SnapshotCache += config.TrieDirtyCache * 2 / 5 122 } else { 123 config.TrieCleanCache += config.TrieDirtyCache 124 } 125 config.TrieDirtyCache = 0 126 } 127 log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) 128 129 // Transfer mining-related config to the ethash config. 130 ethashConfig := config.Ethash 131 ethashConfig.NotifyFull = config.Miner.NotifyFull 132 133 // Assemble the Ethereum object 134 chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) 135 if err != nil { 136 return nil, err 137 } 138 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideArrowGlacier) 139 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 140 return nil, genesisErr 141 } 142 log.Info("Initialised chain configuration", "config", chainConfig) 143 144 if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { 145 log.Error("Failed to recover state", "error", err) 146 } 147 eth := &Ethereum{ 148 config: config, 149 chainDb: chainDb, 150 eventMux: stack.EventMux(), 151 accountManager: stack.AccountManager(), 152 engine: ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb), 153 closeBloomHandler: make(chan struct{}), 154 networkID: config.NetworkId, 155 gasPrice: config.Miner.GasPrice, 156 etherbase: config.Miner.Etherbase, 157 bloomRequests: make(chan chan *bloombits.Retrieval), 158 bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 159 p2pServer: stack.Server(), 160 } 161 eth.posa, eth.isPoSA = eth.engine.(consensus.PoSA) 162 163 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 164 var dbVer = "<nil>" 165 if bcVersion != nil { 166 dbVer = fmt.Sprintf("%d", *bcVersion) 167 } 168 log.Info("Initialising Ethereum protocol", "network", config.NetworkId, "dbversion", dbVer) 169 170 if !config.SkipBcVersionCheck { 171 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 172 return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 173 } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { 174 if bcVersion != nil { // only print warning on upgrade, not on init 175 log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) 176 } 177 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 178 } 179 } 180 var ( 181 vmConfig = vm.Config{ 182 EnablePreimageRecording: config.EnablePreimageRecording, 183 } 184 cacheConfig = &core.CacheConfig{ 185 TrieCleanLimit: config.TrieCleanCache, 186 TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), 187 TrieCleanRejournal: config.TrieCleanCacheRejournal, 188 TrieCleanNoPrefetch: config.NoPrefetch, 189 TrieDirtyLimit: config.TrieDirtyCache, 190 TrieDirtyDisabled: config.NoPruning, 191 TrieTimeLimit: config.TrieTimeout, 192 SnapshotLimit: config.SnapshotCache, 193 Preimages: config.Preimages, 194 } 195 ) 196 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) 197 if err != nil { 198 return nil, err 199 } 200 // Rewind the chain in case of an incompatible config upgrade. 201 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 202 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 203 eth.blockchain.SetHead(compat.RewindTo) 204 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 205 } 206 eth.bloomIndexer.Start(eth.blockchain) 207 208 if config.TxPool.Journal != "" { 209 config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) 210 } 211 eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain) 212 213 // do some extra work if consensus engine is congress. 214 if congressEngine, ok := eth.engine.(*congress.Congress); ok { 215 // set state fn 216 congressEngine.SetStateFn(eth.blockchain.StateAt) 217 // set consensus-related transaction validator 218 eth.txPool.InitExTxValidator(congressEngine) 219 // 220 congressEngine.SetChain(eth.blockchain) 221 } 222 223 // Permit the downloader to use the trie cache allowance during fast sync 224 cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit 225 checkpoint := config.Checkpoint 226 if checkpoint == nil { 227 checkpoint = params.TrustedCheckpoints[genesisHash] 228 } 229 if eth.handler, err = newHandler(&handlerConfig{ 230 Database: chainDb, 231 Chain: eth.blockchain, 232 TxPool: eth.txPool, 233 Network: config.NetworkId, 234 Sync: config.SyncMode, 235 BloomCache: uint64(cacheLimit), 236 EventMux: eth.eventMux, 237 Checkpoint: checkpoint, 238 Whitelist: config.Whitelist, 239 }); err != nil { 240 return nil, err 241 } 242 243 eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) 244 eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) 245 246 eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil, nil} 247 if eth.APIBackend.allowUnprotectedTxs { 248 log.Info("Unprotected transactions allowed") 249 } 250 gpoParams := config.GPO 251 if gpoParams.Default == nil { 252 gpoParams.Default = config.Miner.GasPrice 253 } 254 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 255 256 // Setup DNS discovery iterators. 257 dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) 258 eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) 259 if err != nil { 260 return nil, err 261 } 262 eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...) 263 if err != nil { 264 return nil, err 265 } 266 267 // Start the RPC service 268 eth.netRPCService = ethapi.NewPublicNetAPI(eth.p2pServer, config.NetworkId) 269 270 // Register the backend on the node 271 stack.RegisterAPIs(eth.APIs()) 272 stack.RegisterProtocols(eth.Protocols()) 273 stack.RegisterLifecycle(eth) 274 275 // gas price prediction 276 gppCfg := checkPricePredictionConfig(&gpoParams) 277 eth.APIBackend.gpp = gasprice.NewPrediction(*gppCfg, eth.APIBackend, eth.txPool) 278 279 // Check for unclean shutdown 280 if uncleanShutdowns, discards, err := rawdb.PushUncleanShutdownMarker(chainDb); err != nil { 281 log.Error("Could not update unclean-shutdown-marker list", "error", err) 282 } else { 283 if discards > 0 { 284 log.Warn("Old unclean shutdowns found", "count", discards) 285 } 286 for _, tstamp := range uncleanShutdowns { 287 t := time.Unix(int64(tstamp), 0) 288 log.Warn("Unclean shutdown detected", "booted", t, 289 "age", common.PrettyAge(t)) 290 } 291 } 292 return eth, nil 293 } 294 295 func checkPricePredictionConfig(cfg *gasprice.Config) *gasprice.Config { 296 if cfg == nil { 297 cfg1 := ethconfig.FullNodeGPO 298 return &cfg1 299 } 300 defaultConf := ethconfig.FullNodeGPO 301 if cfg.PredictIntervalSecs == 0 { 302 cfg.PredictIntervalSecs = defaultConf.PredictIntervalSecs 303 } 304 if cfg.MinTxCntPerBlock == 0 { 305 cfg.MinTxCntPerBlock = defaultConf.MinTxCntPerBlock 306 } 307 308 if cfg.MinMedianIndex == 0 { 309 cfg.MinMedianIndex = defaultConf.MinMedianIndex 310 } 311 if cfg.MinLowIndex == 0 { 312 cfg.MinLowIndex = defaultConf.MinLowIndex 313 } 314 if cfg.FastPercentile == 0 { 315 cfg.FastPercentile = defaultConf.FastPercentile 316 } 317 if cfg.MeidanPercentile == 0 { 318 cfg.MeidanPercentile = defaultConf.MeidanPercentile 319 } 320 if cfg.FastFactor == 0 { 321 cfg.FastFactor = defaultConf.FastFactor 322 } 323 if cfg.MedianFactor == 0 { 324 cfg.MedianFactor = defaultConf.MedianFactor 325 } 326 if cfg.LowFactor == 0 { 327 cfg.LowFactor = defaultConf.LowFactor 328 } 329 if cfg.MaxValidPendingSecs == 0 { 330 cfg.MaxValidPendingSecs = defaultConf.MaxValidPendingSecs 331 } 332 return cfg 333 } 334 335 func makeExtraData(extra []byte) []byte { 336 if len(extra) == 0 { 337 // create default extradata 338 extra, _ = rlp.EncodeToBytes([]interface{}{ 339 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 340 "geth", 341 runtime.Version(), 342 runtime.GOOS, 343 }) 344 } 345 if uint64(len(extra)) > params.MaximumExtraDataSize { 346 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 347 extra = nil 348 } 349 return extra 350 } 351 352 // APIs return the collection of RPC services the ethereum package offers. 353 // NOTE, some of these services probably need to be moved to somewhere else. 354 func (s *Ethereum) APIs() []rpc.API { 355 apis := ethapi.GetAPIs(s.APIBackend) 356 357 // Append any APIs exposed explicitly by the consensus engine 358 apis = append(apis, s.engine.APIs(s.BlockChain())...) 359 360 // Append all the local APIs and return 361 return append(apis, []rpc.API{ 362 { 363 Namespace: "eth", 364 Version: "1.0", 365 Service: NewPublicEthereumAPI(s), 366 Public: true, 367 }, { 368 Namespace: "eth", 369 Version: "1.0", 370 Service: NewPublicMinerAPI(s), 371 Public: true, 372 }, { 373 Namespace: "eth", 374 Version: "1.0", 375 Service: downloader.NewPublicDownloaderAPI(s.handler.downloader, s.eventMux), 376 Public: true, 377 }, { 378 Namespace: "miner", 379 Version: "1.0", 380 Service: NewPrivateMinerAPI(s), 381 Public: false, 382 }, { 383 Namespace: "eth", 384 Version: "1.0", 385 Service: filters.NewPublicFilterAPI(s.APIBackend, false, 5*time.Minute), 386 Public: true, 387 }, { 388 Namespace: "admin", 389 Version: "1.0", 390 Service: NewPrivateAdminAPI(s), 391 }, { 392 Namespace: "debug", 393 Version: "1.0", 394 Service: NewPublicDebugAPI(s), 395 Public: true, 396 }, { 397 Namespace: "debug", 398 Version: "1.0", 399 Service: NewPrivateDebugAPI(s), 400 }, { 401 Namespace: "net", 402 Version: "1.0", 403 Service: s.netRPCService, 404 Public: true, 405 }, 406 }...) 407 } 408 409 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 410 s.blockchain.ResetWithGenesisBlock(gb) 411 } 412 413 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 414 s.lock.RLock() 415 etherbase := s.etherbase 416 s.lock.RUnlock() 417 418 if etherbase != (common.Address{}) { 419 return etherbase, nil 420 } 421 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 422 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 423 etherbase := accounts[0].Address 424 425 s.lock.Lock() 426 s.etherbase = etherbase 427 s.lock.Unlock() 428 429 log.Info("Etherbase automatically configured", "address", etherbase) 430 return etherbase, nil 431 } 432 } 433 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 434 } 435 436 // isLocalBlock checks whether the specified block is mined 437 // by local miner accounts. 438 // 439 // We regard two types of accounts as local miner account: etherbase 440 // and accounts specified via `txpool.locals` flag. 441 func (s *Ethereum) isLocalBlock(block *types.Block) bool { 442 author, err := s.engine.Author(block.Header()) 443 if err != nil { 444 log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err) 445 return false 446 } 447 // Check whether the given address is etherbase. 448 s.lock.RLock() 449 etherbase := s.etherbase 450 s.lock.RUnlock() 451 if author == etherbase { 452 return true 453 } 454 // Check whether the given address is specified by `txpool.local` 455 // CLI flag. 456 for _, account := range s.config.TxPool.Locals { 457 if account == author { 458 return true 459 } 460 } 461 return false 462 } 463 464 // shouldPreserve checks whether we should preserve the given block 465 // during the chain reorg depending on whether the author of block 466 // is a local account. 467 func (s *Ethereum) shouldPreserve(block *types.Block) bool { 468 // The reason we need to disable the self-reorg preserving for clique 469 // is it can be probable to introduce a deadlock. 470 // 471 // e.g. If there are 7 available signers 472 // 473 // r1 A 474 // r2 B 475 // r3 C 476 // r4 D 477 // r5 A [X] F G 478 // r6 [X] 479 // 480 // In the round5, the inturn signer E is offline, so the worst case 481 // is A, F and G sign the block of round5 and reject the block of opponents 482 // and in the round6, the last available signer B is offline, the whole 483 // network is stuck. 484 if _, ok := s.engine.(*clique.Clique); ok { 485 return false 486 } 487 if _, ok := s.engine.(*congress.Congress); ok { 488 return false 489 } 490 return s.isLocalBlock(block) 491 } 492 493 // SetEtherbase sets the mining reward address. 494 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 495 s.lock.Lock() 496 s.etherbase = etherbase 497 s.lock.Unlock() 498 499 s.miner.SetEtherbase(etherbase) 500 } 501 502 // StartMining starts the miner with the given number of CPU threads. If mining 503 // is already running, this method adjust the number of threads allowed to use 504 // and updates the minimum price required by the transaction pool. 505 func (s *Ethereum) StartMining(threads int) error { 506 // Update the thread count within the consensus engine 507 type threaded interface { 508 SetThreads(threads int) 509 } 510 if th, ok := s.engine.(threaded); ok { 511 log.Info("Updated mining threads", "threads", threads) 512 if threads == 0 { 513 threads = -1 // Disable the miner from within 514 } 515 th.SetThreads(threads) 516 } 517 // If the miner was not running, initialize it 518 if !s.IsMining() { 519 // Propagate the initial price point to the transaction pool 520 s.lock.RLock() 521 price := s.gasPrice 522 s.lock.RUnlock() 523 s.txPool.SetGasPrice(price) 524 525 // Configure the local mining address 526 eb, err := s.Etherbase() 527 if err != nil { 528 log.Error("Cannot start mining without etherbase", "err", err) 529 return fmt.Errorf("etherbase missing: %v", err) 530 } 531 if clique, ok := s.engine.(*clique.Clique); ok { 532 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 533 if wallet == nil || err != nil { 534 log.Error("Etherbase account unavailable locally", "err", err) 535 return fmt.Errorf("signer missing: %v", err) 536 } 537 clique.Authorize(eb, wallet.SignData) 538 } 539 if congress, ok := s.engine.(*congress.Congress); ok { 540 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 541 if wallet == nil || err != nil { 542 log.Error("Etherbase account unavailable locally", "err", err) 543 return fmt.Errorf("signer missing: %v", err) 544 } 545 congress.Authorize(eb, wallet.SignData, wallet.SignTx) 546 } 547 // If mining is started, we can disable the transaction rejection mechanism 548 // introduced to speed sync times. 549 atomic.StoreUint32(&s.handler.acceptTxs, 1) 550 551 go s.miner.Start(eb) 552 } 553 return nil 554 } 555 556 // StopMining terminates the miner, both at the consensus engine level as well as 557 // at the block creation level. 558 func (s *Ethereum) StopMining() { 559 // Update the thread count within the consensus engine 560 type threaded interface { 561 SetThreads(threads int) 562 } 563 if th, ok := s.engine.(threaded); ok { 564 th.SetThreads(-1) 565 } 566 // Stop the block creating itself 567 s.miner.Stop() 568 } 569 570 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 571 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 572 573 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 574 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 575 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 576 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 577 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 578 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 579 func (s *Ethereum) IsListening() bool { return true } // Always listening 580 func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } 581 func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.handler.acceptTxs) == 1 } 582 func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } 583 func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } 584 585 // Protocols returns all the currently configured 586 // network protocols to start. 587 func (s *Ethereum) Protocols() []p2p.Protocol { 588 protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) 589 if s.config.SnapshotCache > 0 { 590 protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) 591 } 592 return protos 593 } 594 595 // Start implements node.Lifecycle, starting all internal goroutines needed by the 596 // Ethereum protocol implementation. 597 func (s *Ethereum) Start() error { 598 eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) 599 600 // Start the bloom bits servicing goroutines 601 s.startBloomHandlers(params.BloomBitsBlocks) 602 603 // Figure out a max peers count based on the server limits 604 maxPeers := s.p2pServer.MaxPeers 605 if s.config.LightServ > 0 { 606 if s.config.LightPeers >= s.p2pServer.MaxPeers { 607 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) 608 } 609 maxPeers -= s.config.LightPeers 610 } 611 // Start the networking layer and the light server if requested 612 s.handler.Start(maxPeers) 613 return nil 614 } 615 616 // Stop implements node.Lifecycle, terminating all internal goroutines used by the 617 // Ethereum protocol. 618 func (s *Ethereum) Stop() error { 619 // Stop all the peer-related stuff first. 620 s.ethDialCandidates.Close() 621 s.snapDialCandidates.Close() 622 s.handler.Stop() 623 624 // Then stop everything else. 625 s.bloomIndexer.Close() 626 close(s.closeBloomHandler) 627 s.txPool.Stop() 628 s.miner.Close() 629 s.blockchain.Stop() 630 s.engine.Close() 631 rawdb.PopUncleanShutdownMarker(s.chainDb) 632 s.chainDb.Close() 633 s.eventMux.Stop() 634 635 return nil 636 }