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