github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/miner/miner.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:40</date> 10 //</624450100424347648> 11 12 13 //Package Miner实现以太坊块创建和挖掘。 14 package miner 15 16 import ( 17 "fmt" 18 "sync/atomic" 19 "time" 20 21 "github.com/ethereum/go-ethereum/common" 22 "github.com/ethereum/go-ethereum/consensus" 23 "github.com/ethereum/go-ethereum/core" 24 "github.com/ethereum/go-ethereum/core/state" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/eth/downloader" 27 "github.com/ethereum/go-ethereum/event" 28 "github.com/ethereum/go-ethereum/log" 29 "github.com/ethereum/go-ethereum/params" 30 ) 31 32 //后端包装挖掘所需的所有方法。 33 type Backend interface { 34 BlockChain() *core.BlockChain 35 TxPool() *core.TxPool 36 } 37 38 //Miner创建块并搜索工作证明值。 39 type Miner struct { 40 mux *event.TypeMux 41 worker *worker 42 coinbase common.Address 43 eth Backend 44 engine consensus.Engine 45 exitCh chan struct{} 46 47 canStart int32 //can start指示是否可以启动挖掘操作 48 shouldStart int32 //should start指示是否应在同步后启动 49 } 50 51 func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, recommit time.Duration, gasFloor, gasCeil uint64, isLocalBlock func(block *types.Block) bool) *Miner { 52 miner := &Miner{ 53 eth: eth, 54 mux: mux, 55 engine: engine, 56 exitCh: make(chan struct{}), 57 worker: newWorker(config, engine, eth, mux, recommit, gasFloor, gasCeil, isLocalBlock), 58 canStart: 1, 59 } 60 go miner.update() 61 62 return miner 63 } 64 65 //更新可以跟踪下载程序事件。请注意,这是一种一次性更新循环。 66 //一旦广播“完成”或“失败”,事件将被取消注册,并且 67 //循环已退出。这是为了防止一个主要的安全漏洞,外部方可以在其中阻止您 68 //只要DOS继续,就停止您的挖掘操作。 69 func (self *Miner) update() { 70 events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) 71 defer events.Unsubscribe() 72 73 for { 74 select { 75 case ev := <-events.Chan(): 76 if ev == nil { 77 return 78 } 79 switch ev.Data.(type) { 80 case downloader.StartEvent: 81 atomic.StoreInt32(&self.canStart, 0) 82 if self.Mining() { 83 self.Stop() 84 atomic.StoreInt32(&self.shouldStart, 1) 85 log.Info("Mining aborted due to sync") 86 } 87 case downloader.DoneEvent, downloader.FailedEvent: 88 shouldStart := atomic.LoadInt32(&self.shouldStart) == 1 89 90 atomic.StoreInt32(&self.canStart, 1) 91 atomic.StoreInt32(&self.shouldStart, 0) 92 if shouldStart { 93 self.Start(self.coinbase) 94 } 95 //立即停止并忽略所有其他挂起事件 96 return 97 } 98 case <-self.exitCh: 99 return 100 } 101 } 102 } 103 104 func (self *Miner) Start(coinbase common.Address) { 105 atomic.StoreInt32(&self.shouldStart, 1) 106 self.SetEtherbase(coinbase) 107 108 if atomic.LoadInt32(&self.canStart) == 0 { 109 log.Info("Network syncing, will start miner afterwards") 110 return 111 } 112 self.worker.start() 113 } 114 115 func (self *Miner) Stop() { 116 self.worker.stop() 117 atomic.StoreInt32(&self.shouldStart, 0) 118 } 119 120 func (self *Miner) Close() { 121 self.worker.close() 122 close(self.exitCh) 123 } 124 125 func (self *Miner) Mining() bool { 126 return self.worker.isRunning() 127 } 128 129 func (self *Miner) HashRate() uint64 { 130 if pow, ok := self.engine.(consensus.PoW); ok { 131 return uint64(pow.Hashrate()) 132 } 133 return 0 134 } 135 136 func (self *Miner) SetExtra(extra []byte) error { 137 if uint64(len(extra)) > params.MaximumExtraDataSize { 138 return fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize) 139 } 140 self.worker.setExtra(extra) 141 return nil 142 } 143 144 //setrecommittinterval设置密封工作重新提交的间隔。 145 func (self *Miner) SetRecommitInterval(interval time.Duration) { 146 self.worker.setRecommitInterval(interval) 147 } 148 149 //挂起返回当前挂起的块和关联状态。 150 func (self *Miner) Pending() (*types.Block, *state.StateDB) { 151 return self.worker.pending() 152 } 153 154 //PendingBlock返回当前挂起的块。 155 // 156 //注意,要访问挂起块和挂起状态 157 //同时,请使用pending(),因为pending状态可以 158 //在多个方法调用之间切换 159 func (self *Miner) PendingBlock() *types.Block { 160 return self.worker.pendingBlock() 161 } 162 163 func (self *Miner) SetEtherbase(addr common.Address) { 164 self.coinbase = addr 165 self.worker.setEtherbase(addr) 166 } 167