Skip to content

Commit

Permalink
Min bid (#274)
Browse files Browse the repository at this point in the history
* add min-bid feature

* Add Float to U256 test, other minor review changes

* Re-wrote floatEthTo256Wei + addressed review comments

* Apply suggestions from jtraglia's code review

Co-authored-by: Justin Traglia <[email protected]>

* fix typo

* Changed default min-bid to 0 and added logging

Co-authored-by: allboxes <[email protected]>
Co-authored-by: Justin Traglia <[email protected]>
  • Loading branch information
3 people authored Oct 20, 2022
1 parent 909e004 commit dd4665d
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 2 deletions.
49 changes: 49 additions & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package cli

import (
"flag"
"math/big"
"os"
"strconv"
"strings"
"time"

"github.com/flashbots/go-boost-utils/types"
"github.com/flashbots/mev-boost/config"
"github.com/flashbots/mev-boost/server"
"github.com/sirupsen/logrus"
Expand All @@ -25,6 +27,7 @@ var (
defaultListenAddr = getEnv("BOOST_LISTEN_ADDR", "localhost:18550")
defaultRelayCheck = os.Getenv("RELAY_STARTUP_CHECK") != ""
defaultGenesisForkVersion = getEnv("GENESIS_FORK_VERSION", "")
defaultRelayMinBidEth = getEnvFloat64("MIN_BID_ETH", 0)
defaultDisableLogVersion = os.Getenv("DISABLE_LOG_VERSION") == "1" // disables adding the version to every log entry

// mev-boost relay request timeouts (see also https://github.com/flashbots/mev-boost/issues/287)
Expand All @@ -46,6 +49,7 @@ var (
listenAddr = flag.String("addr", defaultListenAddr, "listen-address for mev-boost server")
relayURLs = flag.String("relays", "", "relay urls - single entry or comma-separated list (scheme://pubkey@host)")
relayCheck = flag.Bool("relay-check", defaultRelayCheck, "check relay status on startup and on the status API call")
relayMinBidEth = flag.Float64("min-bid", defaultRelayMinBidEth, "minimum bid to accept from a relay [eth]")
relayMonitorURLs = flag.String("relay-monitors", "", "relay monitor urls - single entry or comma-separated list (scheme://host)")

relayTimeoutMsGetHeader = flag.Int("request-timeout-getheader", defaultTimeoutMsGetHeader, "timeout for getHeader requests to the relay [ms]")
Expand Down Expand Up @@ -161,13 +165,31 @@ func Main() {
}
}

if *relayMinBidEth < 0.0 {
log.Fatal("Please specify a non-negative minimum bid")
}

if *relayMinBidEth > 1000000.0 {
log.Fatal("Minimum bid is too large, please ensure min-bid is denominated in Ethers")
}

if *relayMinBidEth > 0.0 {
log.Infof("minimum bid: %v eth", *relayMinBidEth)
}

relayMinBidWei, err := floatEthTo256Wei(*relayMinBidEth)
if err != nil {
log.WithError(err).Fatal("failed converting min bid")
}

opts := server.BoostServiceOpts{
Log: log,
ListenAddr: *listenAddr,
Relays: relays,
RelayMonitors: relayMonitors,
GenesisForkVersionHex: genesisForkVersionHex,
RelayCheck: *relayCheck,
RelayMinBid: *relayMinBidWei,
RequestTimeoutGetHeader: time.Duration(*relayTimeoutMsGetHeader) * time.Millisecond,
RequestTimeoutGetPayload: time.Duration(*relayTimeoutMsGetPayload) * time.Millisecond,
RequestTimeoutRegVal: time.Duration(*relayTimeoutMsRegVal) * time.Millisecond,
Expand Down Expand Up @@ -201,3 +223,30 @@ func getEnvInt(key string, defaultValue int) int {
}
return defaultValue
}

func getEnvFloat64(key string, defaultValue float64) float64 {
if value, ok := os.LookupEnv(key); ok {
val, err := strconv.ParseFloat(value, 64)
if err == nil {
return val
}
}
return defaultValue
}

// floatEthTo256Wei converts a float (precision 10) denominated in eth to a U256Str denominated in wei
func floatEthTo256Wei(val float64) (*types.U256Str, error) {
weiU256 := new(types.U256Str)
ethFloat := new(big.Float)
weiFloat := new(big.Float)
weiFloatLessPrecise := new(big.Float)
weiInt := new(big.Int)

ethFloat.SetFloat64(val)
weiFloat.Mul(ethFloat, big.NewFloat(1e18))
weiFloatLessPrecise.SetString(weiFloat.String())
weiFloatLessPrecise.Int(weiInt)

err := weiU256.FromBig(weiInt)
return weiU256, err
}
36 changes: 36 additions & 0 deletions cli/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cli

import (
"math/big"
"testing"

"github.com/flashbots/go-boost-utils/types"
"github.com/stretchr/testify/require"
)

func TestFloatEthTo256Wei(t *testing.T) {
// test with small input
i := 0.000000000000012345
weiU256, err := floatEthTo256Wei(i)
require.NoError(t, err)
require.Equal(t, types.IntToU256(12345), *weiU256)

// test with zero
i = 0
weiU256, err = floatEthTo256Wei(i)
require.NoError(t, err)
require.Equal(t, types.IntToU256(0), *weiU256)

// test with large input
i = 987654.3
weiU256, err = floatEthTo256Wei(i)
require.NoError(t, err)

r := big.NewInt(9876543)
r.Mul(r, big.NewInt(1e17))
referenceWeiU256 := new(types.U256Str)
err = referenceWeiU256.FromBig(r)
require.NoError(t, err)

require.Equal(t, *referenceWeiU256, *weiU256)
}
10 changes: 9 additions & 1 deletion server/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type BoostServiceOpts struct {
RelayMonitors []*url.URL
GenesisForkVersionHex string
RelayCheck bool
RelayMinBid types.U256Str

RequestTimeoutGetHeader time.Duration
RequestTimeoutGetPayload time.Duration
Expand All @@ -63,6 +64,7 @@ type BoostService struct {
log *logrus.Entry
srv *http.Server
relayCheck bool
relayMinBid types.U256Str

builderSigningDomain types.Domain
httpClientGetHeader http.Client
Expand Down Expand Up @@ -90,6 +92,7 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) {
relayMonitors: opts.RelayMonitors,
log: opts.Log,
relayCheck: opts.RelayCheck,
relayMinBid: opts.RelayMinBid,
bids: make(map[bidRespKey]bidResp),

builderSigningDomain: builderSigningDomain,
Expand Down Expand Up @@ -358,9 +361,14 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
log.Warn("ignoring bid with 0 value")
return
}

log.Debug("bid received")

// Skip if value (fee) is lower than the minimum bid
if responsePayload.Data.Message.Value.Cmp(&m.relayMinBid) == -1 {
log.Debug("ignoring bid below min-bid value")
return
}

mu.Lock()
defer mu.Unlock()

Expand Down
50 changes: 49 additions & 1 deletion server/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func newTestBackend(t *testing.T, numRelays int, relayTimeout time.Duration) *te
Relays: relayEntries,
GenesisForkVersionHex: "0x00000000",
RelayCheck: true,
RelayMinBid: types.IntToU256(12345),
RequestTimeoutGetHeader: relayTimeout,
RequestTimeoutGetPayload: relayTimeout,
RequestTimeoutRegVal: relayTimeout,
Expand Down Expand Up @@ -94,7 +95,7 @@ func blindedBlockToExecutionPayload(signedBlindedBeaconBlock *types.SignedBlinde

func TestNewBoostServiceErrors(t *testing.T) {
t.Run("errors when no relays", func(t *testing.T) {
_, err := NewBoostService(BoostServiceOpts{testLog, ":123", []RelayEntry{}, []*url.URL{}, "0x00000000", true, time.Second, time.Second, time.Second})
_, err := NewBoostService(BoostServiceOpts{testLog, ":123", []RelayEntry{}, []*url.URL{}, "0x00000000", true, types.IntToU256(0), time.Second, time.Second, time.Second})
require.Error(t, err)
})
}
Expand Down Expand Up @@ -386,6 +387,53 @@ func TestGetHeader(t *testing.T) {
require.Equal(t, "0xa18385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", resp.Data.Message.Header.BlockHash.String())
})

t.Run("Respect minimum bid cutoff", func(t *testing.T) {
// Create backend and register relay.
backend := newTestBackend(t, 1, time.Second)

// Relay will return signed response with value 12344.
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12344,
"0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

// Run the request.
rr := backend.request(t, http.MethodGet, path, nil)

// Each relay must have received the request.
require.Equal(t, 1, backend.relays[0].GetRequestCount(path))

// Request should have no content (min bid is 12345)
require.Equal(t, http.StatusNoContent, rr.Code)
})

t.Run("Allow bids which meet minimum bid cutoff", func(t *testing.T) {
// Create backend and register relay.
backend := newTestBackend(t, 1, time.Second)

// First relay will return signed response with value 12345.
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12345,
"0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

// Run the request.
rr := backend.request(t, http.MethodGet, path, nil)

// Each relay must have received the request.
require.Equal(t, 1, backend.relays[0].GetRequestCount(path))

// Value should be 12345 (min bid is 12345)
resp := new(types.GetHeaderResponse)
err := json.Unmarshal(rr.Body.Bytes(), resp)
require.NoError(t, err)
require.Equal(t, types.IntToU256(12345), resp.Data.Message.Value)
})

t.Run("Invalid relay public key", func(t *testing.T) {
backend := newTestBackend(t, 1, time.Second)

Expand Down

0 comments on commit dd4665d

Please sign in to comment.