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