Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(BEDS-848) Move search and cursor parameter validation to API #1014

Open
wants to merge 11 commits into
base: staging
Choose a base branch
from

Conversation

remoterami
Copy link
Contributor

No description provided.

Comment on lines 180 to 186
func (s VDBBlocksSearches) GetSearches() []SearchType {
return []SearchType{
Integer,
ValidatorPublicKeyWithPrefix,
Name,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed, we don't really need to provide a list of search types if we always check against every search type and just ignore them in SetSearchType

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's optional now

@@ -170,6 +170,35 @@ var VDBBlocksColumns = struct {
VDBBlockProposerReward,
}

type VDBBlocksSearches struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know if these structs fit in the enum package. But also don't know where else they'd fit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it to types, I think that's slightly better, ptal

@@ -416,6 +435,17 @@ func checkSort[T enums.EnumFactory[T]](v *validationError, sortString string) *t
return &types.Sort[T]{Column: sortCol, Desc: desc}
}

func checkSearch[T enums.Searchable](searchString string) (T, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This func should prob never return an error, in worst case the returning searchable should be empty

Copy link
Contributor Author

@remoterami remoterami Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's returning a bool now to indicate an invalid search (if false), aka the search query didn't match the rules for this search. This includes accepted pattern matching but it may also check extra conditions. E.g. if the aggregateGroups flag is set, the group search is not applied even if the regex would otherwise match. See the three current examples, e.g. https://github.com/gobitfly/beaconchain/pull/1014/files#diff-eeb9062bd8258c1d32e584699f9dc786ad81df60981ec50fbc17b3c8962d7581R666-R669

Motivation for this approach was to allow early-outing with empty responses on the api layer already if possible, before even invoking data access at all.

Comment on lines 23 to 38
Name SearchType = iota // default
Integer
EthereumAddress
WithdrawalCredential
EnsName
NonEmpty
Graffiti
Cursor
Email
Password
EmailUserToken
JsonContentType
// Validator Dashboard
ValidatorDashboardPublicId
ValidatorPublicKeyWithPrefix
ValidatorPublicKey
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since const namespace is package-scoped, pls prefix these enums with SearchType..., like with the other enums.

Copy link

cloudflare-workers-and-pages bot commented Oct 23, 2024

Deploying beaconchain with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2acc450
Status: ✅  Deploy successful!
Preview URL: https://bc262cc5.beaconchain.pages.dev
Branch Preview URL: https://beds-848-move-search-cursor.beaconchain.pages.dev

View logs

@remoterami remoterami force-pushed the BEDS-848/move-search-cursor-validation branch from cd7032b to 6a12467 Compare November 1, 2024 12:55
@@ -267,6 +267,10 @@ func writeResponse(w http.ResponseWriter, r *http.Request, statusCode int, respo
}
}

func emptyPagingResponse() interface{} {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func emptyPagingResponse() interface{} {
func emptyPagingResponse() types.ApiPagingResponse[any] {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better if we seperate the types here. Cursors should probably go in their own cursor.go, and searches should also probably get their own. We prob have to find some good naming to differentiate between the search endpoint and the search filters on tables.

data, paging, err := h.getDataAccessor(r).GetValidatorDashboardValidators(r.Context(), *dashboardId, groupId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
search := &types.VDBManageValidatorsSearch{DashboardId: *dashboardId}
if !checkSearch(search, pagingParams.search) {
returnOk(w, r, emptyPagingResponse())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs a return statement after this (also for all other checkSearch calls)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should maybe also discuss with team whether we want to early return, ignore, or return error (if you did and this was the conclusion please lmk)

type SearchNumber baseSearchResult[uint64]
type SearchString baseSearchResult[string]

func (bs *basicSearch) AsNumber(st SearchType) SearchNumber {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get why this needs to have a SearchType argument, feels like it unnecessarily complicates the API of using searchtypes.

Copy link
Contributor Author

@remoterami remoterami Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was meant to enable increased but unified flexibility in case that different types should be returned in different formats, e.g. to scale ETH -> wei values or something. Atm I also can't think of many examples (removing/adding an optional 0x prefix could be one though), so it's true that this looks like unneeded overhead, didn't think it's a big issue as this is encapsulated away from every-day data access workflow. But I'll disable it for now until a real usecase comes up

case SearchTypeInteger:
number, err := strconv.ParseUint(bs.value, 10, 64)
if err != nil {
log.Error(err, "error converting search value, check regex parsing", 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should definitely return the error and not just log it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to explicitly design the entire validation process in a way that api handles errors early so that data access doesn't have to deal with catching anymore at the point of using the result, as this is kind of the point of everything and greatly improves readability. Converting the raw string result to the expected format should happen earlier though, I'll try to revert back to using struct fields instead of methods

return SearchNumber{}
}

func (bs *basicSearch) AsString(st SearchType) SearchString {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I think the SearchTypes arg makes this more complicated than necessary. I think in practice the data access func would rather just want to have a .GetValue() and format the value itself rather than have something funky happening hidden behind a AsString(). If it turns out we want to reuse formatting logic, it should happen in another func IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I've removed these methods and gone a step in that direction, ptal. Wouldn't remove the conversion entirely as doing it separately requires error handling in data access which would be a form of input validation.


data, paging, err := h.getDataAccessor(r).GetValidatorDashboardSummary(r.Context(), *dashboardId, period, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit, protocolModes)
data, paging, err := h.getDataAccessor(r).GetValidatorDashboardSummary(r.Context(), *dashboardId, period, "", *sort, *search, pagingParams.limit, protocolModes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is passing the "" intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +3 to 6
import (
"time"
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: could remove this change

Comment on lines +371 to +366
SearchTypePassword
SearchTypeEmailUserToken
SearchTypeJsonContentType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these valid search types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are not, just copied all regexes for now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all changes within data access you'd probably want to get the direct opinion of data access team members. For now in total this PR adds more lines than it removes, so currently it's achieving the same thing with more lines. BUT it's good and necessary, that the cursor validation happens in handlers, not in data access. I don't know whether you've applied these search type changes everywhere or if it will scale better in future (e.g. with account dashboard). So I can't form a full opinion here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah you're right, I'll also ask other members. Types haven't been applied everywhere yet, will do so next; imo it simplifies things but the changes also need thorough testing

@remoterami remoterami force-pushed the BEDS-848/move-search-cursor-validation branch from 6a12467 to 3a15cf4 Compare November 29, 2024 10:11
@remoterami remoterami force-pushed the BEDS-848/move-search-cursor-validation branch from 8e79e8f to 2acc450 Compare November 29, 2024 10:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants