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