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