github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/eth/backend.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:37</date> 10 //</624450087703023616> 11 12 13 //包ETH实现以太坊协议。 14 package eth 15 16 import ( 17 "errors" 18 "fmt" 19 "math/big" 20 "runtime" 21 "sync" 22 "sync/atomic" 23 24 "github.com/ethereum/go-ethereum/accounts" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/common/hexutil" 27 "github.com/ethereum/go-ethereum/consensus" 28 "github.com/ethereum/go-ethereum/consensus/clique" 29 "github.com/ethereum/go-ethereum/consensus/ethash" 30 "github.com/ethereum/go-ethereum/core" 31 "github.com/ethereum/go-ethereum/core/bloombits" 32 "github.com/ethereum/go-ethereum/core/rawdb" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/core/vm" 35 "github.com/ethereum/go-ethereum/eth/downloader" 36 "github.com/ethereum/go-ethereum/eth/filters" 37 "github.com/ethereum/go-ethereum/eth/gasprice" 38 "github.com/ethereum/go-ethereum/ethdb" 39 "github.com/ethereum/go-ethereum/event" 40 "github.com/ethereum/go-ethereum/internal/ethapi" 41 "github.com/ethereum/go-ethereum/log" 42 "github.com/ethereum/go-ethereum/miner" 43 "github.com/ethereum/go-ethereum/node" 44 "github.com/ethereum/go-ethereum/p2p" 45 "github.com/ethereum/go-ethereum/params" 46 "github.com/ethereum/go-ethereum/rlp" 47 "github.com/ethereum/go-ethereum/rpc" 48 ) 49 50 type LesServer interface { 51 Start(srvr *p2p.Server) 52 Stop() 53 Protocols() []p2p.Protocol 54 SetBloomBitsIndexer(bbIndexer *core.ChainIndexer) 55 } 56 57 //以太坊实施以太坊全节点服务。 58 type Ethereum struct { 59 config *Config 60 chainConfig *params.ChainConfig 61 62 //关闭服务的通道 63 shutdownChan chan bool //关闭以太坊的通道 64 65 //处理程序 66 txPool *core.TxPool 67 blockchain *core.BlockChain 68 protocolManager *ProtocolManager 69 lesServer LesServer 70 71 //数据库接口 72 chainDb ethdb.Database //区块链数据库 73 74 eventMux *event.TypeMux 75 engine consensus.Engine 76 accountManager *accounts.Manager 77 78 bloomRequests chan chan *bloombits.Retrieval //接收Bloom数据检索请求的通道 79 bloomIndexer *core.ChainIndexer //块导入期间的Bloom索引器操作 80 81 APIBackend *EthAPIBackend 82 83 miner *miner.Miner 84 gasPrice *big.Int 85 etherbase common.Address 86 87 networkID uint64 88 netRPCService *ethapi.PublicNetAPI 89 90 lock sync.RWMutex //保护可变油田(如天然气价格和以太坊) 91 } 92 93 func (s *Ethereum) AddLesServer(ls LesServer) { 94 s.lesServer = ls 95 ls.SetBloomBitsIndexer(s.bloomIndexer) 96 } 97 98 //新建创建新的以太坊对象(包括 99 //公共EythUM对象的初始化 100 func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { 101 //确保配置值兼容且正常 102 if config.SyncMode == downloader.LightSync { 103 return nil, errors.New("can't run eth.Ethereum in light sync mode, use les.LightEthereum") 104 } 105 if !config.SyncMode.IsValid() { 106 return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) 107 } 108 if config.MinerGasPrice == nil || config.MinerGasPrice.Cmp(common.Big0) <= 0 { 109 log.Warn("Sanitizing invalid miner gas price", "provided", config.MinerGasPrice, "updated", DefaultConfig.MinerGasPrice) 110 config.MinerGasPrice = new(big.Int).Set(DefaultConfig.MinerGasPrice) 111 } 112 //组装以太坊对象 113 chainDb, err := CreateDB(ctx, config, "chaindata") 114 if err != nil { 115 return nil, err 116 } 117 chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.ConstantinopleOverride) 118 if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { 119 return nil, genesisErr 120 } 121 log.Info("Initialised chain configuration", "config", chainConfig) 122 123 eth := &Ethereum{ 124 config: config, 125 chainDb: chainDb, 126 chainConfig: chainConfig, 127 eventMux: ctx.EventMux, 128 accountManager: ctx.AccountManager, 129 engine: CreateConsensusEngine(ctx, chainConfig, &config.Ethash, config.MinerNotify, config.MinerNoverify, chainDb), 130 shutdownChan: make(chan bool), 131 networkID: config.NetworkId, 132 gasPrice: config.MinerGasPrice, 133 etherbase: config.Etherbase, 134 bloomRequests: make(chan chan *bloombits.Retrieval), 135 bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks, params.BloomConfirms), 136 } 137 138 log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", config.NetworkId) 139 140 if !config.SkipBcVersionCheck { 141 bcVersion := rawdb.ReadDatabaseVersion(chainDb) 142 if bcVersion != nil && *bcVersion > core.BlockChainVersion { 143 return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, params.VersionWithMeta, core.BlockChainVersion) 144 } else if bcVersion != nil && *bcVersion < core.BlockChainVersion { 145 log.Warn("Upgrade blockchain database version", "from", *bcVersion, "to", core.BlockChainVersion) 146 } 147 rawdb.WriteDatabaseVersion(chainDb, core.BlockChainVersion) 148 } 149 var ( 150 vmConfig = vm.Config{ 151 EnablePreimageRecording: config.EnablePreimageRecording, 152 EWASMInterpreter: config.EWASMInterpreter, 153 EVMInterpreter: config.EVMInterpreter, 154 } 155 cacheConfig = &core.CacheConfig{Disabled: config.NoPruning, TrieCleanLimit: config.TrieCleanCache, TrieDirtyLimit: config.TrieDirtyCache, TrieTimeLimit: config.TrieTimeout} 156 ) 157 eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, eth.chainConfig, eth.engine, vmConfig, eth.shouldPreserve) 158 if err != nil { 159 return nil, err 160 } 161 //Rewind the chain in case of an incompatible config upgrade. 162 if compat, ok := genesisErr.(*params.ConfigCompatError); ok { 163 log.Warn("Rewinding chain to upgrade configuration", "err", compat) 164 eth.blockchain.SetHead(compat.RewindTo) 165 rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) 166 } 167 eth.bloomIndexer.Start(eth.blockchain) 168 169 if config.TxPool.Journal != "" { 170 config.TxPool.Journal = ctx.ResolvePath(config.TxPool.Journal) 171 } 172 eth.txPool = core.NewTxPool(config.TxPool, eth.chainConfig, eth.blockchain) 173 174 if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.SyncMode, config.NetworkId, eth.eventMux, eth.txPool, eth.engine, eth.blockchain, chainDb, config.Whitelist); err != nil { 175 return nil, err 176 } 177 178 eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, config.MinerRecommit, config.MinerGasFloor, config.MinerGasCeil, eth.isLocalBlock) 179 eth.miner.SetExtra(makeExtraData(config.MinerExtraData)) 180 181 eth.APIBackend = &EthAPIBackend{eth, nil} 182 gpoParams := config.GPO 183 if gpoParams.Default == nil { 184 gpoParams.Default = config.MinerGasPrice 185 } 186 eth.APIBackend.gpo = gasprice.NewOracle(eth.APIBackend, gpoParams) 187 188 return eth, nil 189 } 190 191 func makeExtraData(extra []byte) []byte { 192 if len(extra) == 0 { 193 //创建默认额外数据 194 extra, _ = rlp.EncodeToBytes([]interface{}{ 195 uint(params.VersionMajor<<16 | params.VersionMinor<<8 | params.VersionPatch), 196 "geth", 197 runtime.Version(), 198 runtime.GOOS, 199 }) 200 } 201 if uint64(len(extra)) > params.MaximumExtraDataSize { 202 log.Warn("Miner extra data exceed limit", "extra", hexutil.Bytes(extra), "limit", params.MaximumExtraDataSize) 203 extra = nil 204 } 205 return extra 206 } 207 208 //createdb创建链数据库。 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为EUTHUM服务创建所需类型的一致性引擎实例 221 func CreateConsensusEngine(ctx *node.ServiceContext, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine { 222 //如果要求提供授权证明,请将其设置为 223 if chainConfig.Clique != nil { 224 return clique.New(chainConfig.Clique, db) 225 } 226 //否则承担工作证明 227 switch config.PowMode { 228 case ethash.ModeFake: 229 log.Warn("Ethash used in fake mode") 230 return ethash.NewFaker() 231 case ethash.ModeTest: 232 log.Warn("Ethash used in test mode") 233 return ethash.NewTester(nil, noverify) 234 case ethash.ModeShared: 235 log.Warn("Ethash used in shared mode") 236 return ethash.NewShared() 237 default: 238 engine := ethash.New(ethash.Config{ 239 CacheDir: ctx.ResolvePath(config.CacheDir), 240 CachesInMem: config.CachesInMem, 241 CachesOnDisk: config.CachesOnDisk, 242 DatasetDir: config.DatasetDir, 243 DatasetsInMem: config.DatasetsInMem, 244 DatasetsOnDisk: config.DatasetsOnDisk, 245 }, notify, noverify) 246 engine.SetThreads(-1) //禁用CPU挖掘 247 return engine 248 } 249 } 250 251 //API返回以太坊包提供的RPC服务集合。 252 //注意,其中一些服务可能需要转移到其他地方。 253 func (s *Ethereum) APIs() []rpc.API { 254 apis := ethapi.GetAPIs(s.APIBackend) 255 256 //附加由共识引擎显式公开的任何API 257 apis = append(apis, s.engine.APIs(s.BlockChain())...) 258 259 //附加所有本地API并返回 260 return append(apis, []rpc.API{ 261 { 262 Namespace: "eth", 263 Version: "1.0", 264 Service: NewPublicEthereumAPI(s), 265 Public: true, 266 }, { 267 Namespace: "eth", 268 Version: "1.0", 269 Service: NewPublicMinerAPI(s), 270 Public: true, 271 }, { 272 Namespace: "eth", 273 Version: "1.0", 274 Service: downloader.NewPublicDownloaderAPI(s.protocolManager.downloader, s.eventMux), 275 Public: true, 276 }, { 277 Namespace: "miner", 278 Version: "1.0", 279 Service: NewPrivateMinerAPI(s), 280 Public: false, 281 }, { 282 Namespace: "eth", 283 Version: "1.0", 284 Service: filters.NewPublicFilterAPI(s.APIBackend, false), 285 Public: true, 286 }, { 287 Namespace: "admin", 288 Version: "1.0", 289 Service: NewPrivateAdminAPI(s), 290 }, { 291 Namespace: "debug", 292 Version: "1.0", 293 Service: NewPublicDebugAPI(s), 294 Public: true, 295 }, { 296 Namespace: "debug", 297 Version: "1.0", 298 Service: NewPrivateDebugAPI(s.chainConfig, s), 299 }, { 300 Namespace: "net", 301 Version: "1.0", 302 Service: s.netRPCService, 303 Public: true, 304 }, 305 }...) 306 } 307 308 func (s *Ethereum) ResetWithGenesisBlock(gb *types.Block) { 309 s.blockchain.ResetWithGenesisBlock(gb) 310 } 311 312 func (s *Ethereum) Etherbase() (eb common.Address, err error) { 313 s.lock.RLock() 314 etherbase := s.etherbase 315 s.lock.RUnlock() 316 317 if etherbase != (common.Address{}) { 318 return etherbase, nil 319 } 320 if wallets := s.AccountManager().Wallets(); len(wallets) > 0 { 321 if accounts := wallets[0].Accounts(); len(accounts) > 0 { 322 etherbase := accounts[0].Address 323 324 s.lock.Lock() 325 s.etherbase = etherbase 326 s.lock.Unlock() 327 328 log.Info("Etherbase automatically configured", "address", etherbase) 329 return etherbase, nil 330 } 331 } 332 return common.Address{}, fmt.Errorf("etherbase must be explicitly specified") 333 } 334 335 //IsLocalBlock检查是否挖掘指定的块 336 //根据当地矿工的账户。 337 // 338 //我们将两种类型的账户视为本地矿工账户:以太坊 339 //以及通过'txpool.locals'标志指定的帐户。 340 func (s *Ethereum) isLocalBlock(block *types.Block) bool { 341 author, err := s.engine.Author(block.Header()) 342 if err != nil { 343 log.Warn("Failed to retrieve block author", "number", block.NumberU64(), "hash", block.Hash(), "err", err) 344 return false 345 } 346 //检查给定地址是否为etherbase。 347 s.lock.RLock() 348 etherbase := s.etherbase 349 s.lock.RUnlock() 350 if author == etherbase { 351 return true 352 } 353 //检查给定地址是否由“txPo.本地”指定 354 //CLI标志。 355 for _, account := range s.config.TxPool.Locals { 356 if account == author { 357 return true 358 } 359 } 360 return false 361 } 362 363 //是否应检查是否应保留给定的块 364 //during the chain reorg depending on whether the author of block 365 //是本地帐户。 366 func (s *Ethereum) shouldPreserve(block *types.Block) bool { 367 //我们为什么要禁用对集团的自重组保护? 368 //是否可能导致僵局? 369 // 370 //例如,如果有7个可用的签名者 371 // 372 //R1A 373 //R2B 374 //R3C 375 //R4D 376 //R5 A[X]F G/克 377 //R6[X] 378 // 379 //In the round5, the inturn signer E is offline, so the worst case 380 //是A、F和G在Round5块上签名并拒绝对手的块 381 //在Round6中,最后一个可用的签名者B是离线的,整个 382 //网络被卡住了。 383 if _, ok := s.engine.(*clique.Clique); ok { 384 return false 385 } 386 return s.isLocalBlock(block) 387 } 388 389 //setetherbase设置挖掘奖励地址。 390 func (s *Ethereum) SetEtherbase(etherbase common.Address) { 391 s.lock.Lock() 392 s.etherbase = etherbase 393 s.lock.Unlock() 394 395 s.miner.SetEtherbase(etherbase) 396 } 397 398 //StartMining使用给定数量的CPU线程启动Miner。中频开采 399 //已经运行,此方法调整允许使用的线程数。 400 //并更新交易池所需的最低价格。 401 func (s *Ethereum) StartMining(threads int) error { 402 //更新共识引擎中的线程计数 403 type threaded interface { 404 SetThreads(threads int) 405 } 406 if th, ok := s.engine.(threaded); ok { 407 log.Info("Updated mining threads", "threads", threads) 408 if threads == 0 { 409 threads = -1 //从内部禁用矿工 410 } 411 th.SetThreads(threads) 412 } 413 //如果矿工没有运行,初始化它 414 if !s.IsMining() { 415 //将初始价格点传播到交易池 416 s.lock.RLock() 417 price := s.gasPrice 418 s.lock.RUnlock() 419 s.txPool.SetGasPrice(price) 420 421 //配置本地挖掘地址 422 eb, err := s.Etherbase() 423 if err != nil { 424 log.Error("Cannot start mining without etherbase", "err", err) 425 return fmt.Errorf("etherbase missing: %v", err) 426 } 427 if clique, ok := s.engine.(*clique.Clique); ok { 428 wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) 429 if wallet == nil || err != nil { 430 log.Error("Etherbase account unavailable locally", "err", err) 431 return fmt.Errorf("signer missing: %v", err) 432 } 433 clique.Authorize(eb, wallet.SignHash) 434 } 435 //如果开始挖掘,我们可以禁用事务拒绝机制。 436 //介绍速度同步时间。 437 atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) 438 439 go s.miner.Start(eb) 440 } 441 return nil 442 } 443 444 //在共识引擎级别和 445 //在块创建级别。 446 func (s *Ethereum) StopMining() { 447 //更新共识引擎中的线程计数 448 type threaded interface { 449 SetThreads(threads int) 450 } 451 if th, ok := s.engine.(threaded); ok { 452 th.SetThreads(-1) 453 } 454 //停止创建块本身 455 s.miner.Stop() 456 } 457 458 func (s *Ethereum) IsMining() bool { return s.miner.Mining() } 459 func (s *Ethereum) Miner() *miner.Miner { return s.miner } 460 461 func (s *Ethereum) AccountManager() *accounts.Manager { return s.accountManager } 462 func (s *Ethereum) BlockChain() *core.BlockChain { return s.blockchain } 463 func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } 464 func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } 465 func (s *Ethereum) Engine() consensus.Engine { return s.engine } 466 func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb } 467 func (s *Ethereum) IsListening() bool { return true } //总是倾听 468 func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) } 469 func (s *Ethereum) NetVersion() uint64 { return s.networkID } 470 func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader } 471 472 //协议实现node.service,返回所有当前配置的 473 //要启动的网络协议。 474 func (s *Ethereum) Protocols() []p2p.Protocol { 475 if s.lesServer == nil { 476 return s.protocolManager.SubProtocols 477 } 478 return append(s.protocolManager.SubProtocols, s.lesServer.Protocols()...) 479 } 480 481 //start实现node.service,启动 482 //Ethereum protocol implementation. 483 func (s *Ethereum) Start(srvr *p2p.Server) error { 484 //启动为Goroutines提供服务的Bloom钻头 485 s.startBloomHandlers(params.BloomBitsBlocks) 486 487 //启动RPC服务 488 s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.NetVersion()) 489 490 //根据服务器限制计算最大对等数 491 maxPeers := srvr.MaxPeers 492 if s.config.LightServ > 0 { 493 if s.config.LightPeers >= srvr.MaxPeers { 494 return fmt.Errorf("invalid peer config: light peer count (%d) >= total peer count (%d)", s.config.LightPeers, srvr.MaxPeers) 495 } 496 maxPeers -= s.config.LightPeers 497 } 498 //如果需要,启动网络层和轻型服务器 499 s.protocolManager.Start(maxPeers) 500 if s.lesServer != nil { 501 s.lesServer.Start(srvr) 502 } 503 return nil 504 } 505 506 //停止实现node.service,终止由 507 //以太坊协议。 508 func (s *Ethereum) Stop() error { 509 s.bloomIndexer.Close() 510 s.blockchain.Stop() 511 s.engine.Close() 512 s.protocolManager.Stop() 513 if s.lesServer != nil { 514 s.lesServer.Stop() 515 } 516 s.txPool.Stop() 517 s.miner.Stop() 518 s.eventMux.Stop() 519 520 s.chainDb.Close() 521 close(s.shutdownChan) 522 return nil 523 } 524