Skip to content

Commit 51db597

Browse files
rjl493456442karalabe
authored andcommitted
consensus/ethash: move remote agent logic to ethash internal (#15853)
* consensus/ethash: start remote ggoroutine to handle remote mining * consensus/ethash: expose remote miner api * consensus/ethash: expose submitHashrate api * miner, ethash: push empty block to sealer without waiting execution * consensus, internal: add getHashrate API for ethash * consensus: add three method for consensus interface * miner: expose consensus engine running status to miner * eth, miner: specify etherbase when miner created * miner: commit new work when consensus engine is started * consensus, miner: fix some logics * all: delete useless interfaces * consensus: polish a bit
1 parent 70176cd commit 51db597

File tree

16 files changed

+608
-361
lines changed

16 files changed

+608
-361
lines changed

cmd/geth/consolecmd_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
)
3232

3333
const (
34-
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
34+
ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 shh:1.0 txpool:1.0 web3:1.0"
3535
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
3636
)
3737

consensus/clique/clique.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,11 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
672672
return new(big.Int).Set(diffNoTurn)
673673
}
674674

675+
// Close implements consensus.Engine. It's a noop for clique as there is are no background threads.
676+
func (c *Clique) Close() error {
677+
return nil
678+
}
679+
675680
// APIs implements consensus.Engine, returning the user facing RPC API to allow
676681
// controlling the signer voting.
677682
func (c *Clique) APIs(chain consensus.ChainReader) []rpc.API {

consensus/consensus.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ type Engine interface {
9696

9797
// APIs returns the RPC APIs this consensus engine provides.
9898
APIs(chain ChainReader) []rpc.API
99+
100+
// Close terminates any background threads maintained by the consensus engine.
101+
Close() error
99102
}
100103

101104
// PoW is a consensus engine based on proof-of-work.

consensus/ethash/algorithm_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,7 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) {
730730
go func(idx int) {
731731
defer pend.Done()
732732
ethash := New(Config{cachedir, 0, 1, "", 0, 0, ModeNormal})
733+
defer ethash.Close()
733734
if err := ethash.VerifySeal(nil, block.Header()); err != nil {
734735
t.Errorf("proc %d: block verification failed: %v", idx, err)
735736
}

consensus/ethash/api.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2018 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
18+
19+
import (
20+
"errors"
21+
22+
"github.com/ethereum/go-ethereum/common"
23+
"github.com/ethereum/go-ethereum/common/hexutil"
24+
"github.com/ethereum/go-ethereum/core/types"
25+
)
26+
27+
var errEthashStopped = errors.New("ethash stopped")
28+
29+
// API exposes ethash related methods for the RPC interface.
30+
type API struct {
31+
ethash *Ethash // Make sure the mode of ethash is normal.
32+
}
33+
34+
// GetWork returns a work package for external miner.
35+
//
36+
// The work package consists of 3 strings:
37+
// result[0] - 32 bytes hex encoded current block header pow-hash
38+
// result[1] - 32 bytes hex encoded seed hash used for DAG
39+
// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
40+
func (api *API) GetWork() ([3]string, error) {
41+
if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest {
42+
return [3]string{}, errors.New("not supported")
43+
}
44+
45+
var (
46+
workCh = make(chan [3]string, 1)
47+
errc = make(chan error, 1)
48+
)
49+
50+
select {
51+
case api.ethash.fetchWorkCh <- &sealWork{errc: errc, res: workCh}:
52+
case <-api.ethash.exitCh:
53+
return [3]string{}, errEthashStopped
54+
}
55+
56+
select {
57+
case work := <-workCh:
58+
return work, nil
59+
case err := <-errc:
60+
return [3]string{}, err
61+
}
62+
}
63+
64+
// SubmitWork can be used by external miner to submit their POW solution.
65+
// It returns an indication if the work was accepted.
66+
// Note either an invalid solution, a stale work a non-existent work will return false.
67+
func (api *API) SubmitWork(nonce types.BlockNonce, hash, digest common.Hash) bool {
68+
if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest {
69+
return false
70+
}
71+
72+
var errc = make(chan error, 1)
73+
74+
select {
75+
case api.ethash.submitWorkCh <- &mineResult{
76+
nonce: nonce,
77+
mixDigest: digest,
78+
hash: hash,
79+
errc: errc,
80+
}:
81+
case <-api.ethash.exitCh:
82+
return false
83+
}
84+
85+
err := <-errc
86+
return err == nil
87+
}
88+
89+
// SubmitHashrate can be used for remote miners to submit their hash rate.
90+
// This enables the node to report the combined hash rate of all miners
91+
// which submit work through this node.
92+
//
93+
// It accepts the miner hash rate and an identifier which must be unique
94+
// between nodes.
95+
func (api *API) SubmitHashRate(rate hexutil.Uint64, id common.Hash) bool {
96+
if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest {
97+
return false
98+
}
99+
100+
var done = make(chan struct{}, 1)
101+
102+
select {
103+
case api.ethash.submitRateCh <- &hashrate{done: done, rate: uint64(rate), id: id}:
104+
case <-api.ethash.exitCh:
105+
return false
106+
}
107+
108+
// Block until hash rate submitted successfully.
109+
<-done
110+
111+
return true
112+
}
113+
114+
// GetHashrate returns the current hashrate for local CPU miner and remote miner.
115+
func (api *API) GetHashrate() uint64 {
116+
return uint64(api.ethash.Hashrate())
117+
}

consensus/ethash/ethash.go

Lines changed: 119 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
394420
type 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.
415451
func 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.
437482
func 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.
564642
func (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.
570661
func (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

Comments
 (0)