github.com/Elemental-core/elementalcore@v0.0.0-20191206075037-63891242267a/eth/backend.go (about) 1 // Copyright 2014 The elementalcore Authors 2 // This file is part of the elementalcore library. 3 // 4 // The elementalcore 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 elementalcore 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 elementalcore 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/Elemental-core/elementalcore/accounts" 29 "github.com/Elemental-core/elementalcore/common" 30 "github.com/Elemental-core/elementalcore/common/hexutil" 31 "github.com/Elemental-core/elementalcore/consensus" 32 "github.com/Elemental-core/elementalcore/consensus/dpos" 33 "github.com/Elemental-core/elementalcore/core" 34 "github.com/Elemental-core/elementalcore/core/bloombits" 35 "github.com/Elemental-core/elementalcore/core/types" 36 "github.com/Elemental-core/elementalcore/core/vm" 37 "github.com/Elemental-core/elementalcore/eth/downloader" 38 "github.com/Elemental-core/elementalcore/eth/filters" 39 "github.com/Elemental-core/elementalcore/eth/gasprice" 40 "github.com/Elemental-core/elementalcore/ethdb" 41 "github.com/Elemental-core/elementalcore/event" 42 "github.com/Elemental-core/elementalcore/internal/ethapi" 43 "github.com/Elemental-core/elementalcore/log" 44 "github.com/Elemental-core/elementalcore/miner" 45 "github.com/Elemental-core/elementalcore/node" 46 "github.com/Elemental-core/elementalcore/p2p" 47 "github.com/Elemental-core/elementalcore/params" 48 "github.com/Elemental-core/elementalcore/rlp" 49 "github.com/Elemental-core/elementalcore/rpc" 50 ) 51 52 type LesServer interface { 53 Start(srvr *p2p.Server) 54 Stop() 55 Protocols() []p2p.Protocol 56 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 57 } 58 59 // Ethereum implements the Ethereum full node service. 60 type Ethereum struct { 61 config *Config 62 chainConfig *params.ChainConfig 63 64 // Channel for shutting down the service 65 shutdownChan chan bool // Channel for shutting down the ethereum 66 stopDbUpgrade func() error // stop chain db sequential key upgrade 67 68 // Handlers 69 txPool *core.TxPool 70 blockchain *core.BlockChain 71 protocolManager *ProtocolManager 72 lesServer LesServer 73 74 // DB interfaces 75 chainDb ethdb.Database // Block chain database 76 77 eventMux *event.TypeMux 78 engine consensus.Engine 79 accountManager *accounts.Manager 80 81 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 82 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 83 84 ApiBackend *EthApiBackend 85 86 miner *miner.Miner 87 gasPrice *big.Int 88 validator common.Address 89 coinbase common.Address 90 91 networkId uint64 92 netRPCService *ethapi.PublicNetAPI 93 94 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and coinbase) 95 } 96 97 func (s *Ethereum) AddLesServer(ls LesServer) { 98 s.lesServer = ls 99 ls.SetBloomBitsIndexer(s.bloomIndexer) 100 } 101 102 // New creates a new Ethereum object (including the 103 // initialisation of the common Ethereum object) 104 func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { 105 if config.SyncMode == downloader.LightSync { 106 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 107 } 108 if !config.SyncMode.IsValid() { 109 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 110 } 111 chainDb, err := CreateDB(ctx, config, "chaindata") 112 if err != nil { 113 return nil, err 114 } 115 stopDbUpgrade := upgradeDeduplicateData(chainDb) 116 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 117 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 118 return nil, genesisErr 119 } 120 log.Info("Initialised chain configuration", "config", chainConfig) 121 122 eth := &Ethereum{ 123 config: config, 124 chainDb: chainDb, 125 chainConfig: chainConfig, 126 eventMux: ctx.EventMux, 127 accountManager: ctx.AccountManager, 128 engine: dpos.New(chainConfig.Dpos, chainDb), 129 shutdownChan: make(chan bool), 130 stopDbUpgrade: stopDbUpgrade, 131 networkId: config.NetworkId, 132 gasPrice: config.GasPrice, 133 validator: config.Validator, 134 coinbase: config.Coinbase, 135 bloomRequests: make(chan chan *bloombits.Retrieval), 136 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks), 137 } 138 139 log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId) 140 141 if !config.SkipBcVersionCheck { 142 bcVersion := core.GetBlockChainVersion(chainDb) 143 if bcVersion != core.BlockChainVersion && bcVersion != 0 { 144 return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, core.BlockChainVersion) 145 } 146 core.WriteBlockChainVersion(chainDb, core.BlockChainVersion) 147 } 148 vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording} 149 eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.engine, vmConfig) 150 if err != nil { 151 return nil, err 152 } 153 // Rewind the chain in case of an incompatible config upgrade. 154 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 155 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 156 eth.blockchain.SetHead(compat.RewindTo) 157 core.WriteChainConfig(chainDb, genesisHash, chainConfig) 158 } 159 eth.bloomIndexer.Start(eth.blockchain) 160 161 if config.TxPool.Journal != "" { 162 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 163 } 164 eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) 165 166 if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { 167 return nil, err 168 } 169 eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine) 170 eth.miner.SetExtra(makeExtraData(config.ExtraData)) 171 172 eth.ApiBackend = &EthApiBackend{eth, nil} 173 gpoParams := config.GPO 174 if gpoParams.Default == nil { 175 gpoParams.Default = config.GasPrice 176 } 177 eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, gpoParams) 178 179 return eth, nil 180 } 181 182 func makeExtraData(extra []byte) []byte { 183 if len(extra) == 0 { 184 // create default extradata 185 extra, _ = rlp.EncodeToBytes([]interface{}{ 186 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 187 "geth", 188 runtime.Version(), 189 runtime.GOOS, 190 }) 191 } 192 if uint64(len(extra)) > params.MaximumExtraDataSize { 193 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 194 extra = nil 195 } 196 return extra 197 } 198 199 // CreateDB creates the chain database. 200 func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Database, error) { 201 db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) 202 if err != nil { 203 return nil, err 204 } 205 if db, ok := db.(*ethdb.LDBDatabase); ok { 206 db.Meter("eth/db/chaindata/") 207 } 208 return db, nil 209 } 210 211 // APIs returns the collection of RPC services the ethereum package offers. 212 // NOTE, some of these services probably need to be moved to somewhere else. 213 func (s *Ethereum) APIs() []rpc.API { 214 apis := ethapi.GetAPIs(s.ApiBackend) 215 216 // Append any APIs exposed explicitly by the consensus engine 217 apis = append(apis, s.engine.APIs(s.BlockChain())...) 218 219 // Append all the local APIs and return 220 return append(apis, []rpc.API{ 221 { 222 Namespace: "eth", 223 Version: "1.0", 224 Service: NewPublicEthereumAPI(s), 225 Public: true, 226 }, { 227 Namespace: "eth", 228 Version: "1.0", 229 Service: NewPublicMinerAPI(s), 230 Public: true, 231 }, { 232 Namespace: "eth", 233 Version: "1.0", 234 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 235 Public: true, 236 }, { 237 Namespace: "miner", 238 Version: "1.0", 239 Service: NewPrivateMinerAPI(s), 240 Public: false, 241 }, { 242 Namespace: "eth", 243 Version: "1.0", 244 Service: filters.NewPublicFilterAPI(s.ApiBackend, false), 245 Public: true, 246 }, { 247 Namespace: "admin", 248 Version: "1.0", 249 Service: NewPrivateAdminAPI(s), 250 }, { 251 Namespace: "debug", 252 Version: "1.0", 253 Service: NewPublicDebugAPI(s), 254 Public: true, 255 }, { 256 Namespace: "debug", 257 Version: "1.0", 258 Service: NewPrivateDebugAPI(s.chainConfig, s), 259 }, { 260 Namespace: "net", 261 Version: "1.0", 262 Service: s.netRPCService, 263 Public: true, 264 }, 265 }...) 266 } 267 268 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 269 s.blockchain.ResetWithGenesisBlock(gb) 270 } 271 272 func (s *Ethereum) Validator() (validator common.Address, err error) { 273 s.lock.RLock() 274 validator = s.validator 275 s.lock.RUnlock() 276 277 if validator != (common.Address{}) { 278 return validator, nil 279 } 280 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 281 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 282 return accounts[0].Address, nil 283 } 284 } 285 return common.Address{}, fmt.Errorf("validator address must be explicitly specified") 286 } 287 288 // set in js console via admin interface or wrapper from cli flags 289 func (self *Ethereum) SetValidator(validator common.Address) { 290 self.lock.Lock() 291 self.validator = validator 292 self.lock.Unlock() 293 } 294 295 func (s *Ethereum) Coinbase() (eb common.Address, err error) { 296 s.lock.RLock() 297 coinbase := s.coinbase 298 s.lock.RUnlock() 299 300 if coinbase != (common.Address{}) { 301 return coinbase, nil 302 } 303 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 304 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 305 return accounts[0].Address, nil 306 } 307 } 308 return common.Address{}, fmt.Errorf("coinbase address must be explicitly specified") 309 } 310 311 // set in js console via admin interface or wrapper from cli flags 312 func (self *Ethereum) SetCoinbase(coinbase common.Address) { 313 self.lock.Lock() 314 self.coinbase = coinbase 315 self.lock.Unlock() 316 317 self.miner.SetCoinbase(coinbase) 318 } 319 320 func (s *Ethereum) StartMining(local bool) error { 321 validator, err := s.Validator() 322 if err != nil { 323 log.Error("Cannot start mining without validator", "err", err) 324 return fmt.Errorf("validator missing: %v", err) 325 } 326 cb, err := s.Coinbase() 327 if err != nil { 328 log.Error("Cannot start mining without coinbase", "err", err) 329 return fmt.Errorf("coinbase missing: %v", err) 330 } 331 332 if dpos, ok := s.engine.(*dpos.Dpos); ok { 333 wallet, err := s.accountManager.Find(accounts.Account{Address: validator}) 334 if wallet == nil || err != nil { 335 log.Error("Coinbase account unavailable locally", "err", err) 336 return fmt.Errorf("signer missing: %v", err) 337 } 338 dpos.Authorize(validator, wallet.SignHash) 339 } 340 if local { 341 // If local (CPU) mining is started, we can disable the transaction rejection 342 // mechanism introduced to speed sync times. CPU mining on mainnet is ludicrous 343 // so noone will ever hit this path, whereas marking sync done on CPU mining 344 // will ensure that private networks work in single miner mode too. 345 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 346 } 347 go s.miner.Start(cb) 348 return nil 349 } 350 351 func (s *Ethereum) StopMining() { s.miner.Stop() } 352 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 353 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 354 355 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 356 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 357 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 358 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 359 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 360 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 361 func (s *Ethereum) IsListening() bool { return true } // Always listening 362 func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 363 func (s *Ethereum) NetVersion() uint64 { return s.networkId } 364 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 365 366 // Protocols implements node.Service, returning all the currently configured 367 // network protocols to start. 368 func (s *Ethereum) Protocols() []p2p.Protocol { 369 if s.lesServer == nil { 370 return s.protocolManager.SubProtocols 371 } 372 return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...) 373 } 374 375 // Start implements node.Service, starting all internal goroutines needed by the 376 // Ethereum protocol implementation. 377 func (s *Ethereum) Start(srvr *p2p.Server) error { 378 // Start the bloom bits servicing goroutines 379 s.startBloomHandlers() 380 381 // Start the RPC service 382 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion()) 383 384 // Figure out a max peers count based on the server limits 385 maxPeers := srvr.MaxPeers 386 if s.config.LightServ > 0 { 387 maxPeers -= s.config.LightPeers 388 if maxPeers < srvr.MaxPeers/2 { 389 maxPeers = srvr.MaxPeers / 2 390 } 391 } 392 // Start the networking layer and the light server if requested 393 s.protocolManager.Start(maxPeers) 394 if s.lesServer != nil { 395 s.lesServer.Start(srvr) 396 } 397 return nil 398 } 399 400 // Stop implements node.Service, terminating all internal goroutines used by the 401 // Ethereum protocol. 402 func (s *Ethereum) Stop() error { 403 if s.stopDbUpgrade != nil { 404 s.stopDbUpgrade() 405 } 406 s.bloomIndexer.Close() 407 s.blockchain.Stop() 408 s.protocolManager.Stop() 409 if s.lesServer != nil { 410 s.lesServer.Stop() 411 } 412 s.txPool.Stop() 413 s.miner.Stop() 414 s.eventMux.Stop() 415 416 s.chainDb.Close() 417 close(s.shutdownChan) 418 419 return nil 420 }