From 369d0c1a2fd5f0f212253c065c0ca942cf414bf3 Mon Sep 17 00:00:00 2001 From: Roshan Date: Mon, 29 Apr 2024 01:19:10 +0800 Subject: [PATCH 1/4] feat: add `reconnectLoop` for mev validators --- miner/bidder.go | 81 ++++++++++++++++++++++++++++++++++++------------- miner/worker.go | 2 ++ 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/miner/bidder.go b/miner/bidder.go index e8e3a24dd2..acccbec395 100644 --- a/miner/bidder.go +++ b/miner/bidder.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/miner/validatorclient" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" + "errors" ) const maxBid int64 = 3 @@ -37,7 +38,8 @@ type Bidder struct { engine consensus.Engine chain *core.BlockChain - validators map[common.Address]*validator // address -> validator + validatorsMu sync.RWMutex + validators map[common.Address]*validator // address -> validator bestWorksMu sync.RWMutex bestWorks map[int64]*environment @@ -74,31 +76,16 @@ func NewBidder(config *MevConfig, delayLeftOver time.Duration, engine consensus. b.wallet = wallet for _, v := range config.Validators { - cl, err := validatorclient.DialOptions(context.Background(), v.URL, rpc.WithHTTPClient(client)) - if err != nil { - log.Error("Bidder: failed to dial validator", "url", v.URL, "err", err) - continue - } - - params, err := cl.MevParams(context.Background()) - if err != nil { - log.Error("Bidder: failed to get mev params", "url", v.URL, "err", err) - continue - } - - b.validators[v.Address] = &validator{ - Client: cl, - BidSimulationLeftOver: params.BidSimulationLeftOver, - GasCeil: params.GasCeil, - } + b.registerValidator(v) } if len(b.validators) == 0 { log.Warn("Bidder: No valid validators") } - b.wg.Add(1) + b.wg.Add(2) go b.mainLoop() + go b.reconnectLoop() return b } @@ -124,9 +111,11 @@ func (b *Bidder) mainLoop() { bidNum = 0 parentHeader := b.chain.GetHeaderByHash(work.header.ParentHash) var bidSimulationLeftOver time.Duration + b.validatorsMu.RLock() if b.validators[work.coinbase] != nil { bidSimulationLeftOver = b.validators[work.coinbase].BidSimulationLeftOver } + b.validatorsMu.RUnlock() betterBidBefore = bidutil.BidBetterBefore(parentHeader, b.chain.Config().Parlia.Period, b.delayLeftOver, bidSimulationLeftOver) @@ -157,12 +146,58 @@ func (b *Bidder) mainLoop() { } } +func (b *Bidder) reconnectLoop() { + defer b.wg.Done() + + for { + select { + case <-time.After(10 * time.Minute): + for _, v := range b.config.Validators { + if b.registered(v.Address) { + continue + } + + b.registerValidator(v) + } + case <-b.exitCh: + return + } + } +} + +func (b *Bidder) registerValidator(cfg ValidatorConfig) { + b.validatorsMu.Lock() + defer b.validatorsMu.Unlock() + + cl, err := validatorclient.DialOptions(context.Background(), cfg.URL, rpc.WithHTTPClient(client)) + if err != nil { + log.Error("Bidder: failed to dial validator", "url", cfg.URL, "err", err) + return + } + + params, err := cl.MevParams(context.Background()) + if err != nil { + log.Error("Bidder: failed to get mev params", "url", cfg.URL, "err", err) + return + } + + b.validators[cfg.Address] = &validator{ + Client: cl, + BidSimulationLeftOver: params.BidSimulationLeftOver, + GasCeil: params.GasCeil, + } +} + func (b *Bidder) registered(validator common.Address) bool { + b.validatorsMu.RLock() + defer b.validatorsMu.RUnlock() _, ok := b.validators[validator] return ok } func (b *Bidder) unregister(validator common.Address) { + b.validatorsMu.Lock() + defer b.validatorsMu.Unlock() delete(b.validators, validator) } @@ -188,11 +223,14 @@ func (b *Bidder) exit() { // 2. send bid to validator func (b *Bidder) bid(work *environment) { var ( - cli = b.validators[work.coinbase] parent = b.chain.CurrentBlock() bidArgs types.BidArgs + cli *validator ) + b.validatorsMu.RLock() + cli = b.validators[work.coinbase] + b.validatorsMu.RUnlock() if cli == nil { log.Info("Bidder: validator not integrated", "validator", work.coinbase) return @@ -238,7 +276,8 @@ func (b *Bidder) bid(work *environment) { b.deleteBestWork(work) log.Error("Bidder: bidding failed", "err", err) - bidErr, ok := err.(rpc.Error) + var bidErr rpc.Error + ok := errors.As(err, &bidErr) if ok && bidErr.ErrorCode() == types.MevNotRunningError { b.unregister(work.coinbase) } diff --git a/miner/worker.go b/miner/worker.go index 53d431bd76..6472f1d61f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1182,9 +1182,11 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { return } + w.bidder.validatorsMu.Lock() if w.bidder.validators[coinbase] != nil { w.config.GasCeil = w.bidder.validators[coinbase].GasCeil } + w.bidder.validatorsMu.Unlock() } else { coinbase = w.etherbase() if coinbase == (common.Address{}) { From afea0e70e4d1b48fbda6ac5987a46a98b280d1d5 Mon Sep 17 00:00:00 2001 From: Roshan Date: Mon, 29 Apr 2024 01:31:27 +0800 Subject: [PATCH 2/4] fix lint issue --- miner/bidder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/bidder.go b/miner/bidder.go index acccbec395..21d3d6c814 100644 --- a/miner/bidder.go +++ b/miner/bidder.go @@ -2,6 +2,7 @@ package miner import ( "context" + "errors" "sync" "time" @@ -16,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/miner/validatorclient" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" - "errors" ) const maxBid int64 = 3 From 0fe1911060ada370b779a8960ec4421998ca88bc Mon Sep 17 00:00:00 2001 From: Roshan Date: Mon, 29 Apr 2024 10:46:25 +0800 Subject: [PATCH 3/4] fix review comments --- miner/bidder.go | 29 +++++++++++++++++------------ miner/worker.go | 2 +- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/miner/bidder.go b/miner/bidder.go index 21d3d6c814..b611979aca 100644 --- a/miner/bidder.go +++ b/miner/bidder.go @@ -76,7 +76,7 @@ func NewBidder(config *MevConfig, delayLeftOver time.Duration, engine consensus. b.wallet = wallet for _, v := range config.Validators { - b.registerValidator(v) + b.register(v) } if len(b.validators) == 0 { @@ -149,23 +149,35 @@ func (b *Bidder) mainLoop() { func (b *Bidder) reconnectLoop() { defer b.wg.Done() + timer := time.NewTimer(10 * time.Minute) + defer timer.Stop() + for { select { - case <-time.After(10 * time.Minute): + case <-timer.C: for _, v := range b.config.Validators { - if b.registered(v.Address) { + if b.isRegistered(v.Address) { continue } - b.registerValidator(v) + b.register(v) } + + timer.Reset(10 * time.Minute) case <-b.exitCh: return } } } -func (b *Bidder) registerValidator(cfg ValidatorConfig) { +func (b *Bidder) isRegistered(validator common.Address) bool { + b.validatorsMu.RLock() + defer b.validatorsMu.RUnlock() + _, ok := b.validators[validator] + return ok +} + +func (b *Bidder) register(cfg ValidatorConfig) { b.validatorsMu.Lock() defer b.validatorsMu.Unlock() @@ -188,13 +200,6 @@ func (b *Bidder) registerValidator(cfg ValidatorConfig) { } } -func (b *Bidder) registered(validator common.Address) bool { - b.validatorsMu.RLock() - defer b.validatorsMu.RUnlock() - _, ok := b.validators[validator] - return ok -} - func (b *Bidder) unregister(validator common.Address) { b.validatorsMu.Lock() defer b.validatorsMu.Unlock() diff --git a/miner/worker.go b/miner/worker.go index 6472f1d61f..549e075554 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1169,7 +1169,7 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { } // do not build work if not register to the coinbase - if !w.bidder.registered(coinbase) { + if !w.bidder.isRegistered(coinbase) { log.Warn("Refusing to mine with unregistered validator") return } From 2ba8e68f8f93a688079729bf4743ccaaa528f5a3 Mon Sep 17 00:00:00 2001 From: Roshan Date: Mon, 29 Apr 2024 11:28:40 +0800 Subject: [PATCH 4/4] fix review comments --- miner/bidder.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/miner/bidder.go b/miner/bidder.go index b611979aca..8004880e38 100644 --- a/miner/bidder.go +++ b/miner/bidder.go @@ -149,12 +149,12 @@ func (b *Bidder) mainLoop() { func (b *Bidder) reconnectLoop() { defer b.wg.Done() - timer := time.NewTimer(10 * time.Minute) - defer timer.Stop() + ticker := time.NewTicker(10 * time.Minute) + defer ticker.Stop() for { select { - case <-timer.C: + case <-ticker.C: for _, v := range b.config.Validators { if b.isRegistered(v.Address) { continue @@ -162,8 +162,6 @@ func (b *Bidder) reconnectLoop() { b.register(v) } - - timer.Reset(10 * time.Minute) case <-b.exitCh: return }