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