github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/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 "strings" 26 "sync" 27 "sync/atomic" 28 29 "github.com/ethw3/go-ethereuma/accounts" 30 "github.com/ethw3/go-ethereuma/common" 31 "github.com/ethw3/go-ethereuma/common/hexutil" 32 "github.com/ethw3/go-ethereuma/consensus" 33 "github.com/ethw3/go-ethereuma/consensus/beacon" 34 "github.com/ethw3/go-ethereuma/consensus/clique" 35 "github.com/ethw3/go-ethereuma/core" 36 "github.com/ethw3/go-ethereuma/core/bloombits" 37 "github.com/ethw3/go-ethereuma/core/rawdb" 38 "github.com/ethw3/go-ethereuma/core/state/pruner" 39 "github.com/ethw3/go-ethereuma/core/types" 40 "github.com/ethw3/go-ethereuma/core/vm" 41 "github.com/ethw3/go-ethereuma/eth/downloader" 42 "github.com/ethw3/go-ethereuma/eth/ethconfig" 43 "github.com/ethw3/go-ethereuma/eth/gasprice" 44 "github.com/ethw3/go-ethereuma/eth/protocols/eth" 45 "github.com/ethw3/go-ethereuma/eth/protocols/snap" 46 "github.com/ethw3/go-ethereuma/ethdb" 47 "github.com/ethw3/go-ethereuma/event" 48 "github.com/ethw3/go-ethereuma/internal/ethapi" 49 "github.com/ethw3/go-ethereuma/internal/shutdowncheck" 50 "github.com/ethw3/go-ethereuma/log" 51 "github.com/ethw3/go-ethereuma/miner" 52 "github.com/ethw3/go-ethereuma/node" 53 "github.com/ethw3/go-ethereuma/p2p" 54 "github.com/ethw3/go-ethereuma/p2p/dnsdisc" 55 "github.com/ethw3/go-ethereuma/p2p/enode" 56 "github.com/ethw3/go-ethereuma/params" 57 "github.com/ethw3/go-ethereuma/rlp" 58 "github.com/ethw3/go-ethereuma/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 merger *consensus.Merger 76 77 // DB interfaces 78 chainDb ethdb.Database // Block chain database 79 80 eventMux *event.TypeMux 81 engine consensus.Engine 82 accountManager *accounts.Manager 83 84 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 85 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 86 closeBloomHandler chan struct{} 87 88 APIBackend *EthAPIBackend 89 90 miner *miner.Miner 91 gasPrice *big.Int 92 etherbase common.Address 93 94 networkID uint64 95 netRPCService *ethapi.NetAPI 96 97 p2pServer *p2p.Server 98 99 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 100 101 shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully 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.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed) 139 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 140 return nil, genesisErr 141 } 142 143 if !config.IsNetworkIdSet && chainConfig != nil { 144 if chainConfig.ChainID_ALT != nil && chainConfig.EthPoWForkSupport { 145 config.NetworkId = chainConfig.ChainID_ALT.Uint64() 146 } 147 } 148 149 log.Info("") 150 log.Info(strings.Repeat("-", 153)) 151 for _, line := range strings.Split(chainConfig.String(), "\n") { 152 log.Info(line) 153 } 154 log.Info(strings.Repeat("-", 153)) 155 log.Info("") 156 157 if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { 158 log.Error("Failed to recover state", "error", err) 159 } 160 merger := consensus.NewMerger(chainDb) 161 eth := &Ethereum{ 162 config: config, 163 merger: merger, 164 chainDb: chainDb, 165 eventMux: stack.EventMux(), 166 accountManager: stack.AccountManager(), 167 engine: ethconfig.CreateConsensusEngine(stack, chainConfig, ðashConfig, config.Miner.Notify, config.Miner.Noverify, chainDb), 168 closeBloomHandler: make(chan struct{}), 169 networkID: config.NetworkId, 170 gasPrice: config.Miner.GasPrice, 171 etherbase: config.Miner.Etherbase, 172 bloomRequests: make(chan chan *bloombits.Retrieval), 173 bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 174 p2pServer: stack.Server(), 175 shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), 176 } 177 178 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 179 var dbVer = "<nil>" 180 if bcVersion != nil { 181 dbVer = fmt.Sprintf("%d", *bcVersion) 182 } 183 log.Info("Initialising Ethereum protocol", "network", config.NetworkId, "dbversion", dbVer) 184 185 if !config.SkipBcVersionCheck { 186 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 187 return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 188 } else if bcVersion == nil || *bcVersion < core.BlockChainVersion { 189 if bcVersion != nil { // only print warning on upgrade, not on init 190 log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) 191 } 192 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 193 } 194 } 195 var ( 196 vmConfig = vm.Config{ 197 EnablePreimageRecording: config.EnablePreimageRecording, 198 } 199 cacheConfig = &core.CacheConfig{ 200 TrieCleanLimit: config.TrieCleanCache, 201 TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), 202 TrieCleanRejournal: config.TrieCleanCacheRejournal, 203 TrieCleanNoPrefetch: config.NoPrefetch, 204 TrieDirtyLimit: config.TrieDirtyCache, 205 TrieDirtyDisabled: config.NoPruning, 206 TrieTimeLimit: config.TrieTimeout, 207 SnapshotLimit: config.SnapshotCache, 208 Preimages: config.Preimages, 209 } 210 ) 211 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) 212 if err != nil { 213 return nil, err 214 } 215 // Rewind the chain in case of an incompatible config upgrade. 216 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 217 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 218 eth.blockchain.SetHead(compat.RewindTo) 219 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 220 } 221 eth.bloomIndexer.Start(eth.blockchain) 222 223 if config.TxPool.Journal != "" { 224 config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) 225 } 226 eth.txPool = core.NewTxPool(config.TxPool, chainConfig, eth.blockchain) 227 228 // Permit the downloader to use the trie cache allowance during fast sync 229 cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit 230 checkpoint := config.Checkpoint 231 if checkpoint == nil { 232 checkpoint = params.TrustedCheckpoints[genesisHash] 233 } 234 if eth.handler, err = newHandler(&handlerConfig{ 235 Database: chainDb, 236 Chain: eth.blockchain, 237 TxPool: eth.txPool, 238 Merger: merger, 239 Network: config.NetworkId, 240 Sync: config.SyncMode, 241 BloomCache: uint64(cacheLimit), 242 EventMux: eth.eventMux, 243 Checkpoint: checkpoint, 244 RequiredBlocks: config.RequiredBlocks, 245 }); err != nil { 246 return nil, err 247 } 248 249 eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) 250 eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) 251 252 eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} 253 if eth.APIBackend.allowUnprotectedTxs { 254 log.Info("Unprotected transactions allowed") 255 } 256 gpoParams := config.GPO 257 if gpoParams.Default == nil { 258 gpoParams.Default = config.Miner.GasPrice 259 } 260 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 261 262 // Setup DNS discovery iterators. 263 dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) 264 eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) 265 if err != nil { 266 return nil, err 267 } 268 eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...) 269 if err != nil { 270 return nil, err 271 } 272 273 // Start the RPC service 274 eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, config.NetworkId) 275 276 // Register the backend on the node 277 stack.RegisterAPIs(eth.APIs()) 278 stack.RegisterProtocols(eth.Protocols()) 279 stack.RegisterLifecycle(eth) 280 281 // Successful startup; push a marker and check previous unclean shutdowns. 282 eth.shutdownTracker.MarkStartup() 283 284 return eth, nil 285 } 286 287 func makeExtraData(extra []byte) []byte { 288 if len(extra) == 0 { 289 // create default extradata 290 extra, _ = rlp.EncodeToBytes([]interface{}{ 291 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 292 "geth", 293 runtime.Version(), 294 runtime.GOOS, 295 }) 296 } 297 if uint64(len(extra)) > params.MaximumExtraDataSize { 298 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 299 extra = nil 300 } 301 return extra 302 } 303 304 // APIs return the collection of RPC services the ethereum package offers. 305 // NOTE, some of these services probably need to be moved to somewhere else. 306 func (s *Ethereum) APIs() []rpc.API { 307 apis := ethapi.GetAPIs(s.APIBackend) 308 309 // Append any APIs exposed explicitly by the consensus engine 310 apis = append(apis, s.engine.APIs(s.BlockChain())...) 311 312 // Append all the local APIs and return 313 return append(apis, []rpc.API{ 314 { 315 Namespace: "eth", 316 Service: NewEthereumAPI(s), 317 }, { 318 Namespace: "miner", 319 Service: NewMinerAPI(s), 320 }, { 321 Namespace: "eth", 322 Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), 323 }, { 324 Namespace: "admin", 325 Service: NewAdminAPI(s), 326 }, { 327 Namespace: "debug", 328 Service: NewDebugAPI(s), 329 }, { 330 Namespace: "net", 331 Service: s.netRPCService, 332 }, 333 }...) 334 } 335 336 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 337 s.blockchain.ResetWithGenesisBlock(gb) 338 } 339 340 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 341 s.lock.RLock() 342 etherbase := s.etherbase 343 s.lock.RUnlock() 344 345 if etherbase != (common.Address{}) { 346 return etherbase, nil 347 } 348 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 349 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 350 etherbase := accounts[0].Address 351 352 s.lock.Lock() 353 s.etherbase = etherbase 354 s.lock.Unlock() 355 356 log.Info("Etherbase automatically configured", "address", etherbase) 357 return etherbase, nil 358 } 359 } 360 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 361 } 362 363 // isLocalBlock checks whether the specified block is mined 364 // by local miner accounts. 365 // 366 // We regard two types of accounts as local miner account: etherbase 367 // and accounts specified via `txpool.locals` flag. 368 func (s *Ethereum) isLocalBlock(header *types.Header) bool { 369 author, err := s.engine.Author(header) 370 if err != nil { 371 log.Warn("Failed to retrieve block author", "number", header.Number.Uint64(), "hash", header.Hash(), "err", err) 372 return false 373 } 374 // Check whether the given address is etherbase. 375 s.lock.RLock() 376 etherbase := s.etherbase 377 s.lock.RUnlock() 378 if author == etherbase { 379 return true 380 } 381 // Check whether the given address is specified by `txpool.local` 382 // CLI flag. 383 for _, account := range s.config.TxPool.Locals { 384 if account == author { 385 return true 386 } 387 } 388 return false 389 } 390 391 // shouldPreserve checks whether we should preserve the given block 392 // during the chain reorg depending on whether the author of block 393 // is a local account. 394 func (s *Ethereum) shouldPreserve(header *types.Header) bool { 395 // The reason we need to disable the self-reorg preserving for clique 396 // is it can be probable to introduce a deadlock. 397 // 398 // e.g. If there are 7 available signers 399 // 400 // r1 A 401 // r2 B 402 // r3 C 403 // r4 D 404 // r5 A [X] F G 405 // r6 [X] 406 // 407 // In the round5, the inturn signer E is offline, so the worst case 408 // is A, F and G sign the block of round5 and reject the block of opponents 409 // and in the round6, the last available signer B is offline, the whole 410 // network is stuck. 411 if _, ok := s.engine.(*clique.Clique); ok { 412 return false 413 } 414 return s.isLocalBlock(header) 415 } 416 417 // SetEtherbase sets the mining reward address. 418 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 419 s.lock.Lock() 420 s.etherbase = etherbase 421 s.lock.Unlock() 422 423 s.miner.SetEtherbase(etherbase) 424 } 425 426 // StartMining starts the miner with the given number of CPU threads. If mining 427 // is already running, this method adjust the number of threads allowed to use 428 // and updates the minimum price required by the transaction pool. 429 func (s *Ethereum) StartMining(threads int) error { 430 // Update the thread count within the consensus engine 431 type threaded interface { 432 SetThreads(threads int) 433 } 434 if th, ok := s.engine.(threaded); ok { 435 log.Info("Updated mining threads", "threads", threads) 436 if threads == 0 { 437 threads = -1 // Disable the miner from within 438 } 439 th.SetThreads(threads) 440 } 441 // If the miner was not running, initialize it 442 if !s.IsMining() { 443 // Propagate the initial price point to the transaction pool 444 s.lock.RLock() 445 price := s.gasPrice 446 s.lock.RUnlock() 447 s.txPool.SetGasPrice(price) 448 449 // Configure the local mining address 450 eb, err := s.Etherbase() 451 if err != nil { 452 log.Error("Cannot start mining without etherbase", "err", err) 453 return fmt.Errorf("etherbase missing: %v", err) 454 } 455 var cli *clique.Clique 456 if c, ok := s.engine.(*clique.Clique); ok { 457 cli = c 458 } else if cl, ok := s.engine.(*beacon.Beacon); ok { 459 if c, ok := cl.InnerEngine().(*clique.Clique); ok { 460 cli = c 461 } 462 } 463 if cli != nil { 464 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 465 if wallet == nil || err != nil { 466 log.Error("Etherbase account unavailable locally", "err", err) 467 return fmt.Errorf("signer missing: %v", err) 468 } 469 cli.Authorize(eb, wallet.SignData) 470 } 471 // If mining is started, we can disable the transaction rejection mechanism 472 // introduced to speed sync times. 473 atomic.StoreUint32(&s.handler.acceptTxs, 1) 474 475 go s.miner.Start(eb) 476 } 477 return nil 478 } 479 480 // StopMining terminates the miner, both at the consensus engine level as well as 481 // at the block creation level. 482 func (s *Ethereum) StopMining() { 483 // Update the thread count within the consensus engine 484 type threaded interface { 485 SetThreads(threads int) 486 } 487 if th, ok := s.engine.(threaded); ok { 488 th.SetThreads(-1) 489 } 490 // Stop the block creating itself 491 s.miner.Stop() 492 } 493 494 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 495 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 496 497 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 498 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 499 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 500 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 501 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 502 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 503 func (s *Ethereum) IsListening() bool { return true } // Always listening 504 func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } 505 func (s *Ethereum) Synced() bool { return atomic.LoadUint32(&s.handler.acceptTxs) == 1 } 506 func (s *Ethereum) SetSynced() { atomic.StoreUint32(&s.handler.acceptTxs, 1) } 507 func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } 508 func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } 509 func (s *Ethereum) Merger() *consensus.Merger { return s.merger } 510 func (s *Ethereum) SyncMode() downloader.SyncMode { 511 mode, _ := s.handler.chainSync.modeAndLocalHead() 512 return mode 513 } 514 515 // Protocols returns all the currently configured 516 // network protocols to start. 517 func (s *Ethereum) Protocols() []p2p.Protocol { 518 protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) 519 if s.config.SnapshotCache > 0 { 520 protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) 521 } 522 return protos 523 } 524 525 // Start implements node.Lifecycle, starting all internal goroutines needed by the 526 // Ethereum protocol implementation. 527 func (s *Ethereum) Start() error { 528 eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) 529 530 // Start the bloom bits servicing goroutines 531 s.startBloomHandlers(params.BloomBitsBlocks) 532 533 // Regularly update shutdown marker 534 s.shutdownTracker.Start() 535 536 // Figure out a max peers count based on the server limits 537 maxPeers := s.p2pServer.MaxPeers 538 if s.config.LightServ > 0 { 539 if s.config.LightPeers >= s.p2pServer.MaxPeers { 540 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) 541 } 542 maxPeers -= s.config.LightPeers 543 } 544 // Start the networking layer and the light server if requested 545 s.handler.Start(maxPeers) 546 return nil 547 } 548 549 // Stop implements node.Lifecycle, terminating all internal goroutines used by the 550 // Ethereum protocol. 551 func (s *Ethereum) Stop() error { 552 // Stop all the peer-related stuff first. 553 s.ethDialCandidates.Close() 554 s.snapDialCandidates.Close() 555 s.handler.Stop() 556 557 // Then stop everything else. 558 s.bloomIndexer.Close() 559 close(s.closeBloomHandler) 560 s.txPool.Stop() 561 s.miner.Close() 562 s.blockchain.Stop() 563 s.engine.Close() 564 565 // Clean shutdown marker as the last thing before closing db 566 s.shutdownTracker.Stop() 567 568 s.chainDb.Close() 569 s.eventMux.Stop() 570 571 return nil 572 }