consensus: customized getWork endpoint

This commit is contained in:
rjl493456442 2018-09-17 13:28:10 +08:00
parent 7c71e936a7
commit dc62da5c8c
4 changed files with 72 additions and 7 deletions

View file

@ -31,13 +31,16 @@ type API struct {
ethash *Ethash // Make sure the mode of ethash is normal. ethash *Ethash // Make sure the mode of ethash is normal.
} }
// GetWork returns a work package for external miner. // getWork returns a work package for external miner.
//
// User can specify a customized extra to replace the extra field
// in the block header when the given string is not empty.
// //
// The work package consists of 3 strings: // The work package consists of 3 strings:
// result[0] - 32 bytes hex encoded current block header pow-hash // result[0] - 32 bytes hex encoded current block header pow-hash
// result[1] - 32 bytes hex encoded seed hash used for DAG // result[1] - 32 bytes hex encoded seed hash used for DAG
// result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty // result[2] - 32 bytes hex encoded boundary condition ("target"), 2^256/difficulty
func (api *API) GetWork() ([3]string, error) { func (api *API) getWork(extra string) ([3]string, error) {
if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest { if api.ethash.config.PowMode != ModeNormal && api.ethash.config.PowMode != ModeTest {
return [3]string{}, errors.New("not supported") return [3]string{}, errors.New("not supported")
} }
@ -48,7 +51,7 @@ func (api *API) GetWork() ([3]string, error) {
) )
select { select {
case api.ethash.fetchWorkCh <- &sealWork{errc: errc, res: workCh}: case api.ethash.fetchWorkCh <- &sealWork{extra: extra, errc: errc, res: workCh}:
case <-api.ethash.exitCh: case <-api.ethash.exitCh:
return [3]string{}, errEthashStopped return [3]string{}, errEthashStopped
} }
@ -61,6 +64,18 @@ func (api *API) GetWork() ([3]string, error) {
} }
} }
// GetWork returns a default work package for external miner.
//
// Note this function is a legacy for backward compatibility.
func (api *API) GetWork() ([3]string, error) {
return api.getWork("")
}
// GetCustomizedWork returns a customized work package for external miner.
func (api *API) GetCustomizedWork(extra string) ([3]string, error) {
return api.getWork(extra)
}
// SubmitWork can be used by external miner to submit their POW solution. // SubmitWork can be used by external miner to submit their POW solution.
// It returns an indication if the work was accepted. // It returns an indication if the work was accepted.
// Note either an invalid solution, a stale work a non-existent work will return false. // Note either an invalid solution, a stale work a non-existent work will return false.

View file

@ -431,6 +431,7 @@ type hashrate struct {
// sealWork wraps a seal work package for remote sealer. // sealWork wraps a seal work package for remote sealer.
type sealWork struct { type sealWork struct {
extra string // The specified string used to fill the block extra field
errc chan error errc chan error
res chan [3]string res chan [3]string
} }

View file

@ -117,6 +117,7 @@ func TestRemoteSealer(t *testing.T) {
if res := api.SubmitWork(types.BlockNonce{}, sealhash, common.Hash{}); res { if res := api.SubmitWork(types.BlockNonce{}, sealhash, common.Hash{}); res {
t.Error("expect to return false when submit a fake solution") t.Error("expect to return false when submit a fake solution")
} }
// Push new block with same block number to replace the original one. // Push new block with same block number to replace the original one.
header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)} header = &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(1000)}
block = types.NewBlockWithHeader(header) block = types.NewBlockWithHeader(header)
@ -128,6 +129,31 @@ func TestRemoteSealer(t *testing.T) {
} }
} }
func TestCustomizedWork(t *testing.T) {
ethash := NewTester(nil, true)
defer ethash.Close()
api := &API{ethash}
header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)}
block := types.NewBlockWithHeader(header)
// Push new work.
results := make(chan *types.Block, 1)
ethash.Seal(nil, block, results, nil)
// Get customized mining work.
expect := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100), Extra: []byte("extra")}
expectSealhash := ethash.SealHash(expect)
if work, err := api.GetCustomizedWork("extra"); err != nil || work[0] != expectSealhash.Hex() {
t.Errorf("expect to return a customized work, have %s, want %s", work[0], expectSealhash.Hex())
}
// Submit fake solution for customized work
if !api.SubmitWork(types.BlockNonce{}, expectSealhash, common.Hash{}) {
t.Error("submit solution for customized work failed")
}
}
func TestHashRate(t *testing.T) { func TestHashRate(t *testing.T) {
var ( var (
hashrate = []hexutil.Uint64{100, 200, 300} hashrate = []hexutil.Uint64{100, 200, 300}

View file

@ -245,6 +245,24 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
currentBlock = block currentBlock = block
works[hash] = block works[hash] = block
} }
// customizeWork creates a work package for external miner
// with customized extra data.
customizeWork := func(extra string) [3]string {
newHeader := currentBlock.Header()
newHeader.Extra = []byte(extra)
newBlock := types.NewBlockWithHeader(newHeader)
// Recalculate mining work
var work [3]string
hash := ethash.SealHash(newHeader)
work[0] = hash.Hex()
work[1] = currentWork[1]
work[2] = currentWork[2]
// Trace the seal work fetched by remote sealer.
works[hash] = newBlock
return work
}
// submitWork verifies the submitted pow solution, returning // submitWork verifies the submitted pow solution, returning
// whether the solution was accepted or not (not can be both a bad pow as well as // whether the solution was accepted or not (not can be both a bad pow as well as
// any other error, like no pending work or stale mining result). // any other error, like no pending work or stale mining result).
@ -313,11 +331,16 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
notifyWork() notifyWork()
case work := <-ethash.fetchWorkCh: case work := <-ethash.fetchWorkCh:
// Return current mining work to remote miner.
if currentBlock == nil { if currentBlock == nil {
// Return error message if there is no available mining work yet.
work.errc <- errNoMiningWork work.errc <- errNoMiningWork
} else { } else if work.extra == "" {
// Return the default current mining work if no extra customized data
// specified.
work.res <- currentWork work.res <- currentWork
} else {
// Return the customized mining work.
work.res <- customizeWork(work.extra)
} }
case result := <-ethash.submitWorkCh: case result := <-ethash.submitWorkCh: