Skip to content

Commit

Permalink
imp: add query and sudo message types to encapsulate all variants of …
Browse files Browse the repository at this point in the history
…calls (#4133)

* defined query and sudo message types to encapsulate all variants for calls

* pass client message

* add ClientMessage from #4049

* address review comments

* linter

* gofumpt

* review comment

* more gofumpt
  • Loading branch information
crodriguezvega authored Aug 1, 2023
1 parent 20d4d7e commit 54f29ee
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 196 deletions.
2 changes: 1 addition & 1 deletion modules/light-clients/08-wasm/types/client_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

var _ exported.ClientMessage = &ClientMessage{}

// ClientType defines that the client message is a Wasm client consensus algorithm
// ClientType is a Wasm light client.
func (c ClientMessage) ClientType() string {
return exported.Wasm
}
Expand Down
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
124 changes: 124 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,124 @@
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{}
exportMetadataMsg struct{}
timestampAtHeightMsg struct {
Height exported.Height `json:"height"`
}
)

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

0 comments on commit 54f29ee

Please sign in to comment.