From 0a3ba384a01e376eac4b3e732fd4db4fc7f33160 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 25 Jun 2024 20:53:57 +0200 Subject: [PATCH] feat: parse home flag earlier (#20771) (cherry picked from commit 5aaff2109642ace58c72d7d68413a024a0de2baf) # Conflicts: # CHANGELOG.md # client/config/config.go # client/v2/CHANGELOG.md # scripts/simapp-v2-init.sh # server/v2/cometbft/flags/flags.go # server/v2/commands.go # simapp/CHANGELOG.md # simapp/app.go # simapp/app_v2.go # simapp/simd/cmd/root.go # simapp/simd/cmd/root_v2.go # simapp/v2/app_di.go # simapp/v2/simdv2/cmd/commands.go # simapp/v2/simdv2/cmd/root_di.go # x/upgrade/CHANGELOG.md # x/upgrade/depinject.go # x/upgrade/go.mod --- CHANGELOG.md | 55 +++++++ client/config/config.go | 8 + client/v2/CHANGELOG.md | 15 ++ client/v2/helpers/home.go | 36 ++++ docs/docs/learn/advanced/07-cli.md | 4 +- scripts/init-simapp.sh | 2 +- scripts/simapp-v2-init.sh | 50 ++++++ server/v2/cometbft/flags/flags.go | 76 +++++++++ server/v2/commands.go | 134 +++++++++++++++ simapp/CHANGELOG.md | 52 ++++++ simapp/app.go | 32 +++- simapp/app_v2.go | 11 +- simapp/simd/cmd/commands.go | 19 --- simapp/simd/cmd/root.go | 14 +- simapp/simd/cmd/root_v2.go | 15 +- simapp/v2/app_di.go | 256 +++++++++++++++++++++++++++++ simapp/v2/simdv2/cmd/commands.go | 197 ++++++++++++++++++++++ simapp/v2/simdv2/cmd/root_di.go | 138 ++++++++++++++++ x/upgrade/CHANGELOG.md | 16 ++ x/upgrade/depinject.go | 100 +++++++++++ x/upgrade/go.mod | 4 + x/upgrade/keeper/keeper.go | 16 +- 22 files changed, 1210 insertions(+), 40 deletions(-) create mode 100644 client/v2/helpers/home.go create mode 100755 scripts/simapp-v2-init.sh create mode 100644 server/v2/cometbft/flags/flags.go create mode 100644 server/v2/commands.go create mode 100644 simapp/CHANGELOG.md create mode 100644 simapp/v2/app_di.go create mode 100644 simapp/v2/simdv2/cmd/commands.go create mode 100644 simapp/v2/simdv2/cmd/root_di.go create mode 100644 x/upgrade/depinject.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 04757e74d396..43bac432eb48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,7 +44,62 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Improvements +<<<<<<< HEAD * (x/authz,x/feegrant) [#20590](https://github.com/cosmos/cosmos-sdk/pull/20590) Provide updated keeper in depinject for authz and feegrant modules. +======= +* (codec) [#20122](https://github.com/cosmos/cosmos-sdk/pull/20122) Added a cache to address codec. +* (bank) [#20354](https://github.com/cosmos/cosmos-sdk/pull/20354) Reduce the number of `ValidateDenom` calls in `bank.SendCoins`. +* (types) [#19869](https://github.com/cosmos/cosmos-sdk/pull/19869) Removed `Any` type from `codec/types` and replaced it with an alias for `cosmos/gogoproto/types/any`. +* (server) [#19854](https://github.com/cosmos/cosmos-sdk/pull/19854) Add customizability to start command. + * Add `StartCmdOptions` in `server.AddCommands` instead of `servertypes.ModuleInitFlags`. To set custom flags set them in the `StartCmdOptions` struct on the `AddFlags` field. + * Add `StartCommandHandler` to `StartCmdOptions` to allow custom start command handlers. Users now have total control over how the app starts. +* (types) [#19672](https://github.com/cosmos/cosmos-sdk/pull/19672) `PreBlock` now returns only an error for consistency with server/v2. The SDK has upgraded x/upgrade accordingly. `ResponsePreBlock` hence has been removed. +* (server) [#19455](https://github.com/cosmos/cosmos-sdk/pull/19455) Allow calling back into the application struct in PostSetup. +* (types) [#19512](https://github.com/cosmos/cosmos-sdk/pull/19512) The notion of basic manager does not exist anymore (and all related helpers). + * The module manager now can do everything that the basic manager was doing. + * `AppModuleBasic` has been deprecated for extension interfaces. + * Modules can now implement `appmodule.HasRegisterInterfaces`, `module.HasGRPCGateway` and `module.HasAminoCodec` when relevant. + * SDK modules now directly implement those extension interfaces on `AppModule` instead of `AppModuleBasic`. +* (client/keys) [#18950](https://github.com/cosmos/cosmos-sdk/pull/18950) Improve ` keys add`, ` keys import` and ` keys rename` by checking name validation. +* (client/keys) [#18745](https://github.com/cosmos/cosmos-sdk/pull/18745) Improve ` keys export` and ` keys mnemonic` by adding --yes option to skip interactive confirmation. +* (client/keys) [#18743](https://github.com/cosmos/cosmos-sdk/pull/18743) Improve ` keys add -i` by hiding inputting of bip39 passphrase. +* (client/keys) [#18703](https://github.com/cosmos/cosmos-sdk/pull/18703) Improve ` keys add` and ` keys show` by checking whether there are duplicate keys in the multisig case. + * Usage of `Must...` kind of functions are avoided in keeper methods. +* (client/keys) [#18687](https://github.com/cosmos/cosmos-sdk/pull/18687) Improve ` keys mnemonic` by displaying mnemonic discreetly on an alternate screen and adding `--indiscreet` option to disable it. +* (client/keys) [#18684](https://github.com/cosmos/cosmos-sdk/pull/18684) Improve ` keys export` by displaying unarmored hex private key discreetly on an alternate screen and adding `--indiscreet` option to disable it. +* (client/keys) [#18663](https://github.com/cosmos/cosmos-sdk/pull/18663) Improve ` keys add` by displaying mnemonic discreetly on an alternate screen and adding `--indiscreet` option to disable it. +* (types) [#18440](https://github.com/cosmos/cosmos-sdk/pull/18440) Add `AmountOfNoValidation` to `sdk.DecCoins`. +* (client) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) Add `client.Context{}.WithAddressCodec`, `WithValidatorAddressCodec`, `WithConsensusAddressCodec` to provide address codecs to the client context. See the [UPGRADING.md](./UPGRADING.md) for more details. +* (crypto/keyring) [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503) Simplify keyring interfaces to use `[]byte` instead of `sdk.Address` for addresses. +* (all) [#16537](https://github.com/cosmos/cosmos-sdk/pull/16537) Properly propagated `fmt.Errorf` errors and using `errors.New` where appropriate. +* (rpc) [#17470](https://github.com/cosmos/cosmos-sdk/pull/17470) Avoid open 0.0.0.0 to public by default and add `listen-ip-address` argument for `testnet init-files` cmd. +* (types) [#17670](https://github.com/cosmos/cosmos-sdk/pull/17670) Use `ctx.CometInfo` in place of `ctx.VoteInfos` +* [#17733](https://github.com/cosmos/cosmos-sdk/pull/17733) Ensure `buf export` exports all proto dependencies +* (crypto/keys) [#18026](https://github.com/cosmos/cosmos-sdk/pull/18026) Made public key generation constant time on `secp256k1` +* (crypto | x/auth) [#14372](https://github.com/cosmos/cosmos-sdk/pull/18194) Key checks on signatures antehandle. +* (types) [#18963](https://github.com/cosmos/cosmos-sdk/pull/18963) Swap out amino json encoding of `ABCIMessageLogs` for std lib json encoding +* (x/auth) [#19651](https://github.com/cosmos/cosmos-sdk/pull/19651) Allow empty public keys in `GetSignBytesAdapter`. +* (x/genutil) [#19735](https://github.com/cosmos/cosmos-sdk/pull/19735) Update genesis api to match new `appmodule.HasGenesis` interface. +* (server) [#19966](https://github.com/cosmos/cosmos-sdk/pull/19966) Return BlockHeader by shallow copy in server Context. +* (proto) [#20098](https://github.com/cosmos/cosmos-sdk/pull/20098) Use cosmos_proto added_in annotation instead of // Since comments. +* (baseapp) [#20208](https://github.com/cosmos/cosmos-sdk/pull/20208) Skip running validateBasic for rechecking txs. +* (baseapp) [#20380](https://github.com/cosmos/cosmos-sdk/pull/20380) Enhanced OfferSnapshot documentation. +* (client) [#20771](https://github.com/cosmos/cosmos-sdk/pull/20771) Remove `ReadDefaultValuesFromDefaultClientConfig` from `client` package. (It was introduced in `v0.50.6` as a quick fix). + +### Bug Fixes + +* (baseapp) [#18727](https://github.com/cosmos/cosmos-sdk/pull/18727) Ensure that `BaseApp.Init` firstly returns any errors from a nil commit multistore instead of panicking on nil dereferencing and before sealing the app. +* (client) [#18622](https://github.com/cosmos/cosmos-sdk/pull/18622) Fixed a potential under/overflow from `uint64->int64` when computing gas fees as a LegacyDec. +* (client/keys) [#18562](https://github.com/cosmos/cosmos-sdk/pull/18562) `keys delete` won't terminate when a key is not found. +* (baseapp) [#18383](https://github.com/cosmos/cosmos-sdk/pull/18383) Fixed a data race inside BaseApp.getContext, found by end-to-end (e2e) tests. +* (client/server) [#18345](https://github.com/cosmos/cosmos-sdk/pull/18345) Consistently set viper prefix in client and server. It defaults for the binary name for both client and server. +* (simulation) [#17911](https://github.com/cosmos/cosmos-sdk/pull/17911) Fix all problems with executing command `make test-sim-custom-genesis-fast` for simulation test. +* (simulation) [#18196](https://github.com/cosmos/cosmos-sdk/pull/18196) Fix the problem of `validator set is empty after InitGenesis` in simulation test. +* (baseapp) [#18551](https://github.com/cosmos/cosmos-sdk/pull/18551) Fix SelectTxForProposal the calculation method of tx bytes size is inconsistent with CometBFT +* (server) [#18994](https://github.com/cosmos/cosmos-sdk/pull/18994) Update server context directly rather than a reference to a sub-object +* [#19833](https://github.com/cosmos/cosmos-sdk/pull/19833) Fix some places in which we call Remove inside a Walk. +* [#19851](https://github.com/cosmos/cosmos-sdk/pull/19851) Fix some places in which we call Remove inside a Walk (x/staking and x/gov). +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) * [#20631](https://github.com/cosmos/cosmos-sdk/pull/20631) Fix json parsing in the wait-tx command. * (x/auth) [#20438](https://github.com/cosmos/cosmos-sdk/pull/20438) Add `--skip-signature-verification` flag to multisign command to allow nested multisigs. diff --git a/client/config/config.go b/client/config/config.go index e3a2a8646d93..736f6c7eb51e 100644 --- a/client/config/config.go +++ b/client/config/config.go @@ -46,6 +46,7 @@ func (c *ClientConfig) SetBroadcastMode(broadcastMode string) { c.BroadcastMode = broadcastMode } +<<<<<<< HEAD // ReadDefaultValuesFromDefaultClientConfig reads default values from default client.toml file and updates them in client.Context // The client.toml is then discarded. func ReadDefaultValuesFromDefaultClientConfig(ctx client.Context) (client.Context, error) { @@ -68,6 +69,13 @@ func ReadDefaultValuesFromDefaultClientConfig(ctx client.Context) (client.Contex // ReadFromClientConfig reads values from client.toml file and updates them in client Context func ReadFromClientConfig(ctx client.Context) (client.Context, error) { +======= +// CreateClientConfig reads the client.toml file and returns a new populated client.Context +// If the client.toml file does not exist, it creates one with default values. +// It takes a customClientTemplate and customConfig as input that can be used to overwrite the default config and enhance the client.toml file. +// The custom template/config must be both provided or be "" and nil. +func CreateClientConfig(ctx client.Context, customClientTemplate string, customConfig interface{}) (client.Context, error) { +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) configPath := filepath.Join(ctx.HomeDir, "config") configFilePath := filepath.Join(configPath, "client.toml") conf := DefaultConfig() diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md index 4e7b6c91e8af..a732e94dde81 100644 --- a/client/v2/CHANGELOG.md +++ b/client/v2/CHANGELOG.md @@ -36,6 +36,21 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +<<<<<<< HEAD +======= + + +### Features + +* [#18626](https://github.com/cosmos/cosmos-sdk/pull/18626) Support for off-chain signing and verification of a file. +* [#18461](https://github.com/cosmos/cosmos-sdk/pull/18461) Support governance proposals. +* [#20771](https://github.com/cosmos/cosmos-sdk/pull/20771) Add `GetNodeHomeDirectory` helper. + +### API Breaking Changes + +* [#17709](https://github.com/cosmos/cosmos-sdk/pull/17709) Address codecs have been removed from `autocli.AppOptions` and `flag.Builder`. Instead client/v2 uses the address codecs present in the context (introduced in [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503)). + +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) ## [v2.0.0-beta.2] - 2024-06-19 ### Features diff --git a/client/v2/helpers/home.go b/client/v2/helpers/home.go new file mode 100644 index 000000000000..f62ff30490e9 --- /dev/null +++ b/client/v2/helpers/home.go @@ -0,0 +1,36 @@ +package helpers + +import ( + "os" + "path/filepath" + "strings" +) + +// GetNodeHomeDirectory gets the home directory of the node (where the config is located). +// It parses the home flag if set if the `NODE_HOME` environment variable if set (and ignores name). +// Otherwise, it returns the default home directory given its name. +func GetNodeHomeDirectory(name string) (string, error) { + // get the home directory from the flag + args := os.Args + for i := 0; i < len(args); i++ { + if args[i] == "--home" && i+1 < len(args) { + return filepath.Clean(args[i+1]), nil + } else if strings.HasPrefix(args[i], "--home=") { + return filepath.Clean(args[i][7:]), nil + } + } + + // get the home directory from the environment variable + homeDir := os.Getenv("NODE_HOME") + if homeDir != "" { + return filepath.Clean(homeDir), nil + } + + // return the default home directory + userHomeDir, err := os.UserHomeDir() + if err != nil { + return "", err + } + + return filepath.Join(userHomeDir, name), nil +} diff --git a/docs/docs/learn/advanced/07-cli.md b/docs/docs/learn/advanced/07-cli.md index 2762d83e62a1..3ee93c0524e0 100644 --- a/docs/docs/learn/advanced/07-cli.md +++ b/docs/docs/learn/advanced/07-cli.md @@ -153,7 +153,7 @@ Flags are added to commands directly (generally in the [module's CLI file](../.. ## Environment variables -Each flag is bound to its respective named environment variable. Then name of the environment variable consist of two parts - capital case `basename` followed by flag name of the flag. `-` must be substituted with `_`. For example flag `--home` for application with basename `GAIA` is bound to `GAIA_HOME`. It allows reducing the amount of flags typed for routine operations. For example instead of: +Each flag is bound to its respective named environment variable. Then name of the environment variable consist of two parts - capital case `basename` followed by flag name of the flag. `-` must be substituted with `_`. For example flag `--node` for application with basename `GAIA` is bound to `GAIA_NODE`. It allows reducing the amount of flags typed for routine operations. For example instead of: ```shell gaia --home=./ --node= --chain-id="testchain-1" --keyring-backend=test tx ... --from= @@ -163,7 +163,7 @@ this will be more convenient: ```shell # define env variables in .env, .envrc etc -GAIA_HOME= +NODE_HOME= GAIA_NODE= GAIA_CHAIN_ID="testchain-1" GAIA_KEYRING_BACKEND="test" diff --git a/scripts/init-simapp.sh b/scripts/init-simapp.sh index 982208da0161..6913079e0a31 100755 --- a/scripts/init-simapp.sh +++ b/scripts/init-simapp.sh @@ -4,7 +4,7 @@ SIMD_BIN=${SIMD_BIN:=$(which simd 2>/dev/null)} if [ -z "$SIMD_BIN" ]; then echo "SIMD_BIN is not set. Make sure to run make install before"; exit 1; fi echo "using $SIMD_BIN" -if [ -d "$($SIMD_BIN config home)" ]; then rm -r $($SIMD_BIN config home); fi +if [ -d "$($SIMD_BIN config home)" ]; then rm -rv $($SIMD_BIN config home); fi $SIMD_BIN config set client chain-id demo $SIMD_BIN config set client keyring-backend test $SIMD_BIN config set app api.enable true diff --git a/scripts/simapp-v2-init.sh b/scripts/simapp-v2-init.sh new file mode 100755 index 000000000000..d13960d2d80e --- /dev/null +++ b/scripts/simapp-v2-init.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +set -o errexit +set -o nounset +set -x + +ROOT=$PWD + +SIMD="$ROOT/build/simdv2" +CONFIG="${CONFIG:-$HOME/.simappv2/config}" + +COSMOS_BUILD_OPTIONS=v2 make build + +if [ -d "$($SIMD config home)" ]; then rm -rv $($SIMD config home); fi + +$SIMD init simapp-v2-node --chain-id simapp-v2-chain + +cd "$CONFIG" + +# to change the voting_period +jq '.app_state.gov.voting_params.voting_period = "600s"' genesis.json > temp.json && mv temp.json genesis.json + +# to change the inflation +jq '.app_state.mint.minter.inflation = "0.300000000000000000"' genesis.json > temp.json && mv temp.json genesis.json + +# change the initial height to 2 to work around store/v2 and iavl limitations with a genesis block +jq '.initial_height = 2' genesis.json > temp.json && mv temp.json genesis.json + +$SIMD config set client chain-id simapp-v2-chain +$SIMD keys add test_validator --indiscreet +VALIDATOR_ADDRESS=$($SIMD keys show test_validator -a --keyring-backend test) + +$SIMD genesis add-genesis-account "$VALIDATOR_ADDRESS" 1000000000stake +$SIMD genesis gentx test_validator 1000000000stake --keyring-backend test +$SIMD genesis collect-gentxs + +$SIMD start & +SIMD_PID=$! + +cnt=0 +while ! $SIMD query block --type=height 5; do + cnt=$((cnt + 1)) + if [ $cnt -gt 30 ]; then + kill -9 "$SIMD_PID" + exit 1 + fi + sleep 1 +done + +kill -9 "$SIMD_PID" diff --git a/server/v2/cometbft/flags/flags.go b/server/v2/cometbft/flags/flags.go new file mode 100644 index 000000000000..878cc9c28227 --- /dev/null +++ b/server/v2/cometbft/flags/flags.go @@ -0,0 +1,76 @@ +package flags + +import "github.com/spf13/cobra" + +const ( + FlagQuery = "query" + FlagType = "type" + FlagOrderBy = "order_by" +) + +const ( + FlagChainID = "chain-id" + FlagNode = "node" + FlagGRPC = "grpc-addr" + FlagGRPCInsecure = "grpc-insecure" + FlagHeight = "height" + FlagGasAdjustment = "gas-adjustment" + FlagFrom = "from" + FlagName = "name" + FlagAccountNumber = "account-number" + FlagSequence = "sequence" + FlagNote = "note" + FlagFees = "fees" + FlagGas = "gas" + FlagGasPrices = "gas-prices" + FlagBroadcastMode = "broadcast-mode" + FlagDryRun = "dry-run" + FlagGenerateOnly = "generate-only" + FlagOffline = "offline" + FlagOutputDocument = "output-document" // inspired by wget -O + FlagSkipConfirmation = "yes" + FlagProve = "prove" + FlagKeyringBackend = "keyring-backend" + FlagPage = "page" + FlagLimit = "limit" + FlagSignMode = "sign-mode" + FlagPageKey = "page-key" + FlagOffset = "offset" + FlagCountTotal = "count-total" + FlagTimeoutHeight = "timeout-height" + FlagUnordered = "unordered" + FlagKeyAlgorithm = "algo" + FlagKeyType = "key-type" + FlagFeePayer = "fee-payer" + FlagFeeGranter = "fee-granter" + FlagReverse = "reverse" + FlagTip = "tip" + FlagAux = "aux" + FlagInitHeight = "initial-height" + // FlagOutput is the flag to set the output format. + // This differs from FlagOutputDocument that is used to set the output file. + FlagOutput = "output" + // Logging flags + FlagLogLevel = "log_level" + FlagLogFormat = "log_format" + FlagLogNoColor = "log_no_color" +) + +// List of supported output formats +const ( + OutputFormatJSON = "json" + OutputFormatText = "text" +) + +// AddQueryFlagsToCmd adds common flags to a module query command. +func AddQueryFlagsToCmd(cmd *cobra.Command) { + cmd.Flags().String(FlagNode, "tcp://localhost:26657", ": to CometBFT RPC interface for this chain") + cmd.Flags().String(FlagGRPC, "", "the gRPC endpoint to use for this chain") + cmd.Flags().Bool(FlagGRPCInsecure, false, "allow gRPC over insecure channels, if not the server must use TLS") + cmd.Flags().Int64(FlagHeight, 0, "Use a specific height to query state at (this can error if the node is pruning state)") + cmd.Flags().StringP(FlagOutput, "o", "text", "Output format (text|json)") + + // some base commands does not require chainID e.g `simd testnet` while subcommands do + // hence the flag should not be required for those commands + _ = cmd.MarkFlagRequired(FlagChainID) +} diff --git a/server/v2/commands.go b/server/v2/commands.go new file mode 100644 index 000000000000..a6059388ad2a --- /dev/null +++ b/server/v2/commands.go @@ -0,0 +1,134 @@ +package serverv2 + +import ( + "context" + "errors" + "fmt" + "os" + "os/signal" + "path/filepath" + "syscall" + + "github.com/spf13/cobra" + + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" +) + +func Commands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger log.Logger, components ...ServerComponent[transaction.Tx]) (CLIConfig, error) { + if len(components) == 0 { + return CLIConfig{}, errors.New("no components provided") + } + + server := NewServer(logger, components...) + flags := server.StartFlags() + + startCmd := &cobra.Command{ + Use: "start", + Short: "Run the application", + RunE: func(cmd *cobra.Command, args []string) error { + v := GetViperFromCmd(cmd) + l := GetLoggerFromCmd(cmd) + + for _, startFlags := range flags { + if err := v.BindPFlags(startFlags); err != nil { + return err + } + } + + if err := v.BindPFlags(cmd.Flags()); err != nil { + return err + } + + app := newApp(l, v) + + if err := server.Init(app, v, l); err != nil { + return err + } + + srvConfig := Config{StartBlock: true} + ctx := cmd.Context() + ctx = context.WithValue(ctx, ServerContextKey, srvConfig) + ctx, cancelFn := context.WithCancel(ctx) + go func() { + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) + sig := <-sigCh + cancelFn() + cmd.Printf("caught %s signal\n", sig.String()) + + if err := server.Stop(ctx); err != nil { + cmd.PrintErrln("failed to stop servers:", err) + } + }() + + if err := server.Start(ctx); err != nil { + return fmt.Errorf("failed to start servers: %w", err) + } + + return nil + }, + } + + cmds := server.CLICommands() + cmds.Commands = append(cmds.Commands, startCmd) + + return cmds, nil +} + +func AddCommands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger log.Logger, components ...ServerComponent[transaction.Tx]) error { + cmds, err := Commands(rootCmd, newApp, logger, components...) + if err != nil { + return err + } + + server := NewServer(logger, components...) + originalPersistentPreRunE := rootCmd.PersistentPreRunE + rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { + home, err := cmd.Flags().GetString(FlagHome) + if err != nil { + return err + } + + err = configHandle(server, home, cmd) + if err != nil { + return err + } + + if rootCmd.PersistentPreRun != nil { + rootCmd.PersistentPreRun(cmd, args) + return nil + } + + return originalPersistentPreRunE(cmd, args) + } + + rootCmd.AddCommand(cmds.Commands...) + return nil +} + +// configHandle writes the default config to the home directory if it does not exist and sets the server context +func configHandle(s *Server, home string, cmd *cobra.Command) error { + // we need to check app.toml as the config folder can already exist for the client.toml + if _, err := os.Stat(filepath.Join(home, "config", "app.toml")); os.IsNotExist(err) { + if err = s.WriteConfig(filepath.Join(home, "config")); err != nil { + return err + } + } + + viper, err := ReadConfig(filepath.Join(home, "config")) + if err != nil { + return err + } + viper.Set(FlagHome, home) + if err := viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + + log, err := NewLogger(viper, cmd.OutOrStdout()) + if err != nil { + return err + } + + return SetCmdServerContext(cmd, viper, log) +} diff --git a/simapp/CHANGELOG.md b/simapp/CHANGELOG.md new file mode 100644 index 000000000000..2daff48a15f2 --- /dev/null +++ b/simapp/CHANGELOG.md @@ -0,0 +1,52 @@ + + +# Changelog + +`SimApp` is an application built using the Cosmos SDK for testing and educational purposes. +It won't be tagged or intented to be imported in an application. +This changelog is aimed to help developers understand the wiring changes between SDK versions. +It is an exautive list of changes that completes the SimApp section in the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md#simapp) + +## v0.50 to v0.51 + +Always refer to the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md) to understand the changes. + +* [#20409](https://github.com/cosmos/cosmos-sdk/pull/20409) Add `tx` as `SkipStoreKeys` in `app_config.go`. +* [#20485](https://github.com/cosmos/cosmos-sdk/pull/20485) The signature of `x/upgrade/types.UpgradeHandler` has changed to accept `appmodule.VersionMap` from `module.VersionMap`. These types are interchangeable, but usages of `UpradeKeeper.SetUpgradeHandler` may need to adjust their usages to match the new signature. +* [#20740](https://github.com/cosmos/cosmos-sdk/pull/20740) Update `genutilcli.Commands` to use the genutil modules from the module manager. +* [#20771](https://github.com/cosmos/cosmos-sdk/pull/20771) Use client/v2 `GetNodeHomeDirectory` helper in `app.go` and use the `DefaultNodeHome` constant everywhere in the app. + + + +## v0.47 to v0.50 + +No changelog is provided for this migration. Please refer to the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md#v050x) + +## v0.46 to v0.47 + +No changelog is provided for this migration. Please refer to the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md#v047x) + +## v0.45 to v0.46 + +No changelog is provided for this migration. Please refer to the [UPGRADING.md](https://github.com/cosmos/cosmos-sdk/blob/main/UPGRADING.md#v046x) diff --git a/simapp/app.go b/simapp/app.go index 3c27030af82d..13e270b761e2 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -12,8 +12,13 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" "cosmossdk.io/client/v2/autocli" +<<<<<<< HEAD "cosmossdk.io/core/appmodule" "cosmossdk.io/log" +======= + clienthelpers "cosmossdk.io/client/v2/helpers" + "cosmossdk.io/core/log" +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) storetypes "cosmossdk.io/store/types" "cosmossdk.io/x/circuit" circuitkeeper "cosmossdk.io/x/circuit/keeper" @@ -178,12 +183,11 @@ type SimApp struct { } func init() { - userHomeDir, err := os.UserHomeDir() + var err error + DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".simapp") if err != nil { panic(err) } - - DefaultNodeHome = filepath.Join(userHomeDir, ".simapp") } // NewSimApp returns a reference to an initialized SimApp. @@ -511,6 +515,28 @@ func NewSimApp( } app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) +<<<<<<< HEAD +======= + // create, start, and load the unordered tx manager + utxDataDir := filepath.Join(homePath, "data") + app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir) + app.UnorderedTxManager.Start() + + if err := app.UnorderedTxManager.OnInit(); err != nil { + panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err)) + } + + // register custom snapshot extensions (if any) + if manager := app.SnapshotManager(); manager != nil { + err := manager.RegisterExtensions( + unorderedtx.NewSnapshotter(app.UnorderedTxManager), + ) + if err != nil { + panic(fmt.Errorf("failed to register snapshot extension: %w", err)) + } + } + +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) app.sm.RegisterStoreDecoders() // initialize stores diff --git a/simapp/app_v2.go b/simapp/app_v2.go index e10a54e7449e..b9e969ffea4c 100644 --- a/simapp/app_v2.go +++ b/simapp/app_v2.go @@ -4,11 +4,15 @@ package simapp import ( "io" - "os" "path/filepath" dbm "github.com/cosmos/cosmos-db" +<<<<<<< HEAD:simapp/app_v2.go +======= + clienthelpers "cosmossdk.io/client/v2/helpers" + "cosmossdk.io/core/legacy" +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)):simapp/app_di.go "cosmossdk.io/depinject" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" @@ -89,12 +93,11 @@ type SimApp struct { } func init() { - userHomeDir, err := os.UserHomeDir() + var err error + DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".simapp") if err != nil { panic(err) } - - DefaultNodeHome = filepath.Join(userHomeDir, ".simapp") } // NewSimApp returns a reference to an initialized SimApp. diff --git a/simapp/simd/cmd/commands.go b/simapp/simd/cmd/commands.go index 2b6c2be24901..00c810442f78 100644 --- a/simapp/simd/cmd/commands.go +++ b/simapp/simd/cmd/commands.go @@ -3,7 +3,6 @@ package cmd import ( "errors" "io" - "os" cmtcfg "github.com/cometbft/cometbft/config" dbm "github.com/cosmos/cosmos-db" @@ -16,7 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "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" @@ -216,13 +214,6 @@ func appExport( appOpts servertypes.AppOptions, modulesToExport []string, ) (servertypes.ExportedApp, error) { - // 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") @@ -245,13 +236,3 @@ func appExport( return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } - -var tempDir = func() string { - dir, err := os.MkdirTemp("", "simapp") - if err != nil { - dir = simapp.DefaultNodeHome - } - defer os.RemoveAll(dir) - - return dir -} diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 8fdb0ae87d8f..9cd38457b9a6 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -26,7 +26,7 @@ import ( func NewRootCmd() *cobra.Command { // we "pre"-instantiate the application for getting the injected/configured encoding configuration // note, this is not necessary when using app wiring, as depinject can be directly used (see root_v2.go) - tempApp := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(tempDir())) + tempApp := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(simapp.DefaultNodeHome)) encodingConfig := params.EncodingConfig{ InterfaceRegistry: tempApp.InterfaceRegistry(), Codec: tempApp.AppCodec(), @@ -95,7 +95,19 @@ func NewRootCmd() *cobra.Command { }, } +<<<<<<< HEAD initRootCmd(rootCmd, encodingConfig.TxConfig, tempApp.BasicModuleManager) +======= + initRootCmd(rootCmd, encodingConfig.TxConfig, tempApp.ModuleManager) + + // autocli opts + customClientTemplate, customClientConfig := initClientConfig() + var err error + initClientCtx, err = config.CreateClientConfig(initClientCtx, customClientTemplate, customClientConfig) + if err != nil { + panic(err) + } +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) // add keyring to autocli opts autoCliOpts := tempApp.AutoCliOpts() diff --git a/simapp/simd/cmd/root_v2.go b/simapp/simd/cmd/root_v2.go index 919a79de4c90..9f7752852585 100644 --- a/simapp/simd/cmd/root_v2.go +++ b/simapp/simd/cmd/root_v2.go @@ -17,7 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/server" - simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth/tx" authtxconfig "github.com/cosmos/cosmos-sdk/x/auth/tx/config" @@ -33,11 +32,16 @@ func NewRootCmd() *cobra.Command { ) if err := depinject.Inject( +<<<<<<< HEAD:simapp/simd/cmd/root_v2.go depinject.Configs(simapp.AppConfig, depinject.Supply( log.NewNopLogger(), simtestutil.NewAppOptionsWithFlagHome(tempDir()), ), +======= + depinject.Configs(simapp.AppConfig(), + depinject.Supply(log.NewNopLogger()), +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)):simapp/simd/cmd/root_di.go depinject.Provide( ProvideClientContext, ), @@ -104,8 +108,17 @@ func ProvideClientContext( WithHomeDir(simapp.DefaultNodeHome). WithViper("") // In simapp, we don't use any prefix for env variables. +<<<<<<< HEAD:simapp/simd/cmd/root_v2.go // Read the config again to overwrite the default values with the values from the config file clientCtx, _ = config.ReadDefaultValuesFromDefaultClientConfig(clientCtx) +======= + // Read the config to overwrite the default values with the values from the config file + customClientTemplate, customClientConfig := initClientConfig() + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + if err != nil { + panic(err) + } +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)):simapp/simd/cmd/root_di.go // textual is enabled by default, we need to re-create the tx config grpc instead of bank keeper. txConfigOpts.TextualCoinMetadataQueryFn = authtxconfig.NewGRPCCoinMetadataQueryFn(clientCtx) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go new file mode 100644 index 000000000000..a55d9ec3289b --- /dev/null +++ b/simapp/v2/app_di.go @@ -0,0 +1,256 @@ +package simapp + +import ( + _ "embed" + "path/filepath" + + "github.com/spf13/viper" + + clienthelpers "cosmossdk.io/client/v2/helpers" + coreapp "cosmossdk.io/core/app" + "cosmossdk.io/core/legacy" + "cosmossdk.io/core/log" + "cosmossdk.io/depinject" + "cosmossdk.io/runtime/v2" + serverv2 "cosmossdk.io/server/v2" + "cosmossdk.io/store/v2" + "cosmossdk.io/store/v2/commitment/iavl" + "cosmossdk.io/store/v2/db" + "cosmossdk.io/store/v2/root" + "cosmossdk.io/x/accounts" + authkeeper "cosmossdk.io/x/auth/keeper" + authzkeeper "cosmossdk.io/x/authz/keeper" + bankkeeper "cosmossdk.io/x/bank/keeper" + circuitkeeper "cosmossdk.io/x/circuit/keeper" + consensuskeeper "cosmossdk.io/x/consensus/keeper" + distrkeeper "cosmossdk.io/x/distribution/keeper" + evidencekeeper "cosmossdk.io/x/evidence/keeper" + feegrantkeeper "cosmossdk.io/x/feegrant/keeper" + govkeeper "cosmossdk.io/x/gov/keeper" + groupkeeper "cosmossdk.io/x/group/keeper" + mintkeeper "cosmossdk.io/x/mint/keeper" + nftkeeper "cosmossdk.io/x/nft/keeper" + _ "cosmossdk.io/x/protocolpool" + poolkeeper "cosmossdk.io/x/protocolpool/keeper" + slashingkeeper "cosmossdk.io/x/slashing/keeper" + stakingkeeper "cosmossdk.io/x/staking/keeper" + upgradekeeper "cosmossdk.io/x/upgrade/keeper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/std" +) + +// DefaultNodeHome default home directories for the application daemon +var DefaultNodeHome string + +// SimApp extends an ABCI application, but with most of its parameters exported. +// They are exported for convenience in creating helper functions, as object +// capabilities aren't needed for testing. +type SimApp struct { + *runtime.App + legacyAmino legacy.Amino + appCodec codec.Codec + txConfig client.TxConfig + interfaceRegistry codectypes.InterfaceRegistry + + // keepers + AccountsKeeper accounts.Keeper + AuthKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper *govkeeper.Keeper + UpgradeKeeper *upgradekeeper.Keeper + AuthzKeeper authzkeeper.Keeper + EvidenceKeeper evidencekeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + GroupKeeper groupkeeper.Keeper + NFTKeeper nftkeeper.Keeper + ConsensusParamsKeeper consensuskeeper.Keeper + CircuitBreakerKeeper circuitkeeper.Keeper + PoolKeeper poolkeeper.Keeper +} + +func init() { + var err error + DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".simappv2") + if err != nil { + panic(err) + } +} + +// AppConfig returns the default app config. +func AppConfig() depinject.Config { + return depinject.Configs( + appConfig, // Alternatively use appconfig.LoadYAML(AppConfigYAML) + ) +} + +// NewSimApp returns a reference to an initialized SimApp. +func NewSimApp( + logger log.Logger, + viper *viper.Viper, +) *SimApp { + viper.Set(serverv2.FlagHome, DefaultNodeHome) // TODO possibly set earlier when viper is created + scRawDb, err := db.NewGoLevelDB("application", filepath.Join(DefaultNodeHome, "data"), nil) + if err != nil { + panic(err) + } + var ( + app = &SimApp{} + appBuilder *runtime.AppBuilder + + // merge the AppConfig and other configuration in one config + appConfig = depinject.Configs( + AppConfig(), + depinject.Supply( + logger, + &root.FactoryOptions{ + Logger: logger, + RootDir: DefaultNodeHome, + SSType: 0, + SCType: 0, + SCPruneOptions: &store.PruneOptions{ + KeepRecent: 0, + Interval: 0, + }, + IavlConfig: &iavl.Config{ + CacheSize: 100_000, + SkipFastStorageUpgrade: true, + }, + SCRawDB: scRawDb, + }, + viper, + + // ADVANCED CONFIGURATION + + // + // AUTH + // + // For providing a custom function required in auth to generate custom account types + // add it below. By default the auth module uses simulation.RandomGenesisAccounts. + // + // authtypes.RandomGenesisAccountsFn(simulation.RandomGenesisAccounts), + // + // For providing a custom a base account type add it below. + // By default the auth module uses authtypes.ProtoBaseAccount(). + // + // func() sdk.AccountI { return authtypes.ProtoBaseAccount() }, + // + // For providing a different address codec, add it below. + // By default the auth module uses a Bech32 address codec, + // with the prefix defined in the auth module configuration. + // + // func() address.Codec { return <- custom address codec type -> } + + // + // STAKING + // + // For provinding a different validator and consensus address codec, add it below. + // By default the staking module uses the bech32 prefix provided in the auth config, + // and appends "valoper" and "valcons" for validator and consensus addresses respectively. + // When providing a custom address codec in auth, custom address codecs must be provided here as well. + // + // func() runtime.ValidatorAddressCodec { return <- custom validator address codec type -> } + // func() runtime.ConsensusAddressCodec { return <- custom consensus address codec type -> } + + // + // MINT + // + + // For providing a custom inflation function for x/mint add here your + // custom function that implements the minttypes.InflationCalculationFn + // interface. + ), + depinject.Provide( + codec.ProvideInterfaceRegistry, + codec.ProvideAddressCodec, + codec.ProvideProtoCodec, + codec.ProvideLegacyAmino, + ), + depinject.Invoke( + std.RegisterInterfaces, + std.RegisterLegacyAminoCodec, + ), + ) + ) + + if err := depinject.Inject(appConfig, + &appBuilder, + &app.appCodec, + &app.legacyAmino, + &app.txConfig, + &app.interfaceRegistry, + &app.AuthKeeper, + &app.BankKeeper, + &app.StakingKeeper, + &app.SlashingKeeper, + &app.MintKeeper, + &app.DistrKeeper, + &app.GovKeeper, + &app.UpgradeKeeper, + &app.AuthzKeeper, + &app.EvidenceKeeper, + &app.FeeGrantKeeper, + &app.GroupKeeper, + &app.NFTKeeper, + &app.ConsensusParamsKeeper, + &app.CircuitBreakerKeeper, + &app.PoolKeeper, + ); err != nil { + panic(err) + } + + app.App, err = appBuilder.Build() + if err != nil { + panic(err) + } + + /**** Module Options ****/ + + // RegisterUpgradeHandlers is used for registering any on-chain upgrades. + app.RegisterUpgradeHandlers() + + // TODO (here or in runtime/v2) + // wire simulation manager + // wire snapshot manager + // wire unordered tx manager + + if err := app.LoadLatest(); err != nil { + panic(err) + } + + return app +} + +// AppCodec returns SimApp's app codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *SimApp) AppCodec() codec.Codec { + return app.appCodec +} + +// InterfaceRegistry returns SimApp's InterfaceRegistry. +func (app *SimApp) InterfaceRegistry() coreapp.InterfaceRegistry { + return app.interfaceRegistry +} + +// TxConfig returns SimApp's TxConfig. +func (app *SimApp) TxConfig() client.TxConfig { + return app.txConfig +} + +// GetConsensusAuthority gets the consensus authority. +func (app *SimApp) GetConsensusAuthority() string { + return app.ConsensusParamsKeeper.GetAuthority() +} + +// GetStore gets the app store. +func (app *SimApp) GetStore() any { + return app.App.GetStore() +} diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go new file mode 100644 index 000000000000..b4b186c0f01f --- /dev/null +++ b/simapp/v2/simdv2/cmd/commands.go @@ -0,0 +1,197 @@ +package cmd + +import ( + "errors" + "fmt" + "io" + + dbm "github.com/cosmos/cosmos-db" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "cosmossdk.io/client/v2/offchain" + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" + runtimev2 "cosmossdk.io/runtime/v2" + serverv2 "cosmossdk.io/server/v2" + "cosmossdk.io/server/v2/api/grpc" + "cosmossdk.io/server/v2/cometbft" + "cosmossdk.io/simapp/v2" + confixcmd "cosmossdk.io/tools/confix/cmd" + authcmd "cosmossdk.io/x/auth/client/cli" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/debug" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +var _ transaction.Codec[transaction.Tx] = &temporaryTxDecoder{} + +type temporaryTxDecoder struct { + txConfig client.TxConfig +} + +// Decode implements transaction.Codec. +func (t *temporaryTxDecoder) Decode(bz []byte) (transaction.Tx, error) { + return t.txConfig.TxDecoder()(bz) +} + +// DecodeJSON implements transaction.Codec. +func (t *temporaryTxDecoder) DecodeJSON(bz []byte) (transaction.Tx, error) { + return t.txConfig.TxJSONDecoder()(bz) +} + +func newApp(logger log.Logger, viper *viper.Viper) serverv2.AppI[transaction.Tx] { + return simapp.NewSimApp(logger, viper) +} + +func initRootCmd( + rootCmd *cobra.Command, + txConfig client.TxConfig, + moduleManager *runtimev2.MM, +) { + cfg := sdk.GetConfig() + cfg.Seal() + + rootCmd.AddCommand( + genutilcli.InitCmd(moduleManager), + debug.Cmd(), + confixcmd.ConfigCommand(), + // pruning.Cmd(newApp), // TODO add to comet server + // snapshot.Cmd(newApp), // TODO add to comet server + ) + + logger, err := serverv2.NewLogger(viper.New(), rootCmd.OutOrStdout()) + if err != nil { + panic(fmt.Sprintf("failed to create logger: %v", err)) + } + + // Add empty server struct here for writing default config + if err = serverv2.AddCommands( + rootCmd, + newApp, + logger, + cometbft.New(&temporaryTxDecoder{txConfig}), + grpc.New(), + ); err != nil { + panic(err) + } + + // add keybase, auxiliary RPC, query, genesis, and tx child commands + rootCmd.AddCommand( + server.StatusCommand(), + genesisCommand(txConfig, moduleManager, appExport), + queryCommand(), + txCommand(), + keys.Commands(), + offchain.OffChain(), + ) +} + +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand( + txConfig client.TxConfig, + moduleManager *runtimev2.MM, + appExport func(logger log.Logger, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + viper *viper.Viper, + modulesToExport []string, + ) (servertypes.ExportedApp, error), + cmds ...*cobra.Command, +) *cobra.Command { + compatAppExporter := func(logger log.Logger, db dbm.DB, traceWriter io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOpts servertypes.AppOptions, modulesToExport []string) (servertypes.ExportedApp, error) { + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + return appExport(logger, height, forZeroHeight, jailAllowedAddrs, viperAppOpts, modulesToExport) + } + + cmd := genutilcli.Commands(txConfig, moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule), moduleManager, compatAppExporter) + 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( + rpc.QueryEventForTxCmd(), + server.QueryBlockCmd(), + authcmd.QueryTxsByEventsCmd(), + server.QueryBlocksCmd(), + authcmd.QueryTxCmd(), + server.QueryBlockResultsCmd(), + ) + + 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.GetSimulateCmd(), + ) + + return cmd +} + +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + viper *viper.Viper, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + // overwrite the FlagInvCheckPeriod + viper.Set(server.FlagInvCheckPeriod, 1) + + var simApp *simapp.SimApp + if height != -1 { + simApp = simapp.NewSimApp(logger, viper) + + if err := simApp.LoadHeight(uint64(height)); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = simapp.NewSimApp(logger, viper) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) +} diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go new file mode 100644 index 000000000000..51c873be570b --- /dev/null +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -0,0 +1,138 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" + + "cosmossdk.io/client/v2/autocli" + "cosmossdk.io/core/address" + "cosmossdk.io/core/legacy" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/runtime/v2" + "cosmossdk.io/simapp/v2" + "cosmossdk.io/x/auth/tx" + authtxconfig "cosmossdk.io/x/auth/tx/config" + "cosmossdk.io/x/auth/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/std" +) + +// NewRootCmd creates a new root command for simd. It is called once in the main function. +func NewRootCmd() *cobra.Command { + var ( + autoCliOpts autocli.AppOptions + moduleManager *runtime.MM + clientCtx client.Context + ) + + if err := depinject.Inject( + depinject.Configs( + simapp.AppConfig(), + depinject.Supply(log.NewNopLogger()), + depinject.Provide( + codec.ProvideInterfaceRegistry, + codec.ProvideAddressCodec, + codec.ProvideProtoCodec, + codec.ProvideLegacyAmino, + ProvideClientContext, + ), + depinject.Invoke( + std.RegisterInterfaces, + std.RegisterLegacyAminoCodec, + ), + ), + &autoCliOpts, + &moduleManager, + &clientCtx, + ); err != nil { + panic(err) + } + + rootCmd := &cobra.Command{ + Use: "simd", + Short: "simulation app", + SilenceErrors: true, + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + // set the default command outputs + cmd.SetOut(cmd.OutOrStdout()) + cmd.SetErr(cmd.ErrOrStderr()) + + clientCtx = clientCtx.WithCmdContext(cmd.Context()) + clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags()) + if err != nil { + return err + } + + customClientTemplate, customClientConfig := initClientConfig() + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + if err != nil { + return err + } + + if err := client.SetCmdClientContextHandler(clientCtx, cmd); err != nil { + return err + } + + return nil + }, + } + + initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager) + if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { + panic(err) + } + + return rootCmd +} + +func ProvideClientContext( + appCodec codec.Codec, + interfaceRegistry codectypes.InterfaceRegistry, + txConfigOpts tx.ConfigOptions, + legacyAmino legacy.Amino, + addressCodec address.Codec, + validatorAddressCodec address.ValidatorAddressCodec, + consensusAddressCodec address.ConsensusAddressCodec, +) client.Context { + var err error + + amino, ok := legacyAmino.(*codec.LegacyAmino) + if !ok { + panic("legacy.Amino must be an *codec.LegacyAmino instance for legacy ClientContext") + } + + clientCtx := client.Context{}. + WithCodec(appCodec). + WithInterfaceRegistry(interfaceRegistry). + WithLegacyAmino(amino). + WithInput(os.Stdin). + WithAccountRetriever(types.AccountRetriever{}). + WithAddressCodec(addressCodec). + WithValidatorAddressCodec(validatorAddressCodec). + WithConsensusAddressCodec(consensusAddressCodec). + WithHomeDir(simapp.DefaultNodeHome). + WithViper("") // uses by default the binary name as prefix + + // Read the config to overwrite the default values with the values from the config file + customClientTemplate, customClientConfig := initClientConfig() + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + if err != nil { + panic(err) + } + + // textual is enabled by default, we need to re-create the tx config grpc instead of bank keeper. + txConfigOpts.TextualCoinMetadataQueryFn = authtxconfig.NewGRPCCoinMetadataQueryFn(clientCtx) + txConfig, err := tx.NewTxConfigWithOptions(clientCtx.Codec, txConfigOpts) + if err != nil { + panic(err) + } + clientCtx = clientCtx.WithTxConfig(txConfig) + + return clientCtx +} diff --git a/x/upgrade/CHANGELOG.md b/x/upgrade/CHANGELOG.md index 21cb063d4578..30c87b58456c 100644 --- a/x/upgrade/CHANGELOG.md +++ b/x/upgrade/CHANGELOG.md @@ -25,6 +25,22 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +<<<<<<< HEAD +======= +### Improvements + +* [#19672](https://github.com/cosmos/cosmos-sdk/pull/19672) Follow latest `cosmossdk.io/core` `PreBlock` simplification. +* [#20771](https://github.com/cosmos/cosmos-sdk/pull/20771) Create upgrade directory only when necessary (upgrade flow and not init flow). + +### API Breaking Changes + +* [#19443](https://github.com/cosmos/cosmos-sdk/pull/19443) `NewKeeper` takes an `appmodule.Environment` instead of individual services. + +### State Machine Breaking + +* (x/upgrade) [#16244](https://github.com/cosmos/cosmos-sdk/pull/16244) Upgrade module no longer stores the app version but gets and sets the app version stored in the `ParamStore` of baseapp. + +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) ## [v0.1.3](https://github.com/cosmos/cosmos-sdk/releases/tag/x/upgrade/v0.1.3) - 2024-06-04 * (deps) [#20530](https://github.com/cosmos/cosmos-sdk/pull/20530) Bump vulnerable `github.com/hashicorp/go-getter` to v1.7.4. diff --git a/x/upgrade/depinject.go b/x/upgrade/depinject.go new file mode 100644 index 000000000000..be1187c3f684 --- /dev/null +++ b/x/upgrade/depinject.go @@ -0,0 +1,100 @@ +package upgrade + +import ( + "github.com/spf13/cast" + "github.com/spf13/viper" + + modulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1" + "cosmossdk.io/core/address" + "cosmossdk.io/core/app" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/depinject" + "cosmossdk.io/depinject/appconfig" + authtypes "cosmossdk.io/x/auth/types" + "cosmossdk.io/x/upgrade/keeper" + "cosmossdk.io/x/upgrade/types" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/types/module" +) + +var _ depinject.OnePerModuleType = AppModule{} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +func init() { + appconfig.RegisterModule(&modulev1.Module{}, + appconfig.Provide(ProvideModule), + appconfig.Invoke(PopulateVersionMap), + ) +} + +type ModuleInputs struct { + depinject.In + + Config *modulev1.Module + Environment appmodule.Environment + Cdc codec.Codec + AddressCodec address.Codec + AppVersionModifier app.VersionModifier + + AppOpts servertypes.AppOptions `optional:"true"` // server v0 + Viper *viper.Viper `optional:"true"` // server v2 +} + +type ModuleOutputs struct { + depinject.Out + + UpgradeKeeper *keeper.Keeper + Module appmodule.AppModule +} + +func ProvideModule(in ModuleInputs) ModuleOutputs { + var ( + homePath string + skipUpgradeHeights = make(map[int64]bool) + ) + + if in.Viper != nil { // viper takes precedence over app options + for _, h := range in.Viper.GetIntSlice(server.FlagUnsafeSkipUpgrades) { + skipUpgradeHeights[int64(h)] = true + } + + homePath = in.Viper.GetString(flags.FlagHome) + } else if in.AppOpts != nil { + for _, h := range cast.ToIntSlice(in.AppOpts.Get(server.FlagUnsafeSkipUpgrades)) { + skipUpgradeHeights[int64(h)] = true + } + + homePath = cast.ToString(in.AppOpts.Get(flags.FlagHome)) + } + + // default to governance authority if not provided + authority := authtypes.NewModuleAddress(types.GovModuleName) + if in.Config.Authority != "" { + authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority) + } + + authorityStr, err := in.AddressCodec.BytesToString(authority) + if err != nil { + panic(err) + } + + // set the governance module account as the authority for conducting upgrades + k := keeper.NewKeeper(in.Environment, skipUpgradeHeights, in.Cdc, homePath, in.AppVersionModifier, authorityStr) + m := NewAppModule(k) + + return ModuleOutputs{UpgradeKeeper: k, Module: m} +} + +func PopulateVersionMap(upgradeKeeper *keeper.Keeper, modules map[string]appmodule.AppModule) { + if upgradeKeeper == nil { + return + } + + upgradeKeeper.SetInitVersionMap(module.NewManagerFromMap(modules).GetVersionMap()) +} diff --git a/x/upgrade/go.mod b/x/upgrade/go.mod index 14ab6e854637..dde1832ce964 100644 --- a/x/upgrade/go.mod +++ b/x/upgrade/go.mod @@ -22,6 +22,7 @@ require ( github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de google.golang.org/grpc v1.63.2 @@ -150,7 +151,10 @@ require ( github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect +<<<<<<< HEAD github.com/spf13/viper v1.18.2 // indirect +======= +>>>>>>> 5aaff2109 (feat: parse home flag earlier (#20771)) github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index c8db97c75b42..850b1e221f38 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "os" - "path" "path/filepath" "sort" "strconv" @@ -64,8 +63,8 @@ func NewKeeper(skipUpgradeHeights map[int64]bool, storeService corestore.KVStore authority: authority, } - if upgradePlan, err := k.ReadUpgradeInfoFromDisk(); err == nil && upgradePlan.Height > 0 { - telemetry.SetGaugeWithLabels([]string{"server", "info"}, 1, []metrics.Label{telemetry.NewLabel("upgrade_height", strconv.FormatInt(upgradePlan.Height, 10))}) + if homePath == "" { + k.Logger.Warn("homePath is empty; upgrade info will be written to the current directory") } return k @@ -534,7 +533,7 @@ func (k Keeper) DumpUpgradeInfoToDisk(height int64, p types.Plan) error { // GetUpgradeInfoPath returns the upgrade info file path func (k Keeper) GetUpgradeInfoPath() (string, error) { - upgradeInfoFileDir := path.Join(k.getHomeDir(), "data") + upgradeInfoFileDir := filepath.Join(k.homePath, "data") if err := os.MkdirAll(upgradeInfoFileDir, os.ModePerm); err != nil { return "", fmt.Errorf("could not create directory %q: %w", upgradeInfoFileDir, err) } @@ -542,11 +541,6 @@ func (k Keeper) GetUpgradeInfoPath() (string, error) { return filepath.Join(upgradeInfoFileDir, types.UpgradeInfoFilename), nil } -// getHomeDir returns the height at which the given upgrade was executed -func (k Keeper) getHomeDir() string { - return k.homePath -} - // ReadUpgradeInfoFromDisk returns the name and height of the upgrade which is // written to disk by the old binary when panicking. An error is returned if // the upgrade path directory cannot be created or if the file exists and @@ -577,6 +571,10 @@ func (k Keeper) ReadUpgradeInfoFromDisk() (types.Plan, error) { return upgradeInfo, err } + if upgradeInfo.Height > 0 { + telemetry.SetGaugeWithLabels([]string{"server", "info"}, 1, []metrics.Label{telemetry.NewLabel("upgrade_height", strconv.FormatInt(upgradeInfo.Height, 10))}) + } + return upgradeInfo, nil }