From 3511d88b41be2a450a52d6849002f4c8bf785f0f Mon Sep 17 00:00:00 2001 From: Reece Williams <31943163+Reecepbcups@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:29:41 -0500 Subject: [PATCH] feat!: integrate cosmwasm (#3051) * integrate wasmd into gaia * lint * upload contract script example * add to upgrade handler * lint * rm: windows & arm64 * docker libwasmvm_muslc wasmvm * actually set wasmd params in upgrade * add sleeps * Dockerfile use alpine3.18 Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> * arm64, WASMVM_VERSION, LINK_STATICALLY, AllCapabilities() * security: sha256sum wasmvm libwasmvm * appease linter * tests: use CGO, use correct libwasm; add CGO to runner img * tests: enable CGO in upgrade tests * tests: bump hermes version * tests: print output for upgrate test * tests: print output for upgrate test * attempt building in upgrade container * attempt building in upgrade container * tests: attempt building in upgrade container * tests: correctly download libwasmvm DLLs * chore: cleanup workflow file * tests: increase hermes gas multiplier * wasm: add wasmstack to ibc router * e2e: update ibc failed multihop tests * ante remove unused WasmKeeper * add burner macc perm to wasm * lint * tests: reduce multipliers for hermes --------- Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> Co-authored-by: MSalopek --- .github/workflows/test.yml | 4 +++ .golangci.yml | 1 + .goreleaser.yml | 1 - Dockerfile | 22 +++++++++--- Makefile | 3 ++ ante/ante.go | 20 +++++++---- app/app.go | 38 ++++++++++++++++++--- app/app_test.go | 5 +++ app/helpers/test_helpers.go | 4 +++ app/keepers/keepers.go | 46 ++++++++++++++++++++++++-- app/keepers/keys.go | 3 ++ app/modules.go | 10 ++++++ app/sim_bench_test.go | 1 + app/sim_test.go | 1 + app/upgrades/v18/constants.go | 3 ++ app/upgrades/v18/upgrades.go | 13 ++++++++ cmd/gaiad/cmd/root.go | 19 ++++++++++- contrib/cw_template.wasm | Bin 0 -> 132664 bytes contrib/scripts/local-gaia.sh | 7 ++-- contrib/single-node.sh | 11 +++--- contrib/upload-contract.sh | 14 ++++++++ e2e.Dockerfile | 20 ++++++++--- go.mod | 5 ++- go.sum | 6 ++++ tests/e2e/scripts/hermes_bootstrap.sh | 10 +++--- tests/integration/test_utils.go | 3 +- 26 files changed, 230 insertions(+), 40 deletions(-) create mode 100644 contrib/cw_template.wasm create mode 100644 contrib/upload-contract.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc4c212a5b1..0e6f2a2764d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -171,6 +171,10 @@ jobs: - name: Install New Gaiad run: | git checkout - + curl -LO https://github.com/CosmWasm/wasmvm/releases/download/v1.5.0/libwasmvm.x86_64.so + curl -LO https://github.com/CosmWasm/wasmvm/releases/download/v1.5.0/libwasmvm.aarch64.so + uname -m + sudo cp "./libwasmvm.$(uname -m).so" /usr/lib/ make build cp ./build/gaiad ./build/gaiadnew go clean -modcache diff --git a/.golangci.yml b/.golangci.yml index 6eae92cbe71..27580c5f993 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -68,6 +68,7 @@ linters-settings: - prefix(github.com/cosmos) # cosmos org - prefix(cosmossdk.io) # new modules - prefix(github.com/cosmos/cosmos-sdk) # cosmos sdk + - prefix(github.com/CosmWasm/wasmd) # cosmwasm - prefix(github.com/cosmos/gaia) # Gaia dogsled: max-blank-identifiers: 3 diff --git a/.goreleaser.yml b/.goreleaser.yml index 64776146a60..4b81ae8778c 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -20,7 +20,6 @@ builds: goos: - darwin - linux - - windows goarch: - amd64 - arm64 diff --git a/Dockerfile b/Dockerfile index b27042c0886..88d4e2a1edc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,31 @@ ARG IMG_TAG=latest # Compile the gaiad binary -FROM golang:1.21-alpine AS gaiad-builder +FROM golang:1.21-alpine3.18 AS gaiad-builder WORKDIR /src/app/ +ENV PACKAGES="curl make git libc-dev bash file gcc linux-headers eudev-dev python3" +RUN apk add --no-cache $PACKAGES + +# See https://github.com/CosmWasm/wasmvm/releases +ARG WASMVM_VERSION=v1.5.0 +ADD https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a +RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep 2687afbdae1bc6c7c8b05ae20dfb8ffc7ddc5b4e056697d0f37853dfe294e913 +RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep 465e3a088e96fd009a11bfd234c69fb8a0556967677e54511c084f815cf9ce63 +RUN cp "/lib/libwasmvm_muslc.$(uname -m).a" /lib/libwasmvm_muslc.a + COPY go.mod go.sum* ./ RUN go mod download + COPY . . -ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3 -RUN apk add --no-cache $PACKAGES -RUN CGO_ENABLED=0 make install +RUN LEDGER_ENABLED=false LINK_STATICALLY=true BUILD_TAGS=muslc make build +RUN echo "Ensuring binary is statically linked ..." \ + && file /src/app/build/gaiad | grep "statically linked" # Add to a distroless container FROM cgr.dev/chainguard/static:$IMG_TAG ARG IMG_TAG -COPY --from=gaiad-builder /go/bin/gaiad /usr/local/bin/ +COPY --from=gaiad-builder /src/app/build/gaiad /usr/local/bin/ EXPOSE 26656 26657 1317 9090 USER 0 diff --git a/Makefile b/Makefile index 973971b80b3..94bbd5a30ae 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,9 @@ ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=gaia \ ifeq (cleveldb,$(findstring cleveldb,$(GAIA_BUILD_OPTIONS))) ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb endif +ifeq ($(LINK_STATICALLY),true) + ldflags += -linkmode=external -extldflags "-Wl,-z,muldefs -static" +endif ifeq (,$(findstring nostrip,$(GAIA_BUILD_OPTIONS))) ldflags += -w -s endif diff --git a/ante/ante.go b/ante/ante.go index 5ac37a30ebb..6833dedceff 100644 --- a/ante/ante.go +++ b/ante/ante.go @@ -10,10 +10,14 @@ import ( errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/ante" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + gaiaerrors "github.com/cosmos/gaia/v18/types/errors" ) @@ -24,11 +28,13 @@ var UseFeeMarketDecorator = true // channel keeper. type HandlerOptions struct { ante.HandlerOptions - Codec codec.BinaryCodec - IBCkeeper *ibckeeper.Keeper - StakingKeeper *stakingkeeper.Keeper - FeeMarketKeeper *feemarketkeeper.Keeper - TxFeeChecker ante.TxFeeChecker + Codec codec.BinaryCodec + IBCkeeper *ibckeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + FeeMarketKeeper *feemarketkeeper.Keeper + TxFeeChecker ante.TxFeeChecker + TxCounterStoreKey storetypes.StoreKey + WasmConfig *wasmtypes.WasmConfig } func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { @@ -58,7 +64,9 @@ func NewAnteHandler(opts HandlerOptions) (sdk.AnteHandler, error) { } anteDecorators := []sdk.AnteDecorator{ - ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + wasmkeeper.NewLimitSimulationGasDecorator(opts.WasmConfig.SimulationGasLimit), // after setup context to enforce limits early + wasmkeeper.NewCountTXDecorator(opts.TxCounterStoreKey), ante.NewExtensionOptionsDecorator(opts.ExtensionOptionChecker), ante.NewValidateBasicDecorator(), ante.NewTxTimeoutHeightDecorator(), diff --git a/app/app.go b/app/app.go index 590e0aced5f..e81243547c7 100644 --- a/app/app.go +++ b/app/app.go @@ -20,6 +20,7 @@ import ( tmjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/libs/log" tmos "github.com/cometbft/cometbft/libs/os" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" @@ -52,6 +53,10 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + wasm "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + gaiaante "github.com/cosmos/gaia/v18/ante" "github.com/cosmos/gaia/v18/app/keepers" "github.com/cosmos/gaia/v18/app/params" @@ -112,6 +117,7 @@ func NewGaiaApp( homePath string, encodingConfig params.EncodingConfig, appOpts servertypes.AppOptions, + wasmOpts []wasmkeeper.Option, baseAppOptions ...func(*baseapp.BaseApp), ) *GaiaApp { appCodec := encodingConfig.Marshaler @@ -159,6 +165,7 @@ func NewGaiaApp( invCheckPeriod, logger, appOpts, + wasmOpts, ) // NOTE: Any module instantiated in the module manager that is later modified @@ -214,6 +221,11 @@ func NewGaiaApp( app.MountTransientStores(app.GetTransientStoreKey()) app.MountMemoryStores(app.GetMemoryStoreKey()) + wasmConfig, err := wasm.ReadWasmConfig(appOpts) + if err != nil { + panic("error while reading wasm config: " + err.Error()) + } + anteHandler, err := gaiaante.NewAnteHandler( gaiaante.HandlerOptions{ HandlerOptions: ante.HandlerOptions{ @@ -223,10 +235,12 @@ func NewGaiaApp( SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), SigGasConsumer: ante.DefaultSigVerificationGasConsumer, }, - Codec: appCodec, - IBCkeeper: app.IBCKeeper, - StakingKeeper: app.StakingKeeper, - FeeMarketKeeper: app.FeeMarketKeeper, + Codec: appCodec, + IBCkeeper: app.IBCKeeper, + StakingKeeper: app.StakingKeeper, + FeeMarketKeeper: app.FeeMarketKeeper, + WasmConfig: &wasmConfig, + TxCounterStoreKey: app.AppKeepers.GetKey(wasmtypes.StoreKey), TxFeeChecker: func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { return minTxFeesChecker(ctx, tx, *app.FeeMarketKeeper) }, @@ -255,6 +269,13 @@ func NewGaiaApp( app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) + if manager := app.SnapshotManager(); manager != nil { + err = manager.RegisterExtensions(wasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.AppKeepers.WasmKeeper)) + if err != nil { + panic("failed to register snapshot extension: " + err.Error()) + } + } + app.setupUpgradeHandlers() app.setupUpgradeStoreLoaders() @@ -262,6 +283,12 @@ func NewGaiaApp( if err := app.LoadLatestVersion(); err != nil { tmos.Exit(fmt.Sprintf("failed to load latest version: %s", err)) } + + ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) + + if err := app.AppKeepers.WasmKeeper.InitializePinnedCodes(ctx); err != nil { + tmos.Exit(fmt.Sprintf("WasmKeeper failed initialize pinned codes %s", err)) + } } return app @@ -451,6 +478,9 @@ func (app *GaiaApp) GetTxConfig() client.TxConfig { // EmptyAppOptions is a stub implementing AppOptions type EmptyAppOptions struct{} +// EmptyWasmOptions is a stub implementing Wasmkeeper Option +var EmptyWasmOptions []wasmkeeper.Option + // Get implements AppOptions func (ao EmptyAppOptions) Get(_ string) interface{} { return nil diff --git a/app/app_test.go b/app/app_test.go index 267462d81ad..cd50d09ae8d 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -11,12 +11,16 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + gaia "github.com/cosmos/gaia/v18/app" gaiahelpers "github.com/cosmos/gaia/v18/app/helpers" ) type EmptyAppOptions struct{} +var emptyWasmOption []wasmkeeper.Option + func (ao EmptyAppOptions) Get(_ string) interface{} { return nil } @@ -32,6 +36,7 @@ func TestGaiaApp_BlockedModuleAccountAddrs(t *testing.T) { gaia.DefaultNodeHome, encConfig, EmptyAppOptions{}, + emptyWasmOption, ) moduleAccountAddresses := app.ModuleAccountAddrs() diff --git a/app/helpers/test_helpers.go b/app/helpers/test_helpers.go index 3092214150a..894d921c0e7 100644 --- a/app/helpers/test_helpers.go +++ b/app/helpers/test_helpers.go @@ -24,6 +24,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + gaiaapp "github.com/cosmos/gaia/v18/app" ) @@ -121,6 +123,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs func setup() (*gaiaapp.GaiaApp, gaiaapp.GenesisState) { db := dbm.NewMemDB() appOptions := make(simtestutil.AppOptionsMap, 0) + emptyWasmOpts := []wasmkeeper.Option{} appOptions[server.FlagInvCheckPeriod] = 5 appOptions[server.FlagMinGasPrices] = "0uatom" @@ -135,6 +138,7 @@ func setup() (*gaiaapp.GaiaApp, gaiaapp.GenesisState) { gaiaapp.DefaultNodeHome, encConfig, appOptions, + emptyWasmOpts, ) return gaiaApp, gaiaapp.NewDefaultGenesisState(encConfig) } diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 7f9a5774964..d9279ec7c6c 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -3,6 +3,7 @@ package keepers import ( "fmt" "os" + "strings" ratelimit "github.com/Stride-Labs/ibc-rate-limiting/ratelimit" ratelimitkeeper "github.com/Stride-Labs/ibc-rate-limiting/ratelimit/keeper" @@ -80,6 +81,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/upgrade" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + wasmapp "github.com/CosmWasm/wasmd/app" + "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" ) type AppKeepers struct { @@ -100,6 +106,7 @@ type AppKeepers struct { CrisisKeeper *crisiskeeper.Keeper UpgradeKeeper *upgradekeeper.Keeper ParamsKeeper paramskeeper.Keeper + WasmKeeper wasmkeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly IBCKeeper *ibckeeper.Keeper ICAHostKeeper icahostkeeper.Keeper @@ -131,6 +138,7 @@ type AppKeepers struct { ScopedICAHostKeeper capabilitykeeper.ScopedKeeper ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper ScopedICSproviderkeeper capabilitykeeper.ScopedKeeper + scopedWasmKeeper capabilitykeeper.ScopedKeeper } func NewAppKeeper( @@ -145,6 +153,7 @@ func NewAppKeeper( invCheckPeriod uint, logger log.Logger, appOpts servertypes.AppOptions, + wasmOpts []wasmkeeper.Option, ) AppKeepers { appKeepers := AppKeepers{} @@ -189,6 +198,7 @@ func NewAppKeeper( appKeepers.ScopedICAControllerKeeper = appKeepers.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) appKeepers.ScopedTransferKeeper = appKeepers.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) appKeepers.ScopedICSproviderkeeper = appKeepers.CapabilityKeeper.ScopeToModule(providertypes.ModuleName) + appKeepers.scopedWasmKeeper = appKeepers.CapabilityKeeper.ScopeToModule(wasmtypes.ModuleName) // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating // their scoped modules in `NewApp` with `ScopeToModule` @@ -447,6 +457,31 @@ func NewAppKeeper( // Must be called on PFMRouter AFTER TransferKeeper initialized appKeepers.PFMRouterKeeper.SetTransferKeeper(appKeepers.TransferKeeper) + wasmConfig, err := wasm.ReadWasmConfig(appOpts) + if err != nil { + panic("error while reading wasm config: " + err.Error()) + } + + appKeepers.WasmKeeper = wasmkeeper.NewKeeper( + appCodec, + appKeepers.keys[wasmtypes.StoreKey], + appKeepers.AccountKeeper, + appKeepers.BankKeeper, + appKeepers.StakingKeeper, + distrkeeper.NewQuerier(appKeepers.DistrKeeper), + appKeepers.IBCKeeper.ChannelKeeper, + appKeepers.IBCKeeper.ChannelKeeper, + &appKeepers.IBCKeeper.PortKeeper, + appKeepers.scopedWasmKeeper, + appKeepers.TransferKeeper, + bApp.MsgServiceRouter(), + bApp.GRPCQueryRouter(), + homePath, + wasmConfig, + strings.Join(wasmapp.AllCapabilities(), ","), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + // Middleware Stacks appKeepers.ICAModule = ica.NewAppModule(&appKeepers.ICAControllerKeeper, &appKeepers.ICAHostKeeper) appKeepers.TransferModule = transfer.NewAppModule(appKeepers.TransferKeeper) @@ -484,12 +519,17 @@ func NewAppKeeper( // Create Interchain Accounts Controller Stack var icaControllerStack porttypes.IBCModule = icacontroller.NewIBCMiddleware(nil, appKeepers.ICAControllerKeeper) + var wasmStack porttypes.IBCModule + wasmStack = wasm.NewIBCHandler(appKeepers.WasmKeeper, appKeepers.IBCKeeper.ChannelKeeper, appKeepers.IBCFeeKeeper) + wasmStack = ibcfee.NewIBCMiddleware(wasmStack, appKeepers.IBCFeeKeeper) + // Create IBC Router & seal ibcRouter := porttypes.NewRouter(). AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). AddRoute(ibctransfertypes.ModuleName, transferStack). - AddRoute(providertypes.ModuleName, appKeepers.ProviderModule) + AddRoute(providertypes.ModuleName, appKeepers.ProviderModule). + AddRoute(wasmtypes.ModuleName, wasmStack) appKeepers.IBCKeeper.SetRouter(ibcRouter) @@ -509,8 +549,7 @@ func (appKeepers *AppKeepers) GetSubspace(moduleName string) paramstypes.Subspac func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) - //nolint: staticcheck // SA1019: moduletypes.ParamKeyTable is deprecated - paramsKeeper.Subspace(authtypes.ModuleName).WithKeyTable(authtypes.ParamKeyTable()) + paramsKeeper.Subspace(authtypes.ModuleName).WithKeyTable(authtypes.ParamKeyTable()) //nolint: staticcheck // SA1019 paramsKeeper.Subspace(stakingtypes.ModuleName).WithKeyTable(stakingtypes.ParamKeyTable()) paramsKeeper.Subspace(banktypes.ModuleName).WithKeyTable(banktypes.ParamKeyTable()) //nolint: staticcheck // SA1019 paramsKeeper.Subspace(minttypes.ModuleName).WithKeyTable(minttypes.ParamKeyTable()) //nolint: staticcheck // SA1019 @@ -525,6 +564,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(pfmroutertypes.ModuleName).WithKeyTable(pfmroutertypes.ParamKeyTable()) paramsKeeper.Subspace(ratelimittypes.ModuleName) paramsKeeper.Subspace(providertypes.ModuleName) + paramsKeeper.Subspace(wasmtypes.ModuleName) return paramsKeeper } diff --git a/app/keepers/keys.go b/app/keepers/keys.go index 4b036dc9f28..d1857a9ec43 100644 --- a/app/keepers/keys.go +++ b/app/keepers/keys.go @@ -29,6 +29,8 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" ) func (appKeepers *AppKeepers) GenerateKeys() { @@ -59,6 +61,7 @@ func (appKeepers *AppKeepers) GenerateKeys() { providertypes.StoreKey, consensusparamtypes.StoreKey, feemarkettypes.StoreKey, + wasmtypes.StoreKey, ) // Define transient store keys diff --git a/app/modules.go b/app/modules.go index 1e4f2858712..29a3a1e0d36 100644 --- a/app/modules.go +++ b/app/modules.go @@ -62,6 +62,9 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + wasm "github.com/CosmWasm/wasmd/x/wasm" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + gaiaappparams "github.com/cosmos/gaia/v18/app/params" "github.com/cosmos/gaia/v18/x/metaprotocols" metaprotocolstypes "github.com/cosmos/gaia/v18/x/metaprotocols/types" @@ -79,6 +82,7 @@ var maccPerms = map[string][]string{ ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ibcfeetypes.ModuleName: nil, providertypes.ConsumerRewardsPool: nil, + wasmtypes.ModuleName: {authtypes.Burner}, feemarkettypes.ModuleName: nil, feemarkettypes.FeeCollectorName: nil, } @@ -124,6 +128,7 @@ var ModuleBasics = module.NewBasicManager( icsprovider.AppModuleBasic{}, consensus.AppModuleBasic{}, metaprotocols.AppModuleBasic{}, + wasm.AppModuleBasic{}, feemarket.AppModuleBasic{}, ) @@ -158,6 +163,7 @@ func appModules( ibc.NewAppModule(app.IBCKeeper), sdkparams.NewAppModule(app.ParamsKeeper), consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), + wasm.NewAppModule(appCodec, &app.AppKeepers.WasmKeeper, app.AppKeepers.StakingKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), ibcfee.NewAppModule(app.IBCFeeKeeper), app.TransferModule, app.ICAModule, @@ -192,6 +198,7 @@ func simulationModules( sdkparams.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), + wasm.NewAppModule(appCodec, &app.AppKeepers.WasmKeeper, app.AppKeepers.StakingKeeper, app.AppKeepers.AccountKeeper, app.AppKeepers.BankKeeper, app.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), ibc.NewAppModule(app.IBCKeeper), app.TransferModule, app.ICAModule, @@ -239,6 +246,7 @@ func orderBeginBlockers() []string { providertypes.ModuleName, consensusparamtypes.ModuleName, metaprotocolstypes.ModuleName, + wasmtypes.ModuleName, } } @@ -278,6 +286,7 @@ func orderEndBlockers() []string { providertypes.ModuleName, consensusparamtypes.ModuleName, metaprotocolstypes.ModuleName, + wasmtypes.ModuleName, } } @@ -324,5 +333,6 @@ func orderInitBlockers() []string { providertypes.ModuleName, consensusparamtypes.ModuleName, metaprotocolstypes.ModuleName, + wasmtypes.ModuleName, } } diff --git a/app/sim_bench_test.go b/app/sim_bench_test.go index 5ccec2dcdf7..6a293f7dd3c 100644 --- a/app/sim_bench_test.go +++ b/app/sim_bench_test.go @@ -53,6 +53,7 @@ func BenchmarkFullAppSimulation(b *testing.B) { gaia.DefaultNodeHome, encConfig, appOptions, + emptyWasmOption, interBlockCacheOpt(), baseapp.SetChainID(AppChainID), ) diff --git a/app/sim_test.go b/app/sim_test.go index 734ffc2e833..3aa99b6073e 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -99,6 +99,7 @@ func TestAppStateDeterminism(t *testing.T) { gaia.DefaultNodeHome, encConfig, appOptions, + emptyWasmOption, interBlockCacheOpt(), baseapp.SetChainID(AppChainID), ) diff --git a/app/upgrades/v18/constants.go b/app/upgrades/v18/constants.go index 59e39c16633..66ef6a0acaa 100644 --- a/app/upgrades/v18/constants.go +++ b/app/upgrades/v18/constants.go @@ -5,6 +5,8 @@ import ( store "github.com/cosmos/cosmos-sdk/store/types" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/cosmos/gaia/v18/app/upgrades" ) @@ -20,6 +22,7 @@ var Upgrade = upgrades.Upgrade{ StoreUpgrades: store.StoreUpgrades{ Added: []string{ feemarkettypes.ModuleName, + wasmtypes.ModuleName, }, Deleted: []string{ GlobalFeeModuleName, diff --git a/app/upgrades/v18/upgrades.go b/app/upgrades/v18/upgrades.go index 762c1089522..99dbaa7b8f6 100644 --- a/app/upgrades/v18/upgrades.go +++ b/app/upgrades/v18/upgrades.go @@ -1,10 +1,14 @@ package v18 import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/cosmos/gaia/v18/app/keepers" "github.com/cosmos/gaia/v18/types" ) @@ -27,6 +31,15 @@ func CreateUpgradeHandler( return vm, err } + // Set CosmWasm params + wasmParams := wasmtypes.DefaultParams() + wasmParams.CodeUploadAccess = wasmtypes.AllowNobody + // TODO(reece): only allow specific addresses to instantiate contracts or anyone with AccessTypeEverybody? + wasmParams.InstantiateDefaultPermission = wasmtypes.AccessTypeAnyOfAddresses + if err := keepers.WasmKeeper.SetParams(ctx, wasmParams); err != nil { + return vm, errorsmod.Wrapf(err, "unable to set CosmWasm params") + } + ctx.Logger().Info("Upgrade v18 complete") return vm, nil } diff --git a/cmd/gaiad/cmd/root.go b/cmd/gaiad/cmd/root.go index de02103bf66..309c4f9dc62 100644 --- a/cmd/gaiad/cmd/root.go +++ b/cmd/gaiad/cmd/root.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" + "github.com/prometheus/client_golang/prometheus" "github.com/spf13/cast" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -40,6 +41,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + gaia "github.com/cosmos/gaia/v18/app" "github.com/cosmos/gaia/v18/app/params" ) @@ -107,6 +112,8 @@ func initAppConfig() (string, interface{}) { // Embed additional configurations type CustomAppConfig struct { serverconfig.Config + + Wasm wasmtypes.WasmConfig `mapstructure:"wasm"` } // Can optionally overwrite the SDK's default server config. @@ -116,9 +123,10 @@ func initAppConfig() (string, interface{}) { customAppConfig := CustomAppConfig{ Config: *srvCfg, + Wasm: wasmtypes.DefaultWasmConfig(), } - defaultAppTemplate := serverconfig.DefaultConfigTemplate + defaultAppTemplate := serverconfig.DefaultConfigTemplate + wasmtypes.DefaultConfigTemplate() return defaultAppTemplate, customAppConfig } @@ -156,6 +164,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) + wasm.AddModuleInitFlags(startCmd) } // genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter @@ -236,6 +245,11 @@ func (a appCreator) newApp( cache = store.NewCommitKVStoreCacheManager() } + var wasmOpts []wasmkeeper.Option + if cast.ToBool(appOpts.Get("telemetry.enabled")) { + wasmOpts = append(wasmOpts, wasmkeeper.WithVMCacheMetrics(prometheus.DefaultRegisterer)) + } + pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) if err != nil { panic(err) @@ -297,6 +311,7 @@ func (a appCreator) newApp( cast.ToString(appOpts.Get(flags.FlagHome)), a.encCfg, appOpts, + wasmOpts, baseappOptions..., ) } @@ -332,6 +347,7 @@ func (a appCreator) appExport( loadLatest = true } + var emptyWasmOpts []wasmkeeper.Option gaiaApp = gaia.NewGaiaApp( logger, db, @@ -341,6 +357,7 @@ func (a appCreator) appExport( homePath, a.encCfg, appOpts, + emptyWasmOpts, ) if height != -1 { diff --git a/contrib/cw_template.wasm b/contrib/cw_template.wasm new file mode 100644 index 0000000000000000000000000000000000000000..909cbdd198caf9ececdf0c288ceda0b1a4d912f2 GIT binary patch literal 132664 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 M(t{<21#`lG0|9DE)c^nh literal 0 HcmV?d00001 diff --git a/contrib/scripts/local-gaia.sh b/contrib/scripts/local-gaia.sh index 6e21ed13ea0..8d0e475c245 100755 --- a/contrib/scripts/local-gaia.sh +++ b/contrib/scripts/local-gaia.sh @@ -1,7 +1,7 @@ #!/bin/bash -set -eux +set -eux -# User balance of stake tokens +# User balance of stake tokens USER_COINS="100000000000stake" # Amount of stake tokens staked STAKE="100000000stake" @@ -9,7 +9,7 @@ STAKE="100000000stake" NODE_IP="127.0.0.1" # Home directory -HOME_DIR="/Users/msalopek" +HOME_DIR="$HOME" # Validator moniker MONIKER="coordinator" @@ -53,6 +53,7 @@ sleep 1 sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:26658\"/" ${PROV_NODE_DIR}/config/client.toml sed -i -r 's/timeout_commit = "5s"/timeout_commit = "3s"/g' ${PROV_NODE_DIR}/config/config.toml sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ${PROV_NODE_DIR}/config/config.toml +sed -i -r 's/minimum-gas-prices = ""/minimum-gas-prices = "0stake"/g' ${PROV_NODE_DIR}/config/app.toml # Start gaia diff --git a/contrib/single-node.sh b/contrib/single-node.sh index 6ba8863b913..38c7d492ec6 100755 --- a/contrib/single-node.sh +++ b/contrib/single-node.sh @@ -26,11 +26,12 @@ gaiad genesis collect-gentxs # Set proper defaults and change ports echo "Setting rpc listen address" -sed -i '' 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' ~/.gaia/config/config.toml -echo 2 -sed -i '' 's/timeout_commit = "5s"/timeout_commit = "1s"/g' ~/.gaia/config/config.toml -sed -i '' 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ~/.gaia/config/config.toml -sed -i '' 's/index_all_keys = false/index_all_keys = true/g' ~/.gaia/config/config.toml +# sed -i '' 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' ~/.gaia/config/config.toml +sleep 1 +sed -i -r 's/timeout_commit = "5s"/timeout_commit = "1s"/g' ~/.gaia/config/config.toml +sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ~/.gaia/config/config.toml +sed -i -r 's/index_all_keys = false/index_all_keys = true/g' ~/.gaia/config/config.toml +sed -i -r 's/minimum-gas-prices = ""/minimum-gas-prices = "0stake"/g' ~/.gaia/config/app.toml # Start the gaia gaiad start --pruning=nothing diff --git a/contrib/upload-contract.sh b/contrib/upload-contract.sh new file mode 100644 index 00000000000..f3e7f250108 --- /dev/null +++ b/contrib/upload-contract.sh @@ -0,0 +1,14 @@ +export GAIAD_NODE="tcp://localhost:26657" + +FLAGS="--gas=2500000 --from=validator --keyring-backend=test --chain-id=local-1 --output=json --yes" + +gaiad tx wasm store ./contrib/cw_template.wasm $FLAGS +sleep 2 + +txhash=$(gaiad tx wasm instantiate 1 '{"count":0}' --label=cw_template --no-admin $FLAGS | jq -r .txhash) && echo $txhash +sleep 2 + +addr=$(gaiad q tx $txhash --output=json | jq -r .logs[0].events[2].attributes[0].value) && echo $addr +sleep 2 + +gaiad q wasm contract $addr \ No newline at end of file diff --git a/e2e.Dockerfile b/e2e.Dockerfile index 41f22c0a1c8..732c025f2f0 100644 --- a/e2e.Dockerfile +++ b/e2e.Dockerfile @@ -3,18 +3,30 @@ ARG IMG_TAG=latest # Compile the gaiad binary FROM golang:1.22-alpine AS gaiad-builder WORKDIR /src/app/ +ENV PACKAGES="curl make git libc-dev bash file gcc linux-headers eudev-dev python3" +RUN apk add --no-cache $PACKAGES + +# See https://github.com/CosmWasm/wasmvm/releases +ARG WASMVM_VERSION=v1.5.0 +ADD https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a +RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep 2687afbdae1bc6c7c8b05ae20dfb8ffc7ddc5b4e056697d0f37853dfe294e913 +RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep 465e3a088e96fd009a11bfd234c69fb8a0556967677e54511c084f815cf9ce63 +RUN cp "/lib/libwasmvm_muslc.$(uname -m).a" /lib/libwasmvm_muslc.a + COPY go.mod go.sum* ./ RUN go mod download COPY . . -ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3 -RUN apk add --no-cache $PACKAGES -RUN CGO_ENABLED=0 make install +RUN LEDGER_ENABLED=false LINK_STATICALLY=true BUILD_TAGS=muslc make build +RUN echo "Ensuring binary is statically linked ..." \ + && file /src/app/build/gaiad | grep "statically linked" # Add to a distroless container FROM alpine:$IMG_TAG +RUN apk add --no-cache build-base RUN adduser -D nonroot ARG IMG_TAG -COPY --from=gaiad-builder /go/bin/gaiad /usr/local/bin/ +COPY --from=gaiad-builder /src/app/build/gaiad /usr/local/bin/ EXPOSE 26656 26657 1317 9090 USER nonroot diff --git a/go.mod b/go.mod index 49775f1f099..1de1aa1cdd8 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( cosmossdk.io/math v1.3.0 cosmossdk.io/simapp v0.0.0-20230602123434-616841b9704d cosmossdk.io/tools/rosetta v0.2.1 + github.com/CosmWasm/wasmd v0.45.0 github.com/Stride-Labs/ibc-rate-limiting v1.0.1 github.com/cometbft/cometbft v0.37.6 github.com/cometbft/cometbft-db v0.11.0 @@ -20,6 +21,7 @@ require ( github.com/google/gofuzz v1.2.0 github.com/gorilla/mux v1.8.1 github.com/ory/dockertest/v3 v3.10.0 + github.com/prometheus/client_golang v1.17.0 github.com/rakyll/statik v0.1.7 github.com/skip-mev/feemarket v1.0.3-sdk47 github.com/spf13/cast v1.6.0 @@ -52,6 +54,7 @@ require ( github.com/99designs/keyring v1.2.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect + github.com/CosmWasm/wasmvm v1.5.0 // indirect github.com/DataDog/zstd v1.5.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect @@ -90,6 +93,7 @@ require ( github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/cli v20.10.17+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.9+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -167,7 +171,6 @@ require ( github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.17.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect diff --git a/go.sum b/go.sum index ac6ae349eb2..49051771417 100644 --- a/go.sum +++ b/go.sum @@ -557,6 +557,10 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg6 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= +github.com/CosmWasm/wasmd v0.45.0 h1:9zBqrturKJwC2kVsfHvbrA++EN0PS7UTXCffCGbg6JI= +github.com/CosmWasm/wasmd v0.45.0/go.mod h1:RnSAiqbNIZu4QhO+0pd7qGZgnYAMBPGmXpzTADag944= +github.com/CosmWasm/wasmvm v1.5.0 h1:3hKeT9SfwfLhxTGKH3vXaKFzBz1yuvP8SlfwfQXbQfw= +github.com/CosmWasm/wasmvm v1.5.0/go.mod h1:fXB+m2gyh4v9839zlIXdMZGeLAxqUdYdFQqYsTha2hc= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= @@ -820,6 +824,8 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/ github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M= github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= diff --git a/tests/e2e/scripts/hermes_bootstrap.sh b/tests/e2e/scripts/hermes_bootstrap.sh index 3c662cba441..d8fd93a4714 100755 --- a/tests/e2e/scripts/hermes_bootstrap.sh +++ b/tests/e2e/scripts/hermes_bootstrap.sh @@ -54,7 +54,7 @@ key_name = 'rly01-gaia-a' store_prefix = 'ibc' max_gas = 6000000 gas_price = { price = 0.005, denom = 'uatom' } -gas_multiplier = 2 +gas_multiplier = 1.5 clock_drift = '1m' # to accomdate docker containers trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } @@ -72,7 +72,7 @@ key_name = 'rly01-gaia-b' store_prefix = 'ibc' max_gas = 6000000 gas_price = { price = 0.005, denom = 'uatom' } -gas_multiplier = 2 +gas_multiplier = 1.5 clock_drift = '1m' # to accomdate docker containers trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } @@ -124,7 +124,7 @@ key_name = 'rly01-gaia-a' store_prefix = 'ibc' max_gas = 6000000 gas_price = { price = 0, denom = 'uatom' } -gas_multiplier = 2 +gas_multiplier = 1.5 clock_drift = '1m' # to accommodate docker containers trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } @@ -142,7 +142,7 @@ key_name = 'rly01-gaia-b' store_prefix = 'ibc' max_gas = 6000000 gas_price = { price = 0, denom = 'uatom' } -gas_multiplier = 2 +gas_multiplier = 1.5 clock_drift = '1m' # to accommodate docker containers trusting_period = '14days' trust_threshold = { numerator = '1', denominator = '3' } @@ -154,5 +154,3 @@ EOF hermes keys add --key-name rly01-gaia-b --chain $GAIA_B_E2E_CHAIN_ID --mnemonic-file /root/.hermes/GAIA_B_E2E_RLY_MNEMONIC.txt sleep 5 hermes keys add --key-name rly01-gaia-a --chain $GAIA_A_E2E_CHAIN_ID --mnemonic-file /root/.hermes/GAIA_A_E2E_RLY_MNEMONIC.txt - - diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go index 477a2926f17..54579b5d53c 100644 --- a/tests/integration/test_utils.go +++ b/tests/integration/test_utils.go @@ -35,7 +35,8 @@ func GaiaAppIniter() (ibctesting.TestingApp, map[string]json.RawMessage) { map[int64]bool{}, gaiaApp.DefaultNodeHome, encoding, - gaiaApp.EmptyAppOptions{}) + gaiaApp.EmptyAppOptions{}, + gaiaApp.EmptyWasmOptions) testApp := ibctesting.TestingApp(app)