aboutsummaryrefslogtreecommitdiffstats
path: root/consensus/ethash/ethash.go
diff options
context:
space:
mode:
Diffstat (limited to 'consensus/ethash/ethash.go')
-rw-r--r--consensus/ethash/ethash.go132
1 files changed, 119 insertions, 13 deletions
diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go
index f79dd6c36..0cb3059b9 100644
--- a/consensus/ethash/ethash.go
+++ b/consensus/ethash/ethash.go
@@ -33,7 +33,9 @@ import (
"unsafe"
mmap "github.com/edsrzf/mmap-go"
+ "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/rpc"
@@ -389,6 +391,30 @@ type Config struct {
PowMode Mode
}
+// mineResult wraps the pow solution parameters for the specified block.
+type mineResult struct {
+ nonce types.BlockNonce
+ mixDigest common.Hash
+ hash common.Hash
+
+ errc chan error
+}
+
+// hashrate wraps the hash rate submitted by the remote sealer.
+type hashrate struct {
+ id common.Hash
+ ping time.Time
+ rate uint64
+
+ done chan struct{}
+}
+
+// sealWork wraps a seal work package for remote sealer.
+type sealWork struct {
+ errc chan error
+ res chan [3]string
+}
+
// Ethash is a consensus engine based on proof-of-work implementing the ethash
// algorithm.
type Ethash struct {
@@ -403,15 +429,25 @@ type Ethash struct {
update chan struct{} // Notification channel to update mining parameters
hashrate metrics.Meter // Meter tracking the average hashrate
+ // Remote sealer related fields
+ workCh chan *types.Block // Notification channel to push new work to remote sealer
+ resultCh chan *types.Block // Channel used by mining threads to return result
+ fetchWorkCh chan *sealWork // Channel used for remote sealer to fetch mining work
+ submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result
+ fetchRateCh chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
+ submitRateCh chan *hashrate // Channel used for remote sealer to submit their mining hashrate
+
// The fields below are hooks for testing
shared *Ethash // Shared PoW verifier to avoid cache regeneration
fakeFail uint64 // Block number which fails PoW check even in fake mode
fakeDelay time.Duration // Time delay to sleep for before returning from verify
- lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
+ lock sync.Mutex // Ensures thread safety for the in-memory caches and mining fields
+ closeOnce sync.Once // Ensures exit channel will not be closed twice.
+ exitCh chan chan error // Notification channel to exiting backend threads
}
-// New creates a full sized ethash PoW scheme.
+// New creates a full sized ethash PoW scheme and starts a background thread for remote mining.
func New(config Config) *Ethash {
if config.CachesInMem <= 0 {
log.Warn("One ethash cache must always be in memory", "requested", config.CachesInMem)
@@ -423,19 +459,43 @@ func New(config Config) *Ethash {
if config.DatasetDir != "" && config.DatasetsOnDisk > 0 {
log.Info("Disk storage enabled for ethash DAGs", "dir", config.DatasetDir, "count", config.DatasetsOnDisk)
}
- return &Ethash{
- config: config,
- caches: newlru("cache", config.CachesInMem, newCache),
- datasets: newlru("dataset", config.DatasetsInMem, newDataset),
- update: make(chan struct{}),
- hashrate: metrics.NewMeter(),
+ ethash := &Ethash{
+ config: config,
+ caches: newlru("cache", config.CachesInMem, newCache),
+ datasets: newlru("dataset", config.DatasetsInMem, newDataset),
+ update: make(chan struct{}),
+ hashrate: metrics.NewMeter(),
+ workCh: make(chan *types.Block),
+ resultCh: make(chan *types.Block),
+ fetchWorkCh: make(chan *sealWork),
+ submitWorkCh: make(chan *mineResult),
+ fetchRateCh: make(chan chan uint64),
+ submitRateCh: make(chan *hashrate),
+ exitCh: make(chan chan error),
}
+ go ethash.remote()
+ return ethash
}
// NewTester creates a small sized ethash PoW scheme useful only for testing
// purposes.
func NewTester() *Ethash {
- return New(Config{CachesInMem: 1, PowMode: ModeTest})
+ ethash := &Ethash{
+ config: Config{PowMode: ModeTest},
+ caches: newlru("cache", 1, newCache),
+ datasets: newlru("dataset", 1, newDataset),
+ update: make(chan struct{}),
+ hashrate: metrics.NewMeter(),
+ workCh: make(chan *types.Block),
+ resultCh: make(chan *types.Block),
+ fetchWorkCh: make(chan *sealWork),
+ submitWorkCh: make(chan *mineResult),
+ fetchRateCh: make(chan chan uint64),
+ submitRateCh: make(chan *hashrate),
+ exitCh: make(chan chan error),
+ }
+ go ethash.remote()
+ return ethash
}
// NewFaker creates a ethash consensus engine with a fake PoW scheme that accepts
@@ -489,6 +549,22 @@ func NewShared() *Ethash {
return &Ethash{shared: sharedEthash}
}
+// Close closes the exit channel to notify all backend threads exiting.
+func (ethash *Ethash) Close() error {
+ var err error
+ ethash.closeOnce.Do(func() {
+ // Short circuit if the exit channel is not allocated.
+ if ethash.exitCh == nil {
+ return
+ }
+ errc := make(chan error)
+ ethash.exitCh <- errc
+ err = <-errc
+ close(ethash.exitCh)
+ })
+ return err
+}
+
// cache tries to retrieve a verification cache for the specified block number
// by first checking against a list of in-memory caches, then against caches
// stored on disk, and finally generating one if none can be found.
@@ -561,14 +637,44 @@ func (ethash *Ethash) SetThreads(threads int) {
// Hashrate implements PoW, returning the measured rate of the search invocations
// per second over the last minute.
+// Note the returned hashrate includes local hashrate, but also includes the total
+// hashrate of all remote miner.
func (ethash *Ethash) Hashrate() float64 {
- return ethash.hashrate.Rate1()
+ // Short circuit if we are run the ethash in normal/test mode.
+ if ethash.config.PowMode != ModeNormal && ethash.config.PowMode != ModeTest {
+ return ethash.hashrate.Rate1()
+ }
+ var res = make(chan uint64, 1)
+
+ select {
+ case ethash.fetchRateCh <- res:
+ case <-ethash.exitCh:
+ // Return local hashrate only if ethash is stopped.
+ return ethash.hashrate.Rate1()
+ }
+
+ // Gather total submitted hash rate of remote sealers.
+ return ethash.hashrate.Rate1() + float64(<-res)
}
-// APIs implements consensus.Engine, returning the user facing RPC APIs. Currently
-// that is empty.
+// APIs implements consensus.Engine, returning the user facing RPC APIs.
func (ethash *Ethash) APIs(chain consensus.ChainReader) []rpc.API {
- return nil
+ // In order to ensure backward compatibility, we exposes ethash RPC APIs
+ // to both eth and ethash namespaces.
+ return []rpc.API{
+ {
+ Namespace: "eth",
+ Version: "1.0",
+ Service: &API{ethash},
+ Public: true,
+ },
+ {
+ Namespace: "ethash",
+ Version: "1.0",
+ Service: &API{ethash},
+ Public: true,
+ },
+ }
}
// SeedHash is the seed to use for generating a verification cache and the mining