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