Skip to content

Commit

Permalink
status-check: proxy relay check until first responds ok, enabled with…
Browse files Browse the repository at this point in the history
… feature flag
  • Loading branch information
metachris committed Jul 5, 2022
1 parent 3721723 commit adfc1a0
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 17 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ Please start by reading our [code of conduct](CODE_OF_CONDUCT.md).
Install a few dev dependencies:

```bash
go install github.com/ferranbt/fastssz/sszgen@latest
go install github.com/mgechev/revive@latest
go install honnef.co/go/tools/cmd/staticcheck@master
go install github.com/ferranbt/fastssz/sszgen@latest
```

Look at the [README for instructions to install the dependencies and build `mev-boost`](README.md#install)
Expand Down
13 changes: 11 additions & 2 deletions cmd/mev-boost/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,22 @@ func main() {
log.WithField("relays", relays).Infof("using %d relays", len(relays))

relayTimeout := time.Duration(*relayTimeoutMs) * time.Millisecond
server, err := server.NewBoostService(*listenAddr, relays, log, genesisForkVersionHex, relayTimeout)

opts := server.BoostServiceOpts{
Log: log,
ListenAddr: *listenAddr,
Relays: relays,
GenesisForkVersionHex: genesisForkVersionHex,
RelayRequestTimeout: relayTimeout,
RelayCheck: *relayCheck,
}
server, err := server.NewBoostService(opts)
if err != nil {
log.WithError(err).Fatal("failed creating the server")
}

if *relayCheck && !server.CheckRelays() {
log.Fatal("relays unavailable")
log.Fatal("no relay available")
}

log.Println("listening on", *listenAddr)
Expand Down
46 changes: 34 additions & 12 deletions server/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,35 +35,47 @@ type httpErrorResp struct {
Message string `json:"message"`
}

// BoostServiceOpts provides all available options for use with NewBoostService
type BoostServiceOpts struct {
Log *logrus.Entry
ListenAddr string
Relays []RelayEntry
GenesisForkVersionHex string
RelayRequestTimeout time.Duration
RelayCheck bool
}

// BoostService TODO
type BoostService struct {
listenAddr string
relays []RelayEntry
log *logrus.Entry
srv *http.Server
relayCheck bool

builderSigningDomain types.Domain
httpClient http.Client
}

// NewBoostService created a new BoostService
func NewBoostService(listenAddr string, relays []RelayEntry, log *logrus.Entry, genesisForkVersionHex string, relayRequestTimeout time.Duration) (*BoostService, error) {
if len(relays) == 0 {
func NewBoostService(opts BoostServiceOpts) (*BoostService, error) {
if len(opts.Relays) == 0 {
return nil, errors.New("no relays")
}

builderSigningDomain, err := ComputeDomain(types.DomainTypeAppBuilder, genesisForkVersionHex, types.Root{}.String())
builderSigningDomain, err := ComputeDomain(types.DomainTypeAppBuilder, opts.GenesisForkVersionHex, types.Root{}.String())
if err != nil {
return nil, err
}

return &BoostService{
listenAddr: listenAddr,
relays: relays,
log: log.WithField("module", "service"),
listenAddr: opts.ListenAddr,
relays: opts.Relays,
log: opts.Log.WithField("module", "service"),
relayCheck: opts.RelayCheck,

builderSigningDomain: builderSigningDomain,
httpClient: http.Client{Timeout: relayRequestTimeout},
httpClient: http.Client{Timeout: opts.RelayRequestTimeout},
}, nil
}

Expand Down Expand Up @@ -130,9 +142,15 @@ func (m *BoostService) handleRoot(w http.ResponseWriter, req *http.Request) {
// handleStatus sends calls to the status endpoint of every relay.
// It returns OK if at least one returned OK, and returns KO otherwise.
func (m *BoostService) handleStatus(w http.ResponseWriter, req *http.Request) {
if !m.relayCheck {
m.respondOK(w, nilResponse)
return
}

// If relayCheck is enabled, make sure at least 1 relay returns success
var wg sync.WaitGroup
var numSuccessRequestsToRelay uint32

ctx, cancel := context.WithCancel(context.Background())
for _, r := range m.relays {
wg.Add(1)

Expand All @@ -143,23 +161,27 @@ func (m *BoostService) handleStatus(w http.ResponseWriter, req *http.Request) {
log.Debug("Checking relay status")

url := relay.Address + pathStatus
err := SendHTTPRequest(context.Background(), m.httpClient, http.MethodGet, url, nil, nil)
err := SendHTTPRequest(ctx, m.httpClient, http.MethodGet, url, nil, nil)

if err != nil {
if err != nil && ctx.Err() != context.Canceled {
log.WithError(err).Error("failed to retrieve relay status")
return
}

// Success: increase counter, respond with OK, and then cancel pending requests to other relays
atomic.AddUint32(&numSuccessRequestsToRelay, 1)
m.respondOK(w, nilResponse)
}(r)
}

// After first request is done, cancel other relay requests
cancel()

// At the end, we wait for every routine and return status according to relay's ones.
wg.Wait()

if numSuccessRequestsToRelay == 0 {
m.respondError(w, http.StatusServiceUnavailable, "all relays are unavailable")
} else {
m.respondOK(w, nilResponse)
}
}

Expand Down
13 changes: 11 additions & 2 deletions server/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ func newTestBackend(t *testing.T, numRelays int, relayTimeout time.Duration) *te
backend.relays[i] = newMockRelay(t, blsPrivateKey)
relayEntries[i] = backend.relays[i].RelayEntry
}
service, err := NewBoostService("localhost:12345", relayEntries, testLog, "0x00000000", relayTimeout)

opts := BoostServiceOpts{
Log: testLog,
ListenAddr: "localhost:12345",
Relays: relayEntries,
GenesisForkVersionHex: "0x00000000",
RelayRequestTimeout: relayTimeout,
RelayCheck: true,
}
service, err := NewBoostService(opts)
require.NoError(t, err)

backend.boost = service
Expand All @@ -64,7 +73,7 @@ func (be *testBackend) request(t *testing.T, method string, path string, payload

func TestNewBoostServiceErrors(t *testing.T) {
t.Run("errors when no relays", func(t *testing.T) {
_, err := NewBoostService(":123", []RelayEntry{}, testLog, "0x00000000", time.Second)
_, err := NewBoostService(BoostServiceOpts{testLog, ":123", []RelayEntry{}, "0x00000000", time.Second, true})
require.Error(t, err)
})
}
Expand Down

0 comments on commit adfc1a0

Please sign in to comment.