Skip to content

Commit

Permalink
Add signature verifications (#138)
Browse files Browse the repository at this point in the history
* Add signature verification for getHeader response

Signed-off-by: Luca Georges Francois <[email protected]>

* Remove typo

Signed-off-by: Luca Georges Francois <[email protected]>

* Add signature verification for registerValidator request

Signed-off-by: Luca Georges Francois <[email protected]>

* Update mergemock integration tests

Signed-off-by: Luca Georges Francois <[email protected]>

* Fix typo in flag

Signed-off-by: Luca Georges Francois <[email protected]>

* Add error logging

Signed-off-by: Luca Georges Francois <[email protected]>

* Add signature verification tests

Signed-off-by: Luca Georges Francois <[email protected]>
  • Loading branch information
0xpanoramix authored Jun 9, 2022
1 parent ff25f53 commit b9394bc
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 6 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ run:
./mev-boost

run-boost-with-relay:
./mev-boost -relays 127.0.0.1:28545
./mev-boost -relays http://0x821961b64d99b997c934c22b4fd6109790acf00f7969322c4e9dbf1ca278c333148284c01c5ef551a1536ddd14b178b9@127.0.0.1:28545

run-dev:
go run cmd/mev-boost/main.go
Expand All @@ -58,7 +58,7 @@ run-mergemock-consensus:
cd $(MERGEMOCK_DIR) && $(MERGEMOCK_BIN) consensus --slot-time=4s --engine http://127.0.0.1:8551 --builder http://127.0.0.1:18550 --slot-bound 10

run-mergemock-relay:
cd $(MERGEMOCK_DIR) && $(MERGEMOCK_BIN) relay --listen-addr 127.0.0.1:28545
cd $(MERGEMOCK_DIR) && $(MERGEMOCK_BIN) relay --listen-addr 127.0.0.1:28545 --secret-key 1e64a14cb06073c2d7c8b0b891e5dc3dc719b86e5bf4c131ddbaa115f09f8f52

run-mergemock-integration: build
make -j3 run-boost-with-relay run-mergemock-consensus run-mergemock-relay
Expand Down
28 changes: 26 additions & 2 deletions server/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ func (m *BoostService) handleRegisterValidator(w http.ResponseWriter, req *http.
http.Error(w, errInvalidSignature.Error(), http.StatusBadRequest)
return
}

ok, err := types.VerifySignature(registration.Message, types.DomainBuilder, registration.Message.Pubkey[:], registration.Signature[:])
if err != nil {
log.WithError(err).Warn("error occurred while verifying signature")
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if !ok {
log.WithError(err).Warn("failed to verify signature")
http.Error(w, errInvalidSignature.Error(), http.StatusBadRequest)
return
}
}

numSuccessRequestsToRelay := 0
Expand Down Expand Up @@ -218,7 +230,7 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
var wg sync.WaitGroup
for _, relay := range m.relays {
wg.Add(1)
go func(relayAddr string) {
go func(relayAddr string, relayPubKey types.PublicKey) {
defer wg.Done()
url := fmt.Sprintf("%s/eth/v1/builder/header/%s/%s/%s", relayAddr, slot, parentHashHex, pubkey)
log := log.WithField("url", url)
Expand All @@ -239,6 +251,18 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
return
}

// Verify the relay signature in the relay response
ok, err := types.VerifySignature(responsePayload.Data.Message, types.DomainBuilder, relayPubKey[:],
responsePayload.Data.Signature[:])
if err != nil {
log.WithError(err).Warn("error validating response signature")
return
}
if !ok {
log.WithError(errInvalidSignature).Warn("error verifying signature")
return
}

// Skip if not a higher value
if result.Data != nil && responsePayload.Data.Message.Value.Cmp(&result.Data.Message.Value) < 1 {
return
Expand All @@ -253,7 +277,7 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request)
"value": result.Data.Message.Value.String(),
"url": relayAddr,
}).Info("getHeader: successfully got more valuable payload header")
}(relay.Address)
}(relay.Address, relay.PublicKey)
}

// Wait for all requests to complete...
Expand Down
56 changes: 54 additions & 2 deletions server/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,33 +241,85 @@ func TestGetHeader(t *testing.T) {
})

t.Run("Use header with highest value", func(t *testing.T) {
// Create backend and register 3 relays.
backend := newTestBackend(t, 3, time.Second)

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

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

// First relay will return signed response with value 12346.
backend.relays[2].GetHeaderResponse = backend.relays[2].MakeGetHeaderResponse(
12346,
"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))
require.Equal(t, 1, backend.relays[1].GetRequestCount(path))
require.Equal(t, 1, backend.relays[2].GetRequestCount(path))

require.Equal(t, http.StatusOK, rr.Code, rr.Body.String())

// Highest value should be 12347, i.e. second relay.
resp := new(types.GetHeaderResponse)
err := json.Unmarshal(rr.Body.Bytes(), resp)
require.NoError(t, err)
require.Equal(t, types.IntToU256(12347), resp.Data.Message.Value)
})

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

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

// Simulate a different public key registered to mev-boost
pk := types.PublicKey{}
backend.boost.relays[0].PublicKey = pk

rr := backend.request(t, http.MethodGet, path, nil)
require.Equal(t, 1, backend.relays[0].GetRequestCount(path))

// Request should have failed
require.Equal(t, http.StatusBadGateway, rr.Code, rr.Body.String())
})

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

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

// Scramble the signature
backend.relays[0].GetHeaderResponse.Data.Signature = types.Signature{}

rr := backend.request(t, http.MethodGet, path, nil)
require.Equal(t, 1, backend.relays[0].GetRequestCount(path))

// Request should have failed
require.Equal(t, http.StatusBadGateway, rr.Code, rr.Body.String())
})
}

func TestGetPayload(t *testing.T) {
Expand Down

0 comments on commit b9394bc

Please sign in to comment.