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