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