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  }