ethash.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Package ethash implements the ethash proof-of-work consensus engine.
  17. package ethash
  18. import (
  19. "errors"
  20. "fmt"
  21. "math"
  22. "math/big"
  23. "math/rand"
  24. "os"
  25. "path/filepath"
  26. "reflect"
  27. "runtime"
  28. "strconv"
  29. "sync"
  30. "sync/atomic"
  31. "time"
  32. "unsafe"
  33. mmap "github.com/edsrzf/mmap-go"
  34. "github.com/ethereum/go-ethereum/common"
  35. "github.com/ethereum/go-ethereum/consensus"
  36. "github.com/ethereum/go-ethereum/core/types"
  37. "github.com/ethereum/go-ethereum/log"
  38. "github.com/ethereum/go-ethereum/metrics"
  39. "github.com/ethereum/go-ethereum/rpc"
  40. "github.com/hashicorp/golang-lru/simplelru"
  41. )
  42. var ErrInvalidDumpMagic = errors.New("invalid dump magic")
  43. var (
  44. // two256 is a big integer representing 2^256
  45. two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
  46. // sharedEthash is a full instance that can be shared between multiple users.
  47. sharedEthash = New(Config{"", 3, 0, "", 1, 0, ModeNormal}, nil, false)
  48. // algorithmRevision is the data structure version used for file naming.
  49. algorithmRevision = 23
  50. // dumpMagic is a dataset dump header to sanity check a data dump.
  51. dumpMagic = []uint32{0xbaddcafe, 0xfee1dead}
  52. )
  53. // isLittleEndian returns whether the local system is running in little or big
  54. // endian byte order.
  55. func isLittleEndian() bool {
  56. n := uint32(0x01020304)
  57. return *(*byte)(unsafe.Pointer(&n)) == 0x04
  58. }
  59. // memoryMap tries to memory map a file of uint32s for read only access.
  60. func memoryMap(path string) (*os.File, mmap.MMap, []uint32, error) {
  61. file, err := os.OpenFile(path, os.O_RDONLY, 0644)
  62. if err != nil {
  63. return nil, nil, nil, err
  64. }
  65. mem, buffer, err := memoryMapFile(file, false)
  66. if err != nil {
  67. file.Close()
  68. return nil, nil, nil, err
  69. }
  70. for i, magic := range dumpMagic {
  71. if buffer[i] != magic {
  72. mem.Unmap()
  73. file.Close()
  74. return nil, nil, nil, ErrInvalidDumpMagic
  75. }
  76. }
  77. return file, mem, buffer[len(dumpMagic):], err
  78. }
  79. // memoryMapFile tries to memory map an already opened file descriptor.
  80. func memoryMapFile(file *os.File, write bool) (mmap.MMap, []uint32, error) {
  81. // Try to memory map the file
  82. flag := mmap.RDONLY
  83. if write {
  84. flag = mmap.RDWR
  85. }
  86. mem, err := mmap.Map(file, flag, 0)
  87. if err != nil {
  88. return nil, nil, err
  89. }
  90. // Yay, we managed to memory map the file, here be dragons
  91. header := *(*reflect.SliceHeader)(unsafe.Pointer(&mem))
  92. header.Len /= 4
  93. header.Cap /= 4
  94. return mem, *(*[]uint32)(unsafe.Pointer(&header)), nil
  95. }
  96. // memoryMapAndGenerate tries to memory map a temporary file of uint32s for write
  97. // access, fill it with the data from a generator and then move it into the final
  98. // path requested.
  99. func memoryMapAndGenerate(path string, size uint64, generator func(buffer []uint32)) (*os.File, mmap.MMap, []uint32, error) {
  100. // Ensure the data folder exists
  101. if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
  102. return nil, nil, nil, err
  103. }
  104. // Create a huge temporary empty file to fill with data
  105. temp := path + "." + strconv.Itoa(rand.Int())
  106. dump, err := os.Create(temp)
  107. if err != nil {
  108. return nil, nil, nil, err
  109. }
  110. if err = dump.Truncate(int64(len(dumpMagic))*4 + int64(size)); err != nil {
  111. return nil, nil, nil, err
  112. }
  113. // Memory map the file for writing and fill it with the generator
  114. mem, buffer, err := memoryMapFile(dump, true)
  115. if err != nil {
  116. dump.Close()
  117. return nil, nil, nil, err
  118. }
  119. copy(buffer, dumpMagic)
  120. data := buffer[len(dumpMagic):]
  121. generator(data)
  122. if err := mem.Unmap(); err != nil {
  123. return nil, nil, nil, err
  124. }
  125. if err := dump.Close(); err != nil {
  126. return nil, nil, nil, err
  127. }
  128. if err := os.Rename(temp, path); err != nil {
  129. return nil, nil, nil, err
  130. }
  131. return memoryMap(path)
  132. }
  133. // lru tracks caches or datasets by their last use time, keeping at most N of them.
  134. type lru struct {
  135. what string
  136. new func(epoch uint64) interface{}
  137. mu sync.Mutex
  138. // Items are kept in a LRU cache, but there is a special case:
  139. // We always keep an item for (highest seen epoch) + 1 as the 'future item'.
  140. cache *simplelru.LRU
  141. future uint64
  142. futureItem interface{}
  143. }
  144. // newlru create a new least-recently-used cache for either the verification caches
  145. // or the mining datasets.
  146. func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru {
  147. if maxItems <= 0 {
  148. maxItems = 1
  149. }
  150. cache, _ := simplelru.NewLRU(maxItems, func(key, value interface{}) {
  151. log.Trace("Evicted ethash "+what, "epoch", key)
  152. })
  153. return &lru{what: what, new: new, cache: cache}
  154. }
  155. // get retrieves or creates an item for the given epoch. The first return value is always
  156. // non-nil. The second return value is non-nil if lru thinks that an item will be useful in
  157. // the near future.
  158. func (lru *lru) get(epoch uint64) (item, future interface{}) {
  159. lru.mu.Lock()
  160. defer lru.mu.Unlock()
  161. // Get or create the item for the requested epoch.
  162. item, ok := lru.cache.Get(epoch)
  163. if !ok {
  164. if lru.future > 0 && lru.future == epoch {
  165. item = lru.futureItem
  166. } else {
  167. log.Trace("Requiring new ethash "+lru.what, "epoch", epoch)
  168. item = lru.new(epoch)
  169. }
  170. lru.cache.Add(epoch, item)
  171. }
  172. // Update the 'future item' if epoch is larger than previously seen.
  173. if epoch < maxEpoch-1 && lru.future < epoch+1 {
  174. log.Trace("Requiring new future ethash "+lru.what, "epoch", epoch+1)
  175. future = lru.new(epoch + 1)
  176. lru.future = epoch + 1
  177. lru.futureItem = future
  178. }
  179. return item, future
  180. }
  181. // cache wraps an ethash cache with some metadata to allow easier concurrent use.
  182. type cache struct {
  183. epoch uint64 // Epoch for which this cache is relevant
  184. dump *os.File // File descriptor of the memory mapped cache
  185. mmap mmap.MMap // Memory map itself to unmap before releasing
  186. cache []uint32 // The actual cache data content (may be memory mapped)
  187. once sync.Once // Ensures the cache is generated only once
  188. }
  189. // newCache creates a new ethash verification cache and returns it as a plain Go
  190. // interface to be usable in an LRU cache.
  191. func newCache(epoch uint64) interface{} {
  192. return &cache{epoch: epoch}
  193. }
  194. // generate ensures that the cache content is generated before use.
  195. func (c *cache) generate(dir string, limit int, test bool) {
  196. c.once.Do(func() {
  197. size := cacheSize(c.epoch*epochLength + 1)
  198. seed := seedHash(c.epoch*epochLength + 1)
  199. if test {
  200. size = 1024
  201. }
  202. // If we don't store anything on disk, generate and return.
  203. if dir == "" {
  204. c.cache = make([]uint32, size/4)
  205. generateCache(c.cache, c.epoch, seed)
  206. return
  207. }
  208. // Disk storage is needed, this will get fancy
  209. var endian string
  210. if !isLittleEndian() {
  211. endian = ".be"
  212. }
  213. path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian))
  214. logger := log.New("epoch", c.epoch)
  215. // We're about to mmap the file, ensure that the mapping is cleaned up when the
  216. // cache becomes unused.
  217. runtime.SetFinalizer(c, (*cache).finalizer)
  218. // Try to load the file from disk and memory map it
  219. var err error
  220. c.dump, c.mmap, c.cache, err = memoryMap(path)
  221. if err == nil {
  222. logger.Debug("Loaded old ethash cache from disk")
  223. return
  224. }
  225. logger.Debug("Failed to load old ethash cache", "err", err)
  226. // No previous cache available, create a new cache file to fill
  227. c.dump, c.mmap, c.cache, err = memoryMapAndGenerate(path, size, func(buffer []uint32) { generateCache(buffer, c.epoch, seed) })
  228. if err != nil {
  229. logger.Error("Failed to generate mapped ethash cache", "err", err)
  230. c.cache = make([]uint32, size/4)
  231. generateCache(c.cache, c.epoch, seed)
  232. }
  233. // Iterate over all previous instances and delete old ones
  234. for ep := int(c.epoch) - limit; ep >= 0; ep-- {
  235. seed := seedHash(uint64(ep)*epochLength + 1)
  236. path := filepath.Join(dir, fmt.Sprintf("cache-R%d-%x%s", algorithmRevision, seed[:8], endian))
  237. os.Remove(path)
  238. }
  239. })
  240. }
  241. // finalizer unmaps the memory and closes the file.
  242. func (c *cache) finalizer() {
  243. if c.mmap != nil {
  244. c.mmap.Unmap()
  245. c.dump.Close()
  246. c.mmap, c.dump = nil, nil
  247. }
  248. }
  249. // dataset wraps an ethash dataset with some metadata to allow easier concurrent use.
  250. type dataset struct {
  251. epoch uint64 // Epoch for which this cache is relevant
  252. dump *os.File // File descriptor of the memory mapped cache
  253. mmap mmap.MMap // Memory map itself to unmap before releasing
  254. dataset []uint32 // The actual cache data content
  255. once sync.Once // Ensures the cache is generated only once
  256. done uint32 // Atomic flag to determine generation status
  257. }
  258. // newDataset creates a new ethash mining dataset and returns it as a plain Go
  259. // interface to be usable in an LRU cache.
  260. func newDataset(epoch uint64) interface{} {
  261. return &dataset{epoch: epoch}
  262. }
  263. // generate ensures that the dataset content is generated before use.
  264. func (d *dataset) generate(dir string, limit int, test bool) {
  265. d.once.Do(func() {
  266. // Mark the dataset generated after we're done. This is needed for remote
  267. defer atomic.StoreUint32(&d.done, 1)
  268. csize := cacheSize(d.epoch*epochLength + 1)
  269. dsize := datasetSize(d.epoch*epochLength + 1)
  270. seed := seedHash(d.epoch*epochLength + 1)
  271. if test {
  272. csize = 1024
  273. dsize = 32 * 1024
  274. }
  275. // If we don't store anything on disk, generate and return
  276. if dir == "" {
  277. cache := make([]uint32, csize/4)
  278. generateCache(cache, d.epoch, seed)
  279. d.dataset = make([]uint32, dsize/4)
  280. generateDataset(d.dataset, d.epoch, cache)
  281. return
  282. }
  283. // Disk storage is needed, this will get fancy
  284. var endian string
  285. if !isLittleEndian() {
  286. endian = ".be"
  287. }
  288. path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian))
  289. logger := log.New("epoch", d.epoch)
  290. // We're about to mmap the file, ensure that the mapping is cleaned up when the
  291. // cache becomes unused.
  292. runtime.SetFinalizer(d, (*dataset).finalizer)
  293. // Try to load the file from disk and memory map it
  294. var err error
  295. d.dump, d.mmap, d.dataset, err = memoryMap(path)
  296. if err == nil {
  297. logger.Debug("Loaded old ethash dataset from disk")
  298. return
  299. }
  300. logger.Debug("Failed to load old ethash dataset", "err", err)
  301. // No previous dataset available, create a new dataset file to fill
  302. cache := make([]uint32, csize/4)
  303. generateCache(cache, d.epoch, seed)
  304. d.dump, d.mmap, d.dataset, err = memoryMapAndGenerate(path, dsize, func(buffer []uint32) { generateDataset(buffer, d.epoch, cache) })
  305. if err != nil {
  306. logger.Error("Failed to generate mapped ethash dataset", "err", err)
  307. d.dataset = make([]uint32, dsize/2)
  308. generateDataset(d.dataset, d.epoch, cache)
  309. }
  310. // Iterate over all previous instances and delete old ones
  311. for ep := int(d.epoch) - limit; ep >= 0; ep-- {
  312. seed := seedHash(uint64(ep)*epochLength + 1)
  313. path := filepath.Join(dir, fmt.Sprintf("full-R%d-%x%s", algorithmRevision, seed[:8], endian))
  314. os.Remove(path)
  315. }
  316. })
  317. }
  318. // generated returns whether this particular dataset finished generating already
  319. // or not (it may not have been started at all). This is useful for remote miners
  320. // to default to verification caches instead of blocking on DAG generations.
  321. func (d *dataset) generated() bool {
  322. return atomic.LoadUint32(&d.done) == 1
  323. }
  324. // finalizer closes any file handlers and memory maps open.
  325. func (d *dataset) finalizer() {
  326. if d.mmap != nil {
  327. d.mmap.Unmap()
  328. d.dump.Close()
  329. d.mmap, d.dump = nil, nil
  330. }
  331. }
  332. // MakeCache generates a new ethash cache and optionally stores it to disk.
  333. func MakeCache(block uint64, dir string) {
  334. c := cache{epoch: block / epochLength}
  335. c.generate(dir, math.MaxInt32, false)
  336. }
  337. // MakeDataset generates a new ethash dataset and optionally stores it to disk.
  338. func MakeDataset(block uint64, dir string) {
  339. d := dataset{epoch: block / epochLength}
  340. d.generate(dir, math.MaxInt32, false)
  341. }
  342. // Mode defines the type and amount of PoW verification an ethash engine makes.
  343. type Mode uint
  344. const (
  345. ModeNormal Mode = iota
  346. ModeShared
  347. ModeTest
  348. ModeFake
  349. ModeFullFake
  350. )
  351. // Config are the configuration parameters of the ethash.
  352. type Config struct {
  353. CacheDir string
  354. CachesInMem int
  355. CachesOnDisk int
  356. DatasetDir string
  357. DatasetsInMem int
  358. DatasetsOnDisk int
  359. PowMode Mode
  360. }
  361. // sealTask wraps a seal block with relative result channel for remote sealer thread.
  362. type sealTask struct {
  363. block *types.Block
  364. results chan<- *types.Block
  365. }
  366. // mineResult wraps the pow solution parameters for the specified block.
  367. type mineResult struct {
  368. nonce types.BlockNonce
  369. mixDigest common.Hash
  370. hash common.Hash
  371. errc chan error
  372. }
  373. // hashrate wraps the hash rate submitted by the remote sealer.
  374. type hashrate struct {
  375. id common.Hash
  376. ping time.Time
  377. rate uint64
  378. done chan struct{}
  379. }
  380. // sealWork wraps a seal work package for remote sealer.
  381. type sealWork struct {
  382. errc chan error
  383. res chan [4]string
  384. }
  385. // Ethash is a consensus engine based on proof-of-work implementing the ethash
  386. // algorithm.
  387. type Ethash struct {
  388. config Config
  389. caches *lru // In memory caches to avoid regenerating too often
  390. datasets *lru // In memory datasets to avoid regenerating too often
  391. // Mining related fields
  392. rand *rand.Rand // Properly seeded random source for nonces
  393. threads int // Number of threads to mine on if mining
  394. update chan struct{} // Notification channel to update mining parameters
  395. hashrate metrics.Meter // Meter tracking the average hashrate
  396. // Remote sealer related fields
  397. workCh chan *sealTask // Notification channel to push new work and relative result channel to remote sealer
  398. fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work
  399. submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result
  400. fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
  401. submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate
  402. // The fields below are hooks for testing
  403. shared *Ethash // Shared PoW verifier to avoid cache regeneration
  404. fakeFail uint64 // Block number which fails PoW check even in fake mode
  405. fakeDelay time.Duration // Time delay to sleep for before returning from verify
  406. lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
  407. closeOnce sync.Once // Ensures exit channel will not be closed twice.
  408. exitCh chan chan error // Notification channel to exiting backend threads
  409. }
  410. // New creates a full sized ethash PoW scheme and starts a background thread for
  411. // remote mining, also optionally notifying a batch of remote services of new work
  412. // packages.
  413. func New(config Config, notify []string, noverify bool) *Ethash {
  414. if config.CachesInMem <= 0 {
  415. log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem)
  416. config.CachesInMem = 1
  417. }
  418. if config.CacheDir != "" && config.CachesOnDisk > 0 {
  419. log.Info("Disk storage enabled for ethash caches", "dir", config.CacheDir, "count", config.CachesOnDisk)
  420. }
  421. if config.DatasetDir != "" && config.DatasetsOnDisk > 0 {
  422. log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk)
  423. }
  424. ethash := &Ethash{
  425. config: config,
  426. caches: newlru("cache", config.CachesInMem, newCache),
  427. datasets: newlru("dataset", config.DatasetsInMem, newDataset),
  428. update: make(chan struct{}),
  429. hashrate: metrics.NewMeterForced(),
  430. workCh: make(chan *sealTask),
  431. fetchWorkCh: make(chan *sealWork),
  432. submitWorkCh: make(chan *mineResult),
  433. fetchRateCh: make(chan chan uint64),
  434. submitRateCh: make(chan *hashrate),
  435. exitCh: make(chan chan error),
  436. }
  437. go ethash.remote(notify, noverify)
  438. return ethash
  439. }
  440. // NewTester creates a small sized ethash PoW scheme useful only for testing
  441. // purposes.
  442. func NewTester(notify []string, noverify bool) *Ethash {
  443. ethash := &Ethash{
  444. config: Config{PowMode: ModeTest},
  445. caches: newlru("cache", 1, newCache),
  446. datasets: newlru("dataset", 1, newDataset),
  447. update: make(chan struct{}),
  448. hashrate: metrics.NewMeterForced(),
  449. workCh: make(chan *sealTask),
  450. fetchWorkCh: make(chan *sealWork),
  451. submitWorkCh: make(chan *mineResult),
  452. fetchRateCh: make(chan chan uint64),
  453. submitRateCh: make(chan *hashrate),
  454. exitCh: make(chan chan error),
  455. }
  456. go ethash.remote(notify, noverify)
  457. return ethash
  458. }
  459. // NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts
  460. // all blocks' seal as valid, though they still have to conform to the Ethereum
  461. // consensus rules.
  462. func NewFaker() *Ethash {
  463. return &Ethash{
  464. config: Config{
  465. PowMode: ModeFake,
  466. },
  467. }
  468. }
  469. // NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that
  470. // accepts all blocks as valid apart from the single one specified, though they
  471. // still have to conform to the Ethereum consensus rules.
  472. func NewFakeFailer(fail uint64) *Ethash {
  473. return &Ethash{
  474. config: Config{
  475. PowMode: ModeFake,
  476. },
  477. fakeFail: fail,
  478. }
  479. }
  480. // NewFakeDelayer creates a ethash consensus engine with a fake PoW scheme that
  481. // accepts all blocks as valid, but delays verifications by some time, though
  482. // they still have to conform to the Ethereum consensus rules.
  483. func NewFakeDelayer(delay time.Duration) *Ethash {
  484. return &Ethash{
  485. config: Config{
  486. PowMode: ModeFake,
  487. },
  488. fakeDelay: delay,
  489. }
  490. }
  491. // NewFullFaker creates an ethash consensus engine with a full fake scheme that
  492. // accepts all blocks as valid, without checking any consensus rules whatsoever.
  493. func NewFullFaker() *Ethash {
  494. return &Ethash{
  495. config: Config{
  496. PowMode: ModeFullFake,
  497. },
  498. }
  499. }
  500. // NewShared creates a full sized ethash PoW shared between all requesters running
  501. // in the same process.
  502. func NewShared() *Ethash {
  503. return &Ethash{shared: sharedEthash}
  504. }
  505. // Close closes the exit channel to notify all backend threads exiting.
  506. func (ethash *Ethash) Close() error {
  507. var err error
  508. ethash.closeOnce.Do(func() {
  509. // Short circuit if the exit channel is not allocated.
  510. if ethash.exitCh == nil {
  511. return
  512. }
  513. errc := make(chan error)
  514. ethash.exitCh <- errc
  515. err = <-errc
  516. close(ethash.exitCh)
  517. })
  518. return err
  519. }
  520. // cache tries to retrieve a verification cache for the specified block number
  521. // by first checking against a list of in-memory caches, then against caches
  522. // stored on disk, and finally generating one if none can be found.
  523. func (ethash *Ethash) cache(block uint64) *cache {
  524. epoch := block / epochLength
  525. currentI, futureI := ethash.caches.get(epoch)
  526. current := currentI.(*cache)
  527. // Wait for generation finish.
  528. current.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest)
  529. // If we need a new future cache, now's a good time to regenerate it.
  530. if futureI != nil {
  531. future := futureI.(*cache)
  532. go future.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest)
  533. }
  534. return current
  535. }
  536. // dataset tries to retrieve a mining dataset for the specified block number
  537. // by first checking against a list of in-memory datasets, then against DAGs
  538. // stored on disk, and finally generating one if none can be found.
  539. //
  540. // If async is specified, not only the future but the current DAG is also
  541. // generates on a background thread.
  542. func (ethash *Ethash) dataset(block uint64, async bool) *dataset {
  543. // Retrieve the requested ethash dataset
  544. epoch := block / epochLength
  545. currentI, futureI := ethash.datasets.get(epoch)
  546. current := currentI.(*dataset)
  547. // If async is specified, generate everything in a background thread
  548. if async && !current.generated() {
  549. go func() {
  550. current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest)
  551. if futureI != nil {
  552. future := futureI.(*dataset)
  553. future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest)
  554. }
  555. }()
  556. } else {
  557. // Either blocking generation was requested, or already done
  558. current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest)
  559. if futureI != nil {
  560. future := futureI.(*dataset)
  561. go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest)
  562. }
  563. }
  564. return current
  565. }
  566. // Threads returns the number of mining threads currently enabled. This doesn't
  567. // necessarily mean that mining is running!
  568. func (ethash *Ethash) Threads() int {
  569. ethash.lock.Lock()
  570. defer ethash.lock.Unlock()
  571. return ethash.threads
  572. }
  573. // SetThreads updates the number of mining threads currently enabled. Calling
  574. // this method does not start mining, only sets the thread count. If zero is
  575. // specified, the miner will use all cores of the machine. Setting a thread
  576. // count below zero is allowed and will cause the miner to idle, without any
  577. // work being done.
  578. func (ethash *Ethash) SetThreads(threads int) {
  579. ethash.lock.Lock()
  580. defer ethash.lock.Unlock()
  581. // If we're running a shared PoW, set the thread count on that instead
  582. if ethash.shared != nil {
  583. ethash.shared.SetThreads(threads)
  584. return
  585. }
  586. // Update the threads and ping any running seal to pull in any changes
  587. ethash.threads = threads
  588. select {
  589. case ethash.update <- struct{}{}:
  590. default:
  591. }
  592. }
  593. // Hashrate implements PoW, returning the measured rate of the search invocations
  594. // per second over the last minute.
  595. // Note the returned hashrate includes local hashrate, but also includes the total
  596. // hashrate of all remote miner.
  597. func (ethash *Ethash) Hashrate() float64 {
  598. // Short circuit if we are run the ethash in normal/test mode.
  599. if ethash.config.PowMode != ModeNormal && ethash.config.PowMode != ModeTest {
  600. return ethash.hashrate.Rate1()
  601. }
  602. var res = make(chan uint64, 1)
  603. select {
  604. case ethash.fetchRateCh <- res:
  605. case <-ethash.exitCh:
  606. // Return local hashrate only if ethash is stopped.
  607. return ethash.hashrate.Rate1()
  608. }
  609. // Gather total submitted hash rate of remote sealers.
  610. return ethash.hashrate.Rate1() + float64(<-res)
  611. }
  612. // APIs implements consensus.Engine, returning the user facing RPC APIs.
  613. func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API {
  614. // In order to ensure backward compatibility, we exposes ethash RPC APIs
  615. // to both eth and ethash namespaces.
  616. return []rpc.API{
  617. {
  618. Namespace: "eth",
  619. Version: "1.0",
  620. Service: &API{ethash},
  621. Public: true,
  622. },
  623. {
  624. Namespace: "ethash",
  625. Version: "1.0",
  626. Service: &API{ethash},
  627. Public: true,
  628. },
  629. }
  630. }
  631. // SeedHash is the seed to use for generating a verification cache and the mining
  632. // dataset.
  633. func SeedHash(block uint64) []byte {
  634. return seedHash(block)
  635. }