github.com/edxfund/validator@v1.8.16-0.20181020093046-c1def72855da/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/EDXFund/Validator/accounts" 29 "github.com/EDXFund/Validator/common" 30 "github.com/EDXFund/Validator/common/hexutil" 31 "github.com/EDXFund/Validator/consensus" 32 "github.com/EDXFund/Validator/consensus/clique" 33 "github.com/EDXFund/Validator/consensus/ethash" 34 "github.com/EDXFund/Validator/core" 35 "github.com/EDXFund/Validator/core/bloombits" 36 "github.com/EDXFund/Validator/core/rawdb" 37 "github.com/EDXFund/Validator/core/types" 38 "github.com/EDXFund/Validator/core/vm" 39 "github.com/EDXFund/Validator/eth/downloader" 40 "github.com/EDXFund/Validator/eth/filters" 41 "github.com/EDXFund/Validator/eth/gasprice" 42 "github.com/EDXFund/Validator/ethdb" 43 "github.com/EDXFund/Validator/event" 44 "github.com/EDXFund/Validator/internal/ethapi" 45 "github.com/EDXFund/Validator/log" 46 "github.com/EDXFund/Validator/miner" 47 "github.com/EDXFund/Validator/node" 48 "github.com/EDXFund/Validator/p2p" 49 "github.com/EDXFund/Validator/params" 50 "github.com/EDXFund/Validator/rlp" 51 "github.com/EDXFund/Validator/rpc" 52 ) 53 54 type LesServer interface { 55 Start(srvr *p2p.Server) 56 Stop() 57 Protocols() []p2p.Protocol 58 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 59 } 60 61 // Ethereum implements the Ethereum full node service. 62 type Ethereum struct { 63 config *Config 64 chainConfig *params.ChainConfig 65 66 // Channel for shutting down the service 67 shutdownChan chan bool // Channel for shutting down the Ethereum 68 69 // Handlers 70 txPool *core.TxPool 71 72 blockchain *core.BlockChain 73 protocolManager *ProtocolManager 74 lesServer LesServer 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 86 APIBackend *EthAPIBackend 87 88 miner *miner.Miner 89 gasPrice *big.Int 90 etherbase common.Address 91 92 networkID uint64 93 shardId uint16 94 netRPCService *ethapi.PublicNetAPI 95 96 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 97 } 98 99 func (s *Ethereum) AddLesServer(ls LesServer) { 100 s.lesServer = ls 101 ls.SetBloomBitsIndexer(s.bloomIndexer) 102 } 103 104 // New creates a new Ethereum object (including the 105 // initialisation of the common Ethereum object) 106 // add parameter shardId to this function, enabling change shardId dynamically 107 func New(ctx *node.ServiceContext, config *Config, shardId uint16) (*Ethereum, error) { 108 // Ensure configuration values are compatible and sane 109 if config.SyncMode == downloader.LightSync { 110 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 111 } 112 if !config.SyncMode.IsValid() { 113 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 114 } 115 if config.MinerGasPrice == nil || config.MinerGasPrice.Cmp(common.Big0) <= 0 { 116 log.Warn("Sanitizing invalid miner gas price", "provided", config.MinerGasPrice, "updated", DefaultConfig.MinerGasPrice) 117 config.MinerGasPrice = new(big.Int).Set(DefaultConfig.MinerGasPrice) 118 } 119 // Assemble the Ethereum object 120 chainDb, err := CreateDB(ctx, config, "chaindata") 121 if err != nil { 122 return nil, err 123 } 124 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis, shardId) 125 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 126 return nil, genesisErr 127 } 128 log.Info("Initialised chain configuration", "config", chainConfig) 129 130 eth := &Ethereum{ 131 shardId: shardId, //add shard to node 132 config: config, 133 chainDb: chainDb, 134 chainConfig: chainConfig, 135 eventMux: ctx.EventMux, 136 accountManager: ctx.AccountManager, 137 engine: CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.MinerNotify, config.MinerNoverify, chainDb), 138 shutdownChan: make(chan bool), 139 networkID: config.NetworkId, 140 gasPrice: config.MinerGasPrice, 141 etherbase: config.Etherbase, 142 bloomRequests: make(chan chan *bloombits.Retrieval), 143 bloomIndexer: NewBloomIndexer(chainDb, shardId, params.BloomBitsBlocks, params.BloomConfirms), 144 } 145 146 log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId) 147 148 if !config.SkipBcVersionCheck { 149 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 150 if bcVersion != core.BlockChainVersion && bcVersion != 0 { 151 return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d).\n", bcVersion, core.BlockChainVersion) 152 } 153 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 154 } 155 var ( 156 vmConfig = vm.Config{EnablePreimageRecording: config.EnablePreimageRecording} 157 cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieNodeLimit: config.TrieCache, TrieTimeLimit: config.TrieTimeout} 158 ) 159 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, shardId) 160 if err != nil { 161 return nil, err 162 } 163 // Rewind the chain in case of an incompatible config upgrade. 164 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 165 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 166 eth.blockchain.SetHead(compat.RewindTo) 167 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 168 } 169 eth.bloomIndexer.Start(eth.blockchain) 170 171 if config.TxPool.Journal != "" { 172 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 173 } 174 eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) 175 176 if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { 177 return nil, err 178 } 179 180 eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil) 181 eth.miner.SetExtra(makeExtraData(config.MinerExtraData)) 182 183 eth.APIBackend = &EthAPIBackend{eth, nil} 184 gpoParams := config.GPO 185 if gpoParams.Default == nil { 186 gpoParams.Default = config.MinerGasPrice 187 } 188 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 189 190 return eth, nil 191 } 192 193 func makeExtraData(extra []byte) []byte { 194 if len(extra) == 0 { 195 // create default extradata 196 extra, _ = rlp.EncodeToBytes([]interface{}{ 197 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 198 "geth", 199 runtime.Version(), 200 runtime.GOOS, 201 }) 202 } 203 if uint64(len(extra)) > params.MaximumExtraDataSize { 204 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 205 extra = nil 206 } 207 return extra 208 } 209 210 // CreateDB creates the chain database. 211 func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) { 212 db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) 213 if err != nil { 214 return nil, err 215 } 216 if db, ok := db.(*ethdb.LDBDatabase); ok { 217 db.Meter("eth/db/chaindata/") 218 } 219 return db, nil 220 } 221 222 // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service 223 func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { 224 // If proof-of-authority is requested, set it up 225 if chainConfig.Clique != nil { 226 return clique.New(chainConfig.Clique, db) 227 } 228 // Otherwise assume proof-of-work 229 switch config.PowMode { 230 case ethash.ModeFake: 231 log.Warn("Ethash used in fake mode") 232 return ethash.NewFaker() 233 case ethash.ModeTest: 234 log.Warn("Ethash used in test mode") 235 return ethash.NewTester(nil, noverify) 236 case ethash.ModeShared: 237 log.Warn("Ethash used in shared mode") 238 return ethash.NewShared() 239 default: 240 engine := ethash.New(ethash.Config{ 241 CacheDir: ctx.ResolvePath(config.CacheDir), 242 CachesInMem: config.CachesInMem, 243 CachesOnDisk: config.CachesOnDisk, 244 DatasetDir: config.DatasetDir, 245 DatasetsInMem: config.DatasetsInMem, 246 DatasetsOnDisk: config.DatasetsOnDisk, 247 }, notify, noverify) 248 engine.SetThreads(-1) // Disable CPU mining 249 return engine 250 } 251 } 252 253 // APIs return the collection of RPC services the ethereum package offers. 254 // NOTE, some of these services probably need to be moved to somewhere else. 255 func (s *Ethereum) APIs() []rpc.API { 256 apis := ethapi.GetAPIs(s.APIBackend) 257 258 // Append any APIs exposed explicitly by the consensus engine 259 apis = append(apis, s.engine.APIs(s.BlockChain())...) 260 261 // Append all the local APIs and return 262 return append(apis, []rpc.API{ 263 { 264 Namespace: "eth", 265 Version: "1.0", 266 Service: NewPublicEthereumAPI(s), 267 Public: true, 268 }, { 269 Namespace: "eth", 270 Version: "1.0", 271 Service: NewPublicMinerAPI(s), 272 Public: true, 273 }, { 274 Namespace: "eth", 275 Version: "1.0", 276 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 277 Public: true, 278 }, { 279 Namespace: "miner", 280 Version: "1.0", 281 Service: NewPrivateMinerAPI(s), 282 Public: false, 283 }, { 284 Namespace: "eth", 285 Version: "1.0", 286 Service: filters.NewPublicFilterAPI(s.APIBackend, false), 287 Public: true, 288 }, { 289 Namespace: "admin", 290 Version: "1.0", 291 Service: NewPrivateAdminAPI(s), 292 }, { 293 Namespace: "debug", 294 Version: "1.0", 295 Service: NewPublicDebugAPI(s), 296 Public: true, 297 }, { 298 Namespace: "debug", 299 Version: "1.0", 300 Service: NewPrivateDebugAPI(s.chainConfig, s), 301 }, { 302 Namespace: "net", 303 Version: "1.0", 304 Service: s.netRPCService, 305 Public: true, 306 }, 307 }...) 308 } 309 310 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 311 s.blockchain.ResetWithGenesisBlock(gb) 312 } 313 314 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 315 s.lock.RLock() 316 etherbase := s.etherbase 317 s.lock.RUnlock() 318 319 if etherbase != (common.Address{}) { 320 return etherbase, nil 321 } 322 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 323 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 324 etherbase := accounts[0].Address 325 326 s.lock.Lock() 327 s.etherbase = etherbase 328 s.lock.Unlock() 329 330 log.Info("Etherbase automatically configured", "address", etherbase) 331 return etherbase, nil 332 } 333 } 334 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 335 } 336 337 // SetEtherbase sets the mining reward address. 338 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 339 s.lock.Lock() 340 s.etherbase = etherbase 341 s.lock.Unlock() 342 343 s.miner.SetEtherbase(etherbase) 344 } 345 346 // StartMining starts the miner with the given number of CPU threads. If mining 347 // is already running, this method adjust the number of threads allowed to use 348 // and updates the minimum price required by the transaction pool. 349 func (s *Ethereum) StartMining(threads int) error { 350 // Update the thread count within the consensus engine 351 type threaded interface { 352 SetThreads(threads int) 353 } 354 if th, ok := s.engine.(threaded); ok { 355 log.Info("Updated mining threads", "threads", threads) 356 if threads == 0 { 357 threads = -1 // Disable the miner from within 358 } 359 th.SetThreads(threads) 360 } 361 // If the miner was not running, initialize it 362 if !s.IsMining() { 363 // Propagate the initial price point to the transaction pool 364 s.lock.RLock() 365 price := s.gasPrice 366 s.lock.RUnlock() 367 s.txPool.SetGasPrice(price) 368 369 // Configure the local mining addess 370 eb, err := s.Etherbase() 371 if err != nil { 372 log.Error("Cannot start mining without etherbase", "err", err) 373 return fmt.Errorf("etherbase missing: %v", err) 374 } 375 if clique, ok := s.engine.(*clique.Clique); ok { 376 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 377 if wallet == nil || err != nil { 378 log.Error("Etherbase account unavailable locally", "err", err) 379 return fmt.Errorf("signer missing: %v", err) 380 } 381 clique.Authorize(eb, wallet.SignHash) 382 } 383 // If mining is started, we can disable the transaction rejection mechanism 384 // introduced to speed sync times. 385 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 386 387 go s.miner.Start(eb) 388 } 389 return nil 390 } 391 392 // StopMining terminates the miner, both at the consensus engine level as well as 393 // at the block creation level. 394 func (s *Ethereum) StopMining() { 395 // Update the thread count within the consensus engine 396 type threaded interface { 397 SetThreads(threads int) 398 } 399 if th, ok := s.engine.(threaded); ok { 400 th.SetThreads(-1) 401 } 402 // Stop the block creating itself 403 s.miner.Stop() 404 } 405 406 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 407 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 408 409 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 410 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 411 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 412 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 413 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 414 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 415 func (s *Ethereum) IsListening() bool { return true } // Always listening 416 func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 417 func (s *Ethereum) NetVersion() uint64 { return s.networkID } 418 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 419 func (s *Ethereum) ShardId() uint16 { return s.shardId } 420 421 // Protocols implements node.Service, returning all the currently configured 422 // network protocols to start. 423 func (s *Ethereum) Protocols() []p2p.Protocol { 424 if s.lesServer == nil { 425 return s.protocolManager.SubProtocols 426 } 427 return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...) 428 } 429 430 // Start implements node.Service, starting all internal goroutines needed by the 431 // Ethereum protocol implementation. 432 func (s *Ethereum) Start(srvr *p2p.Server) error { 433 // Start the bloom bits servicing goroutines 434 s.startBloomHandlers(params.BloomBitsBlocks) 435 436 // Start the RPC service 437 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion()) 438 439 // Figure out a max peers count based on the server limits 440 maxPeers := srvr.MaxPeers 441 if s.config.LightServ > 0 { 442 if s.config.LightPeers >= srvr.MaxPeers { 443 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers) 444 } 445 maxPeers -= s.config.LightPeers 446 } 447 // Start the networking layer and the light server if requested 448 s.protocolManager.Start(maxPeers) 449 if s.lesServer != nil { 450 s.lesServer.Start(srvr) 451 } 452 return nil 453 } 454 455 // Stop implements node.Service, terminating all internal goroutines used by the 456 // Ethereum protocol. 457 func (s *Ethereum) Stop() error { 458 s.bloomIndexer.Close() 459 s.blockchain.Stop() 460 s.engine.Close() 461 s.protocolManager.Stop() 462 if s.lesServer != nil { 463 s.lesServer.Stop() 464 } 465 s.txPool.Stop() 466 s.miner.Stop() 467 s.eventMux.Stop() 468 469 s.chainDb.Close() 470 close(s.shutdownChan) 471 return nil 472 }