diff --git a/modules/light-clients/08-wasm/keeper/contract_keeper.go b/modules/light-clients/08-wasm/keeper/contract_keeper.go index e812f2570e4..796e7341b81 100644 --- a/modules/light-clients/08-wasm/keeper/contract_keeper.go +++ b/modules/light-clients/08-wasm/keeper/contract_keeper.go @@ -2,18 +2,20 @@ package keeper import ( "bytes" + "context" "encoding/hex" "encoding/json" "errors" + "fmt" wasmvm "github.com/CosmWasm/wasmvm/v2" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + "cosmossdk.io/core/header" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" internaltypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/types" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -34,70 +36,79 @@ var ( ) // instantiateContract calls vm.Instantiate with appropriate arguments. -func (k Keeper) instantiateContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { - sdkGasMeter := ctx.GasMeter() +func (k Keeper) instantiateContract(ctx context.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { + sdkGasMeter := k.GasService.GasMeter(ctx) multipliedGasMeter := types.NewMultipliedGasMeter(sdkGasMeter, types.VMGasRegister) - gasLimit := VMGasRegister.RuntimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(sdkGasMeter) - env := getEnv(ctx, clientID) + env := getEnv(k.HeaderService.HeaderInfo(ctx), clientID) msgInfo := wasmvmtypes.MessageInfo{ Sender: "", Funds: nil, } - ctx.GasMeter().ConsumeGas(types.VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: instantiate") + if err := sdkGasMeter.Consume(types.VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: instantiate"); err != nil { + return nil, fmt.Errorf("failed to consume gas for Loading Cosmwasm module instantiate: %w", err) + } + resp, gasUsed, err := k.GetVM().Instantiate(checksum, env, msgInfo, msg, internaltypes.NewStoreAdapter(clientStore), wasmvmAPI, k.newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, types.CostJSONDeserialization) - types.VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) + types.VMGasRegister.ConsumeRuntimeGas(sdkGasMeter, gasUsed) return resp, err } // callContract calls vm.Sudo with internally constructed gas meter and environment. -func (k Keeper) callContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { - sdkGasMeter := ctx.GasMeter() +func (k Keeper) callContract(ctx context.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { + sdkGasMeter := k.GasService.GasMeter(ctx) multipliedGasMeter := types.NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.RuntimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(sdkGasMeter) - env := getEnv(ctx, clientID) + env := getEnv(k.HeaderService.HeaderInfo(ctx), clientID) - ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: sudo") + if err := sdkGasMeter.Consume(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: sudo"); err != nil { + return nil, fmt.Errorf("failed to consume gas for Loading Cosmwasm module sudo: %w", err) + } resp, gasUsed, err := k.GetVM().Sudo(checksum, env, msg, internaltypes.NewStoreAdapter(clientStore), wasmvmAPI, k.newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, types.CostJSONDeserialization) - VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) + VMGasRegister.ConsumeRuntimeGas(sdkGasMeter, gasUsed) return resp, err } // queryContract calls vm.Query. -func (k Keeper) queryContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.QueryResult, error) { - sdkGasMeter := ctx.GasMeter() +func (k Keeper) queryContract(ctx context.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.QueryResult, error) { + sdkGasMeter := k.GasService.GasMeter(ctx) multipliedGasMeter := types.NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.RuntimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(sdkGasMeter) - env := getEnv(ctx, clientID) + env := getEnv(k.HeaderService.HeaderInfo(ctx), clientID) - ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: query") + if err := sdkGasMeter.Consume(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: query"); err != nil { + return nil, fmt.Errorf("failed to consume gas for Loading Cosmwasm module query: %w", err) + } resp, gasUsed, err := k.GetVM().Query(checksum, env, msg, internaltypes.NewStoreAdapter(clientStore), wasmvmAPI, k.newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, types.CostJSONDeserialization) - VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) + VMGasRegister.ConsumeRuntimeGas(sdkGasMeter, gasUsed) return resp, err } // migrateContract calls vm.Migrate with internally constructed gas meter and environment. -func (k Keeper) migrateContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { - sdkGasMeter := ctx.GasMeter() +func (k Keeper) migrateContract(ctx context.Context, clientID string, clientStore storetypes.KVStore, checksum types.Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { + sdkGasMeter := k.GasService.GasMeter(ctx) multipliedGasMeter := types.NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.RuntimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(sdkGasMeter) - env := getEnv(ctx, clientID) + env := getEnv(k.HeaderService.HeaderInfo(ctx), clientID) - ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: migrate") + if err := sdkGasMeter.Consume(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: migrate"); err != nil { + return nil, fmt.Errorf("failed to consume gas for Loading Cosmwasm module migrate: %w", err) + } resp, gasUsed, err := k.GetVM().Migrate(checksum, env, msg, internaltypes.NewStoreAdapter(clientStore), wasmvmAPI, k.newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, types.CostJSONDeserialization) - VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) + VMGasRegister.ConsumeRuntimeGas(sdkGasMeter, gasUsed) return resp, err } // WasmInstantiate accepts a message to instantiate a wasm contract, JSON encodes it and calls instantiateContract. -func (k Keeper) WasmInstantiate(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, cs *types.ClientState, payload types.InstantiateMessage) error { +func (k Keeper) WasmInstantiate(ctx context.Context, clientID string, clientStore storetypes.KVStore, cs *types.ClientState, payload types.InstantiateMessage) error { encodedData, err := json.Marshal(payload) if err != nil { return errorsmod.Wrap(err, "failed to marshal payload for wasm contract instantiation") @@ -136,7 +147,7 @@ func (k Keeper) WasmInstantiate(ctx sdk.Context, clientID string, clientStore st // - the response of the contract call contains non-empty events // - the response of the contract call contains non-empty attributes // - the data bytes of the response cannot be unmarshaled into the result type -func (k Keeper) WasmSudo(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, cs *types.ClientState, payload types.SudoMsg) ([]byte, error) { +func (k Keeper) WasmSudo(ctx context.Context, clientID string, clientStore storetypes.KVStore, cs *types.ClientState, payload types.SudoMsg) ([]byte, error) { encodedData, err := json.Marshal(payload) if err != nil { return nil, errorsmod.Wrap(err, "failed to marshal payload for wasm execution") @@ -171,7 +182,7 @@ func (k Keeper) WasmSudo(ctx sdk.Context, clientID string, clientStore storetype // WasmMigrate migrate calls the migrate entry point of the contract with the given payload and returns the result. // WasmMigrate returns an error if: // - the contract migration returns an error -func (k Keeper) WasmMigrate(ctx sdk.Context, clientStore storetypes.KVStore, cs *types.ClientState, clientID string, payload []byte) error { +func (k Keeper) WasmMigrate(ctx context.Context, clientStore storetypes.KVStore, cs *types.ClientState, clientID string, payload []byte) error { res, err := k.migrateContract(ctx, clientID, clientStore, cs.Checksum, payload) if err != nil { return errorsmod.Wrap(types.ErrVMError, err.Error()) @@ -192,7 +203,7 @@ func (k Keeper) WasmMigrate(ctx sdk.Context, clientStore storetypes.KVStore, cs // WasmQuery returns an error if: // - the contract query returns an error // - the data bytes of the response cannot be unmarshal into the result type -func (k Keeper) WasmQuery(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, cs *types.ClientState, payload types.QueryMsg) ([]byte, error) { +func (k Keeper) WasmQuery(ctx context.Context, clientID string, clientStore storetypes.KVStore, cs *types.ClientState, payload types.QueryMsg) ([]byte, error) { encodedData, err := json.Marshal(payload) if err != nil { return nil, errorsmod.Wrap(err, "failed to marshal payload for wasm query") @@ -250,15 +261,15 @@ func unmarshalClientState(cdc codec.BinaryCodec, bz []byte) (exported.ClientStat } // getEnv returns the state of the blockchain environment the contract is running on -func getEnv(ctx sdk.Context, contractAddr string) wasmvmtypes.Env { - chainID := ctx.BlockHeader().ChainID - height := ctx.BlockHeader().Height +func getEnv(headerInfo header.Info, contractAddr string) wasmvmtypes.Env { + chainID := headerInfo.ChainID + height := headerInfo.Height // safety checks before casting below if height < 0 { panic(errors.New("block height must never be negative")) } - nsec := ctx.BlockTime().UnixNano() + nsec := headerInfo.Time.UnixNano() if nsec < 0 { panic(errors.New("block (unix) time must never be negative ")) } diff --git a/modules/light-clients/08-wasm/keeper/events.go b/modules/light-clients/08-wasm/keeper/events.go index 8e9801b9e45..bd6de954342 100644 --- a/modules/light-clients/08-wasm/keeper/events.go +++ b/modules/light-clients/08-wasm/keeper/events.go @@ -1,7 +1,11 @@ package keeper import ( + "context" "encoding/hex" + "errors" + + "cosmossdk.io/core/event" sdk "github.com/cosmos/cosmos-sdk/types" @@ -9,31 +13,33 @@ import ( ) // emitStoreWasmCodeEvent emits a store wasm code event -func emitStoreWasmCodeEvent(ctx sdk.Context, checksum types.Checksum) { - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( +func (k Keeper) emitStoreWasmCodeEvent(ctx context.Context, checksum types.Checksum) error { + em := k.EventService.EventManager(ctx) + return errors.Join( + em.EmitKV( types.EventTypeStoreWasmCode, - sdk.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(checksum)), + event.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(checksum)), ), - sdk.NewEvent( + em.EmitKV( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + event.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), ), - }) + ) } // emitMigrateContractEvent emits a migrate contract event -func emitMigrateContractEvent(ctx sdk.Context, clientID string, checksum, newChecksum types.Checksum) { - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( +func (k Keeper) emitMigrateContractEvent(ctx context.Context, clientID string, checksum, newChecksum types.Checksum) error { + em := k.EventService.EventManager(ctx) + return errors.Join( + em.EmitKV( types.EventTypeMigrateContract, - sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(checksum)), - sdk.NewAttribute(types.AttributeKeyNewChecksum, hex.EncodeToString(newChecksum)), + event.NewAttribute(types.AttributeKeyClientID, clientID), + event.NewAttribute(types.AttributeKeyWasmChecksum, hex.EncodeToString(checksum)), + event.NewAttribute(types.AttributeKeyNewChecksum, hex.EncodeToString(newChecksum)), ), - sdk.NewEvent( + em.EmitKV( sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + event.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), ), - }) + ) } diff --git a/modules/light-clients/08-wasm/keeper/grpc_query.go b/modules/light-clients/08-wasm/keeper/grpc_query.go index 21b2a558894..a2907499561 100644 --- a/modules/light-clients/08-wasm/keeper/grpc_query.go +++ b/modules/light-clients/08-wasm/keeper/grpc_query.go @@ -10,7 +10,6 @@ import ( "cosmossdk.io/collections" errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" sdkquery "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -19,7 +18,7 @@ import ( var _ types.QueryServer = (*Keeper)(nil) // Code implements the Query/Code gRPC method -func (k Keeper) Code(goCtx context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) { +func (k Keeper) Code(ctx context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } @@ -30,7 +29,7 @@ func (k Keeper) Code(goCtx context.Context, req *types.QueryCodeRequest) (*types } // Only return checksums we previously stored, not arbitrary checksums that might be stored via e.g Wasmd. - if !k.HasChecksum(sdk.UnwrapSDKContext(goCtx), checksum) { + if !k.HasChecksum(ctx, checksum) { return nil, status.Error(codes.NotFound, errorsmod.Wrap(types.ErrWasmChecksumNotFound, req.Checksum).Error()) } diff --git a/modules/light-clients/08-wasm/keeper/keeper.go b/modules/light-clients/08-wasm/keeper/keeper.go index 0be1bb9064c..414ce52e097 100644 --- a/modules/light-clients/08-wasm/keeper/keeper.go +++ b/modules/light-clients/08-wasm/keeper/keeper.go @@ -4,24 +4,24 @@ import ( "bytes" "context" "encoding/hex" + "fmt" wasmvm "github.com/CosmWasm/wasmvm/v2" "cosmossdk.io/collections" - "cosmossdk.io/core/store" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/log" errorsmod "cosmossdk.io/errors" - "cosmossdk.io/log" "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v9/modules/core/exported" ) // Keeper defines the 08-wasm keeper type Keeper struct { + appmodule.Environment // implements gRPC QueryServer interface types.QueryServer @@ -30,8 +30,7 @@ type Keeper struct { vm types.WasmEngine - checksums collections.KeySet[[]byte] - storeService store.KVStoreService + checksums collections.KeySet[[]byte] queryPlugins QueryPlugins @@ -49,12 +48,8 @@ func (k Keeper) GetAuthority() string { } // Logger returns a module-specific logger. -func (Keeper) Logger(ctx sdk.Context) log.Logger { - return moduleLogger(ctx) -} - -func moduleLogger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+exported.ModuleName+"-"+types.ModuleName) +func (k Keeper) Logger() log.Logger { + return k.Environment.Logger } // GetVM returns the keeper's vm engine. @@ -77,8 +72,8 @@ func (k *Keeper) setQueryPlugins(plugins QueryPlugins) { k.queryPlugins = plugins } -func (k Keeper) newQueryHandler(ctx sdk.Context, callerID string) *queryHandler { - return newQueryHandler(ctx, k.getQueryPlugins(), callerID) +func (k Keeper) newQueryHandler(ctx context.Context, callerID string) *queryHandler { + return newQueryHandler(ctx, k.Environment, k.getQueryPlugins(), callerID) } // storeWasmCode stores the contract to the VM, pins the checksum in the VM's in memory cache and stores the checksum @@ -87,10 +82,12 @@ func (k Keeper) newQueryHandler(ctx sdk.Context, callerID string) *queryHandler // - Size bounds are checked. Contract length must not be 0 or exceed a specific size (maxWasmSize). // - The contract must not have already been stored in store. func (k Keeper) storeWasmCode(ctx context.Context, code []byte, storeFn func(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error)) ([]byte, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 + meter := k.GasService.GasMeter(ctx) var err error if types.IsGzip(code) { - sdkCtx.GasMeter().ConsumeGas(types.VMGasRegister.UncompressCosts(len(code)), "Uncompress gzip bytecode") + if err := meter.Consume(types.VMGasRegister.UncompressCosts(len(code)), "Uncompress gzip bytecode"); err != nil { + return nil, fmt.Errorf("failed to consume gas for Uncompress gzip bytecode: %w", err) + } code, err = types.Uncompress(code, types.MaxWasmSize) if err != nil { return nil, errorsmod.Wrap(err, "failed to store contract") @@ -113,9 +110,9 @@ func (k Keeper) storeWasmCode(ctx context.Context, code []byte, storeFn func(cod } // create the code in the vm - gasLeft := types.VMGasRegister.RuntimeGasForContract(sdkCtx) + gasLeft := types.VMGasRegister.RuntimeGasForContract(meter) vmChecksum, gasUsed, err := storeFn(code, gasLeft) - types.VMGasRegister.ConsumeRuntimeGas(sdkCtx, gasUsed) + types.VMGasRegister.ConsumeRuntimeGas(meter, gasUsed) if err != nil { return nil, errorsmod.Wrap(err, "failed to store contract") } @@ -141,7 +138,7 @@ func (k Keeper) storeWasmCode(ctx context.Context, code []byte, storeFn func(cod // migrateContractCode migrates the contract for a given light client to one denoted by the given new checksum. The checksum we // are migrating to must first be stored using storeWasmCode and must not match the checksum currently stored for this light client. -func (k Keeper) migrateContractCode(ctx sdk.Context, clientID string, newChecksum, migrateMsg []byte) error { +func (k Keeper) migrateContractCode(ctx context.Context, clientID string, newChecksum, migrateMsg []byte) error { clientStore := k.clientKeeper.ClientStore(ctx, clientID) wasmClientState, found := types.GetClientState(clientStore, k.cdc) if !found { @@ -180,13 +177,15 @@ func (k Keeper) migrateContractCode(ctx sdk.Context, clientID string, newChecksu k.clientKeeper.SetClientState(ctx, clientID, wasmClientState) - emitMigrateContractEvent(ctx, clientID, oldChecksum, newChecksum) + if err = k.emitMigrateContractEvent(ctx, clientID, oldChecksum, newChecksum); err != nil { + return fmt.Errorf("failed to emit migrate contract events: %w", err) + } return nil } // GetWasmClientState returns the 08-wasm client state for the given client identifier. -func (k Keeper) GetWasmClientState(ctx sdk.Context, clientID string) (*types.ClientState, error) { +func (k Keeper) GetWasmClientState(ctx context.Context, clientID string) (*types.ClientState, error) { clientState, found := k.clientKeeper.GetClientState(ctx, clientID) if !found { return nil, errorsmod.Wrapf(clienttypes.ErrClientTypeNotFound, "clientID %s", clientID) @@ -233,7 +232,7 @@ func (k Keeper) HasChecksum(ctx context.Context, checksum types.Checksum) bool { } // InitializePinnedCodes updates wasmvm to pin to cache all contracts marked as pinned -func (k Keeper) InitializePinnedCodes(ctx sdk.Context) error { +func (k Keeper) InitializePinnedCodes(ctx context.Context) error { checksums, err := k.GetAllChecksums(ctx) if err != nil { return err diff --git a/modules/light-clients/08-wasm/keeper/keeper_no_vm.go b/modules/light-clients/08-wasm/keeper/keeper_no_vm.go index 5dcacf5a176..2767800a0c3 100644 --- a/modules/light-clients/08-wasm/keeper/keeper_no_vm.go +++ b/modules/light-clients/08-wasm/keeper/keeper_no_vm.go @@ -15,6 +15,7 @@ import ( // custom build directive: nolink_libwasmvm. // This function is intended to panic and notify users that 08-wasm keeper functionality is not available. func NewKeeperWithVM( + _ environment.Environment, _ codec.BinaryCodec, _ storetypes.KVStoreService, _ types.ClientKeeper, @@ -31,6 +32,7 @@ func NewKeeperWithVM( // custom build directive: nolink_libwasmvm. // This function is intended to panic and notify users that 08-wasm keeper functionality is not available. func NewKeeperWithConfig( + _ environment.Environment, _ codec.BinaryCodec, _ storetypes.KVStoreService, _ types.ClientKeeper, diff --git a/modules/light-clients/08-wasm/keeper/keeper_test.go b/modules/light-clients/08-wasm/keeper/keeper_test.go index 9974671d270..9dd17e958f3 100644 --- a/modules/light-clients/08-wasm/keeper/keeper_test.go +++ b/modules/light-clients/08-wasm/keeper/keeper_test.go @@ -152,8 +152,8 @@ func (suite *KeeperTestSuite) TestNewKeeper() { "success", func() { keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -167,8 +167,8 @@ func (suite *KeeperTestSuite) TestNewKeeper() { "failure: empty authority", func() { keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, "", // authority GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -182,8 +182,8 @@ func (suite *KeeperTestSuite) TestNewKeeper() { "failure: nil client keeper", func() { keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), nil, // client keeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -197,8 +197,8 @@ func (suite *KeeperTestSuite) TestNewKeeper() { "failure: nil wasm VM", func() { keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), nil, @@ -212,8 +212,8 @@ func (suite *KeeperTestSuite) TestNewKeeper() { "failure: nil store service", func() { keeper.NewKeeperWithVM( + runtime.NewEnvironment(nil, log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - nil, GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -227,8 +227,8 @@ func (suite *KeeperTestSuite) TestNewKeeper() { "failure: nil query router", func() { keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), diff --git a/modules/light-clients/08-wasm/keeper/keeper_vm.go b/modules/light-clients/08-wasm/keeper/keeper_vm.go index bcaf2fafa72..70334a32b74 100644 --- a/modules/light-clients/08-wasm/keeper/keeper_vm.go +++ b/modules/light-clients/08-wasm/keeper/keeper_vm.go @@ -10,7 +10,7 @@ import ( wasmvm "github.com/CosmWasm/wasmvm/v2" "cosmossdk.io/collections" - "cosmossdk.io/core/store" + "cosmossdk.io/core/appmodule" "github.com/cosmos/cosmos-sdk/codec" @@ -21,8 +21,8 @@ import ( // 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( + env appmodule.Environment, cdc codec.BinaryCodec, - storeService store.KVStoreService, clientKeeper types.ClientKeeper, authority string, vm types.WasmEngine, @@ -33,6 +33,10 @@ func NewKeeperWithVM( panic(errors.New("client keeper must not be nil")) } + if env.KVStoreService == nil { + panic(errors.New("store service must not be nil")) + } + if queryRouter == nil { panic(errors.New("query router must not be nil")) } @@ -41,21 +45,17 @@ func NewKeeperWithVM( panic(errors.New("wasm VM must not be nil")) } - if storeService == nil { - panic(errors.New("store service must not be nil")) - } - if strings.TrimSpace(authority) == "" { panic(errors.New("authority must be non-empty")) } - sb := collections.NewSchemaBuilder(storeService) + sb := collections.NewSchemaBuilder(env.KVStoreService) keeper := &Keeper{ + Environment: env, cdc: cdc, vm: vm, checksums: collections.NewKeySet(sb, types.ChecksumsKey, "checksums", collections.BytesKey), - storeService: storeService, clientKeeper: clientKeeper, authority: authority, } @@ -80,8 +80,8 @@ func NewKeeperWithVM( // 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( + env appmodule.Environment, cdc codec.BinaryCodec, - storeService store.KVStoreService, clientKeeper types.ClientKeeper, authority string, wasmConfig types.WasmConfig, @@ -93,5 +93,5 @@ func NewKeeperWithConfig( panic(fmt.Errorf("failed to instantiate new Wasm VM instance: %v", err)) } - return NewKeeperWithVM(cdc, storeService, clientKeeper, authority, vm, queryRouter, opts...) + return NewKeeperWithVM(env, cdc, clientKeeper, authority, vm, queryRouter, opts...) } diff --git a/modules/light-clients/08-wasm/keeper/migrations.go b/modules/light-clients/08-wasm/keeper/migrations.go index 45005d625df..1888ae6af54 100644 --- a/modules/light-clients/08-wasm/keeper/migrations.go +++ b/modules/light-clients/08-wasm/keeper/migrations.go @@ -3,8 +3,6 @@ package keeper import ( "context" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ) @@ -26,8 +24,7 @@ func NewMigrator(keeper Keeper) Migrator { // It grabs the checksums stored previously under the old key and stores // them in the global KeySet collection. It then deletes the old key and // the checksums stored under it. -func (m Migrator) MigrateChecksums(goCtx context.Context) error { - ctx := sdk.UnwrapSDKContext(goCtx) +func (m Migrator) MigrateChecksums(ctx context.Context) error { checksums, err := m.getStoredChecksums(ctx) if err != nil { return err @@ -44,13 +41,13 @@ func (m Migrator) MigrateChecksums(goCtx context.Context) error { return err } - m.keeper.Logger(ctx).Info("successfully migrated Checksums to collections") + m.keeper.Logger().Info("successfully migrated Checksums to collections") return nil } // getStoredChecksums returns the checksums stored under the KeyChecksums key. -func (m Migrator) getStoredChecksums(ctx sdk.Context) ([][]byte, error) { - store := m.keeper.storeService.OpenKVStore(ctx) +func (m Migrator) getStoredChecksums(ctx context.Context) ([][]byte, error) { + store := m.keeper.KVStoreService.OpenKVStore(ctx) bz, err := store.Get([]byte(types.KeyChecksums)) if err != nil { @@ -67,8 +64,8 @@ func (m Migrator) getStoredChecksums(ctx sdk.Context) ([][]byte, error) { } // deleteChecksums deletes the checksums stored under the KeyChecksums key. -func (m Migrator) deleteChecksums(ctx sdk.Context) error { - store := m.keeper.storeService.OpenKVStore(ctx) +func (m Migrator) deleteChecksums(ctx context.Context) error { + store := m.keeper.KVStoreService.OpenKVStore(ctx) err := store.Delete([]byte(types.KeyChecksums)) return err diff --git a/modules/light-clients/08-wasm/keeper/msg_server.go b/modules/light-clients/08-wasm/keeper/msg_server.go index d08063d6630..45a9422f355 100644 --- a/modules/light-clients/08-wasm/keeper/msg_server.go +++ b/modules/light-clients/08-wasm/keeper/msg_server.go @@ -3,11 +3,10 @@ package keeper import ( "context" "encoding/hex" + "fmt" errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" ) @@ -15,18 +14,19 @@ import ( var _ types.MsgServer = (*Keeper)(nil) // StoreCode defines a rpc handler method for MsgStoreCode -func (k Keeper) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*types.MsgStoreCodeResponse, error) { +func (k Keeper) StoreCode(ctx context.Context, msg *types.MsgStoreCode) (*types.MsgStoreCodeResponse, error) { if k.GetAuthority() != msg.Signer { return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) } - ctx := sdk.UnwrapSDKContext(goCtx) checksum, err := k.storeWasmCode(ctx, msg.WasmByteCode, k.GetVM().StoreCode) if err != nil { return nil, errorsmod.Wrap(err, "failed to store wasm bytecode") } - emitStoreWasmCodeEvent(ctx, checksum) + if err := k.emitStoreWasmCodeEvent(ctx, checksum); err != nil { + return nil, fmt.Errorf("failed to emit store wasm code events: %w", err) + } return &types.MsgStoreCodeResponse{ Checksum: checksum, @@ -57,13 +57,11 @@ func (k Keeper) RemoveChecksum(goCtx context.Context, msg *types.MsgRemoveChecks } // MigrateContract defines a rpc handler method for MsgMigrateContract -func (k Keeper) MigrateContract(goCtx context.Context, msg *types.MsgMigrateContract) (*types.MsgMigrateContractResponse, error) { +func (k Keeper) MigrateContract(ctx context.Context, msg *types.MsgMigrateContract) (*types.MsgMigrateContractResponse, error) { if k.GetAuthority() != msg.Signer { return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) } - ctx := sdk.UnwrapSDKContext(goCtx) - err := k.migrateContractCode(ctx, msg.ClientId, msg.Checksum, msg.Msg) if err != nil { return nil, errorsmod.Wrap(err, "failed to migrate contract") diff --git a/modules/light-clients/08-wasm/keeper/options_test.go b/modules/light-clients/08-wasm/keeper/options_test.go index bec7233df21..3256cba2c92 100644 --- a/modules/light-clients/08-wasm/keeper/options_test.go +++ b/modules/light-clients/08-wasm/keeper/options_test.go @@ -1,11 +1,14 @@ package keeper_test import ( + "context" "encoding/json" "errors" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,14 +16,14 @@ import ( "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ) -func mockErrorCustomQuerier() func(sdk.Context, json.RawMessage) ([]byte, error) { - return func(_ sdk.Context, _ json.RawMessage) ([]byte, error) { +func mockErrorCustomQuerier() func(context.Context, json.RawMessage) ([]byte, error) { + return func(_ context.Context, _ json.RawMessage) ([]byte, error) { return nil, errors.New("custom querier error for TestNewKeeperWithOptions") } } -func mockErrorStargateQuerier() func(sdk.Context, *wasmvmtypes.StargateQuery) ([]byte, error) { - return func(_ sdk.Context, _ *wasmvmtypes.StargateQuery) ([]byte, error) { +func mockErrorStargateQuerier() func(context.Context, *wasmvmtypes.StargateQuery) ([]byte, error) { + return func(_ context.Context, _ *wasmvmtypes.StargateQuery) ([]byte, error) { return nil, errors.New("stargate querier error for TestNewKeeperWithOptions") } } @@ -36,8 +39,8 @@ func (suite *KeeperTestSuite) TestNewKeeperWithOptions() { "success: no options", func() { k = keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -61,8 +64,8 @@ func (suite *KeeperTestSuite) TestNewKeeperWithOptions() { Custom: mockErrorCustomQuerier(), }) k = keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -87,8 +90,8 @@ func (suite *KeeperTestSuite) TestNewKeeperWithOptions() { Stargate: mockErrorStargateQuerier(), }) k = keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), @@ -114,8 +117,8 @@ func (suite *KeeperTestSuite) TestNewKeeperWithOptions() { Stargate: mockErrorStargateQuerier(), }) k = keeper.NewKeeperWithVM( + runtime.NewEnvironment(runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), log.NewNopLogger()), GetSimApp(suite.chainA).AppCodec(), - runtime.NewKVStoreService(GetSimApp(suite.chainA).GetKey(types.StoreKey)), GetSimApp(suite.chainA).IBCKeeper.ClientKeeper, GetSimApp(suite.chainA).WasmClientKeeper.GetAuthority(), GetSimApp(suite.chainA).WasmClientKeeper.GetVM(), diff --git a/modules/light-clients/08-wasm/keeper/querier.go b/modules/light-clients/08-wasm/keeper/querier.go index 20fa56b6ca0..c167f44fd96 100644 --- a/modules/light-clients/08-wasm/keeper/querier.go +++ b/modules/light-clients/08-wasm/keeper/querier.go @@ -1,14 +1,15 @@ package keeper import ( + "context" "encoding/json" "fmt" "slices" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + "cosmossdk.io/core/appmodule" errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -36,52 +37,54 @@ var defaultAcceptList = []string{ "/ibc.core.client.v1.Query/VerifyMembership", } -// queryHandler is a wrapper around the sdk.Context and the CallerID that calls +// queryHandler is a wrapper around the sdk Environment and the CallerID that calls // into the query plugins. type queryHandler struct { - Ctx sdk.Context + appmodule.Environment + Ctx context.Context Plugins QueryPlugins CallerID string } // newQueryHandler returns a default querier that can be used in the contract. -func newQueryHandler(ctx sdk.Context, plugins QueryPlugins, callerID string) *queryHandler { +func newQueryHandler(ctx context.Context, env appmodule.Environment, plugins QueryPlugins, callerID string) *queryHandler { return &queryHandler{ - Ctx: ctx, - Plugins: plugins, - CallerID: callerID, + Ctx: ctx, + Environment: env, + Plugins: plugins, + CallerID: callerID, } } // GasConsumed implements the wasmvmtypes.Querier interface. func (q *queryHandler) GasConsumed() uint64 { - return VMGasRegister.ToWasmVMGas(q.Ctx.GasMeter().GasConsumed()) + return VMGasRegister.ToWasmVMGas(q.GasService.GasMeter(q.Ctx).Consumed()) } // Query implements the wasmvmtypes.Querier interface. func (q *queryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) ([]byte, error) { - sdkGas := VMGasRegister.FromWasmVMGas(gasLimit) - + sdkGasLimit := VMGasRegister.FromWasmVMGas(gasLimit) // discard all changes/events in subCtx by not committing the cached context - subCtx, _ := q.Ctx.WithGasMeter(storetypes.NewGasMeter(sdkGas)).CacheContext() - - // make sure we charge the higher level context even on panic - defer func() { - q.Ctx.GasMeter().ConsumeGas(subCtx.GasMeter().GasConsumed(), "contract sub-query") - }() + var res []byte + _, err := q.BranchService.ExecuteWithGasLimit(q.Ctx, sdkGasLimit, func(ctx context.Context) error { + var err error + res, err = q.Plugins.HandleQuery(ctx, q.CallerID, request) + if err == nil { + return nil + } - res, err := q.Plugins.HandleQuery(subCtx, q.CallerID, request) - if err == nil { - return res, nil + q.Logger.Debug("Redacting query error", "cause", err) + return err + }) + if err != nil { + return nil, redactError(err) } - - moduleLogger(q.Ctx).Debug("Redacting query error", "cause", err) - return nil, redactError(err) + return res, nil } type ( - CustomQuerier func(ctx sdk.Context, request json.RawMessage) ([]byte, error) - StargateQuerier func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) + CustomQuerier func(ctx context.Context, request json.RawMessage) ([]byte, error) + StargateQuerier func(ctx context.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) // QueryPlugins is a list of queriers that can be used to extend the default querier. QueryPlugins struct { @@ -109,7 +112,7 @@ func (e QueryPlugins) Merge(x *QueryPlugins) QueryPlugins { } // HandleQuery implements the ibcwasm.QueryPluginsI interface. -func (e QueryPlugins) HandleQuery(ctx sdk.Context, caller string, request wasmvmtypes.QueryRequest) ([]byte, error) { +func (e QueryPlugins) HandleQuery(ctx context.Context, caller string, request wasmvmtypes.QueryRequest) ([]byte, error) { if request.Stargate != nil { return e.Stargate(ctx, request.Stargate) } @@ -131,8 +134,8 @@ func NewDefaultQueryPlugins(queryRouter types.QueryRouter) QueryPlugins { // AcceptListStargateQuerier allows all queries that are in the provided accept list. // This function returns protobuf encoded responses in bytes. -func AcceptListStargateQuerier(acceptedQueries []string, queryRouter types.QueryRouter) func(sdk.Context, *wasmvmtypes.StargateQuery) ([]byte, error) { - return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { +func AcceptListStargateQuerier(acceptedQueries []string, queryRouter types.QueryRouter) func(context.Context, *wasmvmtypes.StargateQuery) ([]byte, error) { + return func(ctx context.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { // append user defined accepted queries to default list defined above. acceptedQueries = append(defaultAcceptList, acceptedQueries...) @@ -146,7 +149,7 @@ func AcceptListStargateQuerier(acceptedQueries []string, queryRouter types.Query return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", request.Path)} } - res, err := route(ctx, &abci.QueryRequest{ + res, err := route(sdk.UnwrapSDKContext(ctx), &abci.QueryRequest{ Data: request.Data, Path: request.Path, }) @@ -162,8 +165,8 @@ func AcceptListStargateQuerier(acceptedQueries []string, queryRouter types.Query } // RejectCustomQuerier rejects all custom queries -func RejectCustomQuerier() func(sdk.Context, json.RawMessage) ([]byte, error) { - return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) { +func RejectCustomQuerier() func(context.Context, json.RawMessage) ([]byte, error) { + return func(ctx context.Context, request json.RawMessage) ([]byte, error) { return nil, wasmvmtypes.UnsupportedRequest{Kind: "Custom queries are not allowed"} } } diff --git a/modules/light-clients/08-wasm/keeper/querier_test.go b/modules/light-clients/08-wasm/keeper/querier_test.go index e1b31efe032..252a1bd94b5 100644 --- a/modules/light-clients/08-wasm/keeper/querier_test.go +++ b/modules/light-clients/08-wasm/keeper/querier_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "context" "encoding/hex" "encoding/json" "fmt" @@ -9,8 +10,6 @@ import ( wasmvm "github.com/CosmWasm/wasmvm/v2" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -27,8 +26,8 @@ type QueryEcho struct { Data string `json:"data"` } -func mockCustomQuerier() func(sdk.Context, json.RawMessage) ([]byte, error) { - return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) { +func mockCustomQuerier() func(context.Context, json.RawMessage) ([]byte, error) { + return func(ctx context.Context, request json.RawMessage) ([]byte, error) { var customQuery CustomQuery err := json.Unmarshal([]byte(request), &customQuery) if err != nil { diff --git a/modules/light-clients/08-wasm/keeper/snapshotter.go b/modules/light-clients/08-wasm/keeper/snapshotter.go index fa8163c64c2..af0b221cbbd 100644 --- a/modules/light-clients/08-wasm/keeper/snapshotter.go +++ b/modules/light-clients/08-wasm/keeper/snapshotter.go @@ -91,15 +91,15 @@ func (ws *WasmSnapshotter) SnapshotExtension(height uint64, payloadWriter snapsh // RestoreExtension implements the snapshot.ExtensionSnapshotter interface. // RestoreExtension is used to read data from an existing extension state snapshot into the 08-wasm module. // The payload reader returns io.EOF when it has reached the end of the extension state snapshot. -func (ws *WasmSnapshotter) RestoreExtension(height uint64, format uint32, payloadReader snapshot.ExtensionPayloadReader) error { +func (ws *WasmSnapshotter) RestoreExtension(_ uint64, format uint32, payloadReader snapshot.ExtensionPayloadReader) error { if format == ws.SnapshotFormat() { - return ws.processAllItems(height, payloadReader, restoreV1) + return ws.processAllItems(payloadReader, restoreV1) } return errorsmod.Wrapf(snapshot.ErrUnknownFormat, "expected %d, got %d", ws.SnapshotFormat(), format) } -func restoreV1(ctx sdk.Context, k *Keeper, compressedCode []byte) error { +func restoreV1(k *Keeper, compressedCode []byte) error { if !types.IsGzip(compressedCode) { return errorsmod.Wrap(types.ErrInvalidData, "expected wasm code is not gzip format") } @@ -122,11 +122,9 @@ func restoreV1(ctx sdk.Context, k *Keeper, compressedCode []byte) error { } func (ws *WasmSnapshotter) processAllItems( - height uint64, payloadReader snapshot.ExtensionPayloadReader, - cb func(sdk.Context, *Keeper, []byte) error, + cb func(*Keeper, []byte) error, ) error { - ctx := sdk.NewContext(ws.cms, false, nil).WithBlockHeight(int64(height)) for { payload, err := payloadReader() if err == io.EOF { @@ -135,7 +133,7 @@ func (ws *WasmSnapshotter) processAllItems( return err } - if err := cb(ctx, ws.keeper, payload); err != nil { + if err := cb(ws.keeper, payload); err != nil { return errorsmod.Wrap(err, "failure processing snapshot item") } } diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index cd88887418e..5b0680e3b49 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -9,8 +9,6 @@ import ( errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - internaltypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/types" wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -71,8 +69,7 @@ func (l LightClientModule) Initialize(ctx context.Context, clientID string, clie Checksum: clientState.Checksum, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - return l.keeper.WasmInstantiate(sdkCtx, clientID, clientStore, &clientState, payload) + return l.keeper.WasmInstantiate(ctx, clientID, clientStore, &clientState, payload) } // VerifyClientMessage obtains the client state associated with the client identifier, it then must verify the ClientMessage. @@ -97,8 +94,7 @@ func (l LightClientModule) VerifyClientMessage(ctx context.Context, clientID str payload := types.QueryMsg{ VerifyClientMessage: &types.VerifyClientMessageMsg{ClientMessage: clientMessage.Data}, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - _, err := l.keeper.WasmQuery(sdkCtx, clientID, clientStore, clientState, payload) + _, err := l.keeper.WasmQuery(ctx, clientID, clientStore, clientState, payload) return err } @@ -122,8 +118,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx context.Context, clientID st CheckForMisbehaviour: &types.CheckForMisbehaviourMsg{ClientMessage: clientMessage.Data}, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - res, err := l.keeper.WasmQuery(sdkCtx, clientID, clientStore, clientState, payload) + res, err := l.keeper.WasmQuery(ctx, clientID, clientStore, clientState, payload) if err != nil { return false } @@ -157,8 +152,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx context.Context, client UpdateStateOnMisbehaviour: &types.UpdateStateOnMisbehaviourMsg{ClientMessage: clientMessage.Data}, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - _, err := l.keeper.WasmSudo(sdkCtx, clientID, clientStore, clientState, payload) + _, err := l.keeper.WasmSudo(ctx, clientID, clientStore, clientState, payload) if err != nil { panic(err) } @@ -184,8 +178,7 @@ func (l LightClientModule) UpdateState(ctx context.Context, clientID string, cli UpdateState: &types.UpdateStateMsg{ClientMessage: clientMessage.Data}, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - res, err := l.keeper.WasmSudo(sdkCtx, clientID, clientStore, clientState, payload) + res, err := l.keeper.WasmSudo(ctx, clientID, clientStore, clientState, payload) if err != nil { panic(err) } @@ -253,8 +246,7 @@ func (l LightClientModule) VerifyMembership( }, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - _, err := l.keeper.WasmSudo(sdkCtx, clientID, clientStore, clientState, payload) + _, err := l.keeper.WasmSudo(ctx, clientID, clientStore, clientState, payload) return err } @@ -306,8 +298,7 @@ func (l LightClientModule) VerifyNonMembership( }, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - _, err := l.keeper.WasmSudo(sdkCtx, clientID, clientStore, clientState, payload) + _, err := l.keeper.WasmSudo(ctx, clientID, clientStore, clientState, payload) return err } @@ -336,8 +327,7 @@ func (l LightClientModule) Status(ctx context.Context, clientID string) exported } payload := types.QueryMsg{Status: &types.StatusMsg{}} - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - res, err := l.keeper.WasmQuery(sdkCtx, clientID, clientStore, clientState, payload) + res, err := l.keeper.WasmQuery(ctx, clientID, clientStore, clientState, payload) if err != nil { return exported.Unknown } @@ -386,8 +376,7 @@ func (l LightClientModule) TimestampAtHeight(ctx context.Context, clientID strin }, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - res, err := l.keeper.WasmQuery(sdkCtx, clientID, clientStore, clientState, payload) + res, err := l.keeper.WasmQuery(ctx, clientID, clientStore, clientState, payload) if err != nil { return 0, errorsmod.Wrapf(err, "height (%s)", height) } @@ -440,8 +429,7 @@ func (l LightClientModule) RecoverClient(ctx context.Context, clientID, substitu MigrateClientStore: &types.MigrateClientStoreMsg{}, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - _, err = l.keeper.WasmSudo(sdkCtx, clientID, store, subjectClientState, payload) + _, err = l.keeper.WasmSudo(ctx, clientID, store, subjectClientState, payload) return err } @@ -489,7 +477,6 @@ func (l LightClientModule) VerifyUpgradeAndUpdateState( }, } - sdkCtx := sdk.UnwrapSDKContext(ctx) // TODO: https://github.com/cosmos/ibc-go/issues/5917 - _, err := l.keeper.WasmSudo(sdkCtx, clientID, clientStore, clientState, payload) + _, err := l.keeper.WasmSudo(ctx, clientID, clientStore, clientState, payload) return err } diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index 90cc9d4e8de..5f895f14dba 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -548,12 +548,15 @@ func NewSimApp( if mockVM != nil { // NOTE: mockVM is used for testing purposes only! app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( - appCodec, runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, + runtime.NewEnvironment(runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), logger.With(log.ModuleKey, "x/ibc-wasm")), + appCodec, app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), mockVM, app.GRPCQueryRouter(), ) } else { app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( - appCodec, runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, + runtime.NewEnvironment( + runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), logger.With(log.ModuleKey, "x/ibc-wasm")), + appCodec, app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmConfig, app.GRPCQueryRouter(), ) } diff --git a/modules/light-clients/08-wasm/types/gas_register_custom.go b/modules/light-clients/08-wasm/types/gas_register_custom.go index 991d8779c43..524bae342d9 100644 --- a/modules/light-clients/08-wasm/types/gas_register_custom.go +++ b/modules/light-clients/08-wasm/types/gas_register_custom.go @@ -1,14 +1,14 @@ package types import ( + "fmt" "math" wasmvm "github.com/CosmWasm/wasmvm/v2" wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + "cosmossdk.io/core/gas" storetypes "cosmossdk.io/store/types" - - sdk "github.com/cosmos/cosmos-sdk/types" ) // While gas_register.go is a direct copy of https://github.com/CosmWasm/wasmd/blob/main/x/wasm/types/gas_register.go @@ -24,39 +24,47 @@ var CostJSONDeserialization = wasmvmtypes.UFraction{ Denominator: 1, } -func (g WasmGasRegister) RuntimeGasForContract(ctx sdk.Context) uint64 { - meter := ctx.GasMeter() - if meter.IsOutOfGas() { +func (g WasmGasRegister) RuntimeGasForContract(meter gas.Meter) uint64 { + if meter.Remaining() >= meter.Limit() { return 0 } // infinite gas meter with limit=0 or MaxUint64 if meter.Limit() == 0 || meter.Limit() == math.MaxUint64 { return math.MaxUint64 } - return g.ToWasmVMGas(meter.Limit() - meter.GasConsumedToLimit()) + var consumedToLimit gas.Gas + if meter.Remaining() <= meter.Limit() { + consumedToLimit = meter.Limit() + } else { + consumedToLimit = meter.Consumed() + } + return g.ToWasmVMGas(meter.Limit() - consumedToLimit) } -func (g WasmGasRegister) ConsumeRuntimeGas(ctx sdk.Context, gas uint64) { - consumed := g.FromWasmVMGas(gas) - ctx.GasMeter().ConsumeGas(consumed, "wasm contract") - // throw OutOfGas error if we ran out (got exactly to zero due to better limit enforcing) - if ctx.GasMeter().IsOutOfGas() { +func (g WasmGasRegister) ConsumeRuntimeGas(meter gas.Meter, gasAmt uint64) { + consumed := g.FromWasmVMGas(gasAmt) + if err := meter.Consume(consumed, "wasm contract"); err != nil { + panic(fmt.Errorf("ConsumeRuntimeGas: failed to consume gas: %w", err)) + } + + if meter.Consumed() >= meter.Limit() { + // throw OutOfGas error if we ran out (got exactly to zero due to better limit enforcing) panic(storetypes.ErrorOutOfGas{Descriptor: "Wasmer function execution"}) } } // MultipliedGasMeter wraps the GasMeter from context and multiplies all reads by out defined multiplier type MultipliedGasMeter struct { - originalMeter storetypes.GasMeter + originalMeter gas.Meter GasRegister GasRegister } -func NewMultipliedGasMeter(originalMeter storetypes.GasMeter, gr GasRegister) MultipliedGasMeter { +func NewMultipliedGasMeter(originalMeter gas.Meter, gr GasRegister) MultipliedGasMeter { return MultipliedGasMeter{originalMeter: originalMeter, GasRegister: gr} } var _ wasmvm.GasMeter = MultipliedGasMeter{} func (m MultipliedGasMeter) GasConsumed() storetypes.Gas { - return m.GasRegister.ToWasmVMGas(m.originalMeter.GasConsumed()) + return m.GasRegister.ToWasmVMGas(m.originalMeter.Consumed()) }