feat: recommit bid when newBidCh is empty to maximize mev reward (#2424)
This commit is contained in:
parent
6573254a62
commit
ba6726325a
@ -30,8 +30,6 @@ const (
|
||||
// maxBidPerBuilderPerBlock is the max bid number per builder
|
||||
maxBidPerBuilderPerBlock = 3
|
||||
|
||||
commitInterruptBetterBid = 1
|
||||
|
||||
// leftOverTimeRate is the rate of left over time to simulate a bid
|
||||
leftOverTimeRate = 11
|
||||
// leftOverTimeScale is the scale of left over time to simulate a bid
|
||||
@ -311,8 +309,6 @@ func (b *bidSimulator) newBidLoop() {
|
||||
|
||||
// commit aborts in-flight bid execution with given signal and resubmits a new one.
|
||||
commit := func(reason int32, bidRuntime *BidRuntime) {
|
||||
log.Debug("BidSimulator: start", "bidHash", bidRuntime.bid.Hash().Hex())
|
||||
|
||||
// if the left time is not enough to do simulation, return
|
||||
var simDuration time.Duration
|
||||
if lastBid := b.GetBestBid(bidRuntime.bid.ParentHash); lastBid != nil && lastBid.duration != 0 {
|
||||
@ -320,7 +316,8 @@ func (b *bidSimulator) newBidLoop() {
|
||||
}
|
||||
|
||||
if time.Until(b.bidMustBefore(bidRuntime.bid.ParentHash)) <= simDuration*leftOverTimeRate/leftOverTimeScale {
|
||||
log.Debug("BidSimulator: abort commit, not enough time to simulate", "bidHash", bidRuntime.bid.Hash().Hex())
|
||||
log.Debug("BidSimulator: abort commit, not enough time to simulate",
|
||||
"builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
|
||||
return
|
||||
}
|
||||
|
||||
@ -332,6 +329,7 @@ func (b *bidSimulator) newBidLoop() {
|
||||
interruptCh = make(chan int32, 1)
|
||||
select {
|
||||
case b.simBidCh <- &simBidReq{interruptCh: interruptCh, bid: bidRuntime}:
|
||||
log.Debug("BidSimulator: commit", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
|
||||
case <-b.exitCh:
|
||||
return
|
||||
}
|
||||
@ -352,7 +350,8 @@ func (b *bidSimulator) newBidLoop() {
|
||||
|
||||
if expectedValidatorReward.Cmp(big.NewInt(0)) < 0 {
|
||||
// damage self profit, ignore
|
||||
log.Debug("BidSimulator: invalid bid, validator reward is less than 0, ignore", "bidHash", newBid.Hash().Hex())
|
||||
log.Debug("BidSimulator: invalid bid, validator reward is less than 0, ignore",
|
||||
"builder", newBid.Builder, "bidHash", newBid.Hash().Hex())
|
||||
continue
|
||||
}
|
||||
|
||||
@ -375,26 +374,27 @@ func (b *bidSimulator) newBidLoop() {
|
||||
}
|
||||
|
||||
// if bestBid is not nil, check if newBid is better than bestBid
|
||||
if bidRuntime.expectedBlockReward.Cmp(bestBid.expectedBlockReward) > 0 &&
|
||||
bidRuntime.expectedValidatorReward.Cmp(bestBid.expectedValidatorReward) > 0 {
|
||||
if bidRuntime.expectedBlockReward.Cmp(bestBid.expectedBlockReward) >= 0 &&
|
||||
bidRuntime.expectedValidatorReward.Cmp(bestBid.expectedValidatorReward) >= 0 {
|
||||
// if both reward are better than last simulating newBid, commit for simulation
|
||||
commit(commitInterruptBetterBid, bidRuntime)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug("BidSimulator: lower reward, ignore", "bidHash", newBid.Hash().Hex())
|
||||
log.Debug("BidSimulator: lower reward, ignore",
|
||||
"builder", bidRuntime.bid.Builder, "bidHash", newBid.Hash().Hex())
|
||||
continue
|
||||
}
|
||||
|
||||
// simulatingBid must be better than bestBid, if newBid is better than simulatingBid, commit for simulation
|
||||
if bidRuntime.expectedBlockReward.Cmp(simulatingBid.expectedBlockReward) > 0 &&
|
||||
bidRuntime.expectedValidatorReward.Cmp(simulatingBid.expectedValidatorReward) > 0 {
|
||||
if bidRuntime.expectedBlockReward.Cmp(simulatingBid.expectedBlockReward) >= 0 &&
|
||||
bidRuntime.expectedValidatorReward.Cmp(simulatingBid.expectedValidatorReward) >= 0 {
|
||||
// if both reward are better than last simulating newBid, commit for simulation
|
||||
commit(commitInterruptBetterBid, bidRuntime)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug("BidSimulator: lower reward, ignore", "bidHash", newBid.Hash().Hex())
|
||||
log.Debug("BidSimulator: lower reward, ignore", "builder", newBid.Builder, "bidHash", newBid.Hash().Hex())
|
||||
case <-b.exitCh:
|
||||
return
|
||||
}
|
||||
@ -546,12 +546,23 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
go b.reportIssue(bidRuntime, err)
|
||||
}
|
||||
|
||||
if success {
|
||||
bidRuntime.duration = time.Since(simStart)
|
||||
}
|
||||
|
||||
b.RemoveSimulatingBid(parentHash)
|
||||
bidSimTimer.UpdateSince(start)
|
||||
|
||||
if success {
|
||||
bidRuntime.duration = time.Since(simStart)
|
||||
|
||||
// only recommit self bid when newBidCh is empty
|
||||
if len(b.newBidCh) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case b.newBidCh <- bidRuntime.bid:
|
||||
log.Debug("BidSimulator: recommit", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
|
||||
default:
|
||||
}
|
||||
}
|
||||
}(time.Now())
|
||||
|
||||
// prepareWork will configure header with a suitable time according to consensus
|
||||
@ -612,7 +623,8 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
if b.config.GreedyMergeTx {
|
||||
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
||||
if delay != nil && *delay > 0 {
|
||||
log.Debug("BidSimulator: greedy merge tx stopTimer", "block", bidRuntime.env.header.Number,
|
||||
log.Debug("BidSimulator: greedy merge stopTimer", "block", bidRuntime.env.header.Number,
|
||||
"builder", bidRuntime.bid.Builder,
|
||||
"header time", time.Until(time.Unix(int64(bidRuntime.env.header.Time), 0)),
|
||||
"commit delay", *delay, "DelayLeftOver", b.delayLeftOver)
|
||||
|
||||
@ -624,8 +636,8 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
}
|
||||
|
||||
fillErr := b.bidWorker.fillTransactions(interruptCh, bidRuntime.env, stopTimer, bidTxsSet)
|
||||
log.Info("BidSimulator: greedy merge tx fill transactions", "block", bidRuntime.env.header.Number,
|
||||
"tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr)
|
||||
log.Info("BidSimulator: greedy merge stopped", "block", bidRuntime.env.header.Number,
|
||||
"builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr)
|
||||
|
||||
// recalculate the packed reward
|
||||
bidRuntime.packReward(b.config.ValidatorCommission)
|
||||
@ -635,7 +647,8 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
bidRuntime.env.gasPool.AddGas(params.PayBidTxGasLimit)
|
||||
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, payBidTx)
|
||||
if err != nil {
|
||||
log.Error("BidSimulator: failed to commit tx", "bidHash", bidRuntime.bid.Hash(), "tx", payBidTx.Hash(), "err", err)
|
||||
log.Error("BidSimulator: failed to commit tx", "builder", bidRuntime.bid.Builder,
|
||||
"bidHash", bidRuntime.bid.Hash(), "tx", payBidTx.Hash(), "err", err)
|
||||
err = fmt.Errorf("invalid tx in bid, %v", err)
|
||||
return
|
||||
}
|
||||
@ -649,11 +662,22 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
}
|
||||
|
||||
// this is the simplest strategy: best for all the delegators.
|
||||
if bidRuntime.packedBlockReward.Cmp(bestBid.packedBlockReward) > 0 {
|
||||
if bidRuntime.packedBlockReward.Cmp(bestBid.packedBlockReward) >= 0 {
|
||||
b.SetBestBid(bidRuntime.bid.ParentHash, bidRuntime)
|
||||
success = true
|
||||
return
|
||||
}
|
||||
|
||||
// only recommit last best bid when newBidCh is empty
|
||||
if len(b.newBidCh) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case b.newBidCh <- bestBid.bid:
|
||||
log.Debug("BidSimulator: recommit last bid", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// reportIssue reports the issue to the mev-sentry
|
||||
|
@ -73,10 +73,11 @@ var (
|
||||
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
|
||||
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
|
||||
|
||||
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
||||
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
||||
errBlockInterruptedByTimeout = errors.New("timeout while building block")
|
||||
errBlockInterruptedByOutOfGas = errors.New("out of gas while building block")
|
||||
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
||||
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
||||
errBlockInterruptedByTimeout = errors.New("timeout while building block")
|
||||
errBlockInterruptedByOutOfGas = errors.New("out of gas while building block")
|
||||
errBlockInterruptedByBetterBid = errors.New("better bid arrived while building block")
|
||||
)
|
||||
|
||||
// environment is the worker's current environment and holds all
|
||||
@ -145,6 +146,7 @@ const (
|
||||
commitInterruptResubmit
|
||||
commitInterruptTimeout
|
||||
commitInterruptOutOfGas
|
||||
commitInterruptBetterBid
|
||||
)
|
||||
|
||||
// newWorkReq represents a request for new sealing work submitting with relative interrupt notifier.
|
||||
@ -1481,6 +1483,8 @@ func signalToErr(signal int32) error {
|
||||
return errBlockInterruptedByTimeout
|
||||
case commitInterruptOutOfGas:
|
||||
return errBlockInterruptedByOutOfGas
|
||||
case commitInterruptBetterBid:
|
||||
return errBlockInterruptedByBetterBid
|
||||
default:
|
||||
panic(fmt.Errorf("undefined signal %d", signal))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user