github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/consensus/ethash/sealer.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2017 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package ethash 26 27 import ( 28 "bytes" 29 crand "crypto/rand" 30 "encoding/json" 31 "errors" 32 "math" 33 "math/big" 34 "math/rand" 35 "net/http" 36 "runtime" 37 "sync" 38 "time" 39 40 "github.com/ethereum/go-ethereum/common" 41 "github.com/ethereum/go-ethereum/consensus" 42 "github.com/ethereum/go-ethereum/core/types" 43 "github.com/ethereum/go-ethereum/log" 44 ) 45 46 var ( 47 errNoMiningWork = errors.New("no mining work available yet") 48 errInvalidSealResult = errors.New("invalid or stale proof-of-work solution") 49 ) 50 51 // 52 //块的难度要求。 53 func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { 54 //如果我们使用的是假战俘,只需立即返回一个0。 55 if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake { 56 header := block.Header() 57 header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{} 58 return block.WithSeal(header), nil 59 } 60 //如果我们正在运行一个共享的POW,就委托密封它。 61 if ethash.shared != nil { 62 return ethash.shared.Seal(chain, block, stop) 63 } 64 //创建一个运行程序及其所指向的多个搜索线程 65 abort := make(chan struct{}) 66 67 ethash.lock.Lock() 68 threads := ethash.threads 69 if ethash.rand == nil { 70 seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) 71 if err != nil { 72 ethash.lock.Unlock() 73 return nil, err 74 } 75 ethash.rand = rand.New(rand.NewSource(seed.Int64())) 76 } 77 ethash.lock.Unlock() 78 if threads == 0 { 79 threads = runtime.NumCPU() 80 } 81 if threads < 0 { 82 threads = 0 //允许禁用本地挖掘而不在本地/远程周围使用额外逻辑 83 } 84 //将新工作推到远程密封器上 85 if ethash.workCh != nil { 86 ethash.workCh <- block 87 } 88 var pend sync.WaitGroup 89 for i := 0; i < threads; i++ { 90 pend.Add(1) 91 go func(id int, nonce uint64) { 92 defer pend.Done() 93 ethash.mine(block, id, nonce, abort, ethash.resultCh) 94 }(i, uint64(ethash.rand.Int63())) 95 } 96 //等待密封终止或找到一个nonce 97 var result *types.Block 98 select { 99 case <-stop: 100 //外部中止,停止所有矿工线程 101 close(abort) 102 case result = <-ethash.resultCh: 103 //其中一个线程找到一个块,中止所有其他线程 104 close(abort) 105 case <-ethash.update: 106 //线程计数已根据用户请求更改,请重新启动 107 close(abort) 108 pend.Wait() 109 return ethash.Seal(chain, block, stop) 110 } 111 //等待所有矿工终止并返回区块 112 pend.Wait() 113 return result, nil 114 } 115 116 //Mine是工作矿工从 117 //导致正确最终阻塞困难的种子。 118 func (ethash *Ethash) mine(block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block) { 119 //从头中提取一些数据 120 var ( 121 header = block.Header() 122 hash = header.HashNoNonce().Bytes() 123 target = new(big.Int).Div(two256, header.Difficulty) 124 number = header.Number.Uint64() 125 dataset = ethash.dataset(number, false) 126 ) 127 //开始生成随机的nonce,直到我们中止或找到一个好的nonce 128 var ( 129 attempts = int64(0) 130 nonce = seed 131 ) 132 logger := log.New("miner", id) 133 logger.Trace("Started ethash search for new nonces", "seed", seed) 134 search: 135 for { 136 select { 137 case <-abort: 138 //挖掘已终止,更新状态并中止 139 logger.Trace("Ethash nonce search aborted", "attempts", nonce-seed) 140 ethash.hashrate.Mark(attempts) 141 break search 142 143 default: 144 //我们不需要每次更新哈希率,所以在2^x次之后更新 145 attempts++ 146 if (attempts % (1 << 15)) == 0 { 147 ethash.hashrate.Mark(attempts) 148 attempts = 0 149 } 150 //计算这个nonce的pow值 151 digest, result := hashimotoFull(dataset.dataset, hash, nonce) 152 if new(big.Int).SetBytes(result).Cmp(target) <= 0 { 153 //一旦找到正确的标题,就用它创建一个新的标题 154 header = types.CopyHeader(header) 155 header.Nonce = types.EncodeNonce(nonce) 156 header.MixDigest = common.BytesToHash(digest) 157 158 //密封并返回一个块(如果仍然需要) 159 select { 160 case found <- block.WithSeal(header): 161 logger.Trace("Ethash nonce found and reported", "attempts", nonce-seed, "nonce", nonce) 162 case <-abort: 163 logger.Trace("Ethash nonce found but discarded", "attempts", nonce-seed, "nonce", nonce) 164 } 165 break search 166 } 167 nonce++ 168 } 169 } 170 //数据集在终结器中未映射。确保数据集保持活动状态 171 // 172 runtime.KeepAlive(dataset) 173 } 174 175 //远程是一个独立的goroutine,用于处理与远程挖掘相关的内容。 176 func (ethash *Ethash) remote(notify []string) { 177 var ( 178 works = make(map[common.Hash]*types.Block) 179 rates = make(map[common.Hash]hashrate) 180 181 currentBlock *types.Block 182 currentWork [3]string 183 184 notifyTransport = &http.Transport{} 185 notifyClient = &http.Client{ 186 Transport: notifyTransport, 187 Timeout: time.Second, 188 } 189 notifyReqs = make([]*http.Request, len(notify)) 190 ) 191 //notifywork通知所有指定的挖掘终结点 192 //要处理的新工作。 193 notifyWork := func() { 194 work := currentWork 195 blob, _ := json.Marshal(work) 196 197 for i, url := range notify { 198 //终止任何以前挂起的请求并创建新工作 199 if notifyReqs[i] != nil { 200 notifyTransport.CancelRequest(notifyReqs[i]) 201 } 202 notifyReqs[i], _ = http.NewRequest("POST", url, bytes.NewReader(blob)) 203 notifyReqs[i].Header.Set("Content-Type", "application/json") 204 205 //同时将新工作推送到所有远程节点 206 go func(req *http.Request, url string) { 207 res, err := notifyClient.Do(req) 208 if err != nil { 209 log.Warn("Failed to notify remote miner", "err", err) 210 } else { 211 log.Trace("Notified remote miner", "miner", url, "hash", log.Lazy{Fn: func() common.Hash { return common.HexToHash(work[0]) }}, "target", work[2]) 212 res.Body.Close() 213 } 214 }(notifyReqs[i], url) 215 } 216 } 217 //makework为外部矿工创建工作包。 218 // 219 //工作包由3个字符串组成: 220 //结果[0],32字节十六进制编码的当前块头POW哈希 221 // 222 //结果[2],32字节十六进制编码边界条件(“目标”),2^256/难度 223 makeWork := func(block *types.Block) { 224 hash := block.HashNoNonce() 225 226 currentWork[0] = hash.Hex() 227 currentWork[1] = common.BytesToHash(SeedHash(block.NumberU64())).Hex() 228 currentWork[2] = common.BytesToHash(new(big.Int).Div(two256, block.Difficulty()).Bytes()).Hex() 229 230 //追踪遥控封口机取出的封印工作。 231 currentBlock = block 232 works[hash] = block 233 } 234 //SubNetwork验证提交的POW解决方案,返回 235 //解决方案是否被接受(不可能是一个坏的POW以及 236 //任何其他错误,例如没有挂起的工作或过时的挖掘结果)。 237 submitWork := func(nonce types.BlockNonce, mixDigest common.Hash, hash common.Hash) bool { 238 // 239 block := works[hash] 240 if block == nil { 241 log.Info("Work submitted but none pending", "hash", hash) 242 return false 243 } 244 //验证提交结果的正确性。 245 header := block.Header() 246 header.Nonce = nonce 247 header.MixDigest = mixDigest 248 249 start := time.Now() 250 if err := ethash.verifySeal(nil, header, true); err != nil { 251 log.Warn("Invalid proof-of-work submitted", "hash", hash, "elapsed", time.Since(start), "err", err) 252 return false 253 } 254 //确保已创建结果通道。 255 if ethash.resultCh == nil { 256 log.Warn("Ethash result channel is empty, submitted mining result is rejected") 257 return false 258 } 259 log.Trace("Verified correct proof-of-work", "hash", hash, "elapsed", time.Since(start)) 260 261 //解决方案似乎是有效的,返回矿工并通知接受。 262 select { 263 case ethash.resultCh <- block.WithSeal(header): 264 delete(works, hash) 265 return true 266 default: 267 log.Info("Work submitted is stale", "hash", hash) 268 return false 269 } 270 } 271 272 ticker := time.NewTicker(5 * time.Second) 273 defer ticker.Stop() 274 275 for { 276 select { 277 case block := <-ethash.workCh: 278 if currentBlock != nil && block.ParentHash() != currentBlock.ParentHash() { 279 //开始新一轮开采,放弃以前的工作。 280 works = make(map[common.Hash]*types.Block) 281 } 282 //使用新接收的块更新当前工作。 283 //注意,相同的工作可能会过去两次,发生在更改CPU线程时。 284 makeWork(block) 285 286 //通知并请求新工作可用性的URL 287 notifyWork() 288 289 case work := <-ethash.fetchWorkCh: 290 //将当前采矿工作返回给远程矿工。 291 if currentBlock == nil { 292 work.errc <- errNoMiningWork 293 } else { 294 work.res <- currentWork 295 } 296 297 case result := <-ethash.submitWorkCh: 298 //根据维护的采矿块验证提交的POW解决方案。 299 if submitWork(result.nonce, result.mixDigest, result.hash) { 300 result.errc <- nil 301 } else { 302 result.errc <- errInvalidSealResult 303 } 304 305 case result := <-ethash.submitRateCh: 306 //按提交的值跟踪远程密封程序的哈希率。 307 rates[result.id] = hashrate{rate: result.rate, ping: time.Now()} 308 close(result.done) 309 310 case req := <-ethash.fetchRateCh: 311 //收集远程密封程序提交的所有哈希率。 312 var total uint64 313 for _, rate := range rates { 314 //这可能会溢出 315 total += rate.rate 316 } 317 req <- total 318 319 case <-ticker.C: 320 //清除过时提交的哈希率。 321 for id, rate := range rates { 322 if time.Since(rate.ping) > 10*time.Second { 323 delete(rates, id) 324 } 325 } 326 327 case errc := <-ethash.exitCh: 328 //如果ethash关闭,则退出远程回路并返回相关错误。 329 errc <- nil 330 log.Trace("Ethash remote sealer is exiting") 331 return 332 } 333 } 334 }