ethash.go 22 KB

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