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