Skip to content

Commit

Permalink
refactor: better search result types
Browse files Browse the repository at this point in the history
See: BEDS-934
  • Loading branch information
LuccaBitfly committed Nov 12, 2024
1 parent 1dec2d3 commit 25dc471
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 157 deletions.
15 changes: 9 additions & 6 deletions backend/pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ func TestInternalSearchHandler(t *testing.T) {
}`)).Expect().Status(http.StatusOK).JSON().Decode(&resp)

assert.NotEqual(t, 0, len(resp.Data), "response data should not be empty")
assert.NotNil(t, resp.Data[0].NumValue, "validator index should not be nil")
assert.Equal(t, uint64(5), *resp.Data[0].NumValue, "validator index should be 5")
validatorByIndex, ok := resp.Data[0].Value.(api_types.SearchValidator)
assert.True(t, ok, "response data should be of type SearchValidator")
assert.Equal(t, uint64(5), validatorByIndex.Index, "validator index should be 5")

// search for validator by pubkey
resp = api_types.InternalPostSearchResponse{}
Expand All @@ -324,8 +325,9 @@ func TestInternalSearchHandler(t *testing.T) {
}`)).Expect().Status(http.StatusOK).JSON().Decode(&resp)

assert.NotEqual(t, 0, len(resp.Data), "response data should not be empty")
assert.NotNil(t, resp.Data[0].NumValue, "validator index should not be nil")
assert.Equal(t, uint64(5), *resp.Data[0].NumValue, "validator index should be 5")
validatorByPublicKey, ok := resp.Data[0].Value.(api_types.SearchValidator)
assert.True(t, ok, "response data should be of type SearchValidator")
assert.Equal(t, uint64(5), validatorByPublicKey.Index, "validator index should be 5")

// search for validator by withdawal address
resp = api_types.InternalPostSearchResponse{}
Expand All @@ -349,8 +351,9 @@ func TestInternalSearchHandler(t *testing.T) {
}`)).Expect().Status(http.StatusOK).JSON().Decode(&resp)

assert.NotEqual(t, 0, len(resp.Data), "response data should not be empty")
assert.NotNil(t, resp.Data[0].NumValue, "validator index should not be nil")
assert.Greater(t, *resp.Data[0].NumValue, uint64(0), "returned number of validators should be greater than 0")
validatorsByWithdrawalAddress, ok := resp.Data[0].Value.(api_types.SearchValidatorsByWithdrwalCredential)
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")
}

func TestPublicAndSharedDashboards(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,16 +514,16 @@ func (d *DummyService) GetSearchValidatorsByDepositAddress(ctx context.Context,
return getDummyStruct[t.SearchValidatorsByDepositAddress](ctx)
}

func (d *DummyService) GetSearchValidatorsByDepositEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByDepositEnsName, error) {
return getDummyStruct[t.SearchValidatorsByDepositEnsName](ctx)
func (d *DummyService) GetSearchValidatorsByDepositEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByDepositAddress, error) {
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) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithrawalEnsName, error) {
return getDummyStruct[t.SearchValidatorsByWithrawalEnsName](ctx)
func (d *DummyService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrwalCredential, error) {
return getDummyStruct[t.SearchValidatorsByWithdrwalCredential](ctx)
}

func (d *DummyService) GetSearchValidatorsByGraffiti(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error) {
Expand Down
19 changes: 10 additions & 9 deletions backend/pkg/api/data_access/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ type SearchRepository interface {
GetSearchValidatorByIndex(ctx context.Context, chainId, index uint64) (*t.SearchValidator, error)
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.SearchValidatorsByDepositEnsName, 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.SearchValidatorsByWithrawalEnsName, error)
GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrwalCredential, error)
GetSearchValidatorsByGraffiti(ctx context.Context, chainId uint64, graffiti string) (*t.SearchValidatorsByGraffiti, error)
}

Expand All @@ -28,7 +28,7 @@ func (d *DataAccessService) GetSearchValidatorByIndex(ctx context.Context, chain
if int(index) < len(validatorMapping.ValidatorPubkeys) {
return &t.SearchValidator{
Index: index,
PublicKey: hexutil.MustDecode(validatorMapping.ValidatorPubkeys[index]),
PublicKey: validatorMapping.ValidatorPubkeys[index],
}, nil
}

Expand All @@ -46,7 +46,7 @@ func (d *DataAccessService) GetSearchValidatorByPublicKey(ctx context.Context, c
if index, found := validatorMapping.ValidatorIndices[b]; found {
return &t.SearchValidator{
Index: index,
PublicKey: publicKey,
PublicKey: b,
}, nil
}

Expand All @@ -56,9 +56,10 @@ func (d *DataAccessService) GetSearchValidatorByPublicKey(ctx context.Context, c
func (d *DataAccessService) GetSearchValidatorsByDepositAddress(ctx context.Context, chainId uint64, address []byte) (*t.SearchValidatorsByDepositAddress, error) {
// TODO: implement handling of chainid
ret := &t.SearchValidatorsByDepositAddress{
Address: address,
Address: hexutil.Encode(address),
}
err := db.ReaderDb.GetContext(ctx, &ret.Count, "select count(validatorindex) from validators where pubkey in (select publickey from eth1_deposits where from_address = $1);", address)
err := db.ReaderDb.GetContext(ctx, &ret.Count, `
select count(validatorindex) from validators where pubkey in (select publickey from eth1_deposits where from_address = $1);`, address)
if err != nil {
return nil, err
}
Expand All @@ -68,7 +69,7 @@ func (d *DataAccessService) GetSearchValidatorsByDepositAddress(ctx context.Cont
return ret, nil
}

func (d *DataAccessService) GetSearchValidatorsByDepositEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByDepositEnsName, error) {
func (d *DataAccessService) GetSearchValidatorsByDepositEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByDepositAddress, error) {
// TODO: implement handling of chainid
// TODO: finalize ens implementation first
return nil, ErrNotFound
Expand All @@ -77,7 +78,7 @@ func (d *DataAccessService) GetSearchValidatorsByDepositEnsName(ctx context.Cont
func (d *DataAccessService) GetSearchValidatorsByWithdrawalCredential(ctx context.Context, chainId uint64, credential []byte) (*t.SearchValidatorsByWithdrwalCredential, error) {
// TODO: implement handling of chainid
ret := &t.SearchValidatorsByWithdrwalCredential{
WithdrawalCredential: credential,
WithdrawalCredential: hexutil.Encode(credential),
}
err := db.ReaderDb.GetContext(ctx, &ret.Count, "select count(validatorindex) from validators where withdrawalcredentials = $1;", credential)
if err != nil {
Expand All @@ -89,7 +90,7 @@ func (d *DataAccessService) GetSearchValidatorsByWithdrawalCredential(ctx contex
return ret, nil
}

func (d *DataAccessService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithrawalEnsName, error) {
func (d *DataAccessService) GetSearchValidatorsByWithdrawalEnsName(ctx context.Context, chainId uint64, ensName string) (*t.SearchValidatorsByWithdrwalCredential, error) {
// TODO: implement handling of chainid
// TODO: finalize ens implementation first
return nil, ErrNotFound
Expand Down
171 changes: 68 additions & 103 deletions backend/pkg/api/handlers/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,48 @@ const (
)

// source of truth for all possible search types and their regex
var searchTypeToRegex = map[searchTypeKey]*regexp.Regexp{
validatorByIndex: reInteger,
validatorByPublicKey: reValidatorPublicKey,
validatorList: reValidatorList,
validatorsByDepositAddress: reEthereumAddress,
validatorsByDepositEnsName: reEnsName,
validatorsByWithdrawalCredential: reWithdrawalCredential,
validatorsByWithdrawalAddress: reEthereumAddress,
validatorsByWithdrawalEns: reEnsName,
validatorsByGraffiti: reGraffiti,
var searchTypeMap = map[searchTypeKey]searchType{
validatorByIndex: {
regex: reInteger,
responseType: "validator",
},
validatorByPublicKey: {
regex: reValidatorPublicKey,
responseType: "validator",
},
validatorList: {
regex: reValidatorList,
responseType: string(validatorList),
},
validatorsByDepositAddress: {
regex: reEthereumAddress,
responseType: string(validatorsByDepositAddress),
},
validatorsByDepositEnsName: {
regex: reEnsName,
responseType: string(validatorsByDepositAddress),
},
validatorsByWithdrawalCredential: {
regex: reWithdrawalCredential,
responseType: string(validatorsByWithdrawalCredential),
},
validatorsByWithdrawalAddress: {
regex: reEthereumAddress,
responseType: string(validatorsByWithdrawalCredential),
},
validatorsByWithdrawalEns: {
regex: reEnsName,
responseType: string(validatorsByWithdrawalCredential),
},
validatorsByGraffiti: {
regex: reGraffiti,
responseType: string(validatorsByGraffiti),
},
}

type searchType struct {
regex *regexp.Regexp
responseType string
}

// --------------------------------------
Expand Down Expand Up @@ -74,7 +106,7 @@ func (h *HandlerService) InternalPostSearch(w http.ResponseWriter, r *http.Reque
// iterate over all combinations of search types and networks
for _, searchType := range searchTypeSet {
// check if input matches the regex for the search type
if !searchTypeToRegex[searchType].MatchString(req.Input) {
if !searchTypeMap[searchType].regex.MatchString(req.Input) {
continue
}
for _, chainId := range chainIdSet {
Expand Down Expand Up @@ -146,23 +178,25 @@ func (h *HandlerService) handleSearchType(ctx context.Context, input string, sea
}
}

func asSearchResult[In any](searchType searchTypeKey, chainId uint64, result *In, err error) (*types.SearchResult, error) {
if err != nil || result == nil {
return nil, err
}
return &types.SearchResult{
Type: searchTypeMap[searchType].responseType,
ChainId: chainId,
Value: result,
}, nil
}

func (h *HandlerService) handleSearchValidatorByIndex(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
index, err := strconv.ParseUint(input, 10, 64)
if err != nil {
// input should've been checked by the regex before, this should never happen
return nil, err
}
result, err := h.daService.GetSearchValidatorByIndex(ctx, chainId, index)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorByIndex),
ChainId: chainId,
HashValue: "0x" + hex.EncodeToString(result.PublicKey),
NumValue: &result.Index,
}, nil
return asSearchResult(validatorByIndex, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorByPublicKey(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
Expand All @@ -172,16 +206,7 @@ func (h *HandlerService) handleSearchValidatorByPublicKey(ctx context.Context, i
return nil, err
}
result, err := h.daService.GetSearchValidatorByPublicKey(ctx, chainId, publicKey)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorByPublicKey),
ChainId: chainId,
HashValue: "0x" + hex.EncodeToString(result.PublicKey),
NumValue: &result.Index,
}, nil
return asSearchResult(validatorByPublicKey, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorList(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
Expand All @@ -192,18 +217,14 @@ func (h *HandlerService) handleSearchValidatorList(ctx context.Context, input st
return nil, nil // return no error as to not disturb the other search types
}
validators, err := h.daService.GetValidatorsFromSlices(ctx, indices, pubkeys)
if err != nil {
if err != nil || validators == nil || len(validators) == 0 {
return nil, err
}
if len(validators) == 0 {
return nil, nil
}

var resultLength uint64 = uint64(len(validators))
return &types.SearchResult{
Type: string(validatorList),
ChainId: chainId,
NumValue: &resultLength,
Type: searchTypeMap[validatorList].responseType,
ChainId: chainId,
Value: types.SearchValidatorList{Validators: validators},
}, nil
}

Expand All @@ -213,31 +234,12 @@ func (h *HandlerService) handleSearchValidatorsByDepositAddress(ctx context.Cont
return nil, err
}
result, err := h.daService.GetSearchValidatorsByDepositAddress(ctx, chainId, address)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorsByDepositAddress),
ChainId: chainId,
HashValue: "0x" + hex.EncodeToString(result.Address),
NumValue: &result.Count,
}, nil
return asSearchResult(validatorsByDepositAddress, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorsByDepositEnsName(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
result, err := h.daService.GetSearchValidatorsByDepositEnsName(ctx, chainId, input)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorsByDepositEnsName),
ChainId: chainId,
StrValue: result.EnsName,
HashValue: "0x" + hex.EncodeToString(result.Address),
NumValue: &result.Count,
}, nil
return asSearchResult(validatorsByDepositEnsName, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorsByWithdrawalCredential(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
Expand All @@ -246,16 +248,7 @@ func (h *HandlerService) handleSearchValidatorsByWithdrawalCredential(ctx contex
return nil, err
}
result, err := h.daService.GetSearchValidatorsByWithdrawalCredential(ctx, chainId, withdrawalCredential)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorsByWithdrawalCredential),
ChainId: chainId,
HashValue: "0x" + hex.EncodeToString(result.WithdrawalCredential),
NumValue: &result.Count,
}, nil
return asSearchResult(validatorsByWithdrawalCredential, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorsByWithdrawalAddress(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
Expand All @@ -265,45 +258,17 @@ func (h *HandlerService) handleSearchValidatorsByWithdrawalAddress(ctx context.C
return nil, err
}
result, err := h.daService.GetSearchValidatorsByWithdrawalCredential(ctx, chainId, withdrawalCredential)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorsByWithdrawalAddress),
ChainId: chainId,
HashValue: "0x" + hex.EncodeToString(result.WithdrawalCredential),
NumValue: &result.Count,
}, nil
return asSearchResult(validatorsByWithdrawalAddress, chainId, result, err)
}

func (h *HandlerService) handleSearchValidatorsByWithdrawalEnsName(ctx context.Context, input string, chainId uint64) (*types.SearchResult, error) {
result, err := h.daService.GetSearchValidatorsByWithdrawalEnsName(ctx, chainId, input)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorsByWithdrawalEns),
ChainId: chainId,
StrValue: result.EnsName,
HashValue: "0x" + hex.EncodeToString(result.Address),
NumValue: &result.Count,
}, nil
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)
if err != nil {
return nil, err
}

return &types.SearchResult{
Type: string(validatorsByGraffiti),
ChainId: chainId,
StrValue: result.Graffiti,
NumValue: &result.Count,
}, nil
return asSearchResult(validatorsByGraffiti, chainId, result, err)
}

// --------------------------------------
Expand Down Expand Up @@ -336,14 +301,14 @@ func (v *validationError) checkSearchTypes(types []searchTypeKey) []searchTypeKe
typeSet := map[searchTypeKey]struct{}{}
// if the list is empty, query all types
if len(types) == 0 {
for t := range searchTypeToRegex {
for t := range searchTypeMap {
typeSet[t] = struct{}{}
}
return slices.Collect(maps.Keys(typeSet))
}
// list not empty, check if types are valid
for _, t := range types {
if _, typeExists := searchTypeToRegex[t]; !typeExists {
if _, typeExists := searchTypeMap[t]; !typeExists {
v.add("types", fmt.Sprintf("invalid search type '%s'", t))
continue
}
Expand Down
Loading

0 comments on commit 25dc471

Please sign in to comment.