Add mevBoostLoop for requesting mev-boost service for new payload

perioidcally
This commit is contained in:
Jinsuk Park 2023-08-24 15:36:14 +09:00
parent d130217ca2
commit c6db52ee8c
No known key found for this signature in database
GPG key ID: A9356F9336B44ED3
2 changed files with 77 additions and 5 deletions

View file

@ -54,6 +54,7 @@ type Config struct {
NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload NewPayloadTimeout time.Duration // The maximum time allowance for creating a new payload
MevBoostUrl string // URL to mev boost. MevBoostUrl string // URL to mev boost.
MevBoostRequestInterval time.Duration // The interval for requesting mev boost for new block
} }
// DefaultConfig contains default settings for miner. // DefaultConfig contains default settings for miner.
@ -67,6 +68,7 @@ var DefaultConfig = Config{
// run 3 rounds. // run 3 rounds.
Recommit: 2 * time.Second, Recommit: 2 * time.Second,
NewPayloadTimeout: 2 * time.Second, NewPayloadTimeout: 2 * time.Second,
MevBoostRequestInterval: 1 * time.Second,
} }
// Miner creates blocks and searches for proof-of-work values. // Miner creates blocks and searches for proof-of-work values.

View file

@ -17,13 +17,16 @@
package miner package miner
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"net/http"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
@ -205,6 +208,9 @@ type worker struct {
snapshotReceipts types.Receipts snapshotReceipts types.Receipts
snapshotState *state.StateDB snapshotState *state.StateDB
mevSnapshotBlockMu sync.RWMutex // The lock used to protect the mevSnapshotBlock below
mevSnapshotBlock *types.Block
// atomic status counters // atomic status counters
running atomic.Bool // The indicator whether the consensus engine is running or not. running atomic.Bool // The indicator whether the consensus engine is running or not.
newTxs atomic.Int32 // New arrival transaction count since last sealing work submitting. newTxs atomic.Int32 // New arrival transaction count since last sealing work submitting.
@ -278,12 +284,15 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
} }
worker.newpayloadTimeout = newpayloadTimeout worker.newpayloadTimeout = newpayloadTimeout
worker.wg.Add(4) worker.wg.Add(5)
go worker.mainLoop() go worker.mainLoop()
go worker.newWorkLoop(recommit) go worker.newWorkLoop(recommit)
go worker.resultLoop() go worker.resultLoop()
go worker.taskLoop() go worker.taskLoop()
// loop for requesting mev-boost for new block.
go worker.mevBoostLoop(worker.config.MevBoostRequestInterval)
// Submit first work to initialize pending state. // Submit first work to initialize pending state.
if init { if init {
worker.startCh <- struct{}{} worker.startCh <- struct{}{}
@ -497,6 +506,58 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
} }
} }
type ExecutionPayloadResponse struct {
Version string `json:"version"`
Data engine.ExecutableData `json:"data"`
}
func (res *ExecutionPayloadResponse) getBlock() (*types.Block, error) {
return engine.ExecutableDataToBlock(res.Data, nil)
}
// mevBoostLoop queries mev-boost instance for new block.
func (w *worker) mevBoostLoop(interval time.Duration) {
defer w.wg.Done()
timer := time.NewTimer(0)
defer timer.Stop()
<-timer.C // discard the initial tick
request := func(slot *big.Int, parent_hash common.Hash) {
// /eth/v1/builder/block/:slot/:parent_hash
url := fmt.Sprintf("%s/eth/v1/builder/block/%s/%s",
w.config.MevBoostUrl, slot.String(), parent_hash.String())
res, err := http.Get(url)
if err != nil {
log.Error("Failed to get mev-boost response", "err", err)
return
}
defer res.Body.Close()
var response ExecutionPayloadResponse
json.NewDecoder(res.Body).Decode(&response)
block, err := response.getBlock()
if err != nil {
log.Error("Failed to parse payload", "err", err)
return
}
w.updateMevSnapshot(block)
timer.Reset(interval)
}
for {
select {
case <-timer.C:
if w.isRunning() {
// find the parent
parent := w.chain.CurrentBlock()
go request(parent.Number, parent.Hash())
}
case <-w.exitCh:
return
}
}
}
// mainLoop is responsible for generating and submitting sealing work based on // mainLoop is responsible for generating and submitting sealing work based on
// the received event. It can support two modes: automatically generate task and // the received event. It can support two modes: automatically generate task and
// submit it or return task according to given parameters for various proposes. // submit it or return task according to given parameters for various proposes.
@ -734,6 +795,15 @@ func (w *worker) updateSnapshot(env *environment) {
w.snapshotState = env.state.Copy() w.snapshotState = env.state.Copy()
} }
func (w *worker) updateMevSnapshot(block *types.Block) {
w.mevSnapshotBlockMu.Lock()
defer w.mevSnapshotBlockMu.Unlock()
// Update snapshot if and only if the new block received has the larger timestamp and higher block number.
if w.mevSnapshotBlock.Header().Time < block.Header().Time && w.mevSnapshotBlock.Header().Number.Cmp(block.Header().Number) == -1 {
w.mevSnapshotBlock = block
}
}
func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) { func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]*types.Log, error) {
var ( var (
snap = env.state.Snapshot() snap = env.state.Snapshot()