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