Skip to content

Commit

Permalink
Support e2e tests for callback module SimApp (#4406)
Browse files Browse the repository at this point in the history
  • Loading branch information
chatton authored Aug 24, 2023
1 parent ce3cfc0 commit 9a22ede
Show file tree
Hide file tree
Showing 5 changed files with 399 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/build-callbacks-simd-image-from-tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Build Callbacks Simd Image
on:
workflow_dispatch:
inputs:
tag:
description: 'The tag of the image to build'
required: true
type: string

env:
REGISTRY: ghcr.io
ORG: cosmos
IMAGE_NAME: ibc-go-callbacks-simd
GIT_TAG: "${{ inputs.tag }}"

jobs:
build-image-at-tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "${{ env.GIT_TAG }}"
fetch-depth: 0
- name: Log in to the Container registry
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build image
run: |
# remove any `/` characters from the docker tag and replace them with a -
docker_tag="$(echo $GIT_TAG | sed 's/\//-/')"
docker build . -t "${REGISTRY}/${ORG}/${IMAGE_NAME}:${docker_tag}" -f modules/apps/callbacks/Dockerfile
docker push "${REGISTRY}/${ORG}/${IMAGE_NAME}:${docker_tag}"
28 changes: 28 additions & 0 deletions modules/apps/callbacks/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM golang:1.21-alpine3.18 as builder

RUN set -eux; apk add --no-cache git libusb-dev linux-headers gcc musl-dev make;

ENV GOPATH=""
ENV GOMODULE="on"

# Copy relevant files before go mod download. Replace directives to local paths break if local
# files are not copied before go mod download.
ADD internal internal
ADD testing testing
ADD modules modules
ADD LICENSE LICENSE

COPY go.mod .
COPY go.sum .

WORKDIR modules/apps/callbacks

RUN go mod download

RUN GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false go build -mod=readonly -tags "netgo ledger" -ldflags '-X github.com/cosmos/cosmos-sdk/version.Name=sim -X github.com/cosmos/cosmos-sdk/version.AppName=simd -X github.com/cosmos/cosmos-sdk/version.Version= -X github.com/cosmos/cosmos-sdk/version.Commit= -X "github.com/cosmos/cosmos-sdk/version.BuildTags=netgo ledger," -w -s' -trimpath -o /go/build/ ./...

FROM alpine:3.18

COPY --from=builder /go/build/simd /bin/simd

ENTRYPOINT ["simd"]
7 changes: 7 additions & 0 deletions modules/apps/callbacks/testing/simapp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Callbacks Testing SimApp

This testing directory is a duplicate of the ibc-go testing directory.
It is only here as a way of creating a separate SimApp binary to avoid introducing a dependency on the callbacks
module from within ibc-go.

The simapp can be built with the workflow found [here](../../../../../.github/workflows/build-callbacks-simd-image-from-tag.yml).
305 changes: 305 additions & 0 deletions modules/apps/callbacks/testing/simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
package cmd

import (
"errors"
"io"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/debug"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/pruning"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/snapshot"
"github.com/cosmos/cosmos-sdk/server"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/crisis"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"

dbm "github.com/cometbft/cometbft-db"
cmtcfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/libs/log"

"github.com/cosmos/ibc-go/modules/apps/callbacks/testing/simapp"
"github.com/cosmos/ibc-go/modules/apps/callbacks/testing/simapp/params"
)

// NewRootCmd creates a new root command for simd. It is called once in the
// main function.
func NewRootCmd() *cobra.Command {
// we "pre"-instantiate the application for getting the injected/configured encoding configuration
tempApp := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(simapp.DefaultNodeHome))
encodingConfig := params.EncodingConfig{
InterfaceRegistry: tempApp.InterfaceRegistry(),
Codec: tempApp.AppCodec(),
TxConfig: tempApp.TxConfig(),
Amino: tempApp.LegacyAmino(),
}

initClientCtx := client.Context{}.
WithCodec(encodingConfig.Codec).
WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
WithTxConfig(encodingConfig.TxConfig).
WithLegacyAmino(encodingConfig.Amino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithHomeDir(simapp.DefaultNodeHome).
WithViper("") // In simapp, we don't use any prefix for env variables.

rootCmd := &cobra.Command{
Use: "simd",
Short: "simulation app",
PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())

initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags())
if err != nil {
return err
}

initClientCtx, err = config.ReadFromClientConfig(initClientCtx)
if err != nil {
return err
}

if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil {
return err
}

customAppTemplate, customAppConfig := initAppConfig()
customTMConfig := initTendermintConfig()

return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig)
},
}

initRootCmd(rootCmd, encodingConfig)

return rootCmd
}

// initTendermintConfig helps to override default Tendermint Config values.
// return cmtcfg.DefaultConfig if no custom configuration is required for the application.
func initTendermintConfig() *cmtcfg.Config {
cfg := cmtcfg.DefaultConfig()

// these values put a higher strain on node memory
// cfg.P2P.MaxNumInboundPeers = 100
// cfg.P2P.MaxNumOutboundPeers = 40

return cfg
}

// initAppConfig helps to override default appConfig template and configs.
// return "", nil if no custom configuration is required for the application.
func initAppConfig() (string, interface{}) {
// The following code snippet is just for reference.

// WASMConfig defines configuration for the wasm module.
type WASMConfig struct {
// This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
QueryGasLimit uint64 `mapstructure:"query_gas_limit"`

// Address defines the gRPC-web server to listen on
LruSize uint64 `mapstructure:"lru_size"`
}

type CustomAppConfig struct {
serverconfig.Config

WASM WASMConfig `mapstructure:"wasm"`
}

// Optionally allow the chain developer to overwrite the SDK's default
// server config.
srvCfg := serverconfig.DefaultConfig()
// The SDK's default minimum gas price is set to "" (empty value) inside
// app.toml. If left empty by validators, the node will halt on startup.
// However, the chain developer can set a default app.toml value for their
// validators here.
//
// In summary:
// - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their
// own app.toml config,
// - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their
// own app.toml to override, or use this default value.
//
// In simapp, we set the min gas prices to 0.
srvCfg.MinGasPrices = "0stake"
// srvCfg.BaseConfig.IAVLDisableFastNode = true // disable fastnode by default

customAppConfig := CustomAppConfig{
Config: *srvCfg,
WASM: WASMConfig{
LruSize: 1,
QueryGasLimit: 300000,
},
}

customAppTemplate := serverconfig.DefaultConfigTemplate + `
[wasm]
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
query_gas_limit = 300000
# This is the number of wasm vm instances we keep cached in memory for speed-up
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
lru_size = 0`

return customAppTemplate, customAppConfig
}

func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
cfg := sdk.GetConfig()
cfg.Seal()

rootCmd.AddCommand(
genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome),
debug.Cmd(),
config.Cmd(),
pruning.PruningCmd(newApp),
snapshot.Cmd(newApp),
)

server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, appExport, addModuleInitFlags)

// add keybase, auxiliary RPC, query, genesis, and tx child commands
rootCmd.AddCommand(
rpc.StatusCommand(),
genesisCommand(encodingConfig),
queryCommand(),
txCommand(),
keys.Commands(simapp.DefaultNodeHome),
)
}

func addModuleInitFlags(startCmd *cobra.Command) {
crisis.AddModuleInitFlags(startCmd)
}

// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter
func genesisCommand(encodingConfig params.EncodingConfig, cmds ...*cobra.Command) *cobra.Command {
cmd := genutilcli.GenesisCoreCommand(encodingConfig.TxConfig, simapp.ModuleBasics, simapp.DefaultNodeHome)

for _, subCmd := range cmds {
cmd.AddCommand(subCmd)
}
return cmd
}

func queryCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
Aliases: []string{"q"},
Short: "Querying subcommands",
DisableFlagParsing: false,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

cmd.AddCommand(
authcmd.GetAccountCmd(),
rpc.ValidatorCommand(),
rpc.BlockCommand(),
authcmd.QueryTxsByEventsCmd(),
authcmd.QueryTxCmd(),
)

simapp.ModuleBasics.AddQueryCommands(cmd)

return cmd
}

func txCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "tx",
Short: "Transactions subcommands",
DisableFlagParsing: false,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}

cmd.AddCommand(
authcmd.GetSignCommand(),
authcmd.GetSignBatchCommand(),
authcmd.GetMultiSignCommand(),
authcmd.GetMultiSignBatchCmd(),
authcmd.GetValidateSignaturesCommand(),
authcmd.GetBroadcastCommand(),
authcmd.GetEncodeCommand(),
authcmd.GetDecodeCommand(),
authcmd.GetAuxToFeeCommand(),
)

simapp.ModuleBasics.AddTxCommands(cmd)

return cmd
}

// newApp creates the application
func newApp(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
appOpts servertypes.AppOptions,
) servertypes.Application {
baseappOptions := server.DefaultBaseappOptions(appOpts)

return simapp.NewSimApp(
logger, db, traceStore, true,
appOpts,
baseappOptions...,
)
}

// appExport creates a new simapp (optionally at a given height) and exports state.
func appExport(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
height int64,
forZeroHeight bool,
jailAllowedAddrs []string,
appOpts servertypes.AppOptions,
modulesToExport []string,
) (servertypes.ExportedApp, error) {
var simApp *simapp.SimApp

// this check is necessary as we use the flag in x/upgrade.
// we can exit more gracefully by checking the flag here.
homePath, ok := appOpts.Get(flags.FlagHome).(string)
if !ok || homePath == "" {
return servertypes.ExportedApp{}, errors.New("application home not set")
}

viperAppOpts, ok := appOpts.(*viper.Viper)
if !ok {
return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
}

// overwrite the FlagInvCheckPeriod
viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
appOpts = viperAppOpts

if height != -1 {
simApp = simapp.NewSimApp(logger, db, traceStore, false, appOpts)

if err := simApp.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
simApp = simapp.NewSimApp(logger, db, traceStore, true, appOpts)
}

return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
}
Loading

0 comments on commit 9a22ede

Please sign in to comment.