-
Notifications
You must be signed in to change notification settings - Fork 170
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
zoneconcierge: proper initialisation for chain info #285
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff. I'm not entirely onboard with the new errors introduced here and the way they are handled, added corresponding comments
if err != nil { | ||
// chain info has not been initialised yet | ||
// this can only be a programming error | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we panic
since not having a ChainInfo
can only be a programming error. However, on the previous if
condition, we return an error. Why don't we panic
there as well or return an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this is a helper method and it doesn't have a complete view of the entire logic, I would avoid panicking in this function as the reader does not have all the context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! After a second thought, maybe let's return an error here. It will be the AfterHeaderWithValidCommit
hook's responsibility to panic.
chainInfo := k.GetChainInfo(ctx, chainID) | ||
chainInfo, err := k.GetChainInfo(ctx, chainID) | ||
if err != nil { | ||
return sdkerrors.Wrapf(types.ErrChainInfoNotFound, "cannot insert fork header when chain info is not initialized") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In updateLatestHeader
we panic
. What's the difference here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have updated the PR to return errors in tryToUpdateLatestForkHeader
and updateLatestHeader
consistently 👍
|
||
// initialise chain info if not exist | ||
chainInfo, err := h.k.GetChainInfo(ctx, indexedHeader.ChainId) | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if there's another kind of error related to GetChainInfo
? I suggest that GetChainInfo
returns nil
if no chain info exists (or we implement a method ChainInfoExists
) and we create that in this case. In the future, if an extra error is created this might spill over here and we panic for no reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I have changed the PR so that we initialise chain info only when the error is of type ErrEpochChainInfoNotFound
, and panic directly if the error is other types.
I suggest that GetChainInfo returns nil if no chain info exists (or we implement a method ChainInfoExists) and we create that in this case.
I remember we had a discussion on this and the conclusion was that we need to have proper initialisation of chain info and give the invoker a clear message if the chain info does not exist. This was part of the motivation of this PR actually.
return nil, fmt.Errorf("chainID is empty") | ||
} | ||
// ensure chain info has not been initialised yet | ||
if _, err := k.GetChainInfo(ctx, chainID); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GetChainInfo
returning an error is not a good condition for identifying whether a Chain Info exists imo. I would have it return nil
if no such info exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like above, I updated the PR to distinguish errors by using sdkerrors.IsOf
.
If other errors occur maybe AfterHeaderWithValidCommit
will need to do other corresponding things, e.g., panic, rather than just returning nil
. Wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to get around why we return an error under err==nil
, so, I would suggest we don't use k.GetChainInfo()
here. Instead, we could have a k.HasChainInfo()
method that wraps store.Has()
. k.GetChainInfo()
can reuse k.HashChainInfo()
and calling k.HasChainInfo()
would be more efficient as it does not need to read the database and unmarshal the object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep that's a good idea. Fixed 👍
Headers: []*types.IndexedHeader{}, | ||
}, | ||
} | ||
return nil, types.ErrEpochChainInfoNotFound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why return an error here? I don't think it's an error if no chain info exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was not an error before this PR. This PR aims at introducing initialisation of chain info, such that the invokers of GetChainInfo
gets a clear message whether the chain checkpoints to Babylon or not. For example, without this PR, the chain_info
API always returns status code 200 even if the chain does not checkpoint to Babylon. Instead in this case, the status code should be 500.
Thanks Vitalis for the great comments! I have addressed all of them. Since Vitalis is offline this week, @gitferry could you please have a look at this PR? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! Left a few suggestions:
return nil, fmt.Errorf("chainID is empty") | ||
} | ||
// ensure chain info has not been initialised yet | ||
if _, err := k.GetChainInfo(ctx, chainID); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It took me a while to get around why we return an error under err==nil
, so, I would suggest we don't use k.GetChainInfo()
here. Instead, we could have a k.HasChainInfo()
method that wraps store.Has()
. k.GetChainInfo()
can reuse k.HashChainInfo()
and calling k.HasChainInfo()
would be more efficient as it does not need to read the database and unmarshal the object.
// chain info has not been initialised yet | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// chain info has not been initialised yet | |
return err | |
return fmt.Errorf("failed to get chain info of %s: %w", chainID, err) |
chainInfo := k.GetChainInfo(ctx, chainID) | ||
chainInfo, err := k.GetChainInfo(ctx, chainID) | ||
if err != nil { | ||
// chain info does not exist yet, nothing to record |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better if we add a log here? Otherwise, we would loose this information
x/zoneconcierge/keeper/hooks.go
Outdated
// chain info does not exist yet, initialise chain info for this chain | ||
chainInfo, err = h.k.InitChainInfo(ctx, indexedHeader.ChainId) | ||
if err != nil { | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
panic(err) | |
panic(fmt.Errorf("failed to initialize chain info of %s: %w", indexedHeader.ChainId, err) |
x/zoneconcierge/keeper/hooks.go
Outdated
panic(err) | ||
} | ||
} else { | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
panic(err) | |
panic(fmt.Errorf("failed to get chain info of %s: %w", indexedHeader.ChainId, err) |
Fixes an improvement found by @gusin13
This PR introduces the proper initialisation for chain info.
Previously, upon querying
GetChainInfo
, if a chain info does not exist, then ZoneConcierge returns an empty chain info rather than an error. This is not proper since the function has to give a clear message on whether a chain info exists or not. For example, one side effect of this is that the chain info API returns 200 even if the chain info does not exist.This PR introduces the initialisation that works as follows. Upon a header via IBC