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