github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/consensus/ethash/ethash.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 //包ethash实现ethash工作证明共识引擎。 26 package ethash 27 28 import ( 29 "errors" 30 "fmt" 31 "math" 32 "math/big" 33 "math/rand" 34 "os" 35 "path/filepath" 36 "reflect" 37 "runtime" 38 "strconv" 39 "sync" 40 "sync/atomic" 41 "time" 42 "unsafe" 43 44 mmap "github.com/edsrzf/mmap-go" 45 "github.com/ethereum/go-ethereum/common" 46 "github.com/ethereum/go-ethereum/consensus" 47 "github.com/ethereum/go-ethereum/core/types" 48 "github.com/ethereum/go-ethereum/log" 49 "github.com/ethereum/go-ethereum/metrics" 50 "github.com/ethereum/go-ethereum/rpc" 51 "github.com/hashicorp/golang-lru/simplelru" 52 ) 53 54 var ErrInvalidDumpMagic = errors.New("invalid dump magic") 55 56 var ( 57 //two256是表示2^256的大整数 58 two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) 59 60 //sharedethash是可以在多个用户之间共享的完整实例。 61 sharedEthash = New(Config{"", 3, 0, "", 1, 0, ModeNormal}, nil) 62 63 //AlgorithmRevision是用于文件命名的数据结构版本。 64 algorithmRevision = 23 65 66 //dumpmagic是一个数据集转储头,用于检查数据转储是否正常。 67 dumpMagic = []uint32{0xbaddcafe, 0xfee1dead} 68 ) 69 70 //Islittleendian返回本地系统是以小规模还是大规模运行 71 //结束字节顺序。 72 func isLittleEndian() bool { 73 n := uint32(0x01020304) 74 return *(*byte)(unsafe.Pointer(&n)) == 0x04 75 } 76 77 //memory map尝试为只读访问存储uint32s的映射文件。 78 func memoryMap(path string) (*os.File, mmap.MMap, []uint32, error) { 79 file, err := os.OpenFile(path, os.O_RDONLY, 0644) 80 if err != nil { 81 return nil, nil, nil, err 82 } 83 mem, buffer, err := memoryMapFile(file, false) 84 if err != nil { 85 file.Close() 86 return nil, nil, nil, err 87 } 88 for i, magic := range dumpMagic { 89 if buffer[i] != magic { 90 mem.Unmap() 91 file.Close() 92 return nil, nil, nil, ErrInvalidDumpMagic 93 } 94 } 95 return file, mem, buffer[len(dumpMagic):], err 96 } 97 98 //memoryMapFile尝试对已打开的文件描述符进行内存映射。 99 func memoryMapFile(file *os.File, write bool) (mmap.MMap, []uint32, error) { 100 //尝试内存映射文件 101 flag := mmap.RDONLY 102 if write { 103 flag = mmap.RDWR 104 } 105 mem, err := mmap.Map(file, flag, 0) 106 if err != nil { 107 return nil, nil, err 108 } 109 //是的,我们设法记忆地图文件,这里是龙。 110 header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem)) 111 header.Len /= 4 112 header.Cap /= 4 113 114 return mem, *(*[]uint32)(unsafe.Pointer(&header)), nil 115 } 116 117 //memoryMandGenerate尝试对uint32s的临时文件进行内存映射以进行写入 118 //访问,用生成器中的数据填充它,然后将其移动到最终版本 119 //请求路径。 120 func memoryMapAndGenerate(path string, size uint64, generator func(buffer []uint32)) (*os.File, mmap.MMap, []uint32, error) { 121 //确保数据文件夹存在 122 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { 123 return nil, nil, nil, err 124 } 125 //创建一个巨大的临时空文件来填充数据 126 temp := path + "." + strconv.Itoa(rand.Int()) 127 128 dump, err := os.Create(temp) 129 if err != nil { 130 return nil, nil, nil, err 131 } 132 if err = dump.Truncate(int64(len(dumpMagic))*4 + int64(size)); err != nil { 133 return nil, nil, nil, err 134 } 135 //内存映射要写入的文件并用生成器填充它 136 mem, buffer, err := memoryMapFile(dump, true) 137 if err != nil { 138 dump.Close() 139 return nil, nil, nil, err 140 } 141 copy(buffer, dumpMagic) 142 143 data := buffer[len(dumpMagic):] 144 generator(data) 145 146 if err := mem.Unmap(); err != nil { 147 return nil, nil, nil, err 148 } 149 if err := dump.Close(); err != nil { 150 return nil, nil, nil, err 151 } 152 if err := os.Rename(temp, path); err != nil { 153 return nil, nil, nil, err 154 } 155 return memoryMap(path) 156 } 157 158 //lru按缓存或数据集的最后使用时间跟踪它们,最多保留n个缓存或数据集。 159 type lru struct { 160 what string 161 new func(epoch uint64) interface{} 162 mu sync.Mutex 163 //项目保存在LRU缓存中,但有一种特殊情况: 164 //我们总是保留一个项目为(最高看到的时代)+1作为“未来项目”。 165 cache *simplelru.LRU 166 future uint64 167 futureItem interface{} 168 } 169 170 //newlru为验证缓存创建新的最近使用最少的缓存 171 //或挖掘数据集。 172 func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru { 173 if maxItems <= 0 { 174 maxItems = 1 175 } 176 cache, _ := simplelru.NewLRU(maxItems, func(key, value interface{}) { 177 log.Trace("Evicted ethash "+what, "epoch", key) 178 }) 179 return &lru{what: what, new: new, cache: cache} 180 } 181 182 //get为给定的epoch检索或创建项。第一个返回值总是 183 //非零。如果LRU认为某个项目在 184 //不久的将来。 185 func (lru *lru) get(epoch uint64) (item, future interface{}) { 186 lru.mu.Lock() 187 defer lru.mu.Unlock() 188 189 //获取或创建请求的epoch的项。 190 item, ok := lru.cache.Get(epoch) 191 if !ok { 192 if lru.future > 0 && lru.future == epoch { 193 item = lru.futureItem 194 } else { 195 log.Trace("Requiring new ethash "+lru.what, "epoch", epoch) 196 item = lru.new(epoch) 197 } 198 lru.cache.Add(epoch, item) 199 } 200 //如果epoch大于以前看到的值,则更新“future item”。 201 if epoch < maxEpoch-1 && lru.future < epoch+1 { 202 log.Trace("Requiring new future ethash "+lru.what, "epoch", epoch+1) 203 future = lru.new(epoch + 1) 204 lru.future = epoch + 1 205 lru.futureItem = future 206 } 207 return item, future 208 } 209 210 //cache用一些元数据包装ethash缓存,以便于并发使用。 211 type cache struct { 212 epoch uint64 //与此缓存相关的epoch 213 dump *os.File //内存映射缓存的文件描述符 214 mmap mmap.MMap //释放前内存映射到取消映射 215 cache []uint32 //实际缓存数据内容(可能是内存映射) 216 once sync.Once //确保只生成一次缓存 217 } 218 219 //new cache创建一个新的ethash验证缓存,并将其作为普通缓存返回 220 //可在LRU缓存中使用的接口。 221 func newCache(epoch uint64) interface{} { 222 return &cache{epoch: epoch} 223 } 224 225 //generate确保在使用前生成缓存内容。 226 func (c *cache) generate(dir string, limit int, test bool) { 227 c.once.Do(func() { 228 size := cacheSize(c.epoch*epochLength + 1) 229 seed := seedHash(c.epoch*epochLength + 1) 230 if test { 231 size = 1024 232 } 233 //如果我们不在磁盘上存储任何内容,则生成并返回。 234 if dir == "" { 235 c.cache = make([]uint32, size/4) 236 generateCache(c.cache, c.epoch, seed) 237 return 238 } 239 // 240 var endian string 241 if !isLittleEndian() { 242 endian = ".be" 243 } 244 path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian)) 245 logger := log.New("epoch", c.epoch) 246 247 // 248 //缓存将变为未使用。 249 runtime.SetFinalizer(c, (*cache).finalizer) 250 251 //尝试从磁盘和内存中加载文件 252 var err error 253 c.dump, c.mmap, c.cache, err = memoryMap(path) 254 if err == nil { 255 logger.Debug("Loaded old ethash cache from disk") 256 return 257 } 258 logger.Debug("Failed to load old ethash cache", "err", err) 259 260 //以前没有可用的缓存,请创建新的缓存文件以填充 261 c.dump, c.mmap, c.cache, err = memoryMapAndGenerate(path, size, func(buffer []uint32) { generateCache(buffer, c.epoch, seed) }) 262 if err != nil { 263 logger.Error("Failed to generate mapped ethash cache", "err", err) 264 265 c.cache = make([]uint32, size/4) 266 generateCache(c.cache, c.epoch, seed) 267 } 268 // 269 for ep := int(c.epoch) - limit; ep >= 0; ep-- { 270 seed := seedHash(uint64(ep)*epochLength + 1) 271 path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian)) 272 os.Remove(path) 273 } 274 }) 275 } 276 277 //终结器取消映射内存并关闭文件。 278 func (c *cache) finalizer() { 279 if c.mmap != nil { 280 c.mmap.Unmap() 281 c.dump.Close() 282 c.mmap, c.dump = nil, nil 283 } 284 } 285 286 //数据集使用一些元数据包装ethash数据集,以便于并发使用。 287 type dataset struct { 288 epoch uint64 //与此缓存相关的epoch 289 dump *os.File //内存映射缓存的文件描述符 290 mmap mmap.MMap //释放前内存映射到取消映射 291 dataset []uint32 //实际缓存数据内容 292 once sync.Once //确保只生成一次缓存 293 done uint32 //用于确定生成状态的原子标记 294 } 295 296 //NewDataSet创建一个新的ethash挖掘数据集,并将其作为简单的go返回 297 //可在LRU缓存中使用的接口。 298 func newDataset(epoch uint64) interface{} { 299 return &dataset{epoch: epoch} 300 } 301 302 //生成确保在使用前生成数据集内容。 303 func (d *dataset) generate(dir string, limit int, test bool) { 304 d.once.Do(func() { 305 //标记完成后生成的数据集。这是遥控器需要的 306 defer atomic.StoreUint32(&d.done, 1) 307 308 csize := cacheSize(d.epoch*epochLength + 1) 309 dsize := datasetSize(d.epoch*epochLength + 1) 310 seed := seedHash(d.epoch*epochLength + 1) 311 if test { 312 csize = 1024 313 dsize = 32 * 1024 314 } 315 //如果我们不在磁盘上存储任何内容,则生成并返回 316 if dir == "" { 317 cache := make([]uint32, csize/4) 318 generateCache(cache, d.epoch, seed) 319 320 d.dataset = make([]uint32, dsize/4) 321 generateDataset(d.dataset, d.epoch, cache) 322 323 return 324 } 325 //磁盘存储是必需的,这会变得花哨。 326 var endian string 327 if !isLittleEndian() { 328 endian = ".be" 329 } 330 path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian)) 331 logger := log.New("epoch", d.epoch) 332 333 //我们将对该文件进行mmap,确保在 334 //缓存将变为未使用。 335 runtime.SetFinalizer(d, (*dataset).finalizer) 336 337 //尝试从磁盘和内存中加载文件 338 var err error 339 d.dump, d.mmap, d.dataset, err = memoryMap(path) 340 if err == nil { 341 logger.Debug("Loaded old ethash dataset from disk") 342 return 343 } 344 logger.Debug("Failed to load old ethash dataset", "err", err) 345 346 //没有以前的数据集可用,请创建新的数据集文件来填充 347 cache := make([]uint32, csize/4) 348 generateCache(cache, d.epoch, seed) 349 350 d.dump, d.mmap, d.dataset, err = memoryMapAndGenerate(path, dsize, func(buffer []uint32) { generateDataset(buffer, d.epoch, cache) }) 351 if err != nil { 352 logger.Error("Failed to generate mapped ethash dataset", "err", err) 353 354 d.dataset = make([]uint32, dsize/2) 355 generateDataset(d.dataset, d.epoch, cache) 356 } 357 //迭代所有以前的实例并删除旧实例 358 for ep := int(d.epoch) - limit; ep >= 0; ep-- { 359 seed := seedHash(uint64(ep)*epochLength + 1) 360 path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian)) 361 os.Remove(path) 362 } 363 }) 364 } 365 366 //generated返回此特定数据集是否已完成生成 367 //或者没有(可能根本没有启动)。这对远程矿工很有用 368 //默认为验证缓存,而不是在DAG代上阻塞。 369 func (d *dataset) generated() bool { 370 return atomic.LoadUint32(&d.done) == 1 371 } 372 373 //终结器关闭所有打开的文件处理程序和内存映射。 374 func (d *dataset) finalizer() { 375 if d.mmap != nil { 376 d.mmap.Unmap() 377 d.dump.Close() 378 d.mmap, d.dump = nil, nil 379 } 380 } 381 382 //makecache生成一个新的ethash缓存,并可以选择将其存储到磁盘。 383 func MakeCache(block uint64, dir string) { 384 c := cache{epoch: block / epochLength} 385 c.generate(dir, math.MaxInt32, false) 386 } 387 388 // 389 func MakeDataset(block uint64, dir string) { 390 d := dataset{epoch: block / epochLength} 391 d.generate(dir, math.MaxInt32, false) 392 } 393 394 //模式定义了ethash引擎所做的POW验证的类型和数量。 395 type Mode uint 396 397 const ( 398 ModeNormal Mode = iota 399 ModeShared 400 ModeTest 401 ModeFake 402 ModeFullFake 403 ) 404 405 //config是ethash的配置参数。 406 type Config struct { 407 CacheDir string 408 CachesInMem int 409 CachesOnDisk int 410 DatasetDir string 411 DatasetsInMem int 412 DatasetsOnDisk int 413 PowMode Mode 414 } 415 416 //mineresult包装指定块的POW解决方案参数。 417 type mineResult struct { 418 nonce types.BlockNonce 419 mixDigest common.Hash 420 hash common.Hash 421 422 errc chan error 423 } 424 425 //哈希率包装远程密封程序提交的哈希率。 426 type hashrate struct { 427 id common.Hash 428 ping time.Time 429 rate uint64 430 431 done chan struct{} 432 } 433 434 //密封件包裹远程密封件的密封件工作包。 435 type sealWork struct { 436 errc chan error 437 res chan [3]string 438 } 439 440 //ethash是基于实施ethash的工作证明的共识引擎。 441 //算法。 442 type Ethash struct { 443 config Config 444 445 caches *lru //内存缓存以避免重新生成太频繁 446 datasets *lru // 447 448 //采矿相关领域 449 rand *rand.Rand //当前正确播种的随机源 450 threads int //中频挖掘要挖掘的线程数 451 update chan struct{} //更新挖掘参数的通知通道 452 hashrate metrics.Meter //米跟踪平均哈希率 453 454 //远程密封相关字段 455 workCh chan *types.Block //通知通道将新工作推送到远程封口机 456 resultCh chan *types.Block //挖掘线程用于返回结果的通道 457 fetchWorkCh chan *sealWork //用于远程封口机获取采矿作业的通道 458 submitWorkCh chan *mineResult //用于远程封口机提交其采矿结果的通道 459 fetchRateCh chan chan uint64 //用于收集本地或远程密封程序提交的哈希率的通道。 460 submitRateCh chan *hashrate //用于远程密封程序提交其挖掘哈希的通道 461 462 //下面的字段是用于测试的挂钩 463 shared *Ethash //共享POW验证程序以避免缓存重新生成 464 fakeFail uint64 // 465 fakeDelay time.Duration //从验证返回前的睡眠时间延迟 466 467 lock sync.Mutex // 468 closeOnce sync.Once // 469 exitCh chan chan error //退出后端线程的通知通道 470 } 471 472 //new创建一个完整的ethash pow方案,并为 473 //远程挖掘,也可以选择将新工作通知一批远程服务 474 //包装。 475 func New(config Config, notify []string) *Ethash { 476 if config.CachesInMem <= 0 { 477 log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem) 478 config.CachesInMem = 1 479 } 480 if config.CacheDir != "" && config.CachesOnDisk > 0 { 481 log.Info("Disk storage enabled for ethash caches", "dir", config.CacheDir, "count", config.CachesOnDisk) 482 } 483 if config.DatasetDir != "" && config.DatasetsOnDisk > 0 { 484 log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk) 485 } 486 ethash := &Ethash{ 487 config: config, 488 caches: newlru("cache", config.CachesInMem, newCache), 489 datasets: newlru("dataset", config.DatasetsInMem, newDataset), 490 update: make(chan struct{}), 491 hashrate: metrics.NewMeter(), 492 workCh: make(chan *types.Block), 493 resultCh: make(chan *types.Block), 494 fetchWorkCh: make(chan *sealWork), 495 submitWorkCh: make(chan *mineResult), 496 fetchRateCh: make(chan chan uint64), 497 submitRateCh: make(chan *hashrate), 498 exitCh: make(chan chan error), 499 } 500 go ethash.remote(notify) 501 return ethash 502 } 503 504 //NewTester创建了一个小型ethash pow方案,该方案仅用于测试 505 //目的。 506 func NewTester(notify []string) *Ethash { 507 ethash := &Ethash{ 508 config: Config{PowMode: ModeTest}, 509 caches: newlru("cache", 1, newCache), 510 datasets: newlru("dataset", 1, newDataset), 511 update: make(chan struct{}), 512 hashrate: metrics.NewMeter(), 513 workCh: make(chan *types.Block), 514 resultCh: make(chan *types.Block), 515 fetchWorkCh: make(chan *sealWork), 516 submitWorkCh: make(chan *mineResult), 517 fetchRateCh: make(chan chan uint64), 518 submitRateCh: make(chan *hashrate), 519 exitCh: make(chan chan error), 520 } 521 go ethash.remote(notify) 522 return ethash 523 } 524 525 //Newfaker创建了一个具有假POW方案的ethash共识引擎,该方案接受 526 //所有区块的封条都是有效的,尽管它们仍然必须符合以太坊。 527 //共识规则。 528 func NewFaker() *Ethash { 529 return &Ethash{ 530 config: Config{ 531 PowMode: ModeFake, 532 }, 533 } 534 } 535 536 //newfakefailer创建了一个具有假POW方案的ethash共识引擎, 537 //接受除指定的单个块之外的所有块,尽管它们 538 //仍然必须遵守以太坊共识规则。 539 func NewFakeFailer(fail uint64) *Ethash { 540 return &Ethash{ 541 config: Config{ 542 PowMode: ModeFake, 543 }, 544 fakeFail: fail, 545 } 546 } 547 548 //Newfakedelayer创建了一个具有假POW方案的ethash共识引擎, 549 //接受所有块为有效,但将验证延迟一段时间 550 //他们仍然必须遵守以太坊共识规则。 551 func NewFakeDelayer(delay time.Duration) *Ethash { 552 return &Ethash{ 553 config: Config{ 554 PowMode: ModeFake, 555 }, 556 fakeDelay: delay, 557 } 558 } 559 560 //newfullfaker创建了一个具有完全伪造方案的ethash共识引擎, 561 //接受所有块为有效块,而不检查任何共识规则。 562 func NewFullFaker() *Ethash { 563 return &Ethash{ 564 config: Config{ 565 PowMode: ModeFullFake, 566 }, 567 } 568 } 569 570 //newshared创建一个在所有运行的请求者之间共享的完整大小的ethash pow 571 //在同样的过程中。 572 func NewShared() *Ethash { 573 return &Ethash{shared: sharedEthash} 574 } 575 576 //关闭关闭退出通道以通知所有后端线程退出。 577 func (ethash *Ethash) Close() error { 578 var err error 579 ethash.closeOnce.Do(func() { 580 //如果没有分配出口通道,则短路。 581 if ethash.exitCh == nil { 582 return 583 } 584 errc := make(chan error) 585 ethash.exitCh <- errc 586 err = <-errc 587 close(ethash.exitCh) 588 }) 589 return err 590 } 591 592 //缓存尝试检索指定块号的验证缓存 593 //首先检查内存中缓存的列表,然后检查缓存 594 //存储在磁盘上,如果找不到,则最终生成一个。 595 func (ethash *Ethash) cache(block uint64) *cache { 596 epoch := block / epochLength 597 currentI, futureI := ethash.caches.get(epoch) 598 current := currentI.(*cache) 599 600 //等待生成完成。 601 current.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest) 602 603 //如果我们需要一个新的未来缓存,现在是重新生成它的好时机。 604 if futureI != nil { 605 future := futureI.(*cache) 606 go future.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest) 607 } 608 return current 609 } 610 611 // 612 //首先检查内存中的数据集列表,然后检查DAG 613 //存储在磁盘上,如果找不到,则最终生成一个。 614 // 615 //如果指定了异步,那么不仅是将来,而且当前的DAG也是 616 //在后台线程上生成。 617 func (ethash *Ethash) dataset(block uint64, async bool) *dataset { 618 //检索请求的ethash数据集 619 epoch := block / epochLength 620 currentI, futureI := ethash.datasets.get(epoch) 621 current := currentI.(*dataset) 622 623 //如果指定了异步,则在后台线程中生成所有内容 624 if async && !current.generated() { 625 go func() { 626 current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 627 628 if futureI != nil { 629 future := futureI.(*dataset) 630 future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 631 } 632 }() 633 } else { 634 //请求了阻止生成,或已完成生成 635 current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 636 637 if futureI != nil { 638 future := futureI.(*dataset) 639 go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 640 } 641 } 642 return current 643 } 644 645 //线程返回当前启用的挖掘线程数。这不 646 //一定意味着采矿正在进行! 647 func (ethash *Ethash) Threads() int { 648 ethash.lock.Lock() 649 defer ethash.lock.Unlock() 650 651 return ethash.threads 652 } 653 654 //setthreads更新当前启用的挖掘线程数。打电话 655 //此方法不启动挖掘,只设置线程计数。如果为零 656 //指定,矿工将使用机器的所有核心。设置线程 657 //允许计数低于零,将导致矿工闲置,没有任何 658 //正在完成的工作。 659 func (ethash *Ethash) SetThreads(threads int) { 660 ethash.lock.Lock() 661 defer ethash.lock.Unlock() 662 663 //如果我们运行的是一个共享的POW,则改为设置线程计数 664 if ethash.shared != nil { 665 ethash.shared.SetThreads(threads) 666 return 667 } 668 // 669 ethash.threads = threads 670 select { 671 case ethash.update <- struct{}{}: 672 default: 673 } 674 } 675 676 //hashRate实现pow,返回搜索调用的测量速率 677 //最后一分钟的每秒。 678 //注意,返回的哈希率包括本地哈希率,但也包括 679 //所有远程矿工的哈希率。 680 func (ethash *Ethash) Hashrate() float64 { 681 //如果在正常/测试模式下运行ethash,则短路。 682 if ethash.config.PowMode != ModeNormal && ethash.config.PowMode != ModeTest { 683 return ethash.hashrate.Rate1() 684 } 685 var res = make(chan uint64, 1) 686 687 select { 688 case ethash.fetchRateCh <- res: 689 case <-ethash.exitCh: 690 //仅当ethash停止时返回本地哈希率。 691 return ethash.hashrate.Rate1() 692 } 693 694 // 695 return ethash.hashrate.Rate1() + float64(<-res) 696 } 697 698 //API实现共识引擎,返回面向用户的RPC API。 699 func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API { 700 //为了确保向后兼容性,我们公开了ethash RPC API 701 //Eth和Ethash名称空间。 702 return []rpc.API{ 703 { 704 Namespace: "eth", 705 Version: "1.0", 706 Service: &API{ethash}, 707 Public: true, 708 }, 709 { 710 Namespace: "ethash", 711 Version: "1.0", 712 Service: &API{ethash}, 713 Public: true, 714 }, 715 } 716 } 717 718 //seedhash是用于生成验证缓存和挖掘的种子 719 //数据集。 720 func SeedHash(block uint64) []byte { 721 return seedHash(block) 722 }