Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

miner: periodically recommit block #25736

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions eth/catalyst/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/beacon"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/miner"
)

// maxTrackedPayloads is the maximum number of prepared payloads the execution
Expand All @@ -42,7 +43,7 @@ type payload struct {
done bool
empty *types.Block
block *types.Block
result chan *types.Block
result chan *miner.Work
}

// resolve extracts the generated full block from the given channel if possible
Expand All @@ -53,23 +54,20 @@ func (req *payload) resolve() *beacon.ExecutableDataV1 {
req.lock.Lock()
defer req.lock.Unlock()

// Try to resolve the full block first if it's not obtained
// yet. The returned block can be nil if the generation fails.

if !req.done {
timeout := time.NewTimer(500 * time.Millisecond)
defer timeout.Stop()

select {
case req.block = <-req.result:
case res := <-req.result:
req.block = res.Resolve()
req.done = true
case <-timeout.C:
// TODO(rjl49345642, Marius), should we keep this
// 100ms timeout allowance? Why not just use the
// default and then fallback to empty directly?
}
}

if req.block != nil {
return beacon.BlockToExecutableData(req.block)
}
Expand Down
22 changes: 20 additions & 2 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscript
// there is always a result that will be returned through the result channel.
// The difference is that if the execution fails, the returned result is nil
// and the concrete error is dropped silently.
func (miner *Miner) GetSealingBlockAsync(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (chan *types.Block, error) {
func (miner *Miner) GetSealingBlockAsync(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (chan *Work, error) {
resCh, _, err := miner.worker.getSealingBlock(parent, timestamp, coinbase, random, noTxs)
if err != nil {
return nil, err
Expand All @@ -261,5 +261,23 @@ func (miner *Miner) GetSealingBlockSync(parent common.Hash, timestamp uint64, co
if err != nil {
return nil, err
}
return <-resCh, <-errCh
res := <-resCh
return res.Resolve(), <-errCh
}

type Work struct {
b *types.Block
mu *sync.RWMutex
}

func (w *Work) Resolve() *types.Block {
w.mu.RLock()
defer w.mu.RUnlock()
return w.b
}

func (w *Work) set(b *types.Block) {
w.mu.Lock()
defer w.mu.Unlock()
w.b = b
}
35 changes: 23 additions & 12 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ type newWorkReq struct {
// getWorkReq represents a request for getting a new sealing work with provided parameters.
type getWorkReq struct {
params *generateParams
result chan *types.Block // non-blocking channel
result *Work
resCh chan *Work // non-blocking channel
err chan error
}

Expand Down Expand Up @@ -535,12 +536,21 @@ func (w *worker) mainLoop() {

case req := <-w.getWorkCh:
block, err := w.generateWork(req.params)
if err != nil {
res := &Work{b: block, mu: new(sync.RWMutex)}
if req.result == nil {
req.result = res
req.resCh <- res
req.err <- err
req.result <- nil
} else {
req.err <- nil
req.result <- block
} else if err != nil {
// Update the block if no error occurred
req.result.set(block)
}

if time.Since(time.Unix(int64(req.params.timestamp), 0)) < maxRecommitInterval {
go func() {
time.Sleep(minRecommitInterval)
w.getWorkCh <- req
}()
}
case ev := <-w.chainSideCh:
// Short circuit for duplicate side blocks
Expand Down Expand Up @@ -1170,10 +1180,10 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti
// getSealingBlock generates the sealing block based on the given parameters.
// The generation result will be passed back via the given channel no matter
// the generation itself succeeds or not.
func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (chan *types.Block, chan error, error) {
func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, noTxs bool) (chan *Work, chan error, error) {
var (
resCh = make(chan *types.Block, 1)
errCh = make(chan error, 1)
result = make(chan *Work, 1)
errCh = make(chan error, 1)
)
req := &getWorkReq{
params: &generateParams{
Expand All @@ -1186,12 +1196,13 @@ func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase
noExtra: true,
noTxs: noTxs,
},
result: resCh,
err: errCh,
resCh: result,
err: errCh,
}

select {
case w.getWorkCh <- req:
return resCh, errCh, nil
return result, errCh, nil
case <-w.exitCh:
return nil, nil, errors.New("miner closed")
}
Expand Down
4 changes: 2 additions & 2 deletions miner/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
if err != nil {
t.Errorf("Unexpected error %v", err)
}
assertBlock(block, c.expectNumber, c.coinbase, c.random)
assertBlock(block.Resolve(), c.expectNumber, c.coinbase, c.random)
}
}

Expand All @@ -662,7 +662,7 @@ func testGetSealingWork(t *testing.T, chainConfig *params.ChainConfig, engine co
if err != nil {
t.Errorf("Unexpected error %v", err)
}
assertBlock(block, c.expectNumber, c.coinbase, c.random)
assertBlock(block.Resolve(), c.expectNumber, c.coinbase, c.random)
}
}
}