Skip to content

Commit

Permalink
feat: stores validator opted in status in proposer duties map (#4)
Browse files Browse the repository at this point in the history
* feat: stores validator opted in status in proposer duties map

* feat: clean up mevcommit validator redis keys

* feat: verifies correct encoding

* chore: ensures we trim prefix to adhere to contract format

* feat: also removes redundant builder cleanup
  • Loading branch information
ckartik authored Oct 16, 2024
1 parent 0354237 commit b9dcb96
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 197 deletions.
7 changes: 4 additions & 3 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,10 @@ func (p PubkeyHex) String() string {
}

type BuilderGetValidatorsResponseEntry struct {
Slot uint64 `json:"slot,string"`
ValidatorIndex uint64 `json:"validator_index,string"`
Entry *builderApiV1.SignedValidatorRegistration `json:"entry"`
Slot uint64 `json:"slot,string"`
ValidatorIndex uint64 `json:"validator_index,string"`
Entry *builderApiV1.SignedValidatorRegistration `json:"entry"`
IsMevCommitValidator bool `json:"is_mev_commit"`
}

type BidTraceV2 struct {
Expand Down
47 changes: 6 additions & 41 deletions datastore/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/flashbots/mev-boost-relay/common"
"github.com/flashbots/mev-boost-relay/database"
"github.com/go-redis/redis/v9"
lru "github.com/hashicorp/golang-lru"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
uberatomic "go.uber.org/atomic"
Expand All @@ -41,8 +40,6 @@ type Datastore struct {
memcached *Memcached
db database.IDatabaseService

isMevCommitValidatorRegistered *lru.Cache

knownValidatorsByPubkey map[common.PubkeyHex]uint64
knownValidatorsByIndex map[uint64]common.PubkeyHex
knownValidatorsLock sync.RWMutex
Expand All @@ -54,17 +51,13 @@ type Datastore struct {
}

func NewDatastore(redisCache *RedisCache, memcached *Memcached, db database.IDatabaseService) (ds *Datastore, err error) {
mevCommitValidatorRegistrationCache, err := lru.New(5)
if err != nil {
return nil, err
}

ds = &Datastore{
db: db,
memcached: memcached,
redis: redisCache,
knownValidatorsByPubkey: make(map[common.PubkeyHex]uint64),
knownValidatorsByIndex: make(map[uint64]common.PubkeyHex),
isMevCommitValidatorRegistered: mevCommitValidatorRegistrationCache,
db: db,
memcached: memcached,
redis: redisCache,
knownValidatorsByPubkey: make(map[common.PubkeyHex]uint64),
knownValidatorsByIndex: make(map[uint64]common.PubkeyHex),
}

return ds, err
Expand Down Expand Up @@ -192,34 +185,6 @@ func (ds *Datastore) SetKnownValidator(pubkeyHex common.PubkeyHex, index uint64)
ds.knownValidatorsByIndex[index] = pubkeyHex
}

// SaveMevCommitValidatorRegistration saves a validator registration for mev-commit into Redis
func (ds *Datastore) SaveMevCommitValidatorRegistration(pubkeyHex common.PubkeyHex) error {
err := ds.redis.SetMevCommitValidatorRegistration(pubkeyHex)
if err != nil {
return errors.Wrap(err, "failed saving mev-commit validator registration to redis")
}
return nil
}

// IsMevCommitValidatorRegistered checks if a validator is registered for mev-commit
func (ds *Datastore) IsMevCommitValidatorRegistered(pubkeyHex common.PubkeyHex) (bool, error) {
// Check the LRU cache first
if registered, ok := ds.isMevCommitValidatorRegistered.Get(pubkeyHex); ok {
return registered.(bool), nil
}

// If not in cache, check Redis
registered, err := ds.redis.IsMevCommitValidatorRegistered(pubkeyHex)
if err != nil {
return false, err
}

// Update the LRU cache with the result
ds.isMevCommitValidatorRegistered.Add(pubkeyHex, registered)

return registered, nil
}

// IsMevCommitBlockBuilder checks if a builder is registered for mev-commit
func (ds *Datastore) IsMevCommitBlockBuilder(builderPubkey common.PubkeyHex) (bool, error) {
return ds.redis.IsMevCommitBlockBuilder(builderPubkey)
Expand Down
35 changes: 0 additions & 35 deletions datastore/datastore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,38 +73,3 @@ func TestGetPayloadDatabaseFallback(t *testing.T) {
})
}
}

func TestMevCommitValidatorRegistration(t *testing.T) {
mockDB := &database.MockDB{}
ds := setupTestDatastore(t, mockDB)
pubkeys := []common.PubkeyHex{
common.NewPubkeyHex("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"),
common.NewPubkeyHex("0x2345678901abcdef2345678901abcdef2345678901abcdef2345678901abcdef"),
common.NewPubkeyHex("0x3456789012abcdef3456789012abcdef3456789012abcdef3456789012abcdef"),
common.NewPubkeyHex("0x4567890123abcdef4567890123abcdef4567890123abcdef4567890123abcdef"),
common.NewPubkeyHex("0x5678901234abcdef5678901234abcdef5678901234abcdef5678901234abcdef"),
common.NewPubkeyHex("0x6789012345abcdef6789012345abcdef6789012345abcdef6789012345abcdef"),
}

isRegistered, _ := ds.IsMevCommitValidatorRegistered(pubkeys[0])
require.False(t, isRegistered)

// Test saving a validator registration
err := ds.SaveMevCommitValidatorRegistration(pubkeys[0])
require.NoError(t, err)

isRegistered, err = ds.IsMevCommitValidatorRegistered(pubkeys[0])
require.NoError(t, err)
// Stale check should fail since we recently cached the value
require.False(t, isRegistered)

// Add all pubkeys to the cache - this will evict the stale value
for _, pubkey := range pubkeys {
ds.isMevCommitValidatorRegistered.Add(pubkey.String(), true)
}

// Make sure it's coming from recently cached value
isRegistered, err = ds.IsMevCommitValidatorRegistered(pubkeys[0])
require.NoError(t, err)
require.True(t, isRegistered)
}
35 changes: 6 additions & 29 deletions datastore/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ var (
redisScheme = "redis://"
redisPrefix = "boost-relay"

mevCommitValidatorRegistrationExpiry = 1 * time.Hour
expiryBidCache = 45 * time.Second
expiryBidCache = 45 * time.Second

RedisConfigFieldPubkey = "pubkey"
RedisStatsFieldLatestSlot = "latest-slot"
Expand Down Expand Up @@ -96,9 +95,8 @@ type RedisCache struct {
prefixFloorBidValue string

// keys
keyValidatorRegistrationTimestamp string
keyMevCommitValidatorRegistrationHash string
keyMevCommitBlockBuilder string
keyValidatorRegistrationTimestamp string
keyMevCommitBlockBuilder string

keyRelayConfig string
keyStats string
Expand Down Expand Up @@ -138,10 +136,9 @@ func NewRedisCache(prefix, redisURI, readonlyURI string) (*RedisCache, error) {
prefixFloorBid: fmt.Sprintf("%s/%s:bid-floor", redisPrefix, prefix), // prefix:slot_parentHash_proposerPubkey
prefixFloorBidValue: fmt.Sprintf("%s/%s:bid-floor-value", redisPrefix, prefix), // prefix:slot_parentHash_proposerPubkey

keyValidatorRegistrationTimestamp: fmt.Sprintf("%s/%s:validator-registration-timestamp", redisPrefix, prefix),
keyMevCommitValidatorRegistrationHash: fmt.Sprintf("%s/%s:mev-commit-validator-registration", redisPrefix, prefix),
keyMevCommitBlockBuilder: fmt.Sprintf("%s/%s:mev-commit-block-builder", redisPrefix, prefix),
keyRelayConfig: fmt.Sprintf("%s/%s:relay-config", redisPrefix, prefix),
keyValidatorRegistrationTimestamp: fmt.Sprintf("%s/%s:validator-registration-timestamp", redisPrefix, prefix),
keyMevCommitBlockBuilder: fmt.Sprintf("%s/%s:mev-commit-block-builder", redisPrefix, prefix),
keyRelayConfig: fmt.Sprintf("%s/%s:relay-config", redisPrefix, prefix),

keyStats: fmt.Sprintf("%s/%s:stats", redisPrefix, prefix),
keyProposerDuties: fmt.Sprintf("%s/%s:proposer-duties", redisPrefix, prefix),
Expand Down Expand Up @@ -303,26 +300,6 @@ func (r *RedisCache) DeleteMevCommitBlockBuilder(builderPubkey common.PubkeyHex)
return r.client.HDel(ctx, r.keyMevCommitBlockBuilder, builderPubkey.String()).Err()
}

func (r *RedisCache) SetMevCommitValidatorRegistration(proposerPubkey common.PubkeyHex) error {
err := r.client.Set(context.Background(), r.keyMevCommitValidatorRegistrationHash+":"+proposerPubkey.String(), "1", mevCommitValidatorRegistrationExpiry).Err()
if err != nil {
return fmt.Errorf("failed to add validator to mev-commit registration: %w", err)
}
return nil
}

func (r *RedisCache) IsMevCommitValidatorRegistered(proposerPubkey common.PubkeyHex) (bool, error) {
_, err := r.client.Get(context.Background(), r.keyMevCommitValidatorRegistrationHash+":"+proposerPubkey.String()).Result()
if err == redis.Nil {
return false, nil
}
if err != nil {
return false, fmt.Errorf("failed to check mev-commit validator registration: %w", err)
}

return true, nil
}

func (r *RedisCache) SetValidatorRegistrationTimestampIfNewer(proposerPubkey common.PubkeyHex, timestamp uint64) error {
knownTimestamp, err := r.GetValidatorRegistrationTimestamp(proposerPubkey)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions datastore/redis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func TestRedisProposerDuties(t *testing.T) {
Pubkey: phase0.BLSPubKey{},
},
},
IsMevCommitValidator: true,
},
}
err := cache.SetProposerDuties(duties)
Expand All @@ -113,6 +114,9 @@ func TestRedisProposerDuties(t *testing.T) {

require.Len(t, duties2, 1)
require.Equal(t, duties[0].Entry.Message.FeeRecipient, duties2[0].Entry.Message.FeeRecipient)
require.Equal(t, duties[0].IsMevCommitValidator, duties2[0].IsMevCommitValidator)
require.Equal(t, duties[0].IsMevCommitValidator, true)

}

func TestBuilderBids(t *testing.T) {
Expand Down
10 changes: 7 additions & 3 deletions mevcommitclient/mev_commit_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type MevCommitProvider struct {
}

type IMevCommitClient interface {
GetOptInStatusForValidators(pubkeys [][]byte) ([]bool, error)
GetOptInStatusForValidators(pubkeys []string) ([]bool, error)
ListenForBuildersEvents() (<-chan MevCommitProvider, <-chan common.Address, error)
IsBuilderValid(builderAddress common.Address) (bool, error)
}
Expand Down Expand Up @@ -90,7 +90,7 @@ func NewMevCommitClient(l1MainnetURL, mevCommitURL string, validatorRouterAddres
}, nil
}

func (m *MevCommitClient) GetOptInStatusForValidators(pubkeys [][]byte) ([]bool, error) {
func (m *MevCommitClient) GetOptInStatusForValidators(pubkeys []string) ([]bool, error) {
// Get the finalized block number
currentBlockNumber, err := m.l1Client.BlockNumber(context.Background())
if err != nil {
Expand All @@ -100,8 +100,12 @@ func (m *MevCommitClient) GetOptInStatusForValidators(pubkeys [][]byte) ([]bool,
opts := &bind.CallOpts{
BlockNumber: big.NewInt(int64(currentBlockNumber - 64)),
}
pubkeysBytes := make([][]byte, len(pubkeys))
for i, pubkey := range pubkeys {
pubkeysBytes[i] = common.Hex2Bytes(strings.TrimPrefix(pubkey, "0x"))
}

return m.validatorOptInRouterCaller.AreValidatorsOptedIn(opts, pubkeys)
return m.validatorOptInRouterCaller.AreValidatorsOptedIn(opts, pubkeysBytes)
}

func (m *MevCommitClient) ListenForBuildersEvents() (<-chan MevCommitProvider, <-chan common.Address, error) {
Expand Down
31 changes: 27 additions & 4 deletions mevcommitclient/mev_commit_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,10 @@ func TestGetOptInStatusForValidators(t *testing.T) {
common.HexToAddress(providerRegistryAddr),
)
require.NoError(t, err)

// Test with some sample public keys
pubkeys := [][]byte{
{0x01, 0x02, 0x03},
{0x04, 0x05, 0x06},
pubkeys := []string{
"010203",
"040506",
}

statuses, err := client.GetOptInStatusForValidators(pubkeys)
Expand Down Expand Up @@ -85,3 +84,27 @@ func TestListenForBuildersEvents(t *testing.T) {
time.Sleep(15 * time.Second)

}

func TestGetOptInStatusForSpecificValidator(t *testing.T) {
client, err := NewMevCommitClient(
ethereumL1RPC,
mevCommitRPC,
common.HexToAddress(validatorOptInRouterAddr),
common.HexToAddress(providerRegistryAddr),
)
require.NoError(t, err)

// Specific validator public key we know is opted in
pubkey := "0xa7884bb9b06b912ec80d14e408cd88282f813547082b7a86bc1dd9c1881e29a781314f1f9108d6059a7ec10852e14028"
statuses, err := client.GetOptInStatusForValidators([]string{pubkey})
require.NoError(t, err)
require.Len(t, statuses, 1)
assert.True(t, statuses[0], "Expected opt-in status to be true")

pubkeyWithoutPrefix := "a7884bb9b06b912ec80d14e408cd88282f813547082b7a86bc1dd9c1881e29a781314f1f9108d6059a7ec10852e14028"
statuses, err = client.GetOptInStatusForValidators([]string{pubkeyWithoutPrefix})
require.NoError(t, err)
require.Len(t, statuses, 1)
assert.True(t, statuses[0], "Expected opt-in status to be true")

}
9 changes: 1 addition & 8 deletions services/api/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1749,14 +1749,7 @@ func (api *RelayAPI) checkSubmissionSlotDetails(w http.ResponseWriter, log *logr
return false
}

isValidatorRegistered, err := api.datastore.IsMevCommitValidatorRegistered(common.NewPubkeyHex(duty.Entry.Message.Pubkey.String()))
if err != nil {
log.WithError(err).Error("Failed to check validator registration")
api.RespondError(w, http.StatusInternalServerError, "Internal server error")
return false
}

if isValidatorRegistered {
if duty.IsMevCommitValidator {
isBuilderRegistered, err := api.datastore.IsMevCommitBlockBuilder(common.NewPubkeyHex(submission.BidTrace.BuilderPubkey.String()))
if err != nil {
log.WithError(err).Error("Failed to check builder registration")
Expand Down
Loading

0 comments on commit b9dcb96

Please sign in to comment.