From 519c55cd536a42d905cd3842edc981adc203d6f7 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 30 Nov 2023 10:59:23 +0100 Subject: [PATCH] refactor(confix): properly update migrate and diff command (#18596) --- math/int.go | 4 +- tools/confix/README.md | 14 +- tools/confix/cmd/diff.go | 38 +++-- tools/confix/cmd/migrate.go | 35 +++-- tools/confix/cmd/migrate_test.go | 15 +- tools/confix/cmd/mutate_test.go | 3 + tools/confix/data/v0.51-app.toml | 231 +++++++++++++++++++++++++++++++ tools/confix/file.go | 4 +- tools/confix/migrations.go | 6 +- 9 files changed, 295 insertions(+), 55 deletions(-) create mode 100644 tools/confix/data/v0.51-app.toml diff --git a/math/int.go b/math/int.go index bf6eb9b1fd..54ee8f4f23 100644 --- a/math/int.go +++ b/math/int.go @@ -17,9 +17,9 @@ const MaxBitLen = 256 // Integer errors var ( // ErrIntOverflow is the error returned when an integer overflow occurs - ErrIntOverflow = errors.New("Integer overflow") + ErrIntOverflow = errors.New("integer overflow") // ErrDivideByZero is the error returned when a divide by zero occurs - ErrDivideByZero = errors.New("Divide by zero") + ErrDivideByZero = errors.New("divide by zero") ) func newIntegerFromString(s string) (*big.Int, bool) { diff --git a/tools/confix/README.md b/tools/confix/README.md index d7867d5f44..af7a5aa8f5 100644 --- a/tools/confix/README.md +++ b/tools/confix/README.md @@ -96,17 +96,13 @@ confix set ~/.simapp/config/client.toml chain-id "foo-1" # sets the value chain- Migrate a configuration file to a new version, config type defaults to `app.toml`, if you want to change it to `client.toml`, please indicate it by adding the optional parameter, e.g.: ```shell -simd config migrate v0.50 # migrates defaultHome/config/app.toml to the latest v0.47 config +simd config migrate v0.50 # migrates defaultHome/config/app.toml to the latest v0.50 config +simd config migrate v0.50 --client # migrates defaultHome/config/client.toml to the latest v0.50 config ``` ```shell -confix migrate v0.50 ~/.simapp/config/app.toml # migrate ~/.simapp/config/app.toml to the latest v0.47 config -``` - -or - -```shell -confix migrate v0.50 ~/.simapp/config/client.toml client # migrate ~/.simapp/config/client.toml to the latest v0.47 config +confix migrate v0.50 ~/.simapp/config/app.toml # migrate ~/.simapp/config/app.toml to the latest v0.50 config +confix migrate v0.50 ~/.simapp/config/client.toml --client # migrate ~/.simapp/config/client.toml to the latest v0.50 config ``` ### Diff @@ -115,10 +111,12 @@ Get the diff between a given configuration file and the default configuration fi ```shell simd config diff v0.47 # gets the diff between defaultHome/config/app.toml and the latest v0.47 config +simd config diff v0.47 --client # gets the diff between defaultHome/config/client.toml and the latest v0.47 config ``` ```shell confix diff v0.47 ~/.simapp/config/app.toml # gets the diff between ~/.simapp/config/app.toml and the latest v0.47 config +confix diff v0.47 ~/.simapp/config/client.toml --client # gets the diff between ~/.simapp/config/client.toml and the latest v0.47 config ``` ### View diff --git a/tools/confix/cmd/diff.go b/tools/confix/cmd/diff.go index 263095a451..4ce4b4b026 100644 --- a/tools/confix/cmd/diff.go +++ b/tools/confix/cmd/diff.go @@ -5,41 +5,49 @@ import ( "fmt" "strings" - "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" "golang.org/x/exp/maps" "cosmossdk.io/tools/confix" + + "github.com/cosmos/cosmos-sdk/client" ) // DiffCommand creates a new command for comparing configuration files func DiffCommand() *cobra.Command { - return &cobra.Command{ - Use: "diff [target-version] [config-type]", + cmd := &cobra.Command{ + Use: "diff [target-version] ", Short: "Outputs all config values that are different from the default.", Long: "This command compares the specified configuration file (app.toml or client.toml) with the defaults and outputs any differences.", - Args: cobra.MinimumNArgs(2), + Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - targetVersion := args[0] - configPath := args[1] - configType := confix.AppConfigType // Default to app configuration + var configPath string clientCtx := client.GetClientContextFromCmd(cmd) - - if len(args) > 2 { - configType = strings.ToLower(args[2]) + switch { + case len(args) > 1: + configPath = args[1] + case clientCtx.HomeDir != "": + configPath = fmt.Sprintf("%s/config/app.toml", clientCtx.HomeDir) + default: + return errors.New("must provide a path to the app.toml or client.toml") } - if configType != confix.AppConfigType && configType != confix.ClientConfigType { - return errors.New("config type must be 'app' or 'client'") + configType := confix.AppConfigType + if ok, _ := cmd.Flags().GetBool(confix.ClientConfigType); ok { + configPath = strings.ReplaceAll(configPath, "app.toml", "client.toml") // for the case we are using the home dir of client ctx + configType = confix.ClientConfigType + } else if strings.HasSuffix(configPath, "client.toml") { + return errors.New("app.toml file expected, got client.toml, use --client flag to diff client.toml") } + targetVersion := args[0] if _, ok := confix.Migrations[targetVersion]; !ok { return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, maps.Keys(confix.Migrations)) } targetVersionFile, err := confix.LoadLocalConfig(targetVersion, configType) if err != nil { - panic(fmt.Errorf("failed to load internal config: %w", err)) + return fmt.Errorf("failed to load internal config: %w", err) } rawFile, err := confix.LoadConfig(configPath) @@ -60,4 +68,8 @@ func DiffCommand() *cobra.Command { return nil }, } + + cmd.Flags().Bool(confix.ClientConfigType, false, "diff client.toml instead of app.toml") + + return cmd } diff --git a/tools/confix/cmd/migrate.go b/tools/confix/cmd/migrate.go index bdc410b78c..2b27c24478 100644 --- a/tools/confix/cmd/migrate.go +++ b/tools/confix/cmd/migrate.go @@ -6,13 +6,13 @@ import ( "fmt" "strings" - "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" "golang.org/x/exp/maps" "cosmossdk.io/tools/confix" -) + "github.com/cosmos/cosmos-sdk/client" +) var ( FlagStdOut bool @@ -22,7 +22,7 @@ var ( func MigrateCommand() *cobra.Command { cmd := &cobra.Command{ - Use: "migrate [target-version] [config-type]", + Use: "migrate [target-version] ", Short: "Migrate Cosmos SDK configuration file to the specified version", Long: `Migrate the contents of the Cosmos SDK configuration (app.toml or client.toml) to the specified version. Configuration type is app by default. The output is written in-place unless --stdout is provided. @@ -30,29 +30,17 @@ In case of any error in updating the file, no output is written.`, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { var configPath string - clientCtx := client.GetClientContextFromCmd(cmd) - targetVersion := args[0] - configType := confix.AppConfigType // Default to app configuration - - if len(args) > 2 { - configType = strings.ToLower(args[2]) - } - - if configType != confix.AppConfigType && configType != confix.ClientConfigType { - return errors.New("config type must be 'app' or 'client'") - } - - switch { + switch { case len(args) > 1: configPath = args[1] case clientCtx.HomeDir != "": - configPath = fmt.Sprintf("%s/config/%s.toml",clientCtx.HomeDir, configType) + configPath = fmt.Sprintf("%s/config/app.toml", clientCtx.HomeDir) default: - return errors.New("must provide a path to the config file") + return errors.New("must provide a path to the app.toml or client.toml") } - + targetVersion := args[0] plan, ok := confix.Migrations[targetVersion] if !ok { return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, maps.Keys(confix.Migrations)) @@ -73,6 +61,14 @@ In case of any error in updating the file, no output is written.`, outputPath = "" } + configType := confix.AppConfigType + if ok, _ := cmd.Flags().GetBool(confix.ClientConfigType); ok { + configPath = strings.ReplaceAll(configPath, "app.toml", "client.toml") // for the case we are using the home dir of client ctx + configType = confix.ClientConfigType + } else if strings.HasSuffix(configPath, "client.toml") { + return errors.New("app.toml file expected, got client.toml, use --client flag to migrate client.toml") + } + if err := confix.Upgrade(ctx, plan(rawFile, targetVersion, configType), configPath, outputPath, FlagSkipValidate); err != nil { return fmt.Errorf("failed to migrate config: %w", err) } @@ -84,6 +80,7 @@ In case of any error in updating the file, no output is written.`, cmd.Flags().BoolVar(&FlagStdOut, "stdout", false, "print the updated config to stdout") cmd.Flags().BoolVar(&FlagVerbose, "verbose", false, "log changes to stderr") cmd.Flags().BoolVar(&FlagSkipValidate, "skip-validate", false, "skip configuration validation (allows to migrate unknown configurations)") + cmd.Flags().Bool(confix.ClientConfigType, false, "migrate client.toml instead of app.toml") return cmd } diff --git a/tools/confix/cmd/migrate_test.go b/tools/confix/cmd/migrate_test.go index c2291f25b1..8fc67df839 100644 --- a/tools/confix/cmd/migrate_test.go +++ b/tools/confix/cmd/migrate_test.go @@ -16,25 +16,24 @@ func TestMigrateCmd(t *testing.T) { clientCtx, cleanup := initClientContext(t) defer cleanup() - _, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.0","app"}) + _, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.0"}) assert.ErrorContains(t, err, "unknown version") // clientCtx does not create app.toml, so this should fail - _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.45","app"}) + _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.45"}) assert.ErrorContains(t, err, "no such file or directory") - // try to migrate from client.toml it should fail without --skip-validate - _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.46", filepath.Join(clientCtx.HomeDir, "config", "client.toml"), "app"}) + // try to migrate from unsupported.toml it should fail without --skip-validate + _, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.46", filepath.Join(clientCtx.HomeDir, "config", "unsupported.toml")}) assert.ErrorContains(t, err, "failed to migrate config") - // try to migrate from client.toml - it should work and give us a big diff - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.46", filepath.Join(clientCtx.HomeDir, "config", "client.toml"), "--skip-validate", "--verbose"}) + // try to migrate from unspported.toml - it should work and give us a big diff + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.46", filepath.Join(clientCtx.HomeDir, "config", "unsupported.toml"), "--skip-validate", "--verbose"}) assert.NilError(t, err) assert.Assert(t, strings.Contains(out.String(), "add app-db-backend key")) - // this should work - out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.51", filepath.Join(clientCtx.HomeDir, "config", "client.toml"),"client", "--verbose"}) + out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.MigrateCommand(), []string{"v0.51", filepath.Join(clientCtx.HomeDir, "config", "client.toml"), "--client", "--verbose"}) assert.NilError(t, err) assert.Assert(t, strings.Contains(out.String(), "add keyring-default-keyname key")) } diff --git a/tools/confix/cmd/mutate_test.go b/tools/confix/cmd/mutate_test.go index 2aec22cc67..7565b6102d 100644 --- a/tools/confix/cmd/mutate_test.go +++ b/tools/confix/cmd/mutate_test.go @@ -3,6 +3,7 @@ package cmd_test import ( "fmt" "os" + "path/filepath" "strings" "testing" @@ -27,6 +28,8 @@ func initClientContext(t *testing.T) (client.Context, func()) { clientCtx, err := config.ReadFromClientConfig(clientCtx) assert.NilError(t, err) assert.Equal(t, clientCtx.ChainID, chainID) + + _ = os.Link(filepath.Join(home, "config", "client.toml"), filepath.Join(home, "config", "unsupported.toml")) return clientCtx, func() { _ = os.RemoveAll(home) } } diff --git a/tools/confix/data/v0.51-app.toml b/tools/confix/data/v0.51-app.toml new file mode 100644 index 0000000000..df90516dc7 --- /dev/null +++ b/tools/confix/data/v0.51-app.toml @@ -0,0 +1,231 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Base Configuration ### +############################################################################### + +# The minimum gas prices a validator is willing to accept for processing a +# transaction. A transaction's fees must meet the minimum of any denomination +# specified in this config (e.g. 0.25token1,0.0001token2). +minimum-gas-prices = "0stake" + +# The maximum gas a query coming over rest/grpc may consume. +# If this is set to zero, the query can consume an unbounded amount of gas. +query-gas-limit = "0" + +# default: the last 362880 states are kept, pruning at 10 block intervals +# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) +# everything: 2 latest states will be kept; pruning at 10 block intervals. +# custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' +pruning = "default" + +# These are applied if and only if the pruning strategy is custom. +pruning-keep-recent = "0" +pruning-interval = "0" + +# HaltHeight contains a non-zero block height at which a node will gracefully +# halt and shutdown that can be used to assist upgrades and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-height = 0 + +# HaltTime contains a non-zero minimum block time (in Unix seconds) at which +# a node will gracefully halt and shutdown that can be used to assist upgrades +# and testing. +# +# Note: Commitment of state will be attempted on the corresponding block. +halt-time = 0 + +# MinRetainBlocks defines the minimum block height offset from the current +# block being committed, such that all blocks past this offset are pruned +# from CometBFT. It is used as part of the process of determining the +# ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates +# that no blocks should be pruned. +# +# This configuration value is only responsible for pruning CometBFT blocks. +# It has no bearing on application state pruning which is determined by the +# "pruning-*" configurations. +# +# Note: CometBFT block pruning is dependant on this parameter in conjunction +# with the unbonding (safety threshold) period, state pruning and state sync +# snapshot parameters to determine the correct minimum value of +# ResponseCommit.RetainHeight. +min-retain-blocks = 0 + +# InterBlockCache enables inter-block caching. +inter-block-cache = true + +# IndexEvents defines the set of events in the form {eventType}.{attributeKey}, +# which informs CometBFT what to index. If empty, all events will be indexed. +# +# Example: +# ["message.sender", "message.recipient"] +index-events = [] + +# IavlCacheSize set the size of the iavl tree cache (in number of nodes). +iavl-cache-size = 781250 + +# IAVLDisableFastNode enables or disables the fast node feature of IAVL. +# Default is false. +iavl-disable-fastnode = false + +# AppDBBackend defines the database backend type to use for the application and snapshots DBs. +# An empty string indicates that a fallback will be used. +# The fallback is the db_backend value set in CometBFT's config.toml. +app-db-backend = "" + +############################################################################### +### Telemetry Configuration ### +############################################################################### + +[telemetry] + +# Prefixed with keys to separate services. +service-name = "" + +# Enabled enables the application telemetry functionality. When enabled, +# an in-memory sink is also enabled by default. Operators may also enabled +# other sinks such as Prometheus. +enabled = false + +# Enable prefixing gauge values with hostname. +enable-hostname = false + +# Enable adding hostname to labels. +enable-hostname-label = false + +# Enable adding service to labels. +enable-service-label = false + +# PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. +prometheus-retention-time = 0 + +# GlobalLabels defines a global set of name/value label tuples applied to all +# metrics emitted using the wrapper functions defined in telemetry package. +# +# Example: +# [["chain_id", "cosmoshub-1"]] +global-labels = [] + +############################################################################### +### API Configuration ### +############################################################################### + +[api] + +# Enable defines if the API server should be enabled. +enable = true + +# Swagger defines if swagger documentation should automatically be registered. +swagger = false + +# Address defines the API server to listen on. +address = "tcp://localhost:1317" + +# MaxOpenConnections defines the number of maximum open connections. +max-open-connections = 1000 + +# RPCReadTimeout defines the CometBFT RPC read timeout (in seconds). +rpc-read-timeout = 10 + +# RPCWriteTimeout defines the CometBFT RPC write timeout (in seconds). +rpc-write-timeout = 0 + +# RPCMaxBodyBytes defines the CometBFT maximum request body (in bytes). +rpc-max-body-bytes = 1000000 + +# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk). +enabled-unsafe-cors = false + +############################################################################### +### gRPC Configuration ### +############################################################################### + +[grpc] + +# Enable defines if the gRPC server should be enabled. +enable = true + +# Address defines the gRPC server address to bind to. +address = "localhost:9090" + +# MaxRecvMsgSize defines the max message size in bytes the server can receive. +# The default value is 10MB. +max-recv-msg-size = "10485760" + +# MaxSendMsgSize defines the max message size in bytes the server can send. +# The default value is math.MaxInt32. +max-send-msg-size = "2147483647" + +############################################################################### +### gRPC Web Configuration ### +############################################################################### + +[grpc-web] + +# GRPCWebEnable defines if the gRPC-web should be enabled. +# NOTE: gRPC must also be enabled, otherwise, this configuration is a no-op. +# NOTE: gRPC-Web uses the same address as the API server. +enable = true + +############################################################################### +### State Sync Configuration ### +############################################################################### + +# State sync snapshots allow other nodes to rapidly join the network without replaying historical +# blocks, instead downloading and applying a snapshot of the application state at a given height. +[state-sync] + +# snapshot-interval specifies the block interval at which local state sync snapshots are +# taken (0 to disable). +snapshot-interval = 0 + +# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all). +snapshot-keep-recent = 2 + +############################################################################### +### State Streaming ### +############################################################################### + +# Streaming allows nodes to stream state to external systems. +[streaming] + +# streaming.abci specifies the configuration for the ABCI Listener streaming service. +[streaming.abci] + +# List of kv store keys to stream out via gRPC. +# The store key names MUST match the module's StoreKey name. +# +# Example: +# ["acc", "bank", "gov", "staking", "mint"[,...]] +# ["*"] to expose all keys. +keys = [] + +# The plugin name used for streaming via gRPC. +# Streaming is only enabled if this is set. +# Supported plugins: abci +plugin = "" + +# stop-node-on-err specifies whether to stop the node on message delivery error. +stop-node-on-err = true + +############################################################################### +### Mempool ### +############################################################################### + +[mempool] + +# Setting max-txs to 0 will allow for a unbounded amount of transactions in the mempool. +# Setting max_txs to negative 1 (-1) will disable transactions from being inserted into the mempool. +# Setting max_txs to a positive number (> 0) will limit the number of transactions in the mempool, by the specified amount. +# +# Note, this configuration only applies to SDK built-in app-side mempool +# implementations. +max-txs = 5000 + +[custom] + +# That field will be parsed by server.InterceptConfigsPreRunHandler and held by viper. +# Do not forget to add quotes around the value if it is a string. +custom-field = "anything" diff --git a/tools/confix/file.go b/tools/confix/file.go index f6fd8dcad9..dcd3ab35ba 100644 --- a/tools/confix/file.go +++ b/tools/confix/file.go @@ -14,7 +14,7 @@ import ( var data embed.FS // LoadLocalConfig loads and parses the TOML document from confix data -func LoadLocalConfig(name string, configType string) (*tomledit.Document, error) { +func LoadLocalConfig(name, configType string) (*tomledit.Document, error) { fileName, err := getFileName(name, configType) if err != nil { return nil, err @@ -41,7 +41,7 @@ func LoadConfig(path string) (*tomledit.Document, error) { } // getFileName constructs the filename based on the type of configuration (app or client) -func getFileName(name string, configType string) (string, error) { +func getFileName(name, configType string) (string, error) { switch strings.ToLower(configType) { case "app": return fmt.Sprintf("%s-app.toml", name), nil diff --git a/tools/confix/migrations.go b/tools/confix/migrations.go index 91abd61fc6..a164858bb6 100644 --- a/tools/confix/migrations.go +++ b/tools/confix/migrations.go @@ -19,7 +19,7 @@ const ( ) // MigrationMap defines a mapping from a version to a transformation plan. -type MigrationMap map[string]func(from *tomledit.Document, to string, planType string) transform.Plan +type MigrationMap map[string]func(from *tomledit.Document, to, planType string) transform.Plan var Migrations = MigrationMap{ "v0.45": NoPlan, // Confix supports only the current supported SDK version. So we do not support v0.44 -> v0.45. @@ -31,7 +31,7 @@ var Migrations = MigrationMap{ } // PlanBuilder is a function that returns a transformation plan for a given diff between two files. -func PlanBuilder(from *tomledit.Document, to string, planType string) transform.Plan { +func PlanBuilder(from *tomledit.Document, to, planType string) transform.Plan { plan := transform.Plan{} deletedSections := map[string]bool{} @@ -118,7 +118,7 @@ func PlanBuilder(from *tomledit.Document, to string, planType string) transform. } // NoPlan returns a no-op plan. -func NoPlan(_ *tomledit.Document, to string, planType string) transform.Plan { +func NoPlan(_ *tomledit.Document, to, planType string) transform.Plan { fmt.Printf("no migration needed to %s\n", to) return transform.Plan{} }