mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
consensus, miner: track original sealhash in ethash remote sealer
This commit is contained in:
parent
05d9cd1560
commit
012aee25f6
8 changed files with 81 additions and 59 deletions
|
|
@ -590,7 +590,7 @@ func (c *Clique) Authorize(signer common.Address, signFn SignerFn) {
|
||||||
|
|
||||||
// Seal implements consensus.Engine, attempting to create a sealed block using
|
// Seal implements consensus.Engine, attempting to create a sealed block using
|
||||||
// the local signing credentials.
|
// the local signing credentials.
|
||||||
func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
|
func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *consensus.SealResult, stop <-chan struct{}) error {
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
|
|
||||||
// Sealing the genesis block is not supported
|
// Sealing the genesis block is not supported
|
||||||
|
|
@ -635,7 +635,8 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
|
||||||
log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
|
log.Trace("Out-of-turn signing requested", "wiggle", common.PrettyDuration(wiggle))
|
||||||
}
|
}
|
||||||
// Sign all the things!
|
// Sign all the things!
|
||||||
sighash, err := signFn(accounts.Account{Address: signer}, sigHash(header).Bytes())
|
sealhash := sigHash(header)
|
||||||
|
sighash, err := signFn(accounts.Account{Address: signer}, sealhash.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -650,7 +651,7 @@ func (c *Clique) Seal(chain consensus.ChainReader, block *types.Block, results c
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case results <- block.WithSeal(header):
|
case results <- &consensus.SealResult{SealHash: sealhash, Block: block.WithSeal(header)}:
|
||||||
default:
|
default:
|
||||||
log.Warn("Sealing result is not read by miner", "sealhash", c.SealHash(header))
|
log.Warn("Sealing result is not read by miner", "sealhash", c.SealHash(header))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ type Engine interface {
|
||||||
//
|
//
|
||||||
// Note, the method returns immediately and will send the result async. More
|
// Note, the method returns immediately and will send the result async. More
|
||||||
// than one result may also be returned depending on the consensus algorithm.
|
// than one result may also be returned depending on the consensus algorithm.
|
||||||
Seal(chain ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error
|
Seal(chain ChainReader, block *types.Block, results chan<- *SealResult, stop <-chan struct{}) error
|
||||||
|
|
||||||
// SealHash returns the hash of a block prior to it being sealed.
|
// SealHash returns the hash of a block prior to it being sealed.
|
||||||
SealHash(header *types.Header) common.Hash
|
SealHash(header *types.Header) common.Hash
|
||||||
|
|
@ -114,3 +114,14 @@ type PoW interface {
|
||||||
// Hashrate returns the current mining hashrate of a PoW consensus engine.
|
// Hashrate returns the current mining hashrate of a PoW consensus engine.
|
||||||
Hashrate() float64
|
Hashrate() float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SealResult contains a sealed block and the corresponding sealhash.
|
||||||
|
//
|
||||||
|
// Note for ethash, the sealhash in struct may not match the result of SealHash
|
||||||
|
// calculation with the block because we allow remote miner to customize `extra`
|
||||||
|
// field for the mining block. The sealhash in struct is the unique id
|
||||||
|
// for miner tracked mining work.
|
||||||
|
type SealResult struct {
|
||||||
|
SealHash common.Hash
|
||||||
|
Block *types.Block
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,12 @@ func (api *API) GetWork(extra *string) ([3]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
extraData string
|
|
||||||
workCh = make(chan [3]string, 1)
|
workCh = make(chan [3]string, 1)
|
||||||
errc = make(chan error, 1)
|
errc = make(chan error, 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
if extra != nil {
|
|
||||||
extraData = *extra
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case api.ethash.fetchWorkCh <- &sealWork{extra: extraData, 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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -408,7 +408,7 @@ type Config struct {
|
||||||
// sealTask wraps a seal block with relative result channel for remote sealer thread.
|
// sealTask wraps a seal block with relative result channel for remote sealer thread.
|
||||||
type sealTask struct {
|
type sealTask struct {
|
||||||
block *types.Block
|
block *types.Block
|
||||||
results chan<- *types.Block
|
results chan<- *consensus.SealResult
|
||||||
}
|
}
|
||||||
|
|
||||||
// mineResult wraps the pow solution parameters for the specified block.
|
// mineResult wraps the pow solution parameters for the specified block.
|
||||||
|
|
@ -431,7 +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
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -37,15 +38,15 @@ func TestTestMode(t *testing.T) {
|
||||||
ethash := NewTester(nil, false)
|
ethash := NewTester(nil, false)
|
||||||
defer ethash.Close()
|
defer ethash.Close()
|
||||||
|
|
||||||
results := make(chan *types.Block)
|
results := make(chan *consensus.SealResult)
|
||||||
err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil)
|
err := ethash.Seal(nil, types.NewBlockWithHeader(header), results, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to seal block: %v", err)
|
t.Fatalf("failed to seal block: %v", err)
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case block := <-results:
|
case result := <-results:
|
||||||
header.Nonce = types.EncodeNonce(block.Nonce())
|
header.Nonce = types.EncodeNonce(result.Block.Nonce())
|
||||||
header.MixDigest = block.MixDigest()
|
header.MixDigest = result.Block.MixDigest()
|
||||||
if err := ethash.VerifySeal(nil, header); err != nil {
|
if err := ethash.VerifySeal(nil, header); err != nil {
|
||||||
t.Fatalf("unexpected verification error: %v", err)
|
t.Fatalf("unexpected verification error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +104,7 @@ func TestRemoteSealer(t *testing.T) {
|
||||||
sealhash := ethash.SealHash(header)
|
sealhash := ethash.SealHash(header)
|
||||||
|
|
||||||
// Push new work.
|
// Push new work.
|
||||||
results := make(chan *types.Block)
|
results := make(chan *consensus.SealResult)
|
||||||
ethash.Seal(nil, block, results, nil)
|
ethash.Seal(nil, block, results, nil)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -138,7 +139,7 @@ func TestCustomizedWork(t *testing.T) {
|
||||||
block := types.NewBlockWithHeader(header)
|
block := types.NewBlockWithHeader(header)
|
||||||
|
|
||||||
// Push new work.
|
// Push new work.
|
||||||
results := make(chan *types.Block, 1)
|
results := make(chan *consensus.SealResult, 1)
|
||||||
ethash.Seal(nil, block, results, nil)
|
ethash.Seal(nil, block, results, nil)
|
||||||
|
|
||||||
// Get customized mining work.
|
// Get customized mining work.
|
||||||
|
|
|
||||||
|
|
@ -47,13 +47,13 @@ var (
|
||||||
|
|
||||||
// Seal implements consensus.Engine, attempting to find a nonce that satisfies
|
// Seal implements consensus.Engine, attempting to find a nonce that satisfies
|
||||||
// the block's difficulty requirements.
|
// the block's difficulty requirements.
|
||||||
func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
|
func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *consensus.SealResult, stop <-chan struct{}) error {
|
||||||
// If we're running a fake PoW, simply return a 0 nonce immediately
|
// If we're running a fake PoW, simply return a 0 nonce immediately
|
||||||
if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake {
|
if ethash.config.PowMode == ModeFake || ethash.config.PowMode == ModeFullFake {
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{}
|
header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{}
|
||||||
select {
|
select {
|
||||||
case results <- block.WithSeal(header):
|
case results <- &consensus.SealResult{SealHash: ethash.SealHash(header), Block: block.WithSeal(header)}:
|
||||||
default:
|
default:
|
||||||
log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ethash.SealHash(block.Header()))
|
log.Warn("Sealing result is not read by miner", "mode", "fake", "sealhash", ethash.SealHash(block.Header()))
|
||||||
}
|
}
|
||||||
|
|
@ -107,10 +107,11 @@ func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, resu
|
||||||
close(abort)
|
close(abort)
|
||||||
case result = <-locals:
|
case result = <-locals:
|
||||||
// One of the threads found a block, abort all others
|
// One of the threads found a block, abort all others
|
||||||
|
sealhash := ethash.SealHash(block.Header())
|
||||||
select {
|
select {
|
||||||
case results <- result:
|
case results <- &consensus.SealResult{SealHash: sealhash, Block: result}:
|
||||||
default:
|
default:
|
||||||
log.Warn("Sealing result is not read by miner", "mode", "local", "sealhash", ethash.SealHash(block.Header()))
|
log.Warn("Sealing result is not read by miner", "mode", "local", "sealhash", sealhash)
|
||||||
}
|
}
|
||||||
close(abort)
|
close(abort)
|
||||||
case <-ethash.update:
|
case <-ethash.update:
|
||||||
|
|
@ -187,13 +188,21 @@ search:
|
||||||
|
|
||||||
// remote is a standalone goroutine to handle remote mining related stuff.
|
// remote is a standalone goroutine to handle remote mining related stuff.
|
||||||
func (ethash *Ethash) remote(notify []string, noverify bool) {
|
func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
|
// miningWork wraps a mining block fetched by remote miner and
|
||||||
|
// an unique id tracked by miner.
|
||||||
|
type miningWork struct {
|
||||||
|
sealHash common.Hash
|
||||||
|
block *types.Block
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
works = make(map[common.Hash]*types.Block)
|
works = make(map[common.Hash]*miningWork)
|
||||||
rates = make(map[common.Hash]hashrate)
|
rates = make(map[common.Hash]hashrate)
|
||||||
|
|
||||||
results chan<- *types.Block
|
results chan<- *consensus.SealResult
|
||||||
currentBlock *types.Block
|
currentBlock *types.Block
|
||||||
currentWork [3]string
|
currentWork [3]string
|
||||||
|
currentHash common.Hash
|
||||||
|
|
||||||
notifyTransport = &http.Transport{}
|
notifyTransport = &http.Transport{}
|
||||||
notifyClient = &http.Client{
|
notifyClient = &http.Client{
|
||||||
|
|
@ -243,7 +252,9 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
|
|
||||||
// Trace the seal work fetched by remote sealer.
|
// Trace the seal work fetched by remote sealer.
|
||||||
currentBlock = block
|
currentBlock = block
|
||||||
works[hash] = block
|
works[hash] = &miningWork{block: block, sealHash: hash}
|
||||||
|
currentHash = hash
|
||||||
|
log.Trace("Create mining work", "sealhash", hash, "number", currentBlock.NumberU64())
|
||||||
}
|
}
|
||||||
// customizeWork creates a work package for external miner
|
// customizeWork creates a work package for external miner
|
||||||
// with customized extra data.
|
// with customized extra data.
|
||||||
|
|
@ -260,7 +271,8 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
work[2] = currentWork[2]
|
work[2] = currentWork[2]
|
||||||
|
|
||||||
// Trace the seal work fetched by remote sealer.
|
// Trace the seal work fetched by remote sealer.
|
||||||
works[hash] = newBlock
|
log.Trace("Create customized work", "sealhash", hash, "original", currentHash, "number", currentBlock.NumberU64())
|
||||||
|
works[hash] = &miningWork{block: newBlock, sealHash: currentHash}
|
||||||
return work
|
return work
|
||||||
}
|
}
|
||||||
// submitWork verifies the submitted pow solution, returning
|
// submitWork verifies the submitted pow solution, returning
|
||||||
|
|
@ -272,13 +284,13 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Make sure the work submitted is present
|
// Make sure the work submitted is present
|
||||||
block := works[sealhash]
|
work := works[sealhash]
|
||||||
if block == nil {
|
if work == nil {
|
||||||
log.Warn("Work submitted but none pending", "sealhash", sealhash, "curnumber", currentBlock.NumberU64())
|
log.Warn("Work submitted but none pending", "sealhash", sealhash, "curnumber", currentBlock.NumberU64())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Verify the correctness of submitted result.
|
// Verify the correctness of submitted result.
|
||||||
header := block.Header()
|
header := work.block.Header()
|
||||||
header.Nonce = nonce
|
header.Nonce = nonce
|
||||||
header.MixDigest = mixDigest
|
header.MixDigest = mixDigest
|
||||||
|
|
||||||
|
|
@ -297,12 +309,12 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
log.Trace("Verified correct proof-of-work", "sealhash", sealhash, "elapsed", time.Since(start))
|
log.Trace("Verified correct proof-of-work", "sealhash", sealhash, "elapsed", time.Since(start))
|
||||||
|
|
||||||
// Solutions seems to be valid, return to the miner and notify acceptance.
|
// Solutions seems to be valid, return to the miner and notify acceptance.
|
||||||
solution := block.WithSeal(header)
|
solution := work.block.WithSeal(header)
|
||||||
|
|
||||||
// The submitted solution is within the scope of acceptance.
|
// The submitted solution is within the scope of acceptance.
|
||||||
if solution.NumberU64()+staleThreshold > currentBlock.NumberU64() {
|
if solution.NumberU64()+staleThreshold > currentBlock.NumberU64() {
|
||||||
select {
|
select {
|
||||||
case results <- solution:
|
case results <- &consensus.SealResult{SealHash: work.sealHash, Block: solution}:
|
||||||
log.Debug("Work submitted is acceptable", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash())
|
log.Debug("Work submitted is acceptable", "number", solution.NumberU64(), "sealhash", sealhash, "hash", solution.Hash())
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
|
|
@ -334,13 +346,13 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
if currentBlock == nil {
|
if currentBlock == nil {
|
||||||
// Return error message if there is no available mining work yet.
|
// Return error message if there is no available mining work yet.
|
||||||
work.errc <- errNoMiningWork
|
work.errc <- errNoMiningWork
|
||||||
} else if work.extra == "" {
|
} else if work.extra == nil {
|
||||||
// Return the default current mining work if no extra customized data
|
// Return the default current mining work if no extra customized data
|
||||||
// specified.
|
// specified.
|
||||||
work.res <- currentWork
|
work.res <- currentWork
|
||||||
} else {
|
} else {
|
||||||
// Return the customized mining work.
|
// Return the customized mining work.
|
||||||
work.res <- customizeWork(work.extra)
|
work.res <- customizeWork(*work.extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
case result := <-ethash.submitWorkCh:
|
case result := <-ethash.submitWorkCh:
|
||||||
|
|
@ -374,8 +386,8 @@ func (ethash *Ethash) remote(notify []string, noverify bool) {
|
||||||
}
|
}
|
||||||
// Clear stale pending blocks
|
// Clear stale pending blocks
|
||||||
if currentBlock != nil {
|
if currentBlock != nil {
|
||||||
for hash, block := range works {
|
for hash, work := range works {
|
||||||
if block.NumberU64()+staleThreshold <= currentBlock.NumberU64() {
|
if work.block.NumberU64()+staleThreshold <= currentBlock.NumberU64() {
|
||||||
delete(works, hash)
|
delete(works, hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -175,7 +176,7 @@ func TestStaleSubmission(t *testing.T) {
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
results := make(chan *types.Block, 16)
|
results := make(chan *consensus.SealResult, 16)
|
||||||
|
|
||||||
for id, c := range testcases {
|
for id, c := range testcases {
|
||||||
for _, h := range c.headers {
|
for _, h := range c.headers {
|
||||||
|
|
@ -189,20 +190,20 @@ func TestStaleSubmission(t *testing.T) {
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case res := <-results:
|
case res := <-results:
|
||||||
if res.Header().Nonce != fakeNonce {
|
if res.Block.Header().Nonce != fakeNonce {
|
||||||
t.Errorf("case %d block nonce mismatch, want %s, get %s", id+1, fakeNonce, res.Header().Nonce)
|
t.Errorf("case %d block nonce mismatch, want %s, get %s", id+1, fakeNonce, res.Block.Header().Nonce)
|
||||||
}
|
}
|
||||||
if res.Header().MixDigest != fakeDigest {
|
if res.Block.Header().MixDigest != fakeDigest {
|
||||||
t.Errorf("case %d block digest mismatch, want %s, get %s", id+1, fakeDigest, res.Header().MixDigest)
|
t.Errorf("case %d block digest mismatch, want %s, get %s", id+1, fakeDigest, res.Block.Header().MixDigest)
|
||||||
}
|
}
|
||||||
if res.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() {
|
if res.Block.Header().Difficulty.Uint64() != c.headers[c.submitIndex].Difficulty.Uint64() {
|
||||||
t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Header().Difficulty)
|
t.Errorf("case %d block difficulty mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Difficulty, res.Block.Header().Difficulty)
|
||||||
}
|
}
|
||||||
if res.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() {
|
if res.Block.Header().Number.Uint64() != c.headers[c.submitIndex].Number.Uint64() {
|
||||||
t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Header().Number.Uint64())
|
t.Errorf("case %d block number mismatch, want %d, get %d", id+1, c.headers[c.submitIndex].Number.Uint64(), res.Block.Header().Number.Uint64())
|
||||||
}
|
}
|
||||||
if res.Header().ParentHash != c.headers[c.submitIndex].ParentHash {
|
if res.Block.Header().ParentHash != c.headers[c.submitIndex].ParentHash {
|
||||||
t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Header().ParentHash.Hex())
|
t.Errorf("case %d block parent hash mismatch, want %s, get %s", id+1, c.headers[c.submitIndex].ParentHash.Hex(), res.Block.Header().ParentHash.Hex())
|
||||||
}
|
}
|
||||||
case <-time.NewTimer(time.Second).C:
|
case <-time.NewTimer(time.Second).C:
|
||||||
t.Errorf("case %d fetch ethash result timeout", id+1)
|
t.Errorf("case %d fetch ethash result timeout", id+1)
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ type worker struct {
|
||||||
// Channels
|
// Channels
|
||||||
newWorkCh chan *newWorkReq
|
newWorkCh chan *newWorkReq
|
||||||
taskCh chan *task
|
taskCh chan *task
|
||||||
resultCh chan *types.Block
|
resultCh chan *consensus.SealResult
|
||||||
startCh chan struct{}
|
startCh chan struct{}
|
||||||
exitCh chan struct{}
|
exitCh chan struct{}
|
||||||
resubmitIntervalCh chan time.Duration
|
resubmitIntervalCh chan time.Duration
|
||||||
|
|
@ -192,7 +192,7 @@ func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend,
|
||||||
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
||||||
newWorkCh: make(chan *newWorkReq),
|
newWorkCh: make(chan *newWorkReq),
|
||||||
taskCh: make(chan *task),
|
taskCh: make(chan *task),
|
||||||
resultCh: make(chan *types.Block, resultQueueSize),
|
resultCh: make(chan *consensus.SealResult, resultQueueSize),
|
||||||
exitCh: make(chan struct{}),
|
exitCh: make(chan struct{}),
|
||||||
startCh: make(chan struct{}, 1),
|
startCh: make(chan struct{}, 1),
|
||||||
resubmitIntervalCh: make(chan time.Duration),
|
resubmitIntervalCh: make(chan time.Duration),
|
||||||
|
|
@ -524,24 +524,25 @@ func (w *worker) taskLoop() {
|
||||||
func (w *worker) resultLoop() {
|
func (w *worker) resultLoop() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case block := <-w.resultCh:
|
case result := <-w.resultCh:
|
||||||
// Short circuit when receiving empty result.
|
// Short circuit when receiving empty result.
|
||||||
if block == nil {
|
if result == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
block = result.Block
|
||||||
|
hash = result.Block.Hash()
|
||||||
|
)
|
||||||
// Short circuit when receiving duplicate result caused by resubmitting.
|
// Short circuit when receiving duplicate result caused by resubmitting.
|
||||||
if w.chain.HasBlock(block.Hash(), block.NumberU64()) {
|
if w.chain.HasBlock(block.Hash(), block.NumberU64()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var (
|
|
||||||
sealhash = w.engine.SealHash(block.Header())
|
|
||||||
hash = block.Hash()
|
|
||||||
)
|
|
||||||
w.pendingMu.RLock()
|
w.pendingMu.RLock()
|
||||||
task, exist := w.pendingTasks[sealhash]
|
task, exist := w.pendingTasks[result.SealHash]
|
||||||
w.pendingMu.RUnlock()
|
w.pendingMu.RUnlock()
|
||||||
if !exist {
|
if !exist {
|
||||||
log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash)
|
log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", result.SealHash, "hash", hash)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Different block could share same sealhash, deep copy here to prevent write-write conflict.
|
// Different block could share same sealhash, deep copy here to prevent write-write conflict.
|
||||||
|
|
@ -565,7 +566,7 @@ func (w *worker) resultLoop() {
|
||||||
log.Error("Failed writing block to chain", "err", err)
|
log.Error("Failed writing block to chain", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash,
|
log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", result.SealHash, "hash", hash,
|
||||||
"elapsed", common.PrettyDuration(time.Since(task.createdAt)))
|
"elapsed", common.PrettyDuration(time.Since(task.createdAt)))
|
||||||
|
|
||||||
// Broadcast the block and announce chain insertion event
|
// Broadcast the block and announce chain insertion event
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue