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

feat: support multiple chain ids in zoneconcierge chains info api #362

Merged
merged 21 commits into from
Apr 28, 2023

Conversation

gusin13
Copy link
Contributor

@gusin13 gusin13 commented Apr 25, 2023

Description

This PR is part of the optimizations being done to improve babylon-api performance. ChainInfo rpc query is being called multiple times by the explorer apis. I have replaced this method with ChainsInfo which will accept a list of chain ids and will output latest header info of the concerned cz's

Testing

Have added relevant fuzz tests and cli query

@gusin13 gusin13 changed the title zoneconcierge api: chain info of multiple chain ids feat: support multiple chain ids in zoneconcierge chains info endpoint Apr 26, 2023
@gusin13 gusin13 changed the title feat: support multiple chain ids in zoneconcierge chains info endpoint feat: zoneconcierge: support multiple chain ids in chains info endpoint Apr 26, 2023
@gusin13 gusin13 changed the title feat: zoneconcierge: support multiple chain ids in chains info endpoint feat: support multiple chain ids in zoneconcierge chains info api Apr 26, 2023
@gusin13 gusin13 marked this pull request as ready for review April 26, 2023 13:40
Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Nice!

@@ -209,17 +209,6 @@ func (n *NodeConfig) QueryCheckpointChains() (*[]string, error) {
return &chainsResponse.ChainIds, nil
}

func (n *NodeConfig) QueryCheckpointChainInfo(chainId string) (*zctypes.ChainInfo, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Why is this method removed?

Copy link
Contributor Author

@gusin13 gusin13 Apr 26, 2023

Choose a reason for hiding this comment

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

I couldn't find its usage in any of the existing e2e tests so removed it.

@KonradStaniec I am not sure how to run e2e tests properly locally.
I was getting this warning: no tests to run. Can you guide how to setup and add a new test in the suite?

Copy link
Contributor

Choose a reason for hiding this comment

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

so to run tests:

  1. first build docker container on branch with make build-docker
  2. then run make test-e2e
    that should be it.

To add new tests, proper place is e2e_test.go file. One thing to note is that tests there are stateful i.e one needs to be aware what what is current state after previous tests.

Copy link
Contributor Author

@gusin13 gusin13 Apr 27, 2023

Choose a reason for hiding this comment

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

Thanks @KonradStaniec, I have added a relevant assertion in the TestIbcCheckpointing test now.

x/zoneconcierge/keeper/grpc_query.go Outdated Show resolved Hide resolved
}

ctx := sdk.UnwrapSDKContext(c)
var chainsInfo []*types.ChainInfo
for _, chainID := range req.ChainIds {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe also check if a chain ID is an empty string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, fixed.

Copy link
Member

Choose a reason for hiding this comment

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

Could we move the check after L49? so that as long as there is an empty chain ID then no query will be performed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, fixed.

var chainIDs []string
for _, data := range chainsInfo {
chainIDs = append(chainIDs, data.chainID)
}
Copy link
Member

Choose a reason for hiding this comment

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

Maybe you could build the chainIDs list in the above for loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, fixed.

gusin13 and others added 3 commits April 27, 2023 00:46
Copy link
Member

@SebastianElvis SebastianElvis left a comment

Choose a reason for hiding this comment

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

This would be a good optimisation! Just some minor comments

option (google.api.http).get =
"/babylon/zoneconcierge/v1/chain_info/{chain_id}";
"/babylon/zoneconcierge/v1/chains_info";
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to take a list of strings via the URL? Tbh this api is helpful for manually checking the liveness of checkpoints

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, I think it's already being passed that way in current setup. So the GET call would translate to /babylon/zoneconcierge/v1/chains_info?chain_ids=1&chain_ids=2

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 thought about this again, I couldn't test with multiple chain ids so I am not very clear if protobuf repeated strings would translate to HTTP get query params or body.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I could not think of any straightforward way either, nor could I find any practice for such APIs. So probably let's stick to your current change

cmd := &cobra.Command{
Use: "chains-info <chain-ids>",
Short: "retrieve the chain info of given chain ids",
Args: cobra.RangeArgs(1, 5),
Copy link
Member

Choose a reason for hiding this comment

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

Why do we put a limit of 5 here? maybe it's not needed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, have removed the limit now.

return cmd
}

func CmdChainsInfo() *cobra.Command {
Copy link
Member

Choose a reason for hiding this comment

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

Thanks for adding this command!

x/zoneconcierge/client/cli/query.go Outdated Show resolved Hide resolved
}

ctx := sdk.UnwrapSDKContext(c)
var chainsInfo []*types.ChainInfo
for _, chainID := range req.ChainIds {
Copy link
Member

Choose a reason for hiding this comment

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

Could we move the check after L49? so that as long as there is an empty chain ID then no query will be performed

// ChainInfo returns the latest info of a chain with given ID
func (k Keeper) ChainInfo(c context.Context, req *types.QueryChainInfoRequest) (*types.QueryChainInfoResponse, error) {
// ChainsInfo returns the latest info for a list of chains with given IDs
func (k Keeper) ChainsInfo(c context.Context, req *types.QueryChainsInfoRequest) (*types.QueryChainsInfoResponse, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Usually requests which returns lists should be paginated. Here it is a bit tricky as we provide list of chain-ids and return list of chain info responses. In perfect world we would need to put some kinda of limit on number of chain-ids requested and tie it somehow to pagination. The limit is needed to avoid someone querying node for 1M of chain-ids, and exhausting node memory when it will try to read 1M ChainInfo objects into memory.

Maybe for not just put limit in place ? (50 or 100 chain ids ?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, good point. I have hardcoded a max limit of 100 now.

chainInfo, err := k.GetChainInfo(ctx, req.ChainId)
if err != nil {
return nil, err
chainInfo, err := k.GetChainInfo(ctx, chainID)
Copy link
Contributor

Choose a reason for hiding this comment

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

we are missing handling of the case when caller puts duplicated chain-id in the request list, imo it makes no sense to return duplicated chain-info results.

There two ways on handling that:

  1. either deduplicate chain-ids when recveing requrest
  2. or return error in case of first duplicate happening.

I think I would go for 2 as then usually duplicates in such case are callers error, and it would be good to inform caller about the error which happened.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch, sure I have implemented 2 now.

@gusin13
Copy link
Contributor Author

gusin13 commented Apr 27, 2023

@KonradStaniec @vitsalis @SebastianElvis Thanks for the reviews guys, I have addressed above comments. Please feel free to review again :)

Copy link
Contributor

@KonradStaniec KonradStaniec left a comment

Choose a reason for hiding this comment

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

Looks good !

At some point, we need to figure out how to best paginate those list queries so that caller have nice hints how to get next existing chain-ids, but at this point having limits should be enough 👍

Copy link
Member

@vitsalis vitsalis left a comment

Choose a reason for hiding this comment

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

Nice!

@gusin13 gusin13 merged commit 6f14271 into dev Apr 28, 2023
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.

4 participants