Skip to content

Commit

Permalink
getPayload only to origin relays (#342)
Browse files Browse the repository at this point in the history
  • Loading branch information
metachris authored and kailinr committed Sep 25, 2022
1 parent f8e15f4 commit dbb78b4
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 35 deletions.
17 changes: 16 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,22 @@ We appreciate you, friend <3.

The extended deploy steps are necessary for installations with `go install` to include the correct version.

* Ensure linter and tests are working: `make lint && make test-race`
### Before the release

Run these commands:

```bash
make lint
make test-race

# Start mev-boost with relay check, and call the mev-boost status endpoint
go run . -mainnet -relay-check -relays https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com,https://0xb3ee7afcf27f1f1259ac1787876318c6584ee353097a50ed84f51a1f21a323b3736f271a895c7ce918c038e4265918be@relay.edennetwork.io,https://0x9000009807ed12c1f08bf4e81c6da3ba8e3fc3d953898ce0102433094e5f22f21102ec057841fcb81978ed1ea0fa8246@builder-relay-mainnet.blocknative.com -debug
curl localhost:18550/eth/v1/builder/status
```


### Releasing a new version

* Update `Version` in `config/vars.go`
* it will be next_version-dev (eg. `v0.7.11-dev`)
* change it to the next version (eg. `v0.7.11`), and commit
Expand Down
10 changes: 1 addition & 9 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func Main() {
flag.Usage()
log.Fatal("no relays specified")
}
log.WithField("relays", relaysToStrings(relays)).Infof("using %d relays", len(relays))
log.WithField("relays", server.RelayEntriesToStrings(relays)).Infof("using %d relays", len(relays))

relayMonitors := parseRelayMonitorURLs(*relayMonitorURLs)
if len(relayMonitors) > 0 {
Expand Down Expand Up @@ -193,11 +193,3 @@ func parseRelayMonitorURLs(relayMonitorURLs string) (ret []*url.URL) {
}
return ret
}

func relaysToStrings(relays []server.RelayEntry) []string {
ret := []string{}
for _, entry := range relays {
ret = append(ret, entry.String())
}
return ret
}
7 changes: 4 additions & 3 deletions server/mock_relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,12 @@ func (m *mockRelay) handleRegisterValidator(w http.ResponseWriter, req *http.Req

// MakeGetHeaderResponse is used to create the default or can be used to create a custom response to the getHeader
// method
func (m *mockRelay) MakeGetHeaderResponse(value uint64, hash, publicKey string) *types.GetHeaderResponse {
func (m *mockRelay) MakeGetHeaderResponse(value uint64, blockHash, parentHash, publicKey string) *types.GetHeaderResponse {
// Fill the payload with custom values.
message := &types.BuilderBid{
Header: &types.ExecutionPayloadHeader{
BlockHash: _HexToHash(hash),
ParentHash: _HexToHash("0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7"),
BlockHash: _HexToHash(blockHash),
ParentHash: _HexToHash(parentHash),
},
Value: types.IntToU256(value),
Pubkey: _HexToPubkey(publicKey),
Expand Down Expand Up @@ -191,6 +191,7 @@ func (m *mockRelay) handleGetHeader(w http.ResponseWriter, req *http.Request) {
response := m.MakeGetHeaderResponse(
12345,
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)
if m.GetHeaderResponse != nil {
Expand Down
9 changes: 9 additions & 0 deletions server/relay_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@ func NewRelayEntry(relayURL string) (entry RelayEntry, err error) {
err = entry.PublicKey.UnmarshalText([]byte(entry.URL.User.Username()))
return entry, err
}

// RelayEntriesToStrings returns the string representation of a list of relay entries
func RelayEntriesToStrings(relays []RelayEntry) []string {
ret := make([]string, len(relays))
for i, entry := range relays {
ret[i] = entry.String()
}
return ret
}
31 changes: 16 additions & 15 deletions server/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,11 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
return
}

var mu sync.Mutex
relays := make(map[string][]string) // relays per blockHash
result := bidResp{}

ua := UserAgent(req.Header.Get("User-Agent"))
result := bidResp{} // the final response, containing the highest bid (if any)
relays := make(map[BlockHashHex][]RelayEntry) // relays that sent the bid for a specific blockHash

// Call the relays
var mu sync.Mutex
var wg sync.WaitGroup
for _, relay := range m.relays {
wg.Add(1)
Expand All @@ -302,7 +300,7 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
url := relay.GetURI(path)
log := log.WithField("url", url)
responsePayload := new(types.GetHeaderResponse)
code, err := SendHTTPRequest(context.Background(), m.httpClientGetHeader, http.MethodGet, url, ua, nil, responsePayload)
code, err := SendHTTPRequest(context.Background(), m.httpClientGetHeader, http.MethodGet, url, UserAgent(req.Header.Get("User-Agent")), nil, responsePayload)
if err != nil {
log.WithError(err).Warn("error making request to relay")
return
Expand Down Expand Up @@ -365,11 +363,7 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
defer mu.Unlock()

// Remember which relays delivered which bids (multiple relays might deliver the top bid)
if _, ok := relays[blockHash]; !ok {
relays[blockHash] = []string{relay.String()}
} else {
relays[blockHash] = append(relays[blockHash], relay.String())
}
relays[BlockHashHex(blockHash)] = append(relays[BlockHashHex(blockHash)], relay)

// Compare the bid with already known top bid (if any)
if result.response.Data != nil {
Expand Down Expand Up @@ -402,13 +396,13 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
}

// Log result
result.relays = relays[result.blockHash]
result.relays = relays[BlockHashHex(result.blockHash)]
log.WithFields(logrus.Fields{
"blockHash": result.blockHash,
"blockNumber": result.response.Data.Message.Header.BlockNumber,
"txRoot": result.response.Data.Message.Header.TransactionsRoot.String(),
"value": result.response.Data.Message.Value.String(),
"relays": strings.Join(result.relays, ", "),
"relays": strings.Join(RelayEntriesToStrings(result.relays), ", "),
}).Info("best bid")

// Remember the bid, for future logging in case of withholding
Expand Down Expand Up @@ -467,6 +461,12 @@ func (m *BoostService) handleGetPayload(w http.ResponseWriter, req *http.Request
log.Warn("bid found but no associated relays")
}

relays := originalBid.relays
if len(relays) == 0 {
log.Warn("originating relay not found, sending getPayload request to all relays")
relays = m.relays
}

var wg sync.WaitGroup
var mu sync.Mutex
result := new(types.GetPayloadResponse)
Expand All @@ -476,7 +476,7 @@ func (m *BoostService) handleGetPayload(w http.ResponseWriter, req *http.Request
requestCtx, requestCtxCancel := context.WithCancel(context.Background())
defer requestCtxCancel()

for _, relay := range m.relays {
for _, relay := range relays {
wg.Add(1)
go func(relay RelayEntry) {
defer wg.Done()
Expand Down Expand Up @@ -525,7 +525,8 @@ func (m *BoostService) handleGetPayload(w http.ResponseWriter, req *http.Request

// If no payload has been received from relay, log loudly about withholding!
if result.Data == nil || result.Data.BlockHash == nilHash {
log.WithField("relays", strings.Join(originalBid.relays, ", ")).Error("no payload received from relay -- could be a network error or withholding.")
originRelays := RelayEntriesToStrings(originalBid.relays)
log.WithField("relays", strings.Join(originRelays, ", ")).Error("no payload received from relay!")
m.respondError(w, http.StatusBadGateway, errNoSuccessfulRelayResponse.Error())
return
}
Expand Down
60 changes: 54 additions & 6 deletions server/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,15 @@ func TestRegisterValidator(t *testing.T) {
})
}

func TestGetHeader(t *testing.T) {
getPath := func(slot uint64, parentHash types.Hash, pubkey types.PublicKey) string {
return fmt.Sprintf("/eth/v1/builder/header/%d/%s/%s", slot, parentHash.String(), pubkey.String())
}
func getHeaderPath(slot uint64, parentHash types.Hash, pubkey types.PublicKey) string {
return fmt.Sprintf("/eth/v1/builder/header/%d/%s/%s", slot, parentHash.String(), pubkey.String())
}

func TestGetHeader(t *testing.T) {
hash := _HexToHash("0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7")
pubkey := _HexToPubkey(
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249")
path := getPath(1, hash, pubkey)
path := getHeaderPath(1, hash, pubkey)
require.Equal(t, "/eth/v1/builder/header/1/0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7/0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", path)

t.Run("Okay response from relay", func(t *testing.T) {
Expand All @@ -257,6 +257,7 @@ func TestGetHeader(t *testing.T) {
resp := backend.relays[0].MakeGetHeaderResponse(
12345,
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)
resp.Data.Message.Header.BlockHash = nilHash
Expand Down Expand Up @@ -284,20 +285,23 @@ func TestGetHeader(t *testing.T) {
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12345,
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

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

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

Expand Down Expand Up @@ -325,18 +329,21 @@ func TestGetHeader(t *testing.T) {
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12345,
"0xa38385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

backend.relays[1].GetHeaderResponse = backend.relays[1].MakeGetHeaderResponse(
12345,
"0xa18385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

backend.relays[2].GetHeaderResponse = backend.relays[2].MakeGetHeaderResponse(
12345,
"0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

Expand Down Expand Up @@ -364,6 +371,7 @@ func TestGetHeader(t *testing.T) {
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12345,
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

Expand All @@ -384,6 +392,7 @@ func TestGetHeader(t *testing.T) {
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12345,
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)

Expand Down Expand Up @@ -432,7 +441,7 @@ func TestGetHeader(t *testing.T) {
t.Run("Invalid parent hash", func(t *testing.T) {
backend := newTestBackend(t, 1, time.Second)

invalidParentHashPath := getPath(1, types.Hash{}, pubkey)
invalidParentHashPath := getHeaderPath(1, types.Hash{}, pubkey)
rr := backend.request(t, http.MethodGet, invalidParentHashPath, nil)
require.Equal(t, http.StatusNoContent, rr.Code)
require.Equal(t, 0, backend.relays[0].GetRequestCount(path))
Expand Down Expand Up @@ -579,3 +588,42 @@ func TestGetPayloadWithTestdata(t *testing.T) {
})
}
}

func TestGetPayloadToOriginRelayOnly(t *testing.T) {
// Load the signed blinded beacon block used for getPayload
jsonFile, err := os.Open("../testdata/kiln-signed-blinded-beacon-block-899730.json")
require.NoError(t, err)
defer jsonFile.Close()
signedBlindedBeaconBlock := new(types.SignedBlindedBeaconBlock)
require.NoError(t, DecodeJSON(jsonFile, &signedBlindedBeaconBlock))

// Create a test backend with 2 relays
backend := newTestBackend(t, 2, time.Second)

// call getHeader, highest bid is returned by relay 0
getHeaderPath := "/eth/v1/builder/header/899730/0xe8b9bd82aa0e957736c5a029903e53d581edf451e28ab274f4ba314c442e35a4/0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249"
backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse(
12345,
"0x373fb4e59dcb659b94bd58595c25345333426aa639f821567103e2eccf34d126",
"0xe8b9bd82aa0e957736c5a029903e53d581edf451e28ab274f4ba314c442e35a4",
"0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249",
)
rr := backend.request(t, http.MethodGet, getHeaderPath, nil)
require.Equal(t, http.StatusOK, rr.Code, rr.Body.String())
require.Equal(t, 1, backend.relays[0].GetRequestCount(getHeaderPath))
require.Equal(t, 1, backend.relays[1].GetRequestCount(getHeaderPath))

// Prepare getPayload response
backend.relays[0].GetPayloadResponse = &types.GetPayloadResponse{
Data: &types.ExecutionPayload{
BlockHash: signedBlindedBeaconBlock.Message.Body.ExecutionPayloadHeader.BlockHash,
},
}

// call getPayload, ensure it's only called on relay 0 (origin of the bid)
getPayloadPath := "/eth/v1/builder/blinded_blocks"
rr = backend.request(t, http.MethodPost, getPayloadPath, signedBlindedBeaconBlock)
require.Equal(t, http.StatusOK, rr.Code, rr.Body.String())
require.Equal(t, 1, backend.relays[0].GetRequestCount(getPayloadPath))
require.Equal(t, 0, backend.relays[1].GetRequestCount(getPayloadPath))
}
5 changes: 4 additions & 1 deletion server/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import (
// UserAgent is a custom string type to avoid confusing url + userAgent parameters in SendHTTPRequest
type UserAgent string

// BlockHashHex is a hex-string representation of a block hash
type BlockHashHex string

// SendHTTPRequest - prepare and send HTTP request, marshaling the payload if any, and decoding the response if dst is set
func SendHTTPRequest(ctx context.Context, client http.Client, method, url string, userAgent UserAgent, payload any, dst any) (code int, err error) {
var req *http.Request
Expand Down Expand Up @@ -114,7 +117,7 @@ type bidResp struct {
t time.Time
response types.GetHeaderResponse
blockHash string
relays []string
relays []RelayEntry
}

// bidRespKey is used as key for the bids cache
Expand Down

0 comments on commit dbb78b4

Please sign in to comment.