@@ -33,7 +33,9 @@ import (
3333 "unsafe"
3434
3535 mmap "github.com/edsrzf/mmap-go"
36+ "github.com/ethereum/go-ethereum/common"
3637 "github.com/ethereum/go-ethereum/consensus"
38+ "github.com/ethereum/go-ethereum/core/types"
3739 "github.com/ethereum/go-ethereum/log"
3840 "github.com/ethereum/go-ethereum/metrics"
3941 "github.com/ethereum/go-ethereum/rpc"
@@ -389,6 +391,30 @@ type Config struct {
389391 PowMode Mode
390392}
391393
394+ // mineResult wraps the pow solution parameters for the specified block.
395+ type mineResult struct {
396+ nonce types.BlockNonce
397+ mixDigest common.Hash
398+ hash common.Hash
399+
400+ errc chan error
401+ }
402+
403+ // hashrate wraps the hash rate submitted by the remote sealer.
404+ type hashrate struct {
405+ id common.Hash
406+ ping time.Time
407+ rate uint64
408+
409+ done chan struct {}
410+ }
411+
412+ // sealWork wraps a seal work package for remote sealer.
413+ type sealWork struct {
414+ errc chan error
415+ res chan [3 ]string
416+ }
417+
392418// Ethash is a consensus engine based on proof-of-work implementing the ethash
393419// algorithm.
394420type Ethash struct {
@@ -403,15 +429,25 @@ type Ethash struct {
403429 update chan struct {} // Notification channel to update mining parameters
404430 hashrate metrics.Meter // Meter tracking the average hashrate
405431
432+ // Remote sealer related fields
433+ workCh chan * types.Block // Notification channel to push new work to remote sealer
434+ resultCh chan * types.Block // Channel used by mining threads to return result
435+ fetchWorkCh chan * sealWork // Channel used for remote sealer to fetch mining work
436+ submitWorkCh chan * mineResult // Channel used for remote sealer to submit their mining result
437+ fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
438+ submitRateCh chan * hashrate // Channel used for remote sealer to submit their mining hashrate
439+
406440 // The fields below are hooks for testing
407441 shared * Ethash // Shared PoW verifier to avoid cache regeneration
408442 fakeFail uint64 // Block number which fails PoW check even in fake mode
409443 fakeDelay time.Duration // Time delay to sleep for before returning from verify
410444
411- lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
445+ lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
446+ closeOnce sync.Once // Ensures exit channel will not be closed twice.
447+ exitCh chan chan error // Notification channel to exiting backend threads
412448}
413449
414- // New creates a full sized ethash PoW scheme.
450+ // New creates a full sized ethash PoW scheme and starts a background thread for remote mining .
415451func New (config Config ) * Ethash {
416452 if config .CachesInMem <= 0 {
417453 log .Warn ("One ethash cache must always be in memory" , "requested" , config .CachesInMem )
@@ -423,19 +459,43 @@ func New(config Config) *Ethash {
423459 if config .DatasetDir != "" && config .DatasetsOnDisk > 0 {
424460 log .Info ("Disk storage enabled for ethash DAGs" , "dir" , config .DatasetDir , "count" , config .DatasetsOnDisk )
425461 }
426- return & Ethash {
427- config : config ,
428- caches : newlru ("cache" , config .CachesInMem , newCache ),
429- datasets : newlru ("dataset" , config .DatasetsInMem , newDataset ),
430- update : make (chan struct {}),
431- hashrate : metrics .NewMeter (),
462+ ethash := & Ethash {
463+ config : config ,
464+ caches : newlru ("cache" , config .CachesInMem , newCache ),
465+ datasets : newlru ("dataset" , config .DatasetsInMem , newDataset ),
466+ update : make (chan struct {}),
467+ hashrate : metrics .NewMeter (),
468+ workCh : make (chan * types.Block ),
469+ resultCh : make (chan * types.Block ),
470+ fetchWorkCh : make (chan * sealWork ),
471+ submitWorkCh : make (chan * mineResult ),
472+ fetchRateCh : make (chan chan uint64 ),
473+ submitRateCh : make (chan * hashrate ),
474+ exitCh : make (chan chan error ),
432475 }
476+ go ethash .remote ()
477+ return ethash
433478}
434479
435480// NewTester creates a small sized ethash PoW scheme useful only for testing
436481// purposes.
437482func NewTester () * Ethash {
438- return New (Config {CachesInMem : 1 , PowMode : ModeTest })
483+ ethash := & Ethash {
484+ config : Config {PowMode : ModeTest },
485+ caches : newlru ("cache" , 1 , newCache ),
486+ datasets : newlru ("dataset" , 1 , newDataset ),
487+ update : make (chan struct {}),
488+ hashrate : metrics .NewMeter (),
489+ workCh : make (chan * types.Block ),
490+ resultCh : make (chan * types.Block ),
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 ()
498+ return ethash
439499}
440500
441501// NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts
@@ -489,6 +549,22 @@ func NewShared() *Ethash {
489549 return & Ethash {shared : sharedEthash }
490550}
491551
552+ // Close closes the exit channel to notify all backend threads exiting.
553+ func (ethash * Ethash ) Close () error {
554+ var err error
555+ ethash .closeOnce .Do (func () {
556+ // Short circuit if the exit channel is not allocated.
557+ if ethash .exitCh == nil {
558+ return
559+ }
560+ errc := make (chan error )
561+ ethash .exitCh <- errc
562+ err = <- errc
563+ close (ethash .exitCh )
564+ })
565+ return err
566+ }
567+
492568// cache tries to retrieve a verification cache for the specified block number
493569// by first checking against a list of in-memory caches, then against caches
494570// stored on disk, and finally generating one if none can be found.
@@ -561,14 +637,44 @@ func (ethash *Ethash) SetThreads(threads int) {
561637
562638// Hashrate implements PoW, returning the measured rate of the search invocations
563639// per second over the last minute.
640+ // Note the returned hashrate includes local hashrate, but also includes the total
641+ // hashrate of all remote miner.
564642func (ethash * Ethash ) Hashrate () float64 {
565- return ethash .hashrate .Rate1 ()
643+ // Short circuit if we are run the ethash in normal/test mode.
644+ if ethash .config .PowMode != ModeNormal && ethash .config .PowMode != ModeTest {
645+ return ethash .hashrate .Rate1 ()
646+ }
647+ var res = make (chan uint64 , 1 )
648+
649+ select {
650+ case ethash .fetchRateCh <- res :
651+ case <- ethash .exitCh :
652+ // Return local hashrate only if ethash is stopped.
653+ return ethash .hashrate .Rate1 ()
654+ }
655+
656+ // Gather total submitted hash rate of remote sealers.
657+ return ethash .hashrate .Rate1 () + float64 (<- res )
566658}
567659
568- // APIs implements consensus.Engine, returning the user facing RPC APIs. Currently
569- // that is empty.
660+ // APIs implements consensus.Engine, returning the user facing RPC APIs.
570661func (ethash * Ethash ) APIs (chain consensus.ChainReader ) []rpc.API {
571- return nil
662+ // In order to ensure backward compatibility, we exposes ethash RPC APIs
663+ // to both eth and ethash namespaces.
664+ return []rpc.API {
665+ {
666+ Namespace : "eth" ,
667+ Version : "1.0" ,
668+ Service : & API {ethash },
669+ Public : true ,
670+ },
671+ {
672+ Namespace : "ethash" ,
673+ Version : "1.0" ,
674+ Service : & API {ethash },
675+ Public : true ,
676+ },
677+ }
572678}
573679
574680// SeedHash is the seed to use for generating a verification cache and the mining
0 commit comments