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