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