From c7bbf1aea1fbedd66ad212a0d4cdec5274b0817a Mon Sep 17 00:00:00 2001 From: Samuel Rounce Date: Wed, 26 Jun 2024 10:17:10 +0100 Subject: [PATCH 1/3] feat: release workflow pushes to Manifold GHCR fix: Replace deprecated goreleaser flag --skip-publish fix: Replace deprecated goreleaser flag --rm-dist fix: Update docker/metadata-action to latest fix: Add write permission to release workflow --- .github/workflows/release.yaml | 30 +++++++++++++++++++----------- Dockerfile | 2 ++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 959e65c1..a35c6e71 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,6 +7,7 @@ on: permissions: contents: write + packages: write jobs: docker-image: @@ -20,6 +21,10 @@ jobs: - name: Get tag version run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - name: Get release date + run: | + echo "RELEASE_DATE=$(date --rfc-3339=date)" >> ${GITHUB_ENV} + - name: Print version run: | echo $RELEASE_VERSION @@ -27,14 +32,14 @@ jobs: - name: Extract metadata (tags, labels) for Docker images id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@f7b4ed12385588c3f9bc252f0a2b520d83b52d48 with: - images: flashbots/mev-boost + images: ghcr.io/${{ github.event.repository.full_name }} tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} type=sha - type=pep440,pattern={{version}} - type=pep440,pattern={{major}}.{{minor}} - type=raw,value=latest,enable=${{ !contains(env.RELEASE_VERSION, '-') }} - name: Set up QEMU uses: docker/setup-qemu-action@v2 @@ -42,11 +47,12 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Login to DockerHub - uses: docker/login-action@v2 + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push uses: docker/build-push-action@v3 @@ -55,6 +61,8 @@ jobs: push: true build-args: | VERSION=${{ env.RELEASE_VERSION }} + VCS_REF=${{ github.event.ref }} + BUILD_DATE=${{ env.RELEASE_DATE }} platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} @@ -77,7 +85,7 @@ jobs: with: distribution: goreleaser version: latest - args: release --skip-publish --config .goreleaser-build.yaml --rm-dist + args: release --skip=publish --config .goreleaser-build.yaml --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload @@ -120,4 +128,4 @@ jobs: with: args: release --config .goreleaser-release.yaml env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index 32477fb6..6450c2db 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,8 @@ # syntax=docker/dockerfile:1 FROM golang:1.22 as builder ARG VERSION +ARG VCS_REF +ARG BUILD_DATE WORKDIR /build COPY go.mod ./ From 9ce16a0c5976f9c0bab11deae6c5fb26478dff8f Mon Sep 17 00:00:00 2001 From: MrKoberman Date: Tue, 28 May 2024 15:18:07 +0100 Subject: [PATCH 2/3] feat: privileged-builders Privileged builders are a list of public keys of builders from which bids will be accepted first, even if the bid is lower. If no bids are received from the privileged builders, bids from other builders will be accepted. This is useful when you have a special contract with specific relays and you would like to have their blocks used instead of other relays. While still having other relays as a fallback. --- README.md | 4 ++ cli/main.go | 54 +++++++++++------ cli/types.go | 34 +++++++++++ server/mock/mock_relay.go | 20 +++---- server/service.go | 118 ++++++++++++++++++++++++++------------ server/service_test.go | 73 ++++++++++++++++++----- 6 files changed, 222 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 41111059..9f53bcef 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,10 @@ Usage of mev-boost: relay monitor urls - single entry or comma-separated list (scheme://host) -relays string relay urls - single entry or comma-separated list (scheme://pubkey@host) + -privileged-builder + a single privileged builder(relay pubkey), can be specified multiple times + -privileged-builders string + privileged builders(relay pubkey) - single entry or comma-separated list -request-timeout-getheader int timeout for getHeader requests to the relay [ms] (default 950) -request-timeout-getpayload int diff --git a/cli/main.go b/cli/main.go index cc16b1bb..fb258790 100644 --- a/cli/main.go +++ b/cli/main.go @@ -32,17 +32,18 @@ var ( errInvalidLoglevel = errors.New("invalid loglevel") // defaults - defaultLogJSON = os.Getenv("LOG_JSON") != "" - defaultLogLevel = common.GetEnv("LOG_LEVEL", "info") - defaultListenAddr = common.GetEnv("BOOST_LISTEN_ADDR", "localhost:18550") - defaultRelayCheck = os.Getenv("RELAY_STARTUP_CHECK") != "" - defaultRelayMinBidEth = common.GetEnvFloat64("MIN_BID_ETH", 0) - defaultDisableLogVersion = os.Getenv("DISABLE_LOG_VERSION") == "1" // disables adding the version to every log entry - defaultDebug = os.Getenv("DEBUG") != "" - defaultLogServiceTag = os.Getenv("LOG_SERVICE_TAG") - defaultRelays = os.Getenv("RELAYS") - defaultRelayMonitors = os.Getenv("RELAY_MONITORS") - defaultMaxRetries = common.GetEnvInt("REQUEST_MAX_RETRIES", 5) + defaultLogJSON = os.Getenv("LOG_JSON") != "" + defaultLogLevel = common.GetEnv("LOG_LEVEL", "info") + defaultListenAddr = common.GetEnv("BOOST_LISTEN_ADDR", "localhost:18550") + defaultRelayCheck = os.Getenv("RELAY_STARTUP_CHECK") != "" + defaultRelayMinBidEth = common.GetEnvFloat64("MIN_BID_ETH", 0) + defaultDisableLogVersion = os.Getenv("DISABLE_LOG_VERSION") == "1" // disables adding the version to every log entry + defaultDebug = os.Getenv("DEBUG") != "" + defaultLogServiceTag = os.Getenv("LOG_SERVICE_TAG") + defaultRelays = os.Getenv("RELAYS") + defaultRelayMonitors = os.Getenv("RELAY_MONITORS") + defaultMaxRetries = common.GetEnvInt("REQUEST_MAX_RETRIES", 5) + defaultPrivilegedBuilders = os.Getenv("PRIVILEGED_BUILDERS") defaultGenesisForkVersion = common.GetEnv("GENESIS_FORK_VERSION", "") defaultGenesisTime = common.GetEnvInt("GENESIS_TIMESTAMP", -1) @@ -55,8 +56,9 @@ var ( defaultTimeoutMsGetPayload = common.GetEnvInt("RELAY_TIMEOUT_MS_GETPAYLOAD", 4000) // timeout for getPayload requests defaultTimeoutMsRegisterValidator = common.GetEnvInt("RELAY_TIMEOUT_MS_REGVAL", 3000) // timeout for registerValidator requests - relays relayList - relayMonitors relayMonitorList + relays relayList + relayMonitors relayMonitorList + privilegedBuilders privilegedBuilderList // cli flags printVersion = flag.Bool("version", false, "only print version") @@ -66,11 +68,12 @@ var ( logService = flag.String("log-service", defaultLogServiceTag, "add a 'service=...' tag to all log messages") logNoVersion = flag.Bool("log-no-version", defaultDisableLogVersion, "disables adding the version to every log entry") - listenAddr = flag.String("addr", defaultListenAddr, "listen-address for mev-boost server") - relayURLs = flag.String("relays", defaultRelays, "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", defaultRelayMonitors, "relay monitor urls - single entry or comma-separated list (scheme://host)") + listenAddr = flag.String("addr", defaultListenAddr, "listen-address for mev-boost server") + relayURLs = flag.String("relays", defaultRelays, "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", defaultRelayMonitors, "relay monitor urls - single entry or comma-separated list (scheme://host)") + privilegedBuilderKeys = flag.String("privileged-builders", defaultPrivilegedBuilders, "single entry or comma-separated list of relay username (pubkey)") relayTimeoutMsGetHeader = flag.Int("request-timeout-getheader", defaultTimeoutMsGetHeader, "timeout for getHeader requests to the relay [ms]") relayTimeoutMsGetPayload = flag.Int("request-timeout-getpayload", defaultTimeoutMsGetPayload, "timeout for getPayload requests to the relay [ms]") @@ -95,6 +98,7 @@ func Main() { // process repeatable flags flag.Var(&relays, "relay", "a single relay, can be specified multiple times") flag.Var(&relayMonitors, "relay-monitor", "a single relay monitor, can be specified multiple times") + flag.Var(&privilegedBuilders, "privileged-builder", "a single privileged builder, can be specified multiple times") // parse flags and get started flag.Parse() @@ -149,13 +153,24 @@ func Main() { } } + // set relay priorities + if *privilegedBuilderKeys != "" { + for _, builderKey := range strings.Split(*privilegedBuilderKeys, ",") { + err := privilegedBuilders.Set(strings.TrimSpace(builderKey)) + if err != nil { + log.WithError(err).WithField("privilegedBuilder", builderKey).Fatal("Invalid privileged builder") + } + } + } + if len(relays) == 0 { flag.Usage() log.Fatal("no relays specified") } log.Infof("using %d relays", len(relays)) for index, relay := range relays { - log.Infof("relay #%d: %s", index+1, relay.String()) + isPrivileged := privilegedBuilders.Contains(relay.PublicKey) + log.Infof("relay #%d: %s, privileged %t", index+1, relay.String(), isPrivileged) } // For backwards compatibility with the -relay-monitors flag. @@ -188,6 +203,7 @@ func Main() { ListenAddr: *listenAddr, Relays: relays, RelayMonitors: relayMonitors, + PrivilegedBuilders: privilegedBuilders, GenesisForkVersionHex: genesisForkVersionHex, GenesisTime: genesisTime, RelayCheck: *relayCheck, diff --git a/cli/types.go b/cli/types.go index 28c99b39..1b6cde8b 100644 --- a/cli/types.go +++ b/cli/types.go @@ -1,10 +1,13 @@ package cli import ( + "bytes" "errors" "net/url" "strings" + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/flashbots/go-boost-utils/utils" "github.com/flashbots/mev-boost/server/types" ) @@ -67,3 +70,34 @@ func (rm *relayMonitorList) Set(value string) error { *rm = append(*rm, relayMonitor) return nil } + +type privilegedBuilderList []phase0.BLSPubKey + +func (pb *privilegedBuilderList) String() string { + privilegedBuilders := []string{} + for _, privilegedBuilder := range *pb { + privilegedBuilders = append(privilegedBuilders, privilegedBuilder.String()) + } + return strings.Join(privilegedBuilders, ",") +} + +func (pb *privilegedBuilderList) Contains(privilegedBuilder phase0.BLSPubKey) bool { + for _, entry := range *pb { + if bytes.Equal(entry[:], privilegedBuilder[:]) { + return true + } + } + return false +} + +func (pb *privilegedBuilderList) Set(value string) error { + privilegedBuilder, err := utils.HexToPubkey(value) + if err != nil { + return err + } + if pb.Contains(privilegedBuilder) { + return errDuplicateEntry + } + *pb = append(*pb, privilegedBuilder) + return nil +} diff --git a/server/mock/mock_relay.go b/server/mock/mock_relay.go index c74d2c87..8be753b9 100644 --- a/server/mock/mock_relay.go +++ b/server/mock/mock_relay.go @@ -29,16 +29,6 @@ import ( "github.com/stretchr/testify/require" ) -const ( - mockRelaySecretKeyHex = "0x4e343a647c5a5c44d76c2c58b63f02cdf3a9a0ec40f102ebc26363b4b1b95033" -) - -var ( - skBytes, _ = hexutil.Decode(mockRelaySecretKeyHex) - mockRelaySecretKey, _ = bls.SecretKeyFromBytes(skBytes) - mockRelayPublicKey, _ = bls.PublicKeyFromSecretKey(mockRelaySecretKey) -) - // Relay is used to fake a relay's behavior. // You can override each of its handler by setting the instance's HandlerOverride_METHOD_TO_OVERRIDE to your own // handler. @@ -73,7 +63,11 @@ type Relay struct { // A secret key must be provided to sign default and custom response messages func NewRelay(t *testing.T) *Relay { t.Helper() - relay := &Relay{t: t, secretKey: mockRelaySecretKey, publicKey: mockRelayPublicKey, requestCount: make(map[string]int)} + + relay := &Relay{t: t, requestCount: make(map[string]int)} + + relay.secretKey, _, _ = bls.GenerateNewKeypair() + relay.publicKey, _ = bls.PublicKeyFromSecretKey(relay.secretKey) // Initialize server relay.Server = httptest.NewServer(relay.getRouter()) @@ -81,7 +75,7 @@ func NewRelay(t *testing.T) *Relay { // Create the RelayEntry with correct pubkey url, err := url.Parse(relay.Server.URL) require.NoError(t, err) - urlWithKey := fmt.Sprintf("%s://%s@%s", url.Scheme, hexutil.Encode(bls.PublicKeyToBytes(mockRelayPublicKey)), url.Host) + urlWithKey := fmt.Sprintf("%s://%s@%s", url.Scheme, hexutil.Encode(bls.PublicKeyToBytes(relay.publicKey)), url.Host) relay.RelayEntry, err = types.NewRelayEntry(urlWithKey) require.NoError(t, err) return relay @@ -248,7 +242,7 @@ func (m *Relay) defaultHandleGetHeader(w http.ResponseWriter) { 12345, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + m.RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) if m.GetHeaderResponse != nil { diff --git a/server/service.go b/server/service.go index 73aa21fd..c1423288 100644 --- a/server/service.go +++ b/server/service.go @@ -62,6 +62,7 @@ type BoostServiceOpts struct { ListenAddr string Relays []types.RelayEntry RelayMonitors []*url.URL + PrivilegedBuilders []phase0.BLSPubKey GenesisForkVersionHex string GenesisTime uint64 RelayCheck bool @@ -75,14 +76,15 @@ type BoostServiceOpts struct { // BoostService - the mev-boost service type BoostService struct { - listenAddr string - relays []types.RelayEntry - relayMonitors []*url.URL - log *logrus.Entry - srv *http.Server - relayCheck bool - relayMinBid types.U256Str - genesisTime uint64 + listenAddr string + relays []types.RelayEntry + relayMonitors []*url.URL + privilegedBuilders []phase0.BLSPubKey + log *logrus.Entry + srv *http.Server + relayCheck bool + relayMinBid types.U256Str + genesisTime uint64 builderSigningDomain phase0.Domain httpClientGetHeader http.Client @@ -109,15 +111,16 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) { } return &BoostService{ - listenAddr: opts.ListenAddr, - relays: opts.Relays, - relayMonitors: opts.RelayMonitors, - log: opts.Log, - relayCheck: opts.RelayCheck, - relayMinBid: opts.RelayMinBid, - genesisTime: opts.GenesisTime, - bids: make(map[bidRespKey]bidResp), - slotUID: &slotUID{}, + listenAddr: opts.ListenAddr, + relays: opts.Relays, + relayMonitors: opts.RelayMonitors, + privilegedBuilders: opts.PrivilegedBuilders, + log: opts.Log, + relayCheck: opts.RelayCheck, + relayMinBid: opts.RelayMinBid, + genesisTime: opts.GenesisTime, + bids: make(map[bidRespKey]bidResp), + slotUID: &slotUID{}, builderSigningDomain: builderSigningDomain, httpClientGetHeader: http.Client{ @@ -292,7 +295,7 @@ func (m *BoostService) handleRegisterValidator(w http.ResponseWriter, req *http. } // handleGetHeader requests bids from the relays -func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request) { +func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request) { //nolint:maintidx vars := mux.Vars(req) slot := vars["slot"] parentHashHex := vars["parent_hash"] @@ -349,6 +352,7 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request) } // Prepare relay responses result := bidResp{} // the final response, containing the highest bid (if any) + resultPrivileged := bidResp{} // the final response, containing the highest bid (if any) for privileged relays relays := make(map[BlockHashHex][]types.RelayEntry) // relays that sent the bid for a specific blockHash // Call the relays var mu sync.Mutex @@ -444,35 +448,46 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request) // Remember which relays delivered which bids (multiple relays might deliver the top bid) relays[BlockHashHex(bidInfo.blockHash.String())] = append(relays[BlockHashHex(bidInfo.blockHash.String())], relay) - // Compare the bid with already known top bid (if any) - if !result.response.IsEmpty() { - valueDiff := bidInfo.value.Cmp(result.bidInfo.value) - if valueDiff == -1 { // current bid is less profitable than already known one - return - } else if valueDiff == 0 { // current bid is equally profitable as already known one. Use hash as tiebreaker - previousBidBlockHash := result.bidInfo.blockHash - if bidInfo.blockHash.String() >= previousBidBlockHash.String() { - return - } - } + if m.isPrivilegedRelay(relay.PublicKey) { + m.setBestBid(&resultPrivileged, bidInfo, responsePayload, log) + } else { + m.setBestBid(&result, bidInfo, responsePayload, log) } - - // Use this relay's response as mev-boost response because it's most profitable - log.Debug("new best bid") - result.response = *responsePayload - result.bidInfo = bidInfo - result.t = time.Now() }(relay) } // Wait for all requests to complete... wg.Wait() - if result.response.IsEmpty() { + if resultPrivileged.response.IsEmpty() && result.response.IsEmpty() { log.Info("no bid received") w.WriteHeader(http.StatusNoContent) return } + if !resultPrivileged.response.IsEmpty() { + // Log result privileged + valueEth := weiBigIntToEthBigFloat(resultPrivileged.bidInfo.value.ToBig()) + resultPrivileged.relays = relays[BlockHashHex(resultPrivileged.bidInfo.blockHash.String())] + log.WithFields(logrus.Fields{ + "blockHash": resultPrivileged.bidInfo.blockHash.String(), + "blockNumber": resultPrivileged.bidInfo.blockNumber, + "txRoot": resultPrivileged.bidInfo.txRoot.String(), + "value": valueEth.Text('f', 18), + "relays": strings.Join(types.RelayEntriesToStrings(resultPrivileged.relays), ", "), + "privileged": true, + }).Info("best privileged bid") + + // Remember the bid, for future logging in case of withholding + bidKey := bidRespKey{slot: _slot, blockHash: resultPrivileged.bidInfo.blockHash.String()} + m.bidsLock.Lock() + m.bids[bidKey] = resultPrivileged + m.bidsLock.Unlock() + + // Return the bid + m.respondOK(w, &resultPrivileged.response) + return + } + // Log result valueEth := weiBigIntToEthBigFloat(result.bidInfo.value.ToBig()) result.relays = relays[BlockHashHex(result.bidInfo.blockHash.String())] @@ -482,6 +497,7 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request) "txRoot": result.bidInfo.txRoot.String(), "value": valueEth.Text('f', 18), "relays": strings.Join(types.RelayEntriesToStrings(result.relays), ", "), + "privileged": false, }).Info("best bid") // Remember the bid, for future logging in case of withholding @@ -494,6 +510,27 @@ func (m *BoostService) handleGetHeader(w http.ResponseWriter, req *http.Request) m.respondOK(w, &result.response) } +func (m *BoostService) setBestBid(result *bidResp, bidInfo bidInfo, responsePayload *builderSpec.VersionedSignedBuilderBid, log *logrus.Entry) { + // Compare the bid with already known top bid (if any) + if !result.response.IsEmpty() { + valueDiff := bidInfo.value.Cmp(result.bidInfo.value) + if valueDiff == -1 { // current bid is less profitable than already known one + return + } else if valueDiff == 0 { // current bid is equally profitable as already known one. Use hash as tiebreaker + previousBidBlockHash := result.bidInfo.blockHash + if bidInfo.blockHash.String() >= previousBidBlockHash.String() { + return + } + } + } + + // Use this relay's response as mev-boost response because it's most profitable + log.Debug("new best bid") + result.response = *responsePayload + result.bidInfo = bidInfo + result.t = time.Now() +} + func (m *BoostService) processCapellaPayload(w http.ResponseWriter, req *http.Request, log *logrus.Entry, payload *eth2ApiV1Capella.SignedBlindedBeaconBlock, body []byte) { if payload.Message == nil || payload.Message.Body == nil || payload.Message.Body.ExecutionPayloadHeader == nil { log.WithField("body", string(body)).Error("missing parts of the request payload from the beacon-node") @@ -834,3 +871,12 @@ func (m *BoostService) CheckRelays() int { wg.Wait() return int(numSuccessRequestsToRelay) } + +func (m *BoostService) isPrivilegedRelay(pubkey phase0.BLSPubKey) bool { + for _, builder := range m.privilegedBuilders { + if bytes.Equal(builder[:], pubkey[:]) { + return true + } + } + return false +} diff --git a/server/service_test.go b/server/service_test.go index 47d418aa..f8502d2e 100644 --- a/server/service_test.go +++ b/server/service_test.go @@ -72,6 +72,17 @@ func newTestBackend(t *testing.T, numRelays int, relayTimeout time.Duration) *te return &backend } +func (be *testBackend) setPrivilegedBuilders(pubKey phase0.BLSPubKey) *testBackend { + privilegedBuilders := make([]phase0.BLSPubKey, 0) + for _, relay := range be.relays { + if bytes.Equal(relay.RelayEntry.PublicKey[:], pubKey[:]) { + privilegedBuilders = append(privilegedBuilders, relay.RelayEntry.PublicKey) + } + } + be.boost.privilegedBuilders = privilegedBuilders + return be +} + func (be *testBackend) request(t *testing.T, method, path string, payload any) *httptest.ResponseRecorder { t.Helper() var req *http.Request @@ -333,7 +344,7 @@ func TestGetHeader(t *testing.T) { 12345, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionDeneb, ) backend.relays[0].GetHeaderResponse = resp @@ -348,7 +359,7 @@ func TestGetHeader(t *testing.T) { 12345, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) resp.Capella.Message.Header.BlockHash = nilHash @@ -375,7 +386,7 @@ func TestGetHeader(t *testing.T) { 12345, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -397,7 +408,7 @@ func TestGetHeader(t *testing.T) { 12345, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -469,7 +480,7 @@ func TestGetHeaderBids(t *testing.T) { 12345, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -478,7 +489,7 @@ func TestGetHeaderBids(t *testing.T) { 12347, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[1].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -487,7 +498,7 @@ func TestGetHeaderBids(t *testing.T) { 12346, "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[2].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -518,7 +529,7 @@ func TestGetHeaderBids(t *testing.T) { 12345, "0xa38385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -526,7 +537,7 @@ func TestGetHeaderBids(t *testing.T) { 12345, "0xa18385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[1].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -534,7 +545,7 @@ func TestGetHeaderBids(t *testing.T) { 12345, "0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[2].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -570,7 +581,7 @@ func TestGetHeaderBids(t *testing.T) { 12344, "0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -593,7 +604,7 @@ func TestGetHeaderBids(t *testing.T) { 12345, "0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) @@ -611,6 +622,42 @@ func TestGetHeaderBids(t *testing.T) { require.NoError(t, err) require.Equal(t, uint256.NewInt(12345), value) }) + + t.Run("Use header from a privileged relay", func(t *testing.T) { + backend := newTestBackend(t, 2, time.Second) + backend.setPrivilegedBuilders(backend.relays[0].RelayEntry.PublicKey) + + // privileged relay + backend.relays[0].GetHeaderResponse = backend.relays[0].MakeGetHeaderResponse( + 12348, + "0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", + "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", + backend.relays[0].RelayEntry.PublicKey.String(), + spec.DataVersionCapella, + ) + // non-privileged relay with higher value + backend.relays[1].GetHeaderResponse = backend.relays[1].MakeGetHeaderResponse( + 12349, + "0xa28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", + "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", + backend.relays[1].RelayEntry.PublicKey.String(), + spec.DataVersionCapella, + ) + + rr := backend.request(t, http.MethodGet, path, nil) + + require.Equal(t, 1, backend.relays[0].GetRequestCount(path)) + require.Equal(t, 1, backend.relays[1].GetRequestCount(path)) + + require.Equal(t, http.StatusOK, rr.Code, rr.Body.String()) + // Highest value should be 12348, i.e. privileged relay. + resp := new(builderSpec.VersionedSignedBuilderBid) + err := json.Unmarshal(rr.Body.Bytes(), resp) + require.NoError(t, err) + value, err := resp.Value() + require.NoError(t, err) + require.Equal(t, uint256.NewInt(12348), value) + }) } func TestGetPayload(t *testing.T) { @@ -883,7 +930,7 @@ func TestGetPayloadToAllRelays(t *testing.T) { 12345, "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", - "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", + backend.relays[0].RelayEntry.PublicKey.String(), spec.DataVersionCapella, ) rr := backend.request(t, http.MethodGet, getHeaderPath, nil) From 7afa94743da04177c0b8bd6512868c720538f9a2 Mon Sep 17 00:00:00 2001 From: sam bacha Date: Wed, 31 Jul 2024 14:05:34 -0700 Subject: [PATCH 3/3] Update tests.yml --- .github/workflows/tests.yml | 45 ++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5d69e5db..fcaea618 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,27 +5,52 @@ on: branches: - develop pull_request: + branches: + - develop jobs: test: - name: Test + name: Test on Go ${{ matrix.go-version }} runs-on: ubuntu-latest + + strategy: + matrix: + go-version: [1.20, 1.21, 1.22] + steps: + - name: Checkout sources + id: checkout + uses: actions/checkout@v3 + - name: Set up Go - uses: actions/setup-go@v3 + id: setup-go + uses: actions/setup-go@v4 with: - go-version: ^1.22 - id: go + go-version: ${{ matrix.go-version }} + + - name: Cache Go modules + id: cache + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go-${{ matrix.go-version }}- - - name: Checkout sources - uses: actions/checkout@v2 + - name: Install dependencies + id: install-dependencies + run: go mod download - name: Run unit tests and generate the coverage report - run: make test-coverage + id: test + run: go test -coverprofile=coverage-${{ matrix.go-version }}.out -json > TestResults-${{ matrix.go-version }}.json - name: Upload coverage to Codecov - uses: codecov/codecov-action@v2 + id: upload-coverage + uses: codecov/codecov-action@v3 with: - files: ./coverage.out + files: coverage-${{ matrix.go-version }}.out verbose: false - flags: unittests + flags: unittests-${{ matrix.go-version }}