Skip to content

Commit

Permalink
feat(vdb): added validator search by hex graffiti
Browse files Browse the repository at this point in the history
  • Loading branch information
remoterami committed Jan 2, 2025
1 parent 4bb9d8f commit 672d573
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 25 deletions.
11 changes: 7 additions & 4 deletions backend/pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ func TestInternalSearchHandler(t *testing.T) {
"validators_by_withdrawal_credential",
"validator_by_index",
"validator_by_public_key",
"validators_by_graffiti"
"validators_by_graffiti",
"validators_by_graffiti_hex"
]
}`)).Expect().Status(http.StatusOK).JSON().Decode(&resp)

Expand All @@ -320,7 +321,8 @@ func TestInternalSearchHandler(t *testing.T) {
"validators_by_withdrawal_credential",
"validator_by_index",
"validator_by_public_key",
"validators_by_graffiti"
"validators_by_graffiti",
"validators_by_graffiti_hex"
]
}`)).Expect().Status(http.StatusOK).JSON().Decode(&resp)

Expand All @@ -346,12 +348,13 @@ func TestInternalSearchHandler(t *testing.T) {
"validators_by_withdrawal_credential",
"validator_by_index",
"validator_by_public_key",
"validators_by_graffiti"
"validators_by_graffiti",
"validators_by_graffiti_hex"
]
}`)).Expect().Status(http.StatusOK).JSON().Decode(&resp)

assert.NotEqual(t, 0, len(resp.Data), "response data should not be empty")
validatorsByWithdrawalAddress, ok := resp.Data[0].Value.(api_types.SearchValidatorsByWithdrwalCredential)
validatorsByWithdrawalAddress, ok := resp.Data[0].Value.(api_types.SearchValidatorsByWithdrawalCredential)
assert.True(t, ok, "response data should be of type SearchValidator")
assert.Greater(t, validatorsByWithdrawalAddress.Count, uint64(0), "returned number of validators should be greater than 0")
}
Expand Down
14 changes: 9 additions & 5 deletions backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,15 +518,19 @@ func (d *DummyService) GetSearchValidatorsByDepositEnsName(ctx context.Context,
return getDummyStruct[t.SearchValidatorsByDepositAddress](ctx)
}

func (d *DummyService) GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrwalCredential, error) {
return getDummyStruct[t.SearchValidatorsByWithdrwalCredential](ctx)
func (d *DummyService) GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrawalCredential, error) {
return getDummyStruct[t.SearchValidatorsByWithdrawalCredential](ctx)
}

func (d *DummyService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrwalCredential, error) {
return getDummyStruct[t.SearchValidatorsByWithdrwalCredential](ctx)
func (d *DummyService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrawalCredential, error) {
return getDummyStruct[t.SearchValidatorsByWithdrawalCredential](ctx)
}

func (d *DummyService) GetSearchValidatorsByGraffiti(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error) {
func (d *DummyService) GetSearchValidatorsByGraffitiText(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error) {
return getDummyStruct[t.SearchValidatorsByGraffiti](ctx)
}

func (d *DummyService) GetSearchValidatorsByGraffitiHex(ctx context.Context, chainId uint64, graffiti []byte) (*t.SearchValidatorsByGraffiti, error) {
return getDummyStruct[t.SearchValidatorsByGraffiti](ctx)
}

Expand Down
33 changes: 26 additions & 7 deletions backend/pkg/api/data_access/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dataaccess

import (
"context"
"strings"

"github.com/ethereum/go-ethereum/common/hexutil"
t "github.com/gobitfly/beaconchain/pkg/api/types"
Expand All @@ -13,9 +14,10 @@ type SearchRepository interface {
GetSearchValidatorByPublicKey(ctx context.Context, chainId uint64, publicKey []byte) (*t.SearchValidator, error)
GetSearchValidatorsByDepositAddress(ctx context.Context, chainId uint64, address []byte) (*t.SearchValidatorsByDepositAddress, error)
GetSearchValidatorsByDepositEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByDepositAddress, error)
GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrwalCredential, error)
GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrwalCredential, error)
GetSearchValidatorsByGraffiti(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error)
GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrawalCredential, error)
GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrawalCredential, error)
GetSearchValidatorsByGraffitiText(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error)
GetSearchValidatorsByGraffitiHex(ctx context.Context, chainId uint64, graffiti []byte) (*t.SearchValidatorsByGraffiti, error)
}

func (d *DataAccessService) GetSearchValidatorByIndex(ctx context.Context, chainId, index uint64) (*t.SearchValidator, error) {
Expand Down Expand Up @@ -75,9 +77,9 @@ func (d *DataAccessService) GetSearchValidatorsByDepositEnsName(ctx context.Cont
return nil, ErrNotFound
}

func (d *DataAccessService) GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrwalCredential, error) {
func (d *DataAccessService) GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrawalCredential, error) {
// TODO: implement handling of chainid
ret := &t.SearchValidatorsByWithdrwalCredential{
ret := &t.SearchValidatorsByWithdrawalCredential{
WithdrawalCredential: hexutil.Encode(credential),
}
err := db.ReaderDb.GetContext(ctx, &ret.Count, "select count(validatorindex) from validators where withdrawalcredentials = $1;", credential)
Expand All @@ -90,16 +92,17 @@ func (d *DataAccessService) GetSearchValidatorsByWithdrawalCredential(ctx contex
return ret, nil
}

func (d *DataAccessService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrwalCredential, error) {
func (d *DataAccessService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrawalCredential, error) {
// TODO: implement handling of chainid
// TODO: finalize ens implementation first
return nil, ErrNotFound
}

func (d *DataAccessService) GetSearchValidatorsByGraffiti(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error) {
func (d *DataAccessService) GetSearchValidatorsByGraffitiText(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error) {
// TODO: implement handling of chainid
ret := &t.SearchValidatorsByGraffiti{
Graffiti: graffiti,
Hex: hexutil.Encode([]byte(graffiti)),
}
err := db.ReaderDb.GetContext(ctx, &ret.Count, "select count(distinct proposer) from blocks where graffiti_text = $1;", graffiti)
if err != nil {
Expand All @@ -110,3 +113,19 @@ func (d *DataAccessService) GetSearchValidatorsByGraffiti(ctx context.Context, c
}
return ret, nil
}

func (d *DataAccessService) GetSearchValidatorsByGraffitiHex(ctx context.Context, chainId uint64, graffiti []byte) (*t.SearchValidatorsByGraffiti, error) {
// TODO: implement handling of chainid
ret := &t.SearchValidatorsByGraffiti{
Graffiti: strings.TrimRight(string(graffiti), "\u0000"),
Hex: hexutil.Encode(graffiti),
}
err := db.ReaderDb.GetContext(ctx, &ret.Count, "select count(distinct proposer) from blocks where graffiti = $1;", graffiti)
if err != nil {
return nil, err
}
if ret.Count == 0 {
return nil, ErrNotFound
}
return ret, nil
}
5 changes: 3 additions & 2 deletions backend/pkg/api/handlers/input_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ var (
reEthereumAddress = regexp.MustCompile(`^(0x)?[0-9a-fA-F]{40}$`)
reWithdrawalCredential = regexp.MustCompile(`^(0x0[01])?[0-9a-fA-F]{62}$`)
reEnsName = regexp.MustCompile(`^.+\.eth$`)
reGraffiti = regexp.MustCompile(`^.{2,}$`) // at least 2 characters, so that queries won't time out
reCursor = regexp.MustCompile(`^[A-Za-z0-9-_]+$`) // has to be base64
reGraffiti = regexp.MustCompile(`^.{2,}$`) // at least 2 characters, so that queries won't time out
reGraffitiHex = regexp.MustCompile(`^(0x)?([0-9a-fA-F]{2}){2,}$`) // at least 2 bytes, so that queries won't time out
reCursor = regexp.MustCompile(`^[A-Za-z0-9-_]+$`) // has to be base64
reEmail = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
rePassword = regexp.MustCompile(`^.{5,}$`)
reEmailUserToken = regexp.MustCompile(`^[a-z0-9]{40}$`)
Expand Down
22 changes: 19 additions & 3 deletions backend/pkg/api/handlers/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
validatorsByWithdrawalAddress searchTypeKey = "validators_by_withdrawal_address"
validatorsByWithdrawalEns searchTypeKey = "validators_by_withdrawal_ens_name"
validatorsByGraffiti searchTypeKey = "validators_by_graffiti"
validatorsByGraffitiHex searchTypeKey = "validators_by_graffiti_hex"
)

// source of truth for all possible search types and their regex
Expand Down Expand Up @@ -70,6 +71,10 @@ var searchTypeMap = map[searchTypeKey]searchType{
regex: reGraffiti,
responseType: string(validatorsByGraffiti),
},
validatorsByGraffitiHex: {
regex: reGraffitiHex,
responseType: string(validatorsByGraffiti),
},
}

type searchType struct {
Expand Down Expand Up @@ -172,7 +177,9 @@ func (h *HandlerService) handleSearchType(ctx context.Context, input string, sea
case validatorsByWithdrawalEns:
return h.handleSearchValidatorsByWithdrawalEnsName(ctx, input, chainId)
case validatorsByGraffiti:
return h.handleSearchValidatorsByGraffiti(ctx, input, chainId)
return h.handleSearchValidatorsByGraffitiText(ctx, input, chainId)
case validatorsByGraffitiHex:
return h.handleSearchValidatorsByGraffitiHex(ctx, input, chainId)
default:
return nil, errors.New("invalid search type")
}
Expand Down Expand Up @@ -266,11 +273,20 @@ func (h *HandlerService) handleSearchValidatorsByWithdrawalEnsName(ctx context.C
return asSearchResult(validatorsByWithdrawalEns, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorsByGraffiti(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
result, err := h.daService.GetSearchValidatorsByGraffiti(ctx, chainId, input)
func (h *HandlerService) handleSearchValidatorsByGraffitiText(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
result, err := h.daService.GetSearchValidatorsByGraffitiText(ctx, chainId, input)
return asSearchResult(validatorsByGraffiti, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorsByGraffitiHex(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
graffitiHex, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
if err != nil {
return nil, err
}
result, err := h.daService.GetSearchValidatorsByGraffitiHex(ctx, chainId, graffitiHex)
return asSearchResult(validatorsByGraffitiHex, chainId, result, err)
}

// --------------------------------------
// Input Validation

Expand Down
5 changes: 3 additions & 2 deletions backend/pkg/api/types/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ type SearchValidatorsByDepositAddress struct {
Count uint64 `json:"count"`
}

type SearchValidatorsByWithdrwalCredential struct {
type SearchValidatorsByWithdrawalCredential struct {
EnsName string `json:"ens_name,omitempty"`
WithdrawalCredential string `json:"withdrawal_credential"`
Count uint64 `json:"count"`
}

type SearchValidatorsByGraffiti struct {
Graffiti string `json:"graffiti"`
Hex string `json:"hex"`
Count uint64 `json:"count"`
}

Expand All @@ -35,5 +36,5 @@ type SearchResult struct {
}

type InternalPostSearchResponse struct {
Data []SearchResult `json:"data" tstype:"({ type: 'validator'; chain_id: number; value: SearchValidator } | { type: 'validator_list'; chain_id: number; value: SearchValidatorList } | { type: 'validators_by_deposit_address'; chain_id: number; value: SearchValidatorsByDepositAddress } | { type: 'validators_by_withdrawal_credential'; chain_id: number; value: SearchValidatorsByWithdrwalCredential } | { type: 'validators_by_graffiti'; chain_id: number; value: SearchValidatorsByGraffiti })[]"`
Data []SearchResult `json:"data" tstype:"({ type: 'validator'; chain_id: number; value: SearchValidator } | { type: 'validator_list'; chain_id: number; value: SearchValidatorList } | { type: 'validators_by_deposit_address'; chain_id: number; value: SearchValidatorsByDepositAddress } | { type: 'validators_by_withdrawal_credential'; chain_id: number; value: SearchValidatorsByWithdrawalCredential } | { type: 'validators_by_graffiti'; chain_id: number; value: SearchValidatorsByGraffiti })[]"`
}
5 changes: 3 additions & 2 deletions frontend/types/api/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ export interface SearchValidatorsByDepositAddress {
deposit_address: string;
count: number /* uint64 */;
}
export interface SearchValidatorsByWithdrwalCredential {
export interface SearchValidatorsByWithdrawalCredential {
ens_name?: string;
withdrawal_credential: string;
count: number /* uint64 */;
}
export interface SearchValidatorsByGraffiti {
graffiti: string;
hex: string;
count: number /* uint64 */;
}
export interface SearchResult {
Expand All @@ -31,5 +32,5 @@ export interface SearchResult {
value: any;
}
export interface InternalPostSearchResponse {
data: ({ type: 'validator'; chain_id: number; value: SearchValidator } | { type: 'validator_list'; chain_id: number; value: SearchValidatorList } | { type: 'validators_by_deposit_address'; chain_id: number; value: SearchValidatorsByDepositAddress } | { type: 'validators_by_withdrawal_credential'; chain_id: number; value: SearchValidatorsByWithdrwalCredential } | { type: 'validators_by_graffiti'; chain_id: number; value: SearchValidatorsByGraffiti })[];
data: ({ type: 'validator'; chain_id: number; value: SearchValidator } | { type: 'validator_list'; chain_id: number; value: SearchValidatorList } | { type: 'validators_by_deposit_address'; chain_id: number; value: SearchValidatorsByDepositAddress } | { type: 'validators_by_withdrawal_credential'; chain_id: number; value: SearchValidatorsByWithdrawalCredential } | { type: 'validators_by_graffiti'; chain_id: number; value: SearchValidatorsByGraffiti })[];
}

0 comments on commit 672d573

Please sign in to comment.