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