From c4f8da4506da82412b79dec86cd151c46cda66d7 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 1 Aug 2023 23:24:44 +0200 Subject: [PATCH] add 08-wasm Keeper constructor that accepts pointer to Wasm VM instance (#4109) * add constructor that accepts pointer to Wasm VM instance * typo * add functions that returns wasm config with default values * review comment * Apply suggestions from code review Co-authored-by: Cian Hatton * review comments * rename constructor function * address review comments * set contract debug mode to false --------- Co-authored-by: Cian Hatton --- .../light-clients/08-wasm/keeper/keeper.go | 48 ++++++++++++------- modules/light-clients/08-wasm/types/config.go | 37 ++++++++++++++ modules/light-clients/08-wasm/types/vm.go | 10 ++-- testing/simapp/app.go | 28 ++++++++++- 4 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 modules/light-clients/08-wasm/types/config.go diff --git a/modules/light-clients/08-wasm/keeper/keeper.go b/modules/light-clients/08-wasm/keeper/keeper.go index 5e8a8f5c674..6a0019efb3e 100644 --- a/modules/light-clients/08-wasm/keeper/keeper.go +++ b/modules/light-clients/08-wasm/keeper/keeper.go @@ -4,10 +4,9 @@ import ( "bytes" "crypto/sha256" "encoding/hex" - "math" - "strings" + "fmt" - cosmwasm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm" errorsmod "cosmossdk.io/errors" @@ -25,23 +24,23 @@ type Keeper struct { storeKey storetypes.StoreKey cdc codec.BinaryCodec - wasmVM *cosmwasm.VM + wasmVM *wasmvm.VM authority string } -// NewKeeper creates a new NewKeeper instance -func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) Keeper { - // Wasm VM - const wasmDataDir = "ibc_08-wasm_client_data" - wasmSupportedFeatures := strings.Join([]string{"storage", "iterator"}, ",") - wasmMemoryLimitMb := uint32(math.Pow(2, 12)) - wasmPrintDebug := true - wasmCacheSizeMb := uint32(math.Pow(2, 8)) - - vm, err := cosmwasm.NewVM(wasmDataDir, wasmSupportedFeatures, wasmMemoryLimitMb, wasmPrintDebug, wasmCacheSizeMb) - if err != nil { - panic(err) +// NewKeeperWithVM creates a new Keeper instance with the provided Wasm VM. +// This constructor function is meant to be used when the chain uses x/wasm +// and the same Wasm VM instance should be shared with it. +func NewKeeperWithVM( + cdc codec.BinaryCodec, + key storetypes.StoreKey, + authority string, + vm *wasmvm.VM, +) Keeper { + if types.WasmVM != nil { + panic("global Wasm VM instance should not be already set before calling this function") } + types.WasmVM = vm types.WasmStoreKey = key @@ -53,6 +52,23 @@ func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) } } +// NewKeeperWithConfig creates a new Keeper instance with the provided Wasm configuration. +// This constructor function is meant to be used when the chain does not use x/wasm +// and a Wasm VM needs to be instantiated using the provided parameters. +func NewKeeperWithConfig( + cdc codec.BinaryCodec, + key storetypes.StoreKey, + authority string, + wasmConfig types.WasmConfig, +) Keeper { + vm, err := wasmvm.NewVM(wasmConfig.DataDir, wasmConfig.SupportedFeatures, types.ContractMemoryLimit, wasmConfig.ContractDebugMode, wasmConfig.MemoryCacheSize) + if err != nil { + panic(fmt.Sprintf("failed to instantiate new Wasm VM instance: %v", err)) + } + + return NewKeeperWithVM(cdc, key, authority, vm) +} + // GetAuthority returns the 08-wasm module's authority. func (k Keeper) GetAuthority() string { return k.authority diff --git a/modules/light-clients/08-wasm/types/config.go b/modules/light-clients/08-wasm/types/config.go new file mode 100644 index 00000000000..ce7aad44257 --- /dev/null +++ b/modules/light-clients/08-wasm/types/config.go @@ -0,0 +1,37 @@ +package types + +const ( + // contractMemoryLimit is the memory limit of each contract execution (in MiB) + // constant value so all nodes run with the same limit. + ContractMemoryLimit = 32 + + defaultDataDir string = "ibc_08-wasm_client_data" + defaultSupportedFeatures string = "iterator" + defaultMemoryCacheSize uint32 = 256 // in MiB + defaultContractDebugMode = false +) + +type WasmConfig struct { + // DataDir is the directory for Wasm blobs and various caches + DataDir string + // SupportedFeatures is a comma separated list of capabilities supported by the chain + // See https://github.com/CosmWasm/wasmd/blob/e5049ba686ab71164a01f6e71e54347710a1f740/app/wasm.go#L3-L15 + // for more information. + SupportedFeatures string + // MemoryCacheSize in MiB not bytes. It is not consensus-critical and should + // be defined on a per-node basis, often 100-1000 MB. + MemoryCacheSize uint32 + // ContractDebugMode is a flag to log what contracts print. It must be false on all + // production nodes, and only enabled in test environments or debug non-validating nodes. + ContractDebugMode bool +} + +// DefaultWasmConfig returns the default settings for WasmConfig +func DefaultWasmConfig() WasmConfig { + return WasmConfig{ + DataDir: defaultDataDir, + SupportedFeatures: defaultSupportedFeatures, + MemoryCacheSize: defaultMemoryCacheSize, + ContractDebugMode: defaultContractDebugMode, + } +} diff --git a/modules/light-clients/08-wasm/types/vm.go b/modules/light-clients/08-wasm/types/vm.go index 05bf25222f9..8e73564d64d 100644 --- a/modules/light-clients/08-wasm/types/vm.go +++ b/modules/light-clients/08-wasm/types/vm.go @@ -1,7 +1,7 @@ package types import ( - cosmwasm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm" wasmvmtypes "github.com/CosmWasm/wasmvm/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -9,7 +9,7 @@ import ( ) var ( - WasmVM *cosmwasm.VM + WasmVM *wasmvm.VM // Store key for 08-wasm module, required as a global so that the KV store can be retrieved // in the ClientState Initialize function which doesn't have access to the keeper. // The storeKey is used to check the code hash of the contract and determine if the light client @@ -32,7 +32,7 @@ func initContract(ctx sdk.Context, clientStore sdk.KVStore, codeHash []byte, msg } ctx.GasMeter().ConsumeGas(VMGasRegister.NewContractInstanceCosts(len(msg)), "Loading CosmWasm module: instantiate") - response, gasUsed, err := WasmVM.Instantiate(codeHash, env, msgInfo, msg, newStoreAdapter(clientStore), cosmwasm.GoAPI{}, nil, multipliedGasMeter, gasLimit, costJSONDeserialization) + response, gasUsed, err := WasmVM.Instantiate(codeHash, env, msgInfo, msg, newStoreAdapter(clientStore), wasmvm.GoAPI{}, nil, multipliedGasMeter, gasLimit, costJSONDeserialization) VMGasRegister.consumeRuntimeGas(ctx, gasUsed) return response, err } @@ -45,7 +45,7 @@ func callContract(ctx sdk.Context, clientStore sdk.KVStore, codeHash []byte, msg env := getEnv(ctx) ctx.GasMeter().ConsumeGas(VMGasRegister.InstantiateContractCosts(len(msg)), "Loading CosmWasm module: sudo") - resp, gasUsed, err := WasmVM.Sudo(codeHash, env, msg, newStoreAdapter(clientStore), cosmwasm.GoAPI{}, nil, multipliedGasMeter, gasLimit, costJSONDeserialization) + resp, gasUsed, err := WasmVM.Sudo(codeHash, env, msg, newStoreAdapter(clientStore), wasmvm.GoAPI{}, nil, multipliedGasMeter, gasLimit, costJSONDeserialization) VMGasRegister.consumeRuntimeGas(ctx, gasUsed) return resp, err } @@ -59,7 +59,7 @@ func queryContract(ctx sdk.Context, clientStore sdk.KVStore, codeHash []byte, ms env := getEnv(ctx) ctx.GasMeter().ConsumeGas(VMGasRegister.InstantiateContractCosts(len(msg)), "Loading CosmWasm module: query") - resp, gasUsed, err := WasmVM.Query(codeHash, env, msg, newStoreAdapter(clientStore), cosmwasm.GoAPI{}, nil, multipliedGasMeter, gasLimit, costJSONDeserialization) + resp, gasUsed, err := WasmVM.Query(codeHash, env, msg, newStoreAdapter(clientStore), wasmvm.GoAPI{}, nil, multipliedGasMeter, gasLimit, costJSONDeserialization) VMGasRegister.consumeRuntimeGas(ctx, gasUsed) return resp, err } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index f44561029bf..fc0f9721b51 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "math" "os" "path/filepath" @@ -465,7 +466,32 @@ func NewSimApp( ), ) - app.WasmClientKeeper = wasmkeeper.NewKeeper(appCodec, keys[wasmtypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + // 08-wasm's Keeper can be instantiated in two different ways: + // 1. If the chain uses x/wasm: + // Both x/wasm's Keeper and 08-wasm Keeper should share the same Wasm VM instance. + // - Instantiate the Wasm VM in app.go with the parameters of your choice. + // - Create an Option with this Wasm VM instance (see https://github.com/CosmWasm/wasmd/blob/v0.41.0/x/wasm/keeper/options.go#L26-L32). + // - Pass the option to the x/wasm NewKeeper contructor function (https://github.com/CosmWasm/wasmd/blob/v0.41.0/x/wasm/keeper/keeper_cgo.go#L36). + // - Pass a pointer to the Wasm VM instance to 08-wasm NewKeeperWithVM constructor function. + // + // 2. If the chain does not use x/wasm: + // Even though it is still possible to use method 1 above + // (e.g. instantiating a Wasm VM in app.go an pass it in 08-wasm NewKeeper), + // since there is no need to share the Wasm VM instance with another module + // you can use NewKeeperWithConfig constructor function and provide + // the Wasm VM configuration parameters of your choice. + // Check out the WasmConfig type definition for more information on + // each parameter. Some parameters allow node-leve configurations. + // Function DefaultWasmConfig can also be used to use default values. + // + // In the code below we use the second method because we are not using x/wasm in this app.go. + wasmConfig := wasmtypes.WasmConfig{ + DataDir: "ibc_08-wasm_client_data", + SupportedFeatures: "iterator", + MemoryCacheSize: uint32(math.Pow(2, 8)), + ContractDebugMode: false, + } + app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig(appCodec, keys[wasmtypes.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmConfig) // IBC Fee Module keeper app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(