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