github.com/m3shine/gochain@v2.2.26+incompatible/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 GoChain protocol. 18 package eth 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "math/big" 25 "runtime" 26 "sync" 27 "sync/atomic" 28 29 "github.com/gochain-io/gochain/accounts" 30 "github.com/gochain-io/gochain/common" 31 "github.com/gochain-io/gochain/consensus" 32 "github.com/gochain-io/gochain/consensus/clique" 33 "github.com/gochain-io/gochain/core" 34 "github.com/gochain-io/gochain/core/bloombits" 35 "github.com/gochain-io/gochain/core/rawdb" 36 "github.com/gochain-io/gochain/core/types" 37 "github.com/gochain-io/gochain/core/vm" 38 "github.com/gochain-io/gochain/eth/downloader" 39 "github.com/gochain-io/gochain/eth/filters" 40 "github.com/gochain-io/gochain/eth/gasprice" 41 "github.com/gochain-io/gochain/event" 42 "github.com/gochain-io/gochain/internal/ethapi" 43 "github.com/gochain-io/gochain/log" 44 "github.com/gochain-io/gochain/miner" 45 "github.com/gochain-io/gochain/node" 46 "github.com/gochain-io/gochain/p2p" 47 "github.com/gochain-io/gochain/params" 48 "github.com/gochain-io/gochain/rpc" 49 ) 50 51 type LesServer interface { 52 Start(srvr *p2p.Server) 53 Stop() 54 Protocols() []p2p.Protocol 55 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 56 } 57 58 // GoChain implements the GoChain full node service. 59 type GoChain struct { 60 config *Config 61 chainConfig *params.ChainConfig 62 63 // Channel for shutting down the service 64 shutdownChan chan bool // Channel for shutting down the ethereum 65 stopDbUpgrade func() error // stop chain db sequential key upgrade 66 67 // Handlers 68 txPool *core.TxPool 69 blockchain *core.BlockChain 70 protocolManager *ProtocolManager 71 lesServer LesServer 72 73 // DB interfaces 74 chainDb common.Database // Block chain database 75 76 eventMux *event.TypeMux 77 engine consensus.Engine 78 accountManager *accounts.Manager 79 80 bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests 81 bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports 82 83 ApiBackend *EthApiBackend 84 85 miner *miner.Miner 86 gasPrice *big.Int 87 etherbase common.Address 88 89 networkId uint64 90 netRPCService *ethapi.PublicNetAPI 91 92 lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase) 93 } 94 95 func (gc *GoChain) AddLesServer(ls LesServer) { 96 gc.lesServer = ls 97 ls.SetBloomBitsIndexer(gc.bloomIndexer) 98 } 99 100 // New creates a new GoChain object (including the 101 // initialisation of the common GoChain object) 102 func New(sctx *node.ServiceContext, config *Config) (*GoChain, error) { 103 if config.SyncMode == downloader.LightSync { 104 return nil, errors.New("can't run eth.GoChain in light sync mode, use les.LightGoChain") 105 } 106 if !config.SyncMode.IsValid() { 107 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 108 } 109 chainDb, err := CreateDB(sctx, config, "chaindata") 110 if err != nil { 111 return nil, err 112 } 113 114 stopDbUpgrade := func() error { return nil } // upgradeDeduplicateData(chainDb) 115 116 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) 117 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 118 return nil, genesisErr 119 } 120 if config.Genesis == nil { 121 if genesisHash == params.MainnetGenesisHash { 122 config.Genesis = core.DefaultGenesisBlock() 123 } 124 } 125 log.Info("Initialised chain configuration", "config", chainConfig) 126 127 if chainConfig.Clique == nil { 128 return nil, fmt.Errorf("invalid configuration, clique is nil: %v", chainConfig) 129 } 130 eth := &GoChain{ 131 config: config, 132 chainDb: chainDb, 133 chainConfig: chainConfig, 134 eventMux: sctx.EventMux, 135 accountManager: sctx.AccountManager, 136 engine: clique.New(chainConfig.Clique, chainDb), 137 shutdownChan: make(chan bool), 138 stopDbUpgrade: stopDbUpgrade, 139 networkId: config.NetworkId, 140 gasPrice: config.MinerGasPrice, 141 etherbase: config.Etherbase, 142 bloomRequests: make(chan chan *bloombits.Retrieval), 143 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks), 144 } 145 146 log.Info("Initialising GoChain protocol", "versions", ProtocolVersions, "network", config.NetworkId) 147 148 if !config.SkipBcVersionCheck { 149 bcVersion := rawdb.ReadDatabaseVersion(chainDb.GlobalTable()) 150 if bcVersion != core.BlockChainVersion && bcVersion != 0 { 151 return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, core.BlockChainVersion) 152 } 153 rawdb.WriteDatabaseVersion(chainDb.GlobalTable(), 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(context.Background(), chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig) 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 if err := eth.blockchain.SetHead(compat.RewindTo); err != nil { 167 log.Error("Cannot set head during chain rewind", "rewind_to", compat.RewindTo, "err", err) 168 } 169 rawdb.WriteChainConfig(chainDb.GlobalTable(), genesisHash, chainConfig) 170 } 171 eth.bloomIndexer.Start(eth.blockchain) 172 173 if config.TxPool.Journal != "" { 174 config.TxPool.Journal = sctx.ResolvePath(config.TxPool.Journal) 175 } 176 eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) 177 178 if eth.protocolManager, err = NewProtocolManager(context.Background(), eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb); err != nil { 179 return nil, err 180 } 181 eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil, eth.isLocalBlock) 182 if err := eth.miner.SetExtra(makeExtraData(config.MinerExtraData)); err != nil { 183 log.Error("Cannot set extra chain data", "err", err) 184 } 185 186 eth.ApiBackend = &EthApiBackend{eth: eth} 187 if g := eth.config.Genesis; g != nil { 188 eth.ApiBackend.initialSupply = g.Alloc.Total() 189 } 190 gpoParams := config.GPO 191 if gpoParams.Default == nil { 192 gpoParams.Default = config.MinerGasPrice 193 } 194 eth.ApiBackend.gpo = gasprice.NewOracle(eth.ApiBackend, gpoParams) 195 196 return eth, nil 197 } 198 199 // Example: 2.0.73/linux-amd64/go1.10.2 200 var defaultExtraData []byte 201 var defaultExtraDataOnce sync.Once 202 203 func makeExtraData(extra []byte) []byte { 204 if len(extra) == 0 { 205 defaultExtraDataOnce.Do(func() { 206 defaultExtraData = []byte(fmt.Sprintf("%s/%s-%s/%s", params.Version, runtime.GOOS, runtime.GOARCH, runtime.Version())) 207 defaultExtraData = defaultExtraData[:params.MaximumExtraDataSize] 208 }) 209 return defaultExtraData 210 } 211 if uint64(len(extra)) > params.MaximumExtraDataSize { 212 log.Warn("Miner extra data exceed limit", "extra", string(extra), "limit", params.MaximumExtraDataSize) 213 extra = extra[:params.MaximumExtraDataSize] 214 } 215 return extra 216 } 217 218 // CreateDB creates the chain database. 219 func CreateDB(ctx *node.ServiceContext, config *Config, name string) (common.Database, error) { 220 db, err := ctx.OpenDatabase(name, config.DatabaseCache, config.DatabaseHandles) 221 if err != nil { 222 return nil, err 223 } 224 return db, nil 225 } 226 227 // APIs returns the collection of RPC services the ethereum package offers. 228 // NOTE, some of these services probably need to be moved to somewhere else. 229 func (gc *GoChain) APIs() []rpc.API { 230 apis := ethapi.GetAPIs(gc.ApiBackend) 231 232 // Append any APIs exposed explicitly by the consensus engine 233 apis = append(apis, gc.engine.APIs(gc.BlockChain())...) 234 235 // Append all the local APIs and return 236 return append(apis, []rpc.API{ 237 { 238 Namespace: "eth", 239 Version: "1.0", 240 Service: NewPublicEthereumAPI(gc), 241 Public: true, 242 }, { 243 Namespace: "eth", 244 Version: "1.0", 245 Service: NewPublicMinerAPI(gc), 246 Public: true, 247 }, { 248 Namespace: "eth", 249 Version: "1.0", 250 Service: downloader.NewPublicDownloaderAPI(gc.protocolManager.downloader, gc.eventMux), 251 Public: true, 252 }, { 253 Namespace: "miner", 254 Version: "1.0", 255 Service: NewPrivateMinerAPI(gc), 256 Public: false, 257 }, { 258 Namespace: "eth", 259 Version: "1.0", 260 Service: filters.NewPublicFilterAPI(gc.ApiBackend, false), 261 Public: true, 262 }, { 263 Namespace: "admin", 264 Version: "1.0", 265 Service: NewPrivateAdminAPI(gc), 266 }, { 267 Namespace: "debug", 268 Version: "1.0", 269 Service: NewPublicDebugAPI(gc), 270 Public: true, 271 }, { 272 Namespace: "debug", 273 Version: "1.0", 274 Service: NewPrivateDebugAPI(gc.chainConfig, gc), 275 }, { 276 Namespace: "net", 277 Version: "1.0", 278 Service: gc.netRPCService, 279 Public: true, 280 }, 281 }...) 282 } 283 284 func (gc *GoChain) ResetWithGenesisBlock(gb *types.Block) { 285 if err := gc.blockchain.ResetWithGenesisBlock(gb); err != nil { 286 log.Error("Cannot reset with genesis block", "err", err) 287 } 288 } 289 290 func (gc *GoChain) Etherbase() (eb common.Address, err error) { 291 gc.lock.RLock() 292 etherbase := gc.etherbase 293 gc.lock.RUnlock() 294 295 if etherbase != (common.Address{}) { 296 return etherbase, nil 297 } 298 if wallets := gc.AccountManager().Wallets(); len(wallets) > 0 { 299 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 300 etherbase := accounts[0].Address 301 302 gc.lock.Lock() 303 gc.etherbase = etherbase 304 gc.lock.Unlock() 305 306 log.Info("Etherbase automatically configured", "address", etherbase) 307 return etherbase, nil 308 } 309 } 310 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 311 } 312 313 // isLocalBlock checks whether the specified block is mined 314 // by local miner accounts. 315 // 316 // We regard two types of accounts as local miner account: etherbase 317 // and accounts specified via `txpool.locals` flag. 318 func (gc *GoChain) isLocalBlock(block *types.Block) bool { 319 author, err := gc.engine.Author(block.Header()) 320 if err != nil { 321 log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err) 322 return false 323 } 324 // Check whether the given address is etherbase. 325 gc.lock.RLock() 326 etherbase := gc.etherbase 327 gc.lock.RUnlock() 328 if author == etherbase { 329 return true 330 } 331 // Check whether the given address is specified by `txpool.local` 332 // CLI flag. 333 for _, account := range gc.config.TxPool.Locals { 334 if account == author { 335 return true 336 } 337 } 338 return false 339 } 340 341 // SetEtherbase sets the mining reward address. 342 func (gc *GoChain) SetEtherbase(etherbase common.Address) { 343 gc.lock.Lock() 344 gc.etherbase = etherbase 345 gc.lock.Unlock() 346 347 gc.miner.SetEtherbase(etherbase) 348 } 349 350 // StartMining starts the miner with the given number of CPU threads. If mining 351 // is already running, this method adjust the number of threads allowed to use 352 // and updates the minimum price required by the transaction pool. 353 func (gc *GoChain) StartMining(threads int) error { 354 // Update the thread count within the consensus engine 355 type threaded interface { 356 SetThreads(threads int) 357 } 358 if th, ok := gc.engine.(threaded); ok { 359 log.Info("Updated mining threads", "threads", threads) 360 if threads == 0 { 361 threads = -1 // Disable the miner from within 362 } 363 th.SetThreads(threads) 364 } 365 // If the miner was not running, initialize it 366 if !gc.IsMining() { 367 // Propagate the initial price point to the transaction pool 368 gc.lock.RLock() 369 price := gc.gasPrice 370 gc.lock.RUnlock() 371 gc.txPool.SetGasPrice(context.Background(), price) 372 373 // Configure the local mining address 374 eb, err := gc.Etherbase() 375 if err != nil { 376 log.Error("Cannot start mining without etherbase", "err", err) 377 return fmt.Errorf("etherbase missing: %v", err) 378 } 379 if clique, ok := gc.engine.(*clique.Clique); ok { 380 wallet, err := gc.accountManager.Find(accounts.Account{Address: eb}) 381 if wallet == nil || err != nil { 382 log.Error("Etherbase account unavailable locally", "err", err) 383 return fmt.Errorf("signer missing: %v", err) 384 } 385 clique.Authorize(eb, wallet.SignHash) 386 } 387 // If mining is started, we can disable the transaction rejection mechanism 388 // introduced to speed sync times. 389 atomic.StoreUint32(&gc.protocolManager.acceptTxs, 1) 390 391 go gc.miner.Start(eb) 392 } 393 return nil 394 } 395 396 // StopMining terminates the miner, both at the consensus engine level as well as 397 // at the block creation level. 398 func (gc *GoChain) StopMining() { 399 // Update the thread count within the consensus engine 400 type threaded interface { 401 SetThreads(threads int) 402 } 403 if th, ok := gc.engine.(threaded); ok { 404 th.SetThreads(-1) 405 } 406 // Stop the block creating itself 407 gc.miner.Stop() 408 } 409 410 func (gc *GoChain) IsMining() bool { return gc.miner.Mining() } 411 func (gc *GoChain) Miner() *miner.Miner { return gc.miner } 412 413 func (gc *GoChain) AccountManager() *accounts.Manager { return gc.accountManager } 414 func (gc *GoChain) BlockChain() *core.BlockChain { return gc.blockchain } 415 func (gc *GoChain) TxPool() *core.TxPool { return gc.txPool } 416 func (gc *GoChain) EventMux() *event.TypeMux { return gc.eventMux } 417 func (gc *GoChain) Engine() consensus.Engine { return gc.engine } 418 func (gc *GoChain) ChainDb() common.Database { return gc.chainDb } 419 func (gc *GoChain) IsListening() bool { return true } // Always listening 420 func (gc *GoChain) EthVersion() int { return int(gc.protocolManager.SubProtocols[0].Version) } 421 func (gc *GoChain) NetVersion() uint64 { return gc.networkId } 422 func (gc *GoChain) Downloader() *downloader.Downloader { return gc.protocolManager.downloader } 423 424 // Protocols implements node.Service, returning all the currently configured 425 // network protocols to start. 426 func (gc *GoChain) Protocols() []p2p.Protocol { 427 if gc.lesServer == nil { 428 return gc.protocolManager.SubProtocols 429 } 430 return append(gc.protocolManager.SubProtocols, gc.lesServer.Protocols()...) 431 } 432 433 // Start implements node.Service, starting all internal goroutines needed by the 434 // GoChain protocol implementation. 435 func (gc *GoChain) Start(srvr *p2p.Server) error { 436 // Start the bloom bits servicing goroutines 437 gc.startBloomHandlers() 438 439 // Start the RPC service 440 gc.netRPCService = ethapi.NewPublicNetAPI(srvr, gc.NetVersion()) 441 442 // Figure out a max peers count based on the server limits 443 maxPeers := srvr.MaxPeers 444 if gc.config.LightServ > 0 { 445 if gc.config.LightPeers >= srvr.MaxPeers { 446 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", gc.config.LightPeers, srvr.MaxPeers) 447 } 448 maxPeers -= gc.config.LightPeers 449 } 450 // Start the networking layer and the light server if requested 451 gc.protocolManager.Start(maxPeers) 452 if gc.lesServer != nil { 453 gc.lesServer.Start(srvr) 454 } 455 return nil 456 } 457 458 // Stop implements node.Service, terminating all internal goroutines used by the 459 // GoChain protocol. 460 func (gc *GoChain) Stop() error { 461 gc.bloomIndexer.Close() 462 gc.blockchain.Stop() 463 gc.protocolManager.Stop() 464 if gc.lesServer != nil { 465 gc.lesServer.Stop() 466 } 467 gc.txPool.Stop() 468 gc.miner.Stop() 469 gc.eventMux.Stop() 470 471 gc.chainDb.Close() 472 close(gc.shutdownChan) 473 474 return nil 475 }