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

imp: add query and sudo message types to encapsulate all variants of calls #4133

62 changes: 7 additions & 55 deletions modules/light-clients/08-wasm/types/client_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,6 @@ func (cs ClientState) Validate() error {
return nil
}

type (
statusInnerPayload struct{}
statusPayload struct {
Status statusInnerPayload `json:"status"`
}
)

// Status returns the status of the wasm client.
// The client may be:
// - Active: frozen height is zero and client is not expired
Expand All @@ -71,7 +64,7 @@ type (
// A frozen client will become expired, so the Frozen status
// has higher precedence.
func (cs ClientState) Status(ctx sdk.Context, clientStore sdk.KVStore, _ codec.BinaryCodec) exported.Status {
payload := statusPayload{Status: statusInnerPayload{}}
payload := queryMsg{Status: &statusMsg{}}

result, err := wasmQuery[statusResult](ctx, clientStore, &cs, payload)
if err != nil {
Expand All @@ -87,24 +80,15 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState {
return &cs
}

type (
timestampAtHeightInnerPayload struct {
Height exported.Height `json:"height"`
}
timestampAtHeightPayload struct {
TimestampAtHeight timestampAtHeightInnerPayload `json:"timestamp_at_height"`
}
)

// GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height.
func (cs ClientState) GetTimestampAtHeight(
ctx sdk.Context,
clientStore sdk.KVStore,
cdc codec.BinaryCodec,
height exported.Height,
) (uint64, error) {
payload := timestampAtHeightPayload{
TimestampAtHeight: timestampAtHeightInnerPayload{
payload := queryMsg{
TimestampAtHeight: &timestampAtHeightMsg{
Height: height,
},
}
Expand All @@ -117,11 +101,6 @@ func (cs ClientState) GetTimestampAtHeight(
return result.Timestamp, nil
}

type instantiateMessage struct {
ClientState *ClientState `json:"client_state"`
ConsensusState *ConsensusState `json:"consensus_state"`
}

// Initialize checks that the initial consensus state is an 08-wasm consensus state and
// sets the client state, consensus state in the provided client store.
// It also initializes the wasm contract for the client.
Expand Down Expand Up @@ -152,20 +131,6 @@ func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientSto
return nil
}

type (
verifyMembershipInnerPayload struct {
Height exported.Height `json:"height"`
DelayTimePeriod uint64 `json:"delay_time_period"`
DelayBlockPeriod uint64 `json:"delay_block_period"`
Proof []byte `json:"proof"`
Path exported.Path `json:"path"`
Value []byte `json:"value"`
}
verifyMembershipPayload struct {
VerifyMembership verifyMembershipInnerPayload `json:"verify_membership"`
}
)

// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height.
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
// If a zero proof height is passed in, it will fail to retrieve the associated consensus state.
Expand All @@ -192,8 +157,8 @@ func (cs ClientState) VerifyMembership(
return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", commitmenttypes.MerklePath{}, path)
}

payload := verifyMembershipPayload{
VerifyMembership: verifyMembershipInnerPayload{
payload := queryMsg{
VerifyMembership: &verifyMembershipMsg{
Height: height,
DelayTimePeriod: delayTimePeriod,
DelayBlockPeriod: delayBlockPeriod,
Expand All @@ -206,19 +171,6 @@ func (cs ClientState) VerifyMembership(
return err
}

type (
verifyNonMembershipInnerPayload struct {
Height exported.Height `json:"height"`
DelayTimePeriod uint64 `json:"delay_time_period"`
DelayBlockPeriod uint64 `json:"delay_block_period"`
Proof []byte `json:"proof"`
Path exported.Path `json:"path"`
}
verifyNonMembershipPayload struct {
VerifyNonMembership verifyNonMembershipInnerPayload `json:"verify_non_membership"`
}
)

// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height.
// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24).
// If a zero proof height is passed in, it will fail to retrieve the associated consensus state.
Expand All @@ -244,8 +196,8 @@ func (cs ClientState) VerifyNonMembership(
return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", commitmenttypes.MerklePath{}, path)
}

payload := verifyNonMembershipPayload{
VerifyNonMembership: verifyNonMembershipInnerPayload{
payload := queryMsg{
VerifyNonMembership: &verifyNonMembershipMsg{
Height: height,
DelayTimePeriod: delayTimePeriod,
DelayBlockPeriod: delayBlockPeriod,
Expand Down
121 changes: 121 additions & 0 deletions modules/light-clients/08-wasm/types/contract_api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package types

import (
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)

// instantiateMessage
type instantiateMessage struct {
ClientState *ClientState `json:"client_state"`
ConsensusState *ConsensusState `json:"consensus_state"`
}

// queryMsg is used to encode query messages
// omitempty tag is mandatory for JSON serialization
// to be compatible with Rust contract enum matching
type queryMsg struct {
Status *statusMsg `json:"status,omitempty"`
ExportMetadata *exportMetadataMsg `json:"export_metadata,omitempty"`
TimestampAtHeight *timestampAtHeightMsg `json:"timestamp_at_height,omitempty"`
VerifyClientMessage *verifyClientMessageMsg `json:"verify_client_message,omitempty"`
VerifyMembership *verifyMembershipMsg `json:"verify_membership,omitempty"`
VerifyNonMembership *verifyNonMembershipMsg `json:"verify_non_membership,omitempty"`
CheckForMisbehaviour *checkForMisbehaviourMsg `json:"check_for_misbehaviour,omitempty"`
}

type statusMsg struct{}

Check failure on line 27 in modules/light-clients/08-wasm/types/contract_api.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed (gofumpt)
type exportMetadataMsg struct{}
type timestampAtHeightMsg struct {
Height exported.Height `json:"height"`
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

gofumpt disagrees with you guys, @damiannolan and @chatton, and wants to put here a type block. I respect your opinion a lot, guys, you know that, but my religion doesn't allow me to break the 11th commandment: "You will never fight against your beloved linter". :)

type verifyClientMessageMsg struct {
ClientMessage *ClientMessage `json:"client_message"`
}
type verifyMembershipMsg struct {
Height exported.Height `json:"height"`
DelayTimePeriod uint64 `json:"delay_time_period"`
DelayBlockPeriod uint64 `json:"delay_block_period"`
Proof []byte `json:"proof"`
Path exported.Path `json:"path"`
Value []byte `json:"value"`
}
type verifyNonMembershipMsg struct {
Height exported.Height `json:"height"`
DelayTimePeriod uint64 `json:"delay_time_period"`
DelayBlockPeriod uint64 `json:"delay_block_period"`
Proof []byte `json:"proof"`
Path exported.Path `json:"path"`
}
type checkForMisbehaviourMsg struct {
ClientMessage *ClientMessage `json:"client_message"`
}

// sudoMsg is used to encode sudo messages
// omitempty tag is mandatory for JSON serialization
// to be compatible with Rust contract enum matching
type sudoMsg struct {
UpdateState *updateStateMsg `json:"update_state,omitempty"`
UpdateStateOnMisbehaviour *updateStateOnMisbehaviourMsg `json:"update_state_on_misbehaviour,omitempty"`
VerifyUpgradeAndUpdateState *verifyUpgradeAndUpdateStateMsg `json:"verify_upgrade_and_update_state,omitempty"`
CheckSubstituteAndUpdateState *checkSubstituteAndUpdateStateMsg `json:"check_substitute_and_update_state,omitempty"`
}

type updateStateMsg struct {
ClientMessage *ClientMessage `json:"client_message"`
}
type updateStateOnMisbehaviourMsg struct {
ClientMessage *ClientMessage `json:"client_message"`
}
type verifyUpgradeAndUpdateStateMsg struct {
UpgradeClientState exported.ClientState `json:"upgrade_client_state"`
UpgradeConsensusState exported.ConsensusState `json:"upgrade_consensus_state"`
ProofUpgradeClient []byte `json:"proof_upgrade_client"`
ProofUpgradeConsensusState []byte `json:"proof_upgrade_consensus_state"`
}
type checkSubstituteAndUpdateStateMsg struct{}

// ContractResult defines the expected result returned by a contract call
type ContractResult interface {
Validate() bool
Error() string
}

type contractResult struct {
IsValid bool `json:"is_valid,omitempty"`
ErrorMsg string `json:"error_msg,omitempty"`
Data []byte `json:"data,omitempty"`
}

func (r contractResult) Validate() bool {
return r.IsValid
}

func (r contractResult) Error() string {
return r.ErrorMsg
}

type statusResult struct {
contractResult
Status exported.Status `json:"status"`
}

type exportMetadataResult struct {
contractResult
GenesisMetadata []clienttypes.GenesisMetadata `json:"genesis_metadata"`
}

type timestampAtHeightResult struct {
contractResult
Timestamp uint64 `json:"timestamp"`
}

type checkForMisbehaviourResult struct {
contractResult
FoundMisbehaviour bool `json:"found_misbehaviour"`
}

type updateStateResult struct {
contractResult
Heights []exported.Height `json:"heights"`
}
17 changes: 9 additions & 8 deletions modules/light-clients/08-wasm/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package types
import errorsmod "cosmossdk.io/errors"

var (
ErrInvalid = errorsmod.Register(ModuleName, 1, "invalid")
ErrInvalidData = errorsmod.Register(ModuleName, 2, "invalid data")
ErrInvalidCodeHash = errorsmod.Register(ModuleName, 3, "invalid code hash")
ErrInvalid = errorsmod.Register(ModuleName, 2, "invalid")
ErrInvalidData = errorsmod.Register(ModuleName, 3, "invalid data")
ErrInvalidCodeHash = errorsmod.Register(ModuleName, 4, "invalid code hash")
ErrInvalidClientMessage = errorsmod.Register(ModuleName, 5, "invalid client message")
// Wasm specific
ErrWasmEmptyCode = errorsmod.Register(ModuleName, 4, "empty wasm code")
ErrWasmCodeTooLarge = errorsmod.Register(ModuleName, 5, "wasm code too large")
ErrWasmCodeExists = errorsmod.Register(ModuleName, 6, "wasm code already exists")
ErrWasmCodeHashNotFound = errorsmod.Register(ModuleName, 7, "wasm code hash not found")
ErrWasmSubMessagesNotAllowed = errorsmod.Register(ModuleName, 8, "execution of sub messages is not allowed")
ErrWasmEmptyCode = errorsmod.Register(ModuleName, 6, "empty wasm code")
ErrWasmCodeTooLarge = errorsmod.Register(ModuleName, 7, "wasm code too large")
ErrWasmCodeExists = errorsmod.Register(ModuleName, 8, "wasm code already exists")
ErrWasmCodeHashNotFound = errorsmod.Register(ModuleName, 9, "wasm code hash not found")
ErrWasmSubMessagesNotAllowed = errorsmod.Register(ModuleName, 10, "execution of sub messages is not allowed")
)
13 changes: 4 additions & 9 deletions modules/light-clients/08-wasm/types/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ import (
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)

type (
exportMetadataInnerPayload struct{}
exportMetadataPayload struct {
ExportMetadata exportMetadataInnerPayload `json:"export_metadata"`
}
)

// NewGenesisState creates an 08-wasm GenesisState instance.
func NewGenesisState(contracts []Contract) *GenesisState {
return &GenesisState{Contracts: contracts}
Expand All @@ -25,10 +18,12 @@ func NewGenesisState(contracts []Contract) *GenesisState {
// ExportMetadata exports all the consensus metadata in the client store so they
// can be included in clients genesis and imported by a ClientKeeper
func (cs ClientState) ExportMetadata(store sdk.KVStore) []exported.GenesisMetadata {
var payload exportMetadataPayload
payload := queryMsg{
ExportMetadata: &exportMetadataMsg{},
}

ctx := sdk.NewContext(nil, tmproto.Header{Height: 1, Time: time.Now()}, true, nil) // context with infinite gas meter
result, err := wasmQuery[metadataResult](ctx, store, &cs, payload)
result, err := wasmQuery[exportMetadataResult](ctx, store, &cs, payload)
if err != nil {
panic(err)
}
Expand Down
15 changes: 2 additions & 13 deletions modules/light-clients/08-wasm/types/misbehaviour_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,6 @@ import (
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)

type (
checkForMisbehaviourInnerPayload struct {
ClientMessage *ClientMessage `json:"client_message"`
}
checkForMisbehaviourPayload struct {
CheckForMisbehaviour checkForMisbehaviourInnerPayload `json:"check_for_misbehaviour"`
}
)

// CheckForMisbehaviour detects misbehaviour in a submitted Header message and verifies
// the correctness of a submitted Misbehaviour ClientMessage
func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, _ codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) bool {
Expand All @@ -24,10 +15,8 @@ func (cs ClientState) CheckForMisbehaviour(ctx sdk.Context, _ codec.BinaryCodec,
return false
}

payload := checkForMisbehaviourPayload{
CheckForMisbehaviour: checkForMisbehaviourInnerPayload{
ClientMessage: clientMessage,
},
payload := queryMsg{
CheckForMisbehaviour: &checkForMisbehaviourMsg{ClientMessage: clientMessage},
}

result, err := wasmQuery[checkForMisbehaviourResult](ctx, clientStore, &cs, payload)
Expand Down
11 changes: 2 additions & 9 deletions modules/light-clients/08-wasm/types/proposal_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ import (
"github.com/cosmos/ibc-go/v7/modules/core/exported"
)

type (
checkSubstituteAndUpdateStateInnerPayload struct{}
checkSubstituteAndUpdateStatePayload struct {
CheckSubstituteAndUpdateState checkSubstituteAndUpdateStateInnerPayload `json:"check_substitute_and_update_state"`
}
)

// CheckSubstituteAndUpdateState will try to update the client with the state of the
// substitute.
func (cs ClientState) CheckSubstituteAndUpdateState(
Expand All @@ -42,8 +35,8 @@ func (cs ClientState) CheckSubstituteAndUpdateState(

store := newUpdateProposalWrappedStore(subjectClientStore, substituteClientStore, SubjectPrefix, SubstitutePrefix)

payload := checkSubstituteAndUpdateStatePayload{
CheckSubstituteAndUpdateState: checkSubstituteAndUpdateStateInnerPayload{},
payload := sudoMsg{
CheckSubstituteAndUpdateState: &checkSubstituteAndUpdateStateMsg{},
}

_, err := call[contractResult](ctx, store, &cs, payload)
Expand Down
Loading
Loading