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