github.com/luckypickle/go-ethereum-vet@v1.14.2/consensus/ethash/ethash.go (about) 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 17 // Package ethash implements the ethash proof-of-work consensus engine. 18 package ethash 19 20 import ( 21 "errors" 22 "fmt" 23 "math" 24 "math/big" 25 "math/rand" 26 "os" 27 "path/filepath" 28 "reflect" 29 "runtime" 30 "strconv" 31 "sync" 32 "sync/atomic" 33 "time" 34 "unsafe" 35 36 mmap "github.com/edsrzf/mmap-go" 37 "github.com/hashicorp/golang-lru/simplelru" 38 "github.com/luckypickle/go-ethereum-vet/common" 39 "github.com/luckypickle/go-ethereum-vet/consensus" 40 "github.com/luckypickle/go-ethereum-vet/core/types" 41 "github.com/luckypickle/go-ethereum-vet/log" 42 "github.com/luckypickle/go-ethereum-vet/metrics" 43 "github.com/luckypickle/go-ethereum-vet/rpc" 44 ) 45 46 var ErrInvalidDumpMagic = errors.New("invalid dump magic") 47 48 var ( 49 // two256 is a big integer representing 2^256 50 two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0)) 51 52 // sharedEthash is a full instance that can be shared between multiple users. 53 sharedEthash = New(Config{"", 3, 0, "", 1, 0, ModeNormal}, nil) 54 55 // algorithmRevision is the data structure version used for file naming. 56 algorithmRevision = 23 57 58 // dumpMagic is a dataset dump header to sanity check a data dump. 59 dumpMagic = []uint32{0xbaddcafe, 0xfee1dead} 60 ) 61 62 // isLittleEndian returns whether the local system is running in little or big 63 // endian byte order. 64 func isLittleEndian() bool { 65 n := uint32(0x01020304) 66 return *(*byte)(unsafe.Pointer(&n)) == 0x04 67 } 68 69 // memoryMap tries to memory map a file of uint32s for read only access. 70 func memoryMap(path string) (*os.File, mmap.MMap, []uint32, error) { 71 file, err := os.OpenFile(path, os.O_RDONLY, 0644) 72 if err != nil { 73 return nil, nil, nil, err 74 } 75 mem, buffer, err := memoryMapFile(file, false) 76 if err != nil { 77 file.Close() 78 return nil, nil, nil, err 79 } 80 for i, magic := range dumpMagic { 81 if buffer[i] != magic { 82 mem.Unmap() 83 file.Close() 84 return nil, nil, nil, ErrInvalidDumpMagic 85 } 86 } 87 return file, mem, buffer[len(dumpMagic):], err 88 } 89 90 // memoryMapFile tries to memory map an already opened file descriptor. 91 func memoryMapFile(file *os.File, write bool) (mmap.MMap, []uint32, error) { 92 // Try to memory map the file 93 flag := mmap.RDONLY 94 if write { 95 flag = mmap.RDWR 96 } 97 mem, err := mmap.Map(file, flag, 0) 98 if err != nil { 99 return nil, nil, err 100 } 101 // The file is now memory-mapped. Create a []uint32 view of the file. 102 var view []uint32 103 header := (*reflect.SliceHeader)(unsafe.Pointer(&view)) 104 header.Data = (*reflect.SliceHeader)(unsafe.Pointer(&mem)).Data 105 header.Cap = len(mem) / 4 106 header.Len = header.Cap 107 return mem, view, 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 // mineResult wraps the pow solution parameters for the specified block. 410 type mineResult struct { 411 nonce types.BlockNonce 412 mixDigest common.Hash 413 hash common.Hash 414 415 errc chan error 416 } 417 418 // hashrate wraps the hash rate submitted by the remote sealer. 419 type hashrate struct { 420 id common.Hash 421 ping time.Time 422 rate uint64 423 424 done chan struct{} 425 } 426 427 // sealWork wraps a seal work package for remote sealer. 428 type sealWork struct { 429 errc chan error 430 res chan [3]string 431 } 432 433 // Ethash is a consensus engine based on proof-of-work implementing the ethash 434 // algorithm. 435 type Ethash struct { 436 config Config 437 438 caches *lru // In memory caches to avoid regenerating too often 439 datasets *lru // In memory datasets to avoid regenerating too often 440 441 // Mining related fields 442 rand *rand.Rand // Properly seeded random source for nonces 443 threads int // Number of threads to mine on if mining 444 update chan struct{} // Notification channel to update mining parameters 445 hashrate metrics.Meter // Meter tracking the average hashrate 446 447 // Remote sealer related fields 448 workCh chan *types.Block // Notification channel to push new work to remote sealer 449 resultCh chan *types.Block // Channel used by mining threads to return result 450 fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work 451 submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result 452 fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer. 453 submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate 454 455 // The fields below are hooks for testing 456 shared *Ethash // Shared PoW verifier to avoid cache regeneration 457 fakeFail uint64 // Block number which fails PoW check even in fake mode 458 fakeDelay time.Duration // Time delay to sleep for before returning from verify 459 460 lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields 461 closeOnce sync.Once // Ensures exit channel will not be closed twice. 462 exitCh chan chan error // Notification channel to exiting backend threads 463 } 464 465 // New creates a full sized ethash PoW scheme and starts a background thread for 466 // remote mining, also optionally notifying a batch of remote services of new work 467 // packages. 468 func New(config Config, notify []string) *Ethash { 469 if config.CachesInMem <= 0 { 470 log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem) 471 config.CachesInMem = 1 472 } 473 if config.CacheDir != "" && config.CachesOnDisk > 0 { 474 log.Info("Disk storage enabled for ethash caches", "dir", config.CacheDir, "count", config.CachesOnDisk) 475 } 476 if config.DatasetDir != "" && config.DatasetsOnDisk > 0 { 477 log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk) 478 } 479 ethash := &Ethash{ 480 config: config, 481 caches: newlru("cache", config.CachesInMem, newCache), 482 datasets: newlru("dataset", config.DatasetsInMem, newDataset), 483 update: make(chan struct{}), 484 hashrate: metrics.NewMeter(), 485 workCh: make(chan *types.Block), 486 resultCh: make(chan *types.Block), 487 fetchWorkCh: make(chan *sealWork), 488 submitWorkCh: make(chan *mineResult), 489 fetchRateCh: make(chan chan uint64), 490 submitRateCh: make(chan *hashrate), 491 exitCh: make(chan chan error), 492 } 493 go ethash.remote(notify) 494 return ethash 495 } 496 497 // NewTester creates a small sized ethash PoW scheme useful only for testing 498 // purposes. 499 func NewTester(notify []string) *Ethash { 500 ethash := &Ethash{ 501 config: Config{PowMode: ModeTest}, 502 caches: newlru("cache", 1, newCache), 503 datasets: newlru("dataset", 1, newDataset), 504 update: make(chan struct{}), 505 hashrate: metrics.NewMeter(), 506 workCh: make(chan *types.Block), 507 resultCh: make(chan *types.Block), 508 fetchWorkCh: make(chan *sealWork), 509 submitWorkCh: make(chan *mineResult), 510 fetchRateCh: make(chan chan uint64), 511 submitRateCh: make(chan *hashrate), 512 exitCh: make(chan chan error), 513 } 514 go ethash.remote(notify) 515 return ethash 516 } 517 518 // NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts 519 // all blocks' seal as valid, though they still have to conform to the Ethereum 520 // consensus rules. 521 func NewFaker() *Ethash { 522 return &Ethash{ 523 config: Config{ 524 PowMode: ModeFake, 525 }, 526 } 527 } 528 529 // NewFakeFailer creates a ethash consensus engine with a fake PoW scheme that 530 // accepts all blocks as valid apart from the single one specified, though they 531 // still have to conform to the Ethereum consensus rules. 532 func NewFakeFailer(fail uint64) *Ethash { 533 return &Ethash{ 534 config: Config{ 535 PowMode: ModeFake, 536 }, 537 fakeFail: fail, 538 } 539 } 540 541 // NewFakeDelayer creates a ethash consensus engine with a fake PoW scheme that 542 // accepts all blocks as valid, but delays verifications by some time, though 543 // they still have to conform to the Ethereum consensus rules. 544 func NewFakeDelayer(delay time.Duration) *Ethash { 545 return &Ethash{ 546 config: Config{ 547 PowMode: ModeFake, 548 }, 549 fakeDelay: delay, 550 } 551 } 552 553 // NewFullFaker creates an ethash consensus engine with a full fake scheme that 554 // accepts all blocks as valid, without checking any consensus rules whatsoever. 555 func NewFullFaker() *Ethash { 556 return &Ethash{ 557 config: Config{ 558 PowMode: ModeFullFake, 559 }, 560 } 561 } 562 563 // NewShared creates a full sized ethash PoW shared between all requesters running 564 // in the same process. 565 func NewShared() *Ethash { 566 return &Ethash{shared: sharedEthash} 567 } 568 569 // Close closes the exit channel to notify all backend threads exiting. 570 func (ethash *Ethash) Close() error { 571 var err error 572 ethash.closeOnce.Do(func() { 573 // Short circuit if the exit channel is not allocated. 574 if ethash.exitCh == nil { 575 return 576 } 577 errc := make(chan error) 578 ethash.exitCh <- errc 579 err = <-errc 580 close(ethash.exitCh) 581 }) 582 return err 583 } 584 585 // cache tries to retrieve a verification cache for the specified block number 586 // by first checking against a list of in-memory caches, then against caches 587 // stored on disk, and finally generating one if none can be found. 588 func (ethash *Ethash) cache(block uint64) *cache { 589 epoch := block / epochLength 590 currentI, futureI := ethash.caches.get(epoch) 591 current := currentI.(*cache) 592 593 // Wait for generation finish. 594 current.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest) 595 596 // If we need a new future cache, now's a good time to regenerate it. 597 if futureI != nil { 598 future := futureI.(*cache) 599 go future.generate(ethash.config.CacheDir, ethash.config.CachesOnDisk, ethash.config.PowMode == ModeTest) 600 } 601 return current 602 } 603 604 // dataset tries to retrieve a mining dataset for the specified block number 605 // by first checking against a list of in-memory datasets, then against DAGs 606 // stored on disk, and finally generating one if none can be found. 607 // 608 // If async is specified, not only the future but the current DAG is also 609 // generates on a background thread. 610 func (ethash *Ethash) dataset(block uint64, async bool) *dataset { 611 // Retrieve the requested ethash dataset 612 epoch := block / epochLength 613 currentI, futureI := ethash.datasets.get(epoch) 614 current := currentI.(*dataset) 615 616 // If async is specified, generate everything in a background thread 617 if async && !current.generated() { 618 go func() { 619 current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 620 621 if futureI != nil { 622 future := futureI.(*dataset) 623 future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 624 } 625 }() 626 } else { 627 // Either blocking generation was requested, or already done 628 current.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 629 630 if futureI != nil { 631 future := futureI.(*dataset) 632 go future.generate(ethash.config.DatasetDir, ethash.config.DatasetsOnDisk, ethash.config.PowMode == ModeTest) 633 } 634 } 635 return current 636 } 637 638 // Threads returns the number of mining threads currently enabled. This doesn't 639 // necessarily mean that mining is running! 640 func (ethash *Ethash) Threads() int { 641 ethash.lock.Lock() 642 defer ethash.lock.Unlock() 643 644 return ethash.threads 645 } 646 647 // SetThreads updates the number of mining threads currently enabled. Calling 648 // this method does not start mining, only sets the thread count. If zero is 649 // specified, the miner will use all cores of the machine. Setting a thread 650 // count below zero is allowed and will cause the miner to idle, without any 651 // work being done. 652 func (ethash *Ethash) SetThreads(threads int) { 653 ethash.lock.Lock() 654 defer ethash.lock.Unlock() 655 656 // If we're running a shared PoW, set the thread count on that instead 657 if ethash.shared != nil { 658 ethash.shared.SetThreads(threads) 659 return 660 } 661 // Update the threads and ping any running seal to pull in any changes 662 ethash.threads = threads 663 select { 664 case ethash.update <- struct{}{}: 665 default: 666 } 667 } 668 669 // Hashrate implements PoW, returning the measured rate of the search invocations 670 // per second over the last minute. 671 // Note the returned hashrate includes local hashrate, but also includes the total 672 // hashrate of all remote miner. 673 func (ethash *Ethash) Hashrate() float64 { 674 // Short circuit if we are run the ethash in normal/test mode. 675 if ethash.config.PowMode != ModeNormal && ethash.config.PowMode != ModeTest { 676 return ethash.hashrate.Rate1() 677 } 678 var res = make(chan uint64, 1) 679 680 select { 681 case ethash.fetchRateCh <- res: 682 case <-ethash.exitCh: 683 // Return local hashrate only if ethash is stopped. 684 return ethash.hashrate.Rate1() 685 } 686 687 // Gather total submitted hash rate of remote sealers. 688 return ethash.hashrate.Rate1() + float64(<-res) 689 } 690 691 // APIs implements consensus.Engine, returning the user facing RPC APIs. 692 func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API { 693 // In order to ensure backward compatibility, we exposes ethash RPC APIs 694 // to both eth and ethash namespaces. 695 return []rpc.API{ 696 { 697 Namespace: "eth", 698 Version: "1.0", 699 Service: &API{ethash}, 700 Public: true, 701 }, 702 { 703 Namespace: "ethash", 704 Version: "1.0", 705 Service: &API{ethash}, 706 Public: true, 707 }, 708 } 709 } 710 711 // SeedHash is the seed to use for generating a verification cache and the mining 712 // dataset. 713 func SeedHash(block uint64) []byte { 714 return seedHash(block) 715 }