-
Notifications
You must be signed in to change notification settings - Fork 616
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
Modify CheckHeaderAndUpdateState to set client state/consensus states in IBC light client implementations #284
Comments
Revisiting this decision many months later, I'm trying to piece together the exact benefits. This decision was sparked by the motivation of allowing the client state definition to be upgraded over time. The idea was that the light client code internally use a different type than what is stored in the client store. But now I see that it would also be possible to create an entirely new client state definition for the breaking versions of the same client. That is, if we modified the client state definition of the IBC tendermint client, the new definition should be v2 and treated as an entirely different client rather than a continuation of v1. Note, this upgrade path still requires all counterparty chains to understand v2 before upgrading. There do remain subtle benefits, such as the consensus state not necessarily needing to be set for every consensus state (solo machines), or removal of the The changes would also align with the spec, but increases the responsibility of light client developers. One possible adjustment that comes to mind is only removing the setting of consensus states from 02-client. This would require light client developers to set the consensus states themselves (allowing header.GetHeight to be removed and stopping unnecessary state storage for solo machines). Although at that point, I'm not sure why they shouldn't be expected to update the client state as well @mkaczanowski do you have any insights into whether this change would positively or negatively benefit the Wasm client? cc @AdityaSripal @cwgoes any thoughts on how other light client types might be affected by this decision? |
Another consideration which might add to this discussion is the getting of timestamps. Currently ibc-go will attempt to get a timestamp for a height by getting the timestamp of a consensus state at a specific height, but this does not work for solo machines. The solo machine will sign a message at sequence X indicating a timeout, but core IBC will attempt to check the timeout using sequence X as the consensus state height. The consensus state isn't written (if at all) until after the timeout message is expected to succeed. The |
I'm currently leading the development efforts of I'm in support of these changes for 2 reasons:
|
I'm still strongly in favour of this separation of concerns, I think the abstractions are much clearer.
This is true - if we want to simplify light client development, can we just put some sort of standard interface in between for all light clients which use consensus states in a "standard" way (that is currently serviced by the implementation)? That seems also beneficial to me. |
Thanks everyone for contributing to the discussion. This has helped clarify things for me. @seunlanlege would the proposed changes in #668 work for your light client design? Also see minor modifications to the proposal below. I think these reasons provide strong justification for removing the setting of consensus states from the 02-client create/update/upgrade functions. I think it also justifies removing If we remove / Header is the consensus state update information
type Header interface {
proto.Message
ClientType() string
ValidateBasic() error
} // Misbehaviour defines counterparty misbehaviour for a specific consensus type
type Misbehaviour interface {
proto.Message
ClientType() string
GetClientID() string
ValidateBasic() error
} The
with
In relation to #668, instead of adding an additional Under the hood, I would expect switch header.(type) {
case: NormalHeader{}
// check time monotonicity misbehaviour
case: MisbehaviourHeader{}
// check double singing misbehaviour Of course, it might be best to keep these concepts separate, but misbehaviour detection has already become an ingrained concept in updating a client, so I think it might be best to embrace this direction and make it easier for light client developers to reason about. I think when doing these changes we should also move Proposal
The only part I'm still uncertain about is what to do with the ClientState. I don't see good reasons for why it must be set by the client state (since it is being used by 02-client). I guess the only benefit is avoiding unnecessary writes on no-ops when the client state doesn't change. Also, it might be more explicit of a change that all client store changes are now managed by the light client. This part is documenting reasoning which may not be obvious to everyone One question that pops into my head is why 02-client should be capable of understanding the consensus height to consensus state mapping. As the spec states:
So why do we need to allow functionality of introspecting non-self consensus states? Strictly speaking, we don't need to, but if the spec assumes consensus states are associated with a consensus height then we might as well. Why do we need to assume consensus heights are associated with consensus states? Well, we need timeouts. We must have monotonically increasing time and comparing the "time" of two consensus states must determine which is older/newer. In theory, I think, consensus heights could be even more abstract than they already are. Within ibc-go, Thus, it makes sense that each consensus state is associated with a consensus height. It also makes sense that updating from a consensus height via some opaque type like |
I really like the proposal, @colin-axner! My question is if Also, in this case It also looks like we need to inform light client developers to deal with these headers in standard ways:
|
If the SDK supported read-only store access, then I think maybe we could enforce no writes to state, but since the SDK doesn't, I think we should just document the intended behaviour of these functions as clearly as possible. I don't see any potential issues from the core IBC side if light clients write state. It could just be problematic for the light client developer who does go against the recommended functionality.
Yes. In #668 I intended to convey that Alternatively we could create another function, I don't have strong preferences. |
I'm also kinda wondering if we should deprecate |
I found a note here on solo machine's lack of support for ibc-go/modules/core/04-channel/keeper/packet.go Lines 91 to 105 in f822756
It looks like the transaction is aborted and consensus state is not set if the ibc-go/modules/light-clients/06-solomachine/types/client_state.go Lines 475 to 477 in f822756
If Or are you saying that the |
Also wondering how doing the above would fix the solo machine issues. What extra context does the 02-client have that the solo machine light client lacks to support this method? Perhaps the answer to this will also help answer the Qs I had above. |
Seems like removing the height <> header association would allow a light client impl to opaquely accept batched headers? Also, I like the separation of the methods. Think it's more clear to the light client implementer what needs to be done (and where). |
yes it works perfectly 👍🏿 . |
Isn't it already possible for a light client impl to return a different client definition and have that persisted by 02-client as long it satisfies the ibc-go/modules/core/02-client/keeper/client.go Lines 72 to 95 in 01c5848
Update:
Enforce 07-tendermint client type. ibc-go/modules/core/02-client/keeper/keeper.go Lines 270 to 275 in 01c5848
The above would need to be changed to support more client types? |
Agreed, theoretically i think we could wrap the store in an interface with a no-op write but that should be a feature SDK introduces not something we maintain.
Ahh ok, I thought the If that is the case, then why are we splitting up |
Misbehaviour checks also need verified headers |
Ahh got it, ok then. Makes sense |
Though why don't we just do I understand splitting up the functions to make it explicit in-code for the light client developers that they must check for misbehaviour. But we are already moving towards giving them more flexibility and holding their hand less in 02-client. I think given that design direction, it makes sense to go all the way and just document very clearly that misbehaviour should also be checked within that function. To me, it seems like creating these additional methods will cause more confusion and inefficiency than any benefits. |
I disagree. A function should not be overloaded, the greater complexity of a function, the more likely bugs will occur/slip by. The proposed functionality would require light clients developers to:
Given that all light clients need to verify the header, check for misbehaviour, and update state, I don't see a reason why we need to bundle this functionality under the hood of a single function. Furthermore, it makes 02-client event emission difficult. The function could error because of:
In the first two cases we don't want to emit events, in the last two we want to emit different events. What are the points of confusion and inefficiency you foresee? |
Those are all fair points. My concern was as an interface we have one operation: UpdateClient that is split into a stateless verification and stateful update So from an interface standpoint there's this inconsistency that is at best inelegant and at worst confusing without being very clear with our naming. I would prefer to design the interface to be more consistent if possible |
Good point. I suppose we consider the following? if err := clientState.VerifyHeader(header); err != nil {
return err
}
foundMisbehaviour := clientState.CheckForMisbehaviour(header)
if foundMisbehaviour {
clientState.UpdateStateOnMisbehaviour(header)
// emit misbehaviour event
return
}
clientState.UpdateState(header) // expects no-op on duplicate header
// emit update event
return
} MsgSubmitMisbehaviour would reuse the first 3 calls (we could optionally deprecate this message) This would give us stateless verification/checks and 2 explicit types of updates |
Agreed with your final proposal 👍 |
Base64 encoded return data on wasm raw query REST endpoint
* Working state * Fix tests * WIP packet relay * Merge PR cosmos#285: Fixed issues in scripts to start two or three chains * Compling * Finish denom work, move on to streaming relayer proof query issue * working streaming relayer * Add debug logging to faucet for remote debug * add additional logging * moar faucet debugging * Update to v0.40.0-rc0 and ensure working README, other docs, tests, etc... Co-authored-by: Andy Nogueira <me@andynogueira.dev>
Summary
02-client should not set client states and consensus states as generalizing IBC client implementations is difficult. Better to give IBC clients more control and flexibility. This will already be useful for solo machines which don't need to store consensus states for each update height
This design is already specified in ICS, our implementation didn't follow those changes. See comment
For Admin Use
The text was updated successfully, but these errors were encountered: