Skip to content
This repository has been archived by the owner on Oct 25, 2024. It is now read-only.

Commit

Permalink
DRY profit logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Wazzymandias committed Aug 10, 2023
1 parent e526d0e commit da5c54e
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 68 deletions.
2 changes: 1 addition & 1 deletion builder/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error {
}

var validator *blockvalidation.BlockValidationAPI
if cfg.DryRun || !cfg.DryRun {
if cfg.DryRun {
var accessVerifier *blockvalidation.AccessVerifier
if cfg.ValidationBlocklist != "" {
accessVerifier, err = blockvalidation.NewAccessVerifierFromFile(cfg.ValidationBlocklist)
Expand Down
26 changes: 4 additions & 22 deletions builder/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,12 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/log"
"io"
"net/http"
)

var errHTTPErrorResponse = errors.New("HTTP error response")

type JSONRPCResponse struct {
ID interface{} `json:"id"`
Result json.RawMessage `json:"result,omitempty"`
Error json.RawMessage `json:"error,omitempty"`
Version string `json:"jsonrpc"`
}

// SendSSZRequest is a request to send SSZ data to a remote relay.
func SendSSZRequest(ctx context.Context, client http.Client, method, url string, payload []byte, useGzip bool) (code int, err error) {
var req *http.Request
Expand Down Expand Up @@ -63,21 +55,11 @@ func SendSSZRequest(ctx context.Context, client http.Client, method, url string,
}
defer resp.Body.Close()

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return resp.StatusCode, fmt.Errorf("could not read error response body for status code %d: %w", resp.StatusCode, err)
}

res := new(JSONRPCResponse)
if err := json.Unmarshal(bodyBytes, &res); err != nil {
return resp.StatusCode, fmt.Errorf("could not unmarshal error response body for status code %d: %w", resp.StatusCode, err)
}

if res.Error != nil {
log.Info("Error response", "code", resp.StatusCode, "message", string(res.Error))
}

if resp.StatusCode > 299 {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return resp.StatusCode, fmt.Errorf("could not read error response body for status code %d: %w", resp.StatusCode, err)
}
return resp.StatusCode, fmt.Errorf("HTTP error response: %d / %s", resp.StatusCode, string(bodyBytes))
}
return resp.StatusCode, nil
Expand Down
35 changes: 35 additions & 0 deletions miner/algo_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,41 @@ func NewBuildBlockFunc(
}
}

func ValidateGasPriceAndProfit(algoConf algorithmConfig, actualPrice, expectedPrice *big.Int, tolerablePriceDifferencePercent int,
actualProfit, expectedProfit *big.Int) error {
// allow tolerablePriceDifferencePercent % divergence
expectedPriceMultiple := new(big.Int).Mul(expectedPrice, big.NewInt(100-int64(tolerablePriceDifferencePercent)))
actualPriceMultiple := new(big.Int).Mul(actualPrice, common.Big100)

var errLowProfit *lowProfitError = nil
if expectedPriceMultiple.Cmp(actualPriceMultiple) > 0 {
errLowProfit = &lowProfitError{
ExpectedEffectiveGasPrice: expectedPrice,
ActualEffectiveGasPrice: actualPrice,
}
}

if algoConf.EnforceProfit {
// We want to make expected profit smaller to allow for some leeway in cases where the actual profit is
// lower due to transaction ordering
expectedProfitMultiple := common.PercentOf(expectedProfit, algoConf.ProfitThresholdPercent)
actualProfitMultiple := new(big.Int).Mul(actualProfit, common.Big100)

if expectedProfitMultiple.Cmp(actualProfitMultiple) > 0 {
if errLowProfit == nil {
errLowProfit = new(lowProfitError)
}
errLowProfit.ExpectedProfit = expectedProfit
errLowProfit.ActualProfit = actualProfit
}
}

if errLowProfit != nil { // staticcheck linter complains if we don't check for nil here
return errLowProfit
}
return nil
}

func checkInterrupt(i *int32) bool {
return i != nil && atomic.LoadInt32(i) != commitInterruptNone
}
Expand Down
27 changes: 16 additions & 11 deletions miner/env_changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ func (c *envChanges) commitBundle(bundle *types.SimulatedBundle, chData chainDat
if err := c.env.state.MultiTxSnapshotCommit(); err != nil {
panic(fmt.Sprintf("err: %v, receipt: %v", err, receipt))
}

}
//switch err {
//case nil:
Expand Down Expand Up @@ -252,22 +251,28 @@ func (c *envChanges) commitBundle(bundle *types.SimulatedBundle, chData chainDat
bundleProfit = new(big.Int).Sub(c.env.state.GetBalance(c.env.coinbase), coinbaseBefore)
gasUsed = c.usedGas - gasUsedBefore

simEffGP = new(big.Int).Set(bundle.MevGasPrice)
effGP *big.Int
// EGP = Effective Gas Price (Profit / GasUsed)
simulatedEGP = new(big.Int).Set(bundle.MevGasPrice)
actualEGP *big.Int
tolerablePriceDifferencePercent = 1

simulatedBundleProfit = new(big.Int).Set(bundle.TotalEth)
actualBundleProfit = new(big.Int).Set(bundleProfit)
)

if gasUsed == 0 {
effGP = new(big.Int).SetUint64(0)
actualEGP = big.NewInt(0)
} else {
effGP = new(big.Int).Div(bundleProfit, new(big.Int).SetUint64(gasUsed))
actualEGP = new(big.Int).Div(bundleProfit, big.NewInt(int64(gasUsed)))
}

// allow >-1% divergence
effGP.Mul(effGP, common.Big100)
simEffGP.Mul(simEffGP, big.NewInt(99))
if simEffGP.Cmp(effGP) > 0 {
log.Trace("Bundle underpays after inclusion", "bundle", bundle.OriginalBundle.Hash)
err := ValidateGasPriceAndProfit(algoConf,
actualEGP, simulatedEGP, tolerablePriceDifferencePercent,
actualBundleProfit, simulatedBundleProfit,
)
if err != nil {
c.rollback(gasUsedBefore, gasPoolBefore, profitBefore, txsBefore, receiptsBefore)
return errors.New("bundle underpays")
return err
}

c.profit.Add(profitBefore, bundleProfit)
Expand Down
52 changes: 18 additions & 34 deletions miner/environment_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,45 +195,29 @@ func (envDiff *environmentDiff) commitBundle(bundle *types.SimulatedBundle, chDa
coinbaseBalanceDelta := new(big.Int).Sub(coinbaseBalanceAfter, coinbaseBalanceBefore)
tmpEnvDiff.newProfit.Add(profitBefore, coinbaseBalanceDelta)

bundleProfit := coinbaseBalanceDelta
var (
bundleProfit = coinbaseBalanceDelta
// EGP = Effective Gas Price (Profit / GasUsed)
simulatedEGP = new(big.Int).Set(bundle.MevGasPrice)
actualEGP *big.Int
tolerablePriceDifferencePercent = 1

simulatedBundleProfit = new(big.Int).Set(bundle.TotalEth)
actualBundleProfit = new(big.Int).Set(bundleProfit)
)

var bundleActualEffGP *big.Int
if gasUsed == 0 {
bundleActualEffGP = big.NewInt(0)
actualEGP = big.NewInt(0)
} else {
bundleActualEffGP = bundleProfit.Div(bundleProfit, big.NewInt(int64(gasUsed)))
}
bundleSimEffGP := new(big.Int).Set(bundle.MevGasPrice)

// allow >-1% divergence
actualEGP := new(big.Int).Mul(bundleActualEffGP, common.Big100) // bundle actual effective gas price * 100
simulatedEGP := new(big.Int).Mul(bundleSimEffGP, big.NewInt(99)) // bundle simulated effective gas price * 99

if simulatedEGP.Cmp(actualEGP) > 0 {
log.Trace("Bundle underpays after inclusion", "bundle", bundle.OriginalBundle.Hash)
return &lowProfitError{
ExpectedEffectiveGasPrice: bundleSimEffGP,
ActualEffectiveGasPrice: bundleActualEffGP,
}
actualEGP = new(big.Int).Div(bundleProfit, big.NewInt(int64(gasUsed)))
}

if algoConf.EnforceProfit {
// if profit is enforced between simulation and actual commit, only allow ProfitThresholdPercent divergence
simulatedBundleProfit := new(big.Int).Set(bundle.TotalEth)
actualBundleProfit := new(big.Int).Mul(bundleActualEffGP, big.NewInt(int64(gasUsed)))

// We want to make simulated profit smaller to allow for some leeway in cases where the actual profit is
// lower due to transaction ordering
simulatedProfitMultiple := common.PercentOf(simulatedBundleProfit, algoConf.ProfitThresholdPercent)
actualProfitMultiple := new(big.Int).Mul(actualBundleProfit, common.Big100)

if simulatedProfitMultiple.Cmp(actualProfitMultiple) > 0 {
log.Trace("Lower bundle profit found after inclusion", "bundle", bundle.OriginalBundle.Hash)
return &lowProfitError{
ExpectedProfit: simulatedBundleProfit,
ActualProfit: actualBundleProfit,
}
}
err := ValidateGasPriceAndProfit(algoConf,
actualEGP, simulatedEGP, tolerablePriceDifferencePercent,
actualBundleProfit, simulatedBundleProfit,
)
if err != nil {
return err
}

*envDiff = *tmpEnvDiff
Expand Down

0 comments on commit da5c54e

Please sign in to comment.