github.com/calmw/ethereum@v0.1.1/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 27 "github.com/calmw/ethereum/accounts" 28 "github.com/calmw/ethereum/common" 29 "github.com/calmw/ethereum/common/hexutil" 30 "github.com/calmw/ethereum/consensus" 31 "github.com/calmw/ethereum/consensus/beacon" 32 "github.com/calmw/ethereum/consensus/clique" 33 "github.com/calmw/ethereum/core" 34 "github.com/calmw/ethereum/core/bloombits" 35 "github.com/calmw/ethereum/core/rawdb" 36 "github.com/calmw/ethereum/core/state/pruner" 37 "github.com/calmw/ethereum/core/txpool" 38 "github.com/calmw/ethereum/core/types" 39 "github.com/calmw/ethereum/core/vm" 40 "github.com/calmw/ethereum/eth/downloader" 41 "github.com/calmw/ethereum/eth/ethconfig" 42 "github.com/calmw/ethereum/eth/gasprice" 43 "github.com/calmw/ethereum/eth/protocols/eth" 44 "github.com/calmw/ethereum/eth/protocols/snap" 45 "github.com/calmw/ethereum/ethdb" 46 "github.com/calmw/ethereum/event" 47 "github.com/calmw/ethereum/internal/ethapi" 48 "github.com/calmw/ethereum/internal/shutdowncheck" 49 "github.com/calmw/ethereum/log" 50 "github.com/calmw/ethereum/miner" 51 "github.com/calmw/ethereum/node" 52 "github.com/calmw/ethereum/p2p" 53 "github.com/calmw/ethereum/p2p/dnsdisc" 54 "github.com/calmw/ethereum/p2p/enode" 55 "github.com/calmw/ethereum/params" 56 "github.com/calmw/ethereum/rlp" 57 "github.com/calmw/ethereum/rpc" 58 ) 59 60 // Config contains the configuration options of the ETH protocol. 61 // Deprecated: use ethconfig.Config instead. 62 type Config = ethconfig.Config 63 64 // Ethereum implements the Ethereum full node service. 65 type Ethereum struct { 66 config *ethconfig.Config 67 68 // Handlers 69 txPool *txpool.TxPool 70 blockchain *core.BlockChain 71 handler *handler 72 ethDialCandidates enode.Iterator 73 snapDialCandidates enode.Iterator 74 merger *consensus.Merger 75 76 // DB interfaces 77 chainDb ethdb.Database // Block chain database 78 79 eventMux *event.TypeMux 80 engine consensus.Engine 81 accountManager *accounts.Manager 82 83 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 84 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 85 closeBloomHandler chan struct{} 86 87 APIBackend *EthAPIBackend 88 89 miner *miner.Miner 90 gasPrice *big.Int 91 etherbase common.Address 92 93 networkID uint64 94 netRPCService *ethapi.NetAPI 95 96 p2pServer *p2p.Server 97 98 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 99 100 shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully 101 } 102 103 // New creates a new Ethereum object (including the 104 // initialisation of the common Ethereum object) 105 func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { 106 // Ensure configuration values are compatible and sane 107 if config.SyncMode == downloader.LightSync { 108 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 109 } 110 if !config.SyncMode.IsValid() { 111 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 112 } 113 if config.Miner.GasPrice == nil || config.Miner.GasPrice.Cmp(common.Big0) <= 0 { 114 log.Warn("Sanitizing invalid miner gas price", "provided", config.Miner.GasPrice, "updated", ethconfig.Defaults.Miner.GasPrice) 115 config.Miner.GasPrice = new(big.Int).Set(ethconfig.Defaults.Miner.GasPrice) 116 } 117 if config.NoPruning && config.TrieDirtyCache > 0 { 118 if config.SnapshotCache > 0 { 119 config.TrieCleanCache += config.TrieDirtyCache * 3 / 5 120 config.SnapshotCache += config.TrieDirtyCache * 2 / 5 121 } else { 122 config.TrieCleanCache += config.TrieDirtyCache 123 } 124 config.TrieDirtyCache = 0 125 } 126 log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) 127 128 // Assemble the Ethereum object 129 chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false) 130 if err != nil { 131 return nil, err 132 } 133 if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, stack.ResolvePath(config.TrieCleanCacheJournal)); err != nil { 134 log.Error("Failed to recover state", "error", err) 135 } 136 // Transfer mining-related config to the ethash config. 137 chainConfig, err := core.LoadChainConfig(chainDb, config.Genesis) 138 if err != nil { 139 return nil, err 140 } 141 engine, err := ethconfig.CreateConsensusEngine(chainConfig, chainDb) 142 if err != nil { 143 return nil, err 144 } 145 eth := &Ethereum{ 146 config: config, 147 merger: consensus.NewMerger(chainDb), 148 chainDb: chainDb, 149 eventMux: stack.EventMux(), 150 accountManager: stack.AccountManager(), 151 engine: engine, 152 closeBloomHandler: make(chan struct{}), 153 networkID: config.NetworkId, 154 gasPrice: config.Miner.GasPrice, 155 etherbase: config.Miner.Etherbase, 156 bloomRequests: make(chan chan *bloombits.Retrieval), 157 bloomIndexer: core.NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 158 p2pServer: stack.Server(), 159 shutdownTracker: shutdowncheck.NewShutdownTracker(chainDb), 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", "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 if bcVersion != nil { // only print warning on upgrade, not on init 174 log.Warn("Upgrade blockchain database version", "from", dbVer, "to", core.BlockChainVersion) 175 } 176 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 177 } 178 } 179 var ( 180 vmConfig = vm.Config{ 181 EnablePreimageRecording: config.EnablePreimageRecording, 182 } 183 cacheConfig = &core.CacheConfig{ 184 TrieCleanLimit: config.TrieCleanCache, 185 TrieCleanJournal: stack.ResolvePath(config.TrieCleanCacheJournal), 186 TrieCleanRejournal: config.TrieCleanCacheRejournal, 187 TrieCleanNoPrefetch: config.NoPrefetch, 188 TrieDirtyLimit: config.TrieDirtyCache, 189 TrieDirtyDisabled: config.NoPruning, 190 TrieTimeLimit: config.TrieTimeout, 191 SnapshotLimit: config.SnapshotCache, 192 Preimages: config.Preimages, 193 } 194 ) 195 // Override the chain config with provided settings. 196 var overrides core.ChainOverrides 197 if config.OverrideCancun != nil { 198 overrides.OverrideCancun = config.OverrideCancun 199 } 200 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, &overrides, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) 201 if err != nil { 202 return nil, err 203 } 204 eth.bloomIndexer.Start(eth.blockchain) 205 206 if config.TxPool.Journal != "" { 207 config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) 208 } 209 eth.txPool = txpool.NewTxPool(config.TxPool, eth.blockchain.Config(), eth.blockchain) 210 211 // Permit the downloader to use the trie cache allowance during fast sync 212 cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit 213 if eth.handler, err = newHandler(&handlerConfig{ 214 Database: chainDb, 215 Chain: eth.blockchain, 216 TxPool: eth.txPool, 217 Merger: eth.merger, 218 Network: config.NetworkId, 219 Sync: config.SyncMode, 220 BloomCache: uint64(cacheLimit), 221 EventMux: eth.eventMux, 222 RequiredBlocks: config.RequiredBlocks, 223 }); err != nil { 224 return nil, err 225 } 226 227 eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock) 228 eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) 229 230 eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil} 231 if eth.APIBackend.allowUnprotectedTxs { 232 log.Info("Unprotected transactions allowed") 233 } 234 gpoParams := config.GPO 235 if gpoParams.Default == nil { 236 gpoParams.Default = config.Miner.GasPrice 237 } 238 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 239 240 // Setup DNS discovery iterators. 241 dnsclient := dnsdisc.NewClient(dnsdisc.Config{}) 242 eth.ethDialCandidates, err = dnsclient.NewIterator(eth.config.EthDiscoveryURLs...) 243 if err != nil { 244 return nil, err 245 } 246 eth.snapDialCandidates, err = dnsclient.NewIterator(eth.config.SnapDiscoveryURLs...) 247 if err != nil { 248 return nil, err 249 } 250 251 // Start the RPC service 252 eth.netRPCService = ethapi.NewNetAPI(eth.p2pServer, config.NetworkId) 253 254 // Register the backend on the node 255 stack.RegisterAPIs(eth.APIs()) 256 stack.RegisterProtocols(eth.Protocols()) 257 stack.RegisterLifecycle(eth) 258 259 // Successful startup; push a marker and check previous unclean shutdowns. 260 eth.shutdownTracker.MarkStartup() 261 262 return eth, nil 263 } 264 265 func makeExtraData(extra []byte) []byte { 266 if len(extra) == 0 { 267 // create default extradata 268 extra, _ = rlp.EncodeToBytes([]interface{}{ 269 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 270 "geth", 271 runtime.Version(), 272 runtime.GOOS, 273 }) 274 } 275 if uint64(len(extra)) > params.MaximumExtraDataSize { 276 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 277 extra = nil 278 } 279 return extra 280 } 281 282 // APIs return the collection of RPC services the ethereum package offers. 283 // NOTE, some of these services probably need to be moved to somewhere else. 284 func (s *Ethereum) APIs() []rpc.API { 285 apis := ethapi.GetAPIs(s.APIBackend) 286 287 // Append any APIs exposed explicitly by the consensus engine 288 apis = append(apis, s.engine.APIs(s.BlockChain())...) 289 290 // Append all the local APIs and return 291 return append(apis, []rpc.API{ 292 { 293 Namespace: "eth", 294 Service: NewEthereumAPI(s), 295 }, { 296 Namespace: "miner", 297 Service: NewMinerAPI(s), 298 }, { 299 Namespace: "eth", 300 Service: downloader.NewDownloaderAPI(s.handler.downloader, s.eventMux), 301 }, { 302 Namespace: "admin", 303 Service: NewAdminAPI(s), 304 }, { 305 Namespace: "debug", 306 Service: NewDebugAPI(s), 307 }, { 308 Namespace: "net", 309 Service: s.netRPCService, 310 }, 311 }...) 312 } 313 314 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 315 s.blockchain.ResetWithGenesisBlock(gb) 316 } 317 318 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 319 s.lock.RLock() 320 etherbase := s.etherbase 321 s.lock.RUnlock() 322 323 if etherbase != (common.Address{}) { 324 return etherbase, nil 325 } 326 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 327 } 328 329 // isLocalBlock checks whether the specified block is mined 330 // by local miner accounts. 331 // 332 // We regard two types of accounts as local miner account: etherbase 333 // and accounts specified via `txpool.locals` flag. 334 func (s *Ethereum) isLocalBlock(header *types.Header) bool { 335 author, err := s.engine.Author(header) 336 if err != nil { 337 log.Warn("Failed to retrieve block author", "number", header.Number.Uint64(), "hash", header.Hash(), "err", err) 338 return false 339 } 340 // Check whether the given address is etherbase. 341 s.lock.RLock() 342 etherbase := s.etherbase 343 s.lock.RUnlock() 344 if author == etherbase { 345 return true 346 } 347 // Check whether the given address is specified by `txpool.local` 348 // CLI flag. 349 for _, account := range s.config.TxPool.Locals { 350 if account == author { 351 return true 352 } 353 } 354 return false 355 } 356 357 // shouldPreserve checks whether we should preserve the given block 358 // during the chain reorg depending on whether the author of block 359 // is a local account. 360 func (s *Ethereum) shouldPreserve(header *types.Header) bool { 361 // The reason we need to disable the self-reorg preserving for clique 362 // is it can be probable to introduce a deadlock. 363 // 364 // e.g. If there are 7 available signers 365 // 366 // r1 A 367 // r2 B 368 // r3 C 369 // r4 D 370 // r5 A [X] F G 371 // r6 [X] 372 // 373 // In the round5, the inturn signer E is offline, so the worst case 374 // is A, F and G sign the block of round5 and reject the block of opponents 375 // and in the round6, the last available signer B is offline, the whole 376 // network is stuck. 377 if _, ok := s.engine.(*clique.Clique); ok { 378 return false 379 } 380 return s.isLocalBlock(header) 381 } 382 383 // SetEtherbase sets the mining reward address. 384 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 385 s.lock.Lock() 386 s.etherbase = etherbase 387 s.lock.Unlock() 388 389 s.miner.SetEtherbase(etherbase) 390 } 391 392 // StartMining starts the miner with the given number of CPU threads. If mining 393 // is already running, this method adjust the number of threads allowed to use 394 // and updates the minimum price required by the transaction pool. 395 func (s *Ethereum) StartMining() error { 396 // If the miner was not running, initialize it 397 if !s.IsMining() { 398 // Propagate the initial price point to the transaction pool 399 s.lock.RLock() 400 price := s.gasPrice 401 s.lock.RUnlock() 402 s.txPool.SetGasPrice(price) 403 404 // Configure the local mining address 405 eb, err := s.Etherbase() 406 if err != nil { 407 log.Error("Cannot start mining without etherbase", "err", err) 408 return fmt.Errorf("etherbase missing: %v", err) 409 } 410 var cli *clique.Clique 411 if c, ok := s.engine.(*clique.Clique); ok { 412 cli = c 413 } else if cl, ok := s.engine.(*beacon.Beacon); ok { 414 if c, ok := cl.InnerEngine().(*clique.Clique); ok { 415 cli = c 416 } 417 } 418 if cli != nil { 419 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 420 if wallet == nil || err != nil { 421 log.Error("Etherbase account unavailable locally", "err", err) 422 return fmt.Errorf("signer missing: %v", err) 423 } 424 cli.Authorize(eb, wallet.SignData) 425 } 426 // If mining is started, we can disable the transaction rejection mechanism 427 // introduced to speed sync times. 428 s.handler.acceptTxs.Store(true) 429 430 go s.miner.Start() 431 } 432 return nil 433 } 434 435 // StopMining terminates the miner, both at the consensus engine level as well as 436 // at the block creation level. 437 func (s *Ethereum) StopMining() { 438 // Update the thread count within the consensus engine 439 type threaded interface { 440 SetThreads(threads int) 441 } 442 if th, ok := s.engine.(threaded); ok { 443 th.SetThreads(-1) 444 } 445 // Stop the block creating itself 446 s.miner.Stop() 447 } 448 449 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 450 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 451 452 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 453 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 454 func (s *Ethereum) TxPool() *txpool.TxPool { return s.txPool } 455 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 456 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 457 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 458 func (s *Ethereum) IsListening() bool { return true } // Always listening 459 func (s *Ethereum) Downloader() *downloader.Downloader { return s.handler.downloader } 460 func (s *Ethereum) Synced() bool { return s.handler.acceptTxs.Load() } 461 func (s *Ethereum) SetSynced() { s.handler.acceptTxs.Store(true) } 462 func (s *Ethereum) ArchiveMode() bool { return s.config.NoPruning } 463 func (s *Ethereum) BloomIndexer() *core.ChainIndexer { return s.bloomIndexer } 464 func (s *Ethereum) Merger() *consensus.Merger { return s.merger } 465 func (s *Ethereum) SyncMode() downloader.SyncMode { 466 mode, _ := s.handler.chainSync.modeAndLocalHead() 467 return mode 468 } 469 470 // Protocols returns all the currently configured 471 // network protocols to start. 472 func (s *Ethereum) Protocols() []p2p.Protocol { 473 protos := eth.MakeProtocols((*ethHandler)(s.handler), s.networkID, s.ethDialCandidates) 474 if s.config.SnapshotCache > 0 { 475 protos = append(protos, snap.MakeProtocols((*snapHandler)(s.handler), s.snapDialCandidates)...) 476 } 477 return protos 478 } 479 480 // Start implements node.Lifecycle, starting all internal goroutines needed by the 481 // Ethereum protocol implementation. 482 func (s *Ethereum) Start() error { 483 eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode()) 484 485 // Start the bloom bits servicing goroutines 486 s.startBloomHandlers(params.BloomBitsBlocks) 487 488 // Regularly update shutdown marker 489 s.shutdownTracker.Start() 490 491 // Figure out a max peers count based on the server limits 492 maxPeers := s.p2pServer.MaxPeers 493 if s.config.LightServ > 0 { 494 if s.config.LightPeers >= s.p2pServer.MaxPeers { 495 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, s.p2pServer.MaxPeers) 496 } 497 maxPeers -= s.config.LightPeers 498 } 499 // Start the networking layer and the light server if requested 500 s.handler.Start(maxPeers) 501 return nil 502 } 503 504 // Stop implements node.Lifecycle, terminating all internal goroutines used by the 505 // Ethereum protocol. 506 func (s *Ethereum) Stop() error { 507 // Stop all the peer-related stuff first. 508 s.ethDialCandidates.Close() 509 s.snapDialCandidates.Close() 510 s.handler.Stop() 511 512 // Then stop everything else. 513 s.bloomIndexer.Close() 514 close(s.closeBloomHandler) 515 s.txPool.Stop() 516 s.miner.Close() 517 s.blockchain.Stop() 518 s.engine.Close() 519 520 // Clean shutdown marker as the last thing before closing db 521 s.shutdownTracker.Stop() 522 523 s.chainDb.Close() 524 s.eventMux.Stop() 525 526 return nil 527 }