github.com/MaynardMiner/ethereumprogpow@v1.8.23/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 28 "github.com/ethereumprogpow/ethereumprogpow/accounts" 29 "github.com/ethereumprogpow/ethereumprogpow/common" 30 "github.com/ethereumprogpow/ethereumprogpow/common/hexutil" 31 "github.com/ethereumprogpow/ethereumprogpow/consensus" 32 "github.com/ethereumprogpow/ethereumprogpow/consensus/clique" 33 "github.com/ethereumprogpow/ethereumprogpow/consensus/ethash" 34 "github.com/ethereumprogpow/ethereumprogpow/core" 35 "github.com/ethereumprogpow/ethereumprogpow/core/bloombits" 36 "github.com/ethereumprogpow/ethereumprogpow/core/rawdb" 37 "github.com/ethereumprogpow/ethereumprogpow/core/types" 38 "github.com/ethereumprogpow/ethereumprogpow/core/vm" 39 "github.com/ethereumprogpow/ethereumprogpow/eth/downloader" 40 "github.com/ethereumprogpow/ethereumprogpow/eth/filters" 41 "github.com/ethereumprogpow/ethereumprogpow/eth/gasprice" 42 "github.com/ethereumprogpow/ethereumprogpow/ethdb" 43 "github.com/ethereumprogpow/ethereumprogpow/event" 44 "github.com/ethereumprogpow/ethereumprogpow/internal/ethapi" 45 "github.com/ethereumprogpow/ethereumprogpow/log" 46 "github.com/ethereumprogpow/ethereumprogpow/miner" 47 "github.com/ethereumprogpow/ethereumprogpow/node" 48 "github.com/ethereumprogpow/ethereumprogpow/p2p" 49 "github.com/ethereumprogpow/ethereumprogpow/params" 50 "github.com/ethereumprogpow/ethereumprogpow/rlp" 51 "github.com/ethereumprogpow/ethereumprogpow/rpc" 52 ) 53 54 type LesServer interface { 55 Start(srvr *p2p.Server) 56 Stop() 57 Protocols() []p2p.Protocol 58 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 59 } 60 61 // Ethereum implements the Ethereum full node service. 62 type Ethereum struct { 63 config *Config 64 chainConfig *params.ChainConfig 65 66 // Channel for shutting down the service 67 shutdownChan chan bool // Channel for shutting down the Ethereum 68 69 // Handlers 70 txPool *core.TxPool 71 blockchain *core.BlockChain 72 protocolManager *ProtocolManager 73 lesServer LesServer 74 75 // DB interfaces 76 chainDb ethdb.Database // Block chain database 77 78 eventMux *event.TypeMux 79 engine consensus.Engine 80 accountManager *accounts.Manager 81 82 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 83 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 84 85 APIBackend *EthAPIBackend 86 87 miner *miner.Miner 88 gasPrice *big.Int 89 etherbase common.Address 90 91 networkID uint64 92 netRPCService *ethapi.PublicNetAPI 93 94 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 95 } 96 97 func (s *Ethereum) AddLesServer(ls LesServer) { 98 s.lesServer = ls 99 ls.SetBloomBitsIndexer(s.bloomIndexer) 100 } 101 102 // New creates a new Ethereum object (including the 103 // initialisation of the common Ethereum object) 104 func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { 105 // Ensure configuration values are compatible and sane 106 if config.SyncMode == downloader.LightSync { 107 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 108 } 109 if !config.SyncMode.IsValid() { 110 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 111 } 112 if config.MinerGasPrice == nil || config.MinerGasPrice.Cmp(common.Big0) <= 0 { 113 log.Warn("Sanitizing invalid miner gas price", "provided", config.MinerGasPrice, "updated", DefaultConfig.MinerGasPrice) 114 config.MinerGasPrice = new(big.Int).Set(DefaultConfig.MinerGasPrice) 115 } 116 // Assemble the Ethereum object 117 chainDb, err := CreateDB(ctx, config, "chaindata") 118 if err != nil { 119 return nil, err 120 } 121 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride) 122 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 123 return nil, genesisErr 124 } 125 log.Info("Initialised chain configuration", "config", chainConfig) 126 127 eth := &Ethereum{ 128 config: config, 129 chainDb: chainDb, 130 chainConfig: chainConfig, 131 eventMux: ctx.EventMux, 132 accountManager: ctx.AccountManager, 133 engine: CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.MinerNotify, config.MinerNoverify, chainDb), 134 shutdownChan: make(chan bool), 135 networkID: config.NetworkId, 136 gasPrice: config.MinerGasPrice, 137 etherbase: config.Etherbase, 138 bloomRequests: make(chan chan *bloombits.Retrieval), 139 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 140 } 141 142 log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId) 143 144 if !config.SkipBcVersionCheck { 145 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 146 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 147 return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 148 } else if bcVersion != nil && *bcVersion < core.BlockChainVersion { 149 log.Warn("Upgrade blockchain database version", "from", *bcVersion, "to", core.BlockChainVersion) 150 } 151 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 152 } 153 var ( 154 vmConfig = vm.Config{ 155 EnablePreimageRecording: config.EnablePreimageRecording, 156 EWASMInterpreter: config.EWASMInterpreter, 157 EVMInterpreter: config.EVMInterpreter, 158 } 159 cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieCleanLimit: config.TrieCleanCache, TrieDirtyLimit: config.TrieDirtyCache, TrieTimeLimit: config.TrieTimeout} 160 ) 161 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve) 162 if err != nil { 163 return nil, err 164 } 165 // Rewind the chain in case of an incompatible config upgrade. 166 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 167 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 168 eth.blockchain.SetHead(compat.RewindTo) 169 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 170 } 171 eth.bloomIndexer.Start(eth.blockchain) 172 173 if config.TxPool.Journal != "" { 174 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 175 } 176 eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) 177 178 if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, config.Whitelist); err != nil { 179 return nil, err 180 } 181 182 eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil, eth.isLocalBlock) 183 eth.miner.SetExtra(makeExtraData(config.MinerExtraData)) 184 185 eth.APIBackend = &EthAPIBackend{eth, nil} 186 gpoParams := config.GPO 187 if gpoParams.Default == nil { 188 gpoParams.Default = config.MinerGasPrice 189 } 190 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 191 192 return eth, nil 193 } 194 195 func makeExtraData(extra []byte) []byte { 196 if len(extra) == 0 { 197 // create default extradata 198 extra, _ = rlp.EncodeToBytes([]interface{}{ 199 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 200 "geth", 201 runtime.Version(), 202 runtime.GOOS, 203 }) 204 } 205 if uint64(len(extra)) > params.MaximumExtraDataSize { 206 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 207 extra = nil 208 } 209 return extra 210 } 211 212 // CreateDB creates the chain database. 213 func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) { 214 db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) 215 if err != nil { 216 return nil, err 217 } 218 if db, ok := db.(*ethdb.LDBDatabase); ok { 219 db.Meter("eth/db/chaindata/") 220 } 221 return db, nil 222 } 223 224 // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service 225 func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { 226 // If proof-of-authority is requested, set it up 227 if chainConfig.Clique != nil { 228 return clique.New(chainConfig.Clique, db) 229 } 230 // Otherwise assume proof-of-work 231 switch config.PowMode { 232 case ethash.ModeFake: 233 log.Warn("Ethash used in fake mode") 234 return ethash.NewFaker() 235 case ethash.ModeTest: 236 log.Warn("Ethash used in test mode") 237 return ethash.NewTester(nil, noverify) 238 case ethash.ModeShared: 239 log.Warn("Ethash used in shared mode") 240 return ethash.NewShared(chainConfig.ProgPoWBlock) 241 default: 242 engine := ethash.New(ethash.Config{ 243 CacheDir: ctx.ResolvePath(config.CacheDir), 244 CachesInMem: config.CachesInMem, 245 CachesOnDisk: config.CachesOnDisk, 246 DatasetDir: config.DatasetDir, 247 DatasetsInMem: config.DatasetsInMem, 248 DatasetsOnDisk: config.DatasetsOnDisk, 249 ProgPoWBlockNumber: chainConfig.ProgPoWBlock, 250 }, notify, noverify) 251 engine.SetThreads(-1) // Disable CPU mining 252 return engine 253 } 254 } 255 256 // APIs return the collection of RPC services the ethereum package offers. 257 // NOTE, some of these services probably need to be moved to somewhere else. 258 func (s *Ethereum) APIs() []rpc.API { 259 apis := ethapi.GetAPIs(s.APIBackend) 260 261 // Append any APIs exposed explicitly by the consensus engine 262 apis = append(apis, s.engine.APIs(s.BlockChain())...) 263 264 // Append all the local APIs and return 265 return append(apis, []rpc.API{ 266 { 267 Namespace: "eth", 268 Version: "1.0", 269 Service: NewPublicEthereumAPI(s), 270 Public: true, 271 }, { 272 Namespace: "eth", 273 Version: "1.0", 274 Service: NewPublicMinerAPI(s), 275 Public: true, 276 }, { 277 Namespace: "eth", 278 Version: "1.0", 279 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 280 Public: true, 281 }, { 282 Namespace: "miner", 283 Version: "1.0", 284 Service: NewPrivateMinerAPI(s), 285 Public: false, 286 }, { 287 Namespace: "eth", 288 Version: "1.0", 289 Service: filters.NewPublicFilterAPI(s.APIBackend, false), 290 Public: true, 291 }, { 292 Namespace: "admin", 293 Version: "1.0", 294 Service: NewPrivateAdminAPI(s), 295 }, { 296 Namespace: "debug", 297 Version: "1.0", 298 Service: NewPublicDebugAPI(s), 299 Public: true, 300 }, { 301 Namespace: "debug", 302 Version: "1.0", 303 Service: NewPrivateDebugAPI(s.chainConfig, s), 304 }, { 305 Namespace: "net", 306 Version: "1.0", 307 Service: s.netRPCService, 308 Public: true, 309 }, 310 }...) 311 } 312 313 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 314 s.blockchain.ResetWithGenesisBlock(gb) 315 } 316 317 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 318 s.lock.RLock() 319 etherbase := s.etherbase 320 s.lock.RUnlock() 321 322 if etherbase != (common.Address{}) { 323 return etherbase, nil 324 } 325 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 326 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 327 etherbase := accounts[0].Address 328 329 s.lock.Lock() 330 s.etherbase = etherbase 331 s.lock.Unlock() 332 333 log.Info("Etherbase automatically configured", "address", etherbase) 334 return etherbase, nil 335 } 336 } 337 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 338 } 339 340 // isLocalBlock checks whether the specified block is mined 341 // by local miner accounts. 342 // 343 // We regard two types of accounts as local miner account: etherbase 344 // and accounts specified via `txpool.locals` flag. 345 func (s *Ethereum) isLocalBlock(block *types.Block) bool { 346 author, err := s.engine.Author(block.Header()) 347 if err != nil { 348 log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err) 349 return false 350 } 351 // Check whether the given address is etherbase. 352 s.lock.RLock() 353 etherbase := s.etherbase 354 s.lock.RUnlock() 355 if author == etherbase { 356 return true 357 } 358 // Check whether the given address is specified by `txpool.local` 359 // CLI flag. 360 for _, account := range s.config.TxPool.Locals { 361 if account == author { 362 return true 363 } 364 } 365 return false 366 } 367 368 // shouldPreserve checks whether we should preserve the given block 369 // during the chain reorg depending on whether the author of block 370 // is a local account. 371 func (s *Ethereum) shouldPreserve(block *types.Block) bool { 372 // The reason we need to disable the self-reorg preserving for clique 373 // is it can be probable to introduce a deadlock. 374 // 375 // e.g. If there are 7 available signers 376 // 377 // r1 A 378 // r2 B 379 // r3 C 380 // r4 D 381 // r5 A [X] F G 382 // r6 [X] 383 // 384 // In the round5, the inturn signer E is offline, so the worst case 385 // is A, F and G sign the block of round5 and reject the block of opponents 386 // and in the round6, the last available signer B is offline, the whole 387 // network is stuck. 388 if _, ok := s.engine.(*clique.Clique); ok { 389 return false 390 } 391 return s.isLocalBlock(block) 392 } 393 394 // SetEtherbase sets the mining reward address. 395 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 396 s.lock.Lock() 397 s.etherbase = etherbase 398 s.lock.Unlock() 399 400 s.miner.SetEtherbase(etherbase) 401 } 402 403 // StartMining starts the miner with the given number of CPU threads. If mining 404 // is already running, this method adjust the number of threads allowed to use 405 // and updates the minimum price required by the transaction pool. 406 func (s *Ethereum) StartMining(threads int) error { 407 // Update the thread count within the consensus engine 408 type threaded interface { 409 SetThreads(threads int) 410 } 411 if th, ok := s.engine.(threaded); ok { 412 log.Info("Updated mining threads", "threads", threads) 413 if threads == 0 { 414 threads = -1 // Disable the miner from within 415 } 416 th.SetThreads(threads) 417 } 418 // If the miner was not running, initialize it 419 if !s.IsMining() { 420 // Propagate the initial price point to the transaction pool 421 s.lock.RLock() 422 price := s.gasPrice 423 s.lock.RUnlock() 424 s.txPool.SetGasPrice(price) 425 426 // Configure the local mining address 427 eb, err := s.Etherbase() 428 if err != nil { 429 log.Error("Cannot start mining without etherbase", "err", err) 430 return fmt.Errorf("etherbase missing: %v", err) 431 } 432 if clique, ok := s.engine.(*clique.Clique); ok { 433 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 434 if wallet == nil || err != nil { 435 log.Error("Etherbase account unavailable locally", "err", err) 436 return fmt.Errorf("signer missing: %v", err) 437 } 438 clique.Authorize(eb, wallet.SignHash) 439 } 440 // If mining is started, we can disable the transaction rejection mechanism 441 // introduced to speed sync times. 442 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 443 444 go s.miner.Start(eb) 445 } 446 return nil 447 } 448 449 // StopMining terminates the miner, both at the consensus engine level as well as 450 // at the block creation level. 451 func (s *Ethereum) StopMining() { 452 // Update the thread count within the consensus engine 453 type threaded interface { 454 SetThreads(threads int) 455 } 456 if th, ok := s.engine.(threaded); ok { 457 th.SetThreads(-1) 458 } 459 // Stop the block creating itself 460 s.miner.Stop() 461 } 462 463 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 464 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 465 466 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 467 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 468 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 469 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 470 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 471 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 472 func (s *Ethereum) IsListening() bool { return true } // Always listening 473 func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 474 func (s *Ethereum) NetVersion() uint64 { return s.networkID } 475 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 476 477 // Protocols implements node.Service, returning all the currently configured 478 // network protocols to start. 479 func (s *Ethereum) Protocols() []p2p.Protocol { 480 if s.lesServer == nil { 481 return s.protocolManager.SubProtocols 482 } 483 return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...) 484 } 485 486 // Start implements node.Service, starting all internal goroutines needed by the 487 // Ethereum protocol implementation. 488 func (s *Ethereum) Start(srvr *p2p.Server) error { 489 // Start the bloom bits servicing goroutines 490 s.startBloomHandlers(params.BloomBitsBlocks) 491 492 // Start the RPC service 493 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion()) 494 495 // Figure out a max peers count based on the server limits 496 maxPeers := srvr.MaxPeers 497 if s.config.LightServ > 0 { 498 if s.config.LightPeers >= srvr.MaxPeers { 499 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers) 500 } 501 maxPeers -= s.config.LightPeers 502 } 503 // Start the networking layer and the light server if requested 504 s.protocolManager.Start(maxPeers) 505 if s.lesServer != nil { 506 s.lesServer.Start(srvr) 507 } 508 return nil 509 } 510 511 // Stop implements node.Service, terminating all internal goroutines used by the 512 // Ethereum protocol. 513 func (s *Ethereum) Stop() error { 514 s.bloomIndexer.Close() 515 s.blockchain.Stop() 516 s.engine.Close() 517 s.protocolManager.Stop() 518 if s.lesServer != nil { 519 s.lesServer.Stop() 520 } 521 s.txPool.Stop() 522 s.miner.Stop() 523 s.eventMux.Stop() 524 525 s.chainDb.Close() 526 close(s.shutdownChan) 527 return nil 528 }