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

Clean up vm entry points #4279

Merged
merged 4 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 2 additions & 64 deletions modules/light-clients/08-wasm/types/client_state.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package types

import (
"encoding/hex"
"encoding/json"
"errors"

errorsmod "cosmossdk.io/errors"

"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -116,19 +112,11 @@ func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientSto
ConsensusState: consensusState,
}

encodedData, err := json.Marshal(payload)
if err != nil {
return errorsmod.Wrapf(err, "failed to marshal payload for wasm contract instantiation")
}

// The global store key can be used here to implement #4085
// wasmStore := ctx.KVStore(WasmStoreKey)

_, err = initContract(ctx, clientStore, cs.CodeHash, encodedData)
if err != nil {
return errorsmod.Wrapf(err, "failed to initialize contract")
}
return nil
err := wasmInit(ctx, clientStore, &cs, payload)
return err
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
}

// 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.
Expand Down Expand Up @@ -208,53 +196,3 @@ func (cs ClientState) VerifyNonMembership(
_, err := wasmQuery[contractResult](ctx, clientStore, &cs, payload)
return err
}

// call calls the contract with the given payload and returns the result.
func call[T ContractResult](ctx sdk.Context, clientStore sdk.KVStore, cs *ClientState, payload any) (T, error) {
var result T
encodedData, err := json.Marshal(payload)
if err != nil {
return result, errorsmod.Wrapf(err, "failed to marshal payload for wasm execution")
}
resp, err := callContract(ctx, clientStore, cs.CodeHash, encodedData)
if err != nil {
return result, errorsmod.Wrapf(err, "call to wasm contract failed")
}
// Only allow Data to flow back to us. SubMessages, Events and Attributes are not allowed.
if len(resp.Messages) > 0 {
return result, errorsmod.Wrapf(ErrWasmSubMessagesNotAllowed, "code hash (%s)", hex.EncodeToString(cs.CodeHash))
}
if len(resp.Events) > 0 {
return result, errorsmod.Wrapf(ErrWasmEventsNotAllowed, "code hash (%s)", hex.EncodeToString(cs.CodeHash))
}
if len(resp.Attributes) > 0 {
return result, errorsmod.Wrapf(ErrWasmAttributesNotAllowed, "code hash (%s)", hex.EncodeToString(cs.CodeHash))
}
if err := json.Unmarshal(resp.Data, &result); err != nil {
return result, errorsmod.Wrapf(err, "failed to unmarshal result of wasm execution")
}
if !result.Validate() {
return result, errorsmod.Wrapf(errors.New(result.Error()), "error occurred while executing contract with code hash %s", hex.EncodeToString(cs.CodeHash))
}
return result, nil
}

// wasmQuery queries the contract with the given payload and returns the result.
func wasmQuery[T ContractResult](ctx sdk.Context, clientStore sdk.KVStore, cs *ClientState, payload any) (T, error) {
var result T
encodedData, err := json.Marshal(payload)
if err != nil {
return result, errorsmod.Wrapf(err, "failed to marshal payload for wasm query")
}
resp, err := queryContract(ctx, clientStore, cs.CodeHash, encodedData)
if err != nil {
return result, errorsmod.Wrapf(err, "query to wasm contract failed")
}
if err := json.Unmarshal(resp, &result); err != nil {
return result, errorsmod.Wrapf(err, "failed to unmarshal result of wasm query")
}
if !result.Validate() {
return result, errorsmod.Wrapf(errors.New(result.Error()), "error occurred while querying contract with code hash %s", hex.EncodeToString(cs.CodeHash))
}
return result, nil
}
2 changes: 1 addition & 1 deletion modules/light-clients/08-wasm/types/proposal_handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ func (cs ClientState) CheckSubstituteAndUpdateState(
CheckSubstituteAndUpdateState: &checkSubstituteAndUpdateStateMsg{},
}

_, err := call[contractResult](ctx, store, &cs, payload)
_, err := wasmCall[contractResult](ctx, store, &cs, payload)
return err
}
4 changes: 2 additions & 2 deletions modules/light-clients/08-wasm/types/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, client
UpdateState: &updateStateMsg{ClientMessage: clientMessage},
}

result, err := call[updateStateResult](ctx, clientStore, &cs, payload)
result, err := wasmCall[updateStateResult](ctx, clientStore, &cs, payload)
if err != nil {
panic(err)
}
Expand All @@ -62,7 +62,7 @@ func (cs ClientState) UpdateStateOnMisbehaviour(ctx sdk.Context, _ codec.BinaryC
UpdateStateOnMisbehaviour: &updateStateOnMisbehaviourMsg{ClientMessage: clientMessage},
}

_, err := call[contractResult](ctx, clientStore, &cs, payload)
_, err := wasmCall[contractResult](ctx, clientStore, &cs, payload)
if err != nil {
panic(err)
}
Expand Down
2 changes: 1 addition & 1 deletion modules/light-clients/08-wasm/types/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ func (cs ClientState) VerifyUpgradeAndUpdateState(
},
}

_, err := call[contractResult](ctx, clientStore, &cs, payload)
_, err := wasmCall[contractResult](ctx, clientStore, &cs, payload)
return err
}
69 changes: 69 additions & 0 deletions modules/light-clients/08-wasm/types/vm.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package types

import (
"encoding/hex"
"encoding/json"
"errors"

wasmvm "github.com/CosmWasm/wasmvm"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"

errorsmod "cosmossdk.io/errors"

storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
Expand Down Expand Up @@ -64,6 +70,69 @@ func queryContract(ctx sdk.Context, clientStore sdk.KVStore, codeHash []byte, ms
return resp, err
}

// wasmInit accepts a message to instantiate a wasm contract, JSON encodes it and calls initContract.
func wasmInit(ctx sdk.Context, clientStore sdk.KVStore, cs *ClientState, payload instantiateMessage) error {
encodedData, err := json.Marshal(payload)
if err != nil {
return errorsmod.Wrapf(err, "failed to marshal payload for wasm contract instantiation")
}
_, err = initContract(ctx, clientStore, cs.CodeHash, encodedData)
if err != nil {
return errorsmod.Wrapf(err, "call to wasm contract failed")
}
return nil
}

// wasmCall calls the contract with the given payload and returns the result.
func wasmCall[T ContractResult](ctx sdk.Context, clientStore sdk.KVStore, cs *ClientState, payload sudoMsg) (T, error) {
var result T
encodedData, err := json.Marshal(payload)
if err != nil {
return result, errorsmod.Wrapf(err, "failed to marshal payload for wasm execution")
}
resp, err := callContract(ctx, clientStore, cs.CodeHash, encodedData)
if err != nil {
return result, errorsmod.Wrapf(err, "call to wasm contract failed")
}
// Only allow Data to flow back to us. SubMessages, Events and Attributes are not allowed.
if len(resp.Messages) > 0 {
return result, errorsmod.Wrapf(ErrWasmSubMessagesNotAllowed, "code hash (%s)", hex.EncodeToString(cs.CodeHash))
}
if len(resp.Events) > 0 {
return result, errorsmod.Wrapf(ErrWasmEventsNotAllowed, "code hash (%s)", hex.EncodeToString(cs.CodeHash))
}
if len(resp.Attributes) > 0 {
return result, errorsmod.Wrapf(ErrWasmAttributesNotAllowed, "code hash (%s)", hex.EncodeToString(cs.CodeHash))
}
if err := json.Unmarshal(resp.Data, &result); err != nil {
return result, errorsmod.Wrapf(err, "failed to unmarshal result of wasm execution")
}
if !result.Validate() {
return result, errorsmod.Wrapf(errors.New(result.Error()), "error occurred while executing contract with code hash %s", hex.EncodeToString(cs.CodeHash))
}
return result, nil
}

// wasmQuery queries the contract with the given payload and returns the result.
func wasmQuery[T ContractResult](ctx sdk.Context, clientStore sdk.KVStore, cs *ClientState, payload queryMsg) (T, error) {
var result T
encodedData, err := json.Marshal(payload)
if err != nil {
return result, errorsmod.Wrapf(err, "failed to marshal payload for wasm query")
}
resp, err := queryContract(ctx, clientStore, cs.CodeHash, encodedData)
if err != nil {
return result, errorsmod.Wrapf(err, "query to wasm contract failed")
}
if err := json.Unmarshal(resp, &result); err != nil {
return result, errorsmod.Wrapf(err, "failed to unmarshal result of wasm query")
}
if !result.Validate() {
return result, errorsmod.Wrapf(errors.New(result.Error()), "error occurred while querying contract with code hash %s", hex.EncodeToString(cs.CodeHash))
}
return result, nil
}

// getEnv returns the state of the blockchain environment the contract is running on
func getEnv(ctx sdk.Context) wasmvmtypes.Env {
chainID := ctx.BlockHeader().ChainID
Expand Down
Loading