From 81246bcdca51003a9ee2dcd5250e52ee51009d6c Mon Sep 17 00:00:00 2001 From: Akhil Kumar P <36399231+akhilkumarpilli@users.noreply.github.com> Date: Thu, 29 Aug 2024 13:16:58 +0530 Subject: [PATCH 1/2] feat(server/v2): add min gas price and check with tx fee (#21173) Co-authored-by: Julien Robert (cherry picked from commit 81a225e6a29b11361ca18d17dc563484446133ec) # Conflicts: # server/v2/commands.go # server/v2/config.go # server/v2/flags.go # server/v2/server.go # server/v2/server_test.go # server/v2/testdata/app.toml --- server/v2/commands.go | 213 ++++++++++++++++++++++++ server/v2/config.go | 73 +++++++++ server/v2/flags.go | 25 +++ server/v2/server.go | 263 ++++++++++++++++++++++++++++++ server/v2/server_test.go | 99 +++++++++++ server/v2/testdata/app.toml | 51 ++++++ simapp/v2/simdv2/cmd/commands.go | 1 + simapp/v2/simdv2/cmd/config.go | 19 +++ simapp/v2/simdv2/cmd/testnet.go | 10 +- tests/systemtests/staking_test.go | 1 - tools/confix/data/v2-app.toml | 4 + tools/confix/migrations.go | 11 +- x/auth/ante/fee.go | 108 ++++++------ x/auth/ante/fee_test.go | 5 + x/auth/ante/validator_tx_fee.go | 8 +- x/auth/tx/config/depinject.go | 59 +++++-- x/auth/tx/config/module.go | 7 + 17 files changed, 880 insertions(+), 77 deletions(-) create mode 100644 server/v2/commands.go create mode 100644 server/v2/config.go create mode 100644 server/v2/flags.go create mode 100644 server/v2/server.go create mode 100644 server/v2/server_test.go create mode 100644 server/v2/testdata/app.toml diff --git a/server/v2/commands.go b/server/v2/commands.go new file mode 100644 index 000000000000..101a23d3983e --- /dev/null +++ b/server/v2/commands.go @@ -0,0 +1,213 @@ +package serverv2 + +import ( + "context" + "errors" + "os" + "os/signal" + "path/filepath" + "strings" + "syscall" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" +) + +// Execute executes the root command of an application. +// It handles adding core CLI flags, specifically the logging flags. +func Execute(rootCmd *cobra.Command, envPrefix, defaultHome string) error { + rootCmd.PersistentFlags().String(FlagLogLevel, "info", "The logging level (trace|debug|info|warn|error|fatal|panic|disabled or '*:,:')") + rootCmd.PersistentFlags().String(FlagLogFormat, "plain", "The logging format (json|plain)") + rootCmd.PersistentFlags().Bool(FlagLogNoColor, false, "Disable colored logs") + rootCmd.PersistentFlags().StringP(FlagHome, "", defaultHome, "directory for config and data") + + // update the global viper with the root command's configuration + viper.SetEnvPrefix(envPrefix) + viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) + viper.AutomaticEnv() + + return rootCmd.Execute() +} + +// AddCommands add the server commands to the root command +// It configure the config handling and the logger handling +func AddCommands[T transaction.Tx]( + rootCmd *cobra.Command, + newApp AppCreator[T], + logger log.Logger, + serverCfg ServerConfig, + components ...ServerComponent[T], +) error { + if len(components) == 0 { + return errors.New("no components provided") + } + + server := NewServer(logger, serverCfg, components...) + originalPersistentPreRunE := rootCmd.PersistentPreRunE + rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { + // set the default command outputs + cmd.SetOut(cmd.OutOrStdout()) + cmd.SetErr(cmd.ErrOrStderr()) + + if err := configHandle(server, cmd); err != nil { + return err + } + + // call the original PersistentPreRun(E) if it exists + if rootCmd.PersistentPreRun != nil { + rootCmd.PersistentPreRun(cmd, args) + return nil + } + + return originalPersistentPreRunE(cmd, args) + } + + cmds := server.CLICommands() + startCmd := createStartCommand(server, newApp) + startCmd.SetContext(rootCmd.Context()) + cmds.Commands = append(cmds.Commands, startCmd) + rootCmd.AddCommand(cmds.Commands...) + + if len(cmds.Queries) > 0 { + if queryCmd := findSubCommand(rootCmd, "query"); queryCmd != nil { + queryCmd.AddCommand(cmds.Queries...) + } else { + queryCmd := topLevelCmd(rootCmd.Context(), "query", "Querying subcommands") + queryCmd.Aliases = []string{"q"} + queryCmd.AddCommand(cmds.Queries...) + rootCmd.AddCommand(queryCmd) + } + } + + if len(cmds.Txs) > 0 { + if txCmd := findSubCommand(rootCmd, "tx"); txCmd != nil { + txCmd.AddCommand(cmds.Txs...) + } else { + txCmd := topLevelCmd(rootCmd.Context(), "tx", "Transactions subcommands") + txCmd.AddCommand(cmds.Txs...) + rootCmd.AddCommand(txCmd) + } + } + + return nil +} + +// createStartCommand creates the start command for the application. +func createStartCommand[T transaction.Tx]( + server *Server[T], + newApp AppCreator[T], +) *cobra.Command { + flags := server.StartFlags() + + cmd := &cobra.Command{ + Use: "start", + Short: "Run the application", + RunE: func(cmd *cobra.Command, args []string) error { + v := GetViperFromCmd(cmd) + l := GetLoggerFromCmd(cmd) + if err := v.BindPFlags(cmd.Flags()); err != nil { + return err + } + + if err := server.Init(newApp(l, v), v, l); err != nil { + return err + } + + ctx, cancelFn := context.WithCancel(cmd.Context()) + 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 err + } + + return nil + }, + } + + // add the start flags to the command + for _, startFlags := range flags { + cmd.Flags().AddFlagSet(startFlags) + } + + return cmd +} + +// configHandle writes the default config to the home directory if it does not exist and sets the server context +func configHandle[T transaction.Tx](s *Server[T], cmd *cobra.Command) error { + home, err := cmd.Flags().GetString(FlagHome) + if err != nil { + return err + } + + configDir := filepath.Join(home, "config") + + // we need to check app.toml as the config folder can already exist for the client.toml + if _, err := os.Stat(filepath.Join(configDir, "app.toml")); os.IsNotExist(err) { + if err = s.WriteConfig(configDir); err != nil { + return err + } + } + + v, err := ReadConfig(configDir) + if err != nil { + return err + } + + if err := v.BindPFlags(cmd.Flags()); err != nil { + return err + } + + log, err := NewLogger(v, cmd.OutOrStdout()) + if err != nil { + return err + } + + return SetCmdServerContext(cmd, v, log) +} + +// findSubCommand finds a sub-command of the provided command whose Use +// string is or begins with the provided subCmdName. +// It verifies the command's aliases as well. +func findSubCommand(cmd *cobra.Command, subCmdName string) *cobra.Command { + for _, subCmd := range cmd.Commands() { + use := subCmd.Use + if use == subCmdName || strings.HasPrefix(use, subCmdName+" ") { + return subCmd + } + + for _, alias := range subCmd.Aliases { + if alias == subCmdName || strings.HasPrefix(alias, subCmdName+" ") { + return subCmd + } + } + } + return nil +} + +// topLevelCmd creates a new top-level command with the provided name and +// description. The command will have DisableFlagParsing set to false and +// SuggestionsMinimumDistance set to 2. +func topLevelCmd(ctx context.Context, use, short string) *cobra.Command { + cmd := &cobra.Command{ + Use: use, + Short: short, + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + } + cmd.SetContext(ctx) + + return cmd +} diff --git a/server/v2/config.go b/server/v2/config.go new file mode 100644 index 000000000000..b5c525fdf682 --- /dev/null +++ b/server/v2/config.go @@ -0,0 +1,73 @@ +package serverv2 + +import ( + "fmt" + + "github.com/mitchellh/mapstructure" + "github.com/spf13/viper" +) + +// ServerConfig defines configuration for the server component. +type ServerConfig struct { + MinGasPrices string `mapstructure:"minimum-gas-prices" toml:"minimum-gas-prices" comment:"minimum-gas-prices defines the price which 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)."` +} + +// DefaultServerConfig returns the default config of server component +func DefaultServerConfig() ServerConfig { + return ServerConfig{ + MinGasPrices: "0stake", + } +} + +// ReadConfig returns a viper instance of the config file +func ReadConfig(configPath string) (*viper.Viper, error) { + v := viper.New() + v.SetConfigType("toml") + v.SetConfigName("config") + v.AddConfigPath(configPath) + if err := v.ReadInConfig(); err != nil { + return nil, fmt.Errorf("failed to read config: %s: %w", configPath, err) + } + + v.SetConfigName("app") + if err := v.MergeInConfig(); err != nil { + return nil, fmt.Errorf("failed to merge configuration: %w", err) + } + + v.WatchConfig() + + return v, nil +} + +// UnmarshalSubConfig unmarshals the given subconfig from the viper instance. +// It unmarshals the config, env, flags into the target struct. +// Use this instead of viper.Sub because viper does not unmarshal flags. +func UnmarshalSubConfig(v *viper.Viper, subName string, target any) error { + var sub any + for k, val := range v.AllSettings() { + if k == subName { + sub = val + break + } + } + + // Create a new decoder with custom decoding options + decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + ), + Result: target, + WeaklyTypedInput: true, + }) + if err != nil { + return fmt.Errorf("failed to create decoder: %w", err) + } + + // Decode the sub-configuration + if err := decoder.Decode(sub); err != nil { + return fmt.Errorf("failed to decode sub-configuration: %w", err) + } + + return nil +} diff --git a/server/v2/flags.go b/server/v2/flags.go new file mode 100644 index 000000000000..fc36cdcf2b4c --- /dev/null +++ b/server/v2/flags.go @@ -0,0 +1,25 @@ +// Package serverv2 defines constants for server configuration flags and output formats. +package serverv2 + +import "fmt" + +// start flags are prefixed with the server name +// this allows viper to properly bind the flags +func prefix(f string) string { + return fmt.Sprintf("%s.%s", serverName, f) +} + +var FlagMinGasPrices = prefix("minimum-gas-prices") + +const ( + // FlagHome specifies the home directory flag. + FlagHome = "home" + + FlagLogLevel = "log_level" // Sets the logging level + FlagLogFormat = "log_format" // Specifies the log output format + FlagLogNoColor = "log_no_color" // Disables colored log output + FlagTrace = "trace" // Enables trace-level logging + + // OutputFormatJSON defines the JSON output format option. + OutputFormatJSON = "json" +) diff --git a/server/v2/server.go b/server/v2/server.go new file mode 100644 index 000000000000..08ae9a6a06fa --- /dev/null +++ b/server/v2/server.go @@ -0,0 +1,263 @@ +package serverv2 + +import ( + "context" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/pelletier/go-toml/v2" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" + "golang.org/x/sync/errgroup" + + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" +) + +// ServerComponent is a server module that can be started and stopped. +type ServerComponent[T transaction.Tx] interface { + Name() string + + Start(context.Context) error + Stop(context.Context) error + Init(AppI[T], *viper.Viper, log.Logger) error +} + +// HasStartFlags is a server module that has start flags. +type HasStartFlags interface { + // StartCmdFlags returns server start flags. + // Those flags should be prefixed with the server name. + // They are then merged with the server config in one viper instance. + StartCmdFlags() *pflag.FlagSet +} + +// HasConfig is a server module that has a config. +type HasConfig interface { + Config() any +} + +// HasCLICommands is a server module that has CLI commands. +type HasCLICommands interface { + CLICommands() CLIConfig +} + +// CLIConfig defines the CLI configuration for a module server. +type CLIConfig struct { + // Commands defines the main command of a module server. + Commands []*cobra.Command + // Queries defines the query commands of a module server. + // Those commands are meant to be added in the root query command. + Queries []*cobra.Command + // Txs defines the tx commands of a module server. + // Those commands are meant to be added in the root tx command. + Txs []*cobra.Command +} + +const ( + serverName = "server" +) + +var _ ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) + +type Server[T transaction.Tx] struct { + logger log.Logger + components []ServerComponent[T] + config ServerConfig +} + +func NewServer[T transaction.Tx]( + logger log.Logger, + config ServerConfig, + components ...ServerComponent[T], +) *Server[T] { + return &Server[T]{ + logger: logger, + config: config, + components: components, + } +} + +func (s *Server[T]) Name() string { + return serverName +} + +// Start starts all components concurrently. +func (s *Server[T]) Start(ctx context.Context) error { + s.logger.Info("starting servers...") + + g, ctx := errgroup.WithContext(ctx) + for _, mod := range s.components { + mod := mod + g.Go(func() error { + return mod.Start(ctx) + }) + } + + if err := g.Wait(); err != nil { + return fmt.Errorf("failed to start servers: %w", err) + } + + <-ctx.Done() + + return nil +} + +// Stop stops all components concurrently. +func (s *Server[T]) Stop(ctx context.Context) error { + s.logger.Info("stopping servers...") + + g, ctx := errgroup.WithContext(ctx) + for _, mod := range s.components { + mod := mod + g.Go(func() error { + return mod.Stop(ctx) + }) + } + + return g.Wait() +} + +// CLICommands returns all CLI commands of all components. +func (s *Server[T]) CLICommands() CLIConfig { + compart := func(name string, cmds ...*cobra.Command) *cobra.Command { + if len(cmds) == 1 && strings.HasPrefix(cmds[0].Use, name) { + return cmds[0] + } + + subCmd := &cobra.Command{ + Use: name, + Short: fmt.Sprintf("Commands from the %s server component", name), + } + subCmd.AddCommand(cmds...) + + return subCmd + } + + commands := CLIConfig{} + for _, mod := range s.components { + if climod, ok := mod.(HasCLICommands); ok { + srvCmd := climod.CLICommands() + + if len(srvCmd.Commands) > 0 { + commands.Commands = append(commands.Commands, compart(mod.Name(), srvCmd.Commands...)) + } + + if len(srvCmd.Txs) > 0 { + commands.Txs = append(commands.Txs, compart(mod.Name(), srvCmd.Txs...)) + } + + if len(srvCmd.Queries) > 0 { + commands.Queries = append(commands.Queries, compart(mod.Name(), srvCmd.Queries...)) + } + } + } + + return commands +} + +// Config returns config of the server component +func (s *Server[T]) Config() ServerConfig { + return s.config +} + +// Configs returns all configs of all server components. +func (s *Server[T]) Configs() map[string]any { + cfgs := make(map[string]any) + + // add server component config + cfgs[s.Name()] = s.config + + // add other components' config + for _, mod := range s.components { + if configmod, ok := mod.(HasConfig); ok { + cfg := configmod.Config() + cfgs[mod.Name()] = cfg + } + } + + return cfgs +} + +func (s *Server[T]) StartCmdFlags() *pflag.FlagSet { + flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError) + flags.String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") + return flags +} + +// Init initializes all server components with the provided application, configuration, and logger. +// It returns an error if any component fails to initialize. +func (s *Server[T]) Init(appI AppI[T], v *viper.Viper, logger log.Logger) error { + cfg := s.config + if v != nil { + if err := UnmarshalSubConfig(v, s.Name(), &cfg); err != nil { + return fmt.Errorf("failed to unmarshal config: %w", err) + } + } + + var components []ServerComponent[T] + for _, mod := range s.components { + mod := mod + if err := mod.Init(appI, v, logger); err != nil { + return err + } + + components = append(components, mod) + } + + s.config = cfg + s.components = components + return nil +} + +// WriteConfig writes the config to the given path. +// Note: it does not use viper.WriteConfigAs because we do not want to store flag values in the config. +func (s *Server[T]) WriteConfig(configPath string) error { + cfgs := s.Configs() + b, err := toml.Marshal(cfgs) + if err != nil { + return err + } + + if _, err := os.Stat(configPath); os.IsNotExist(err) { + if err := os.MkdirAll(configPath, os.ModePerm); err != nil { + return err + } + } + + if err := os.WriteFile(filepath.Join(configPath, "app.toml"), b, 0o600); err != nil { + return fmt.Errorf("failed to write config: %w", err) + } + + for _, component := range s.components { + // undocumented interface to write the component default config in another file than app.toml + // it is used by cometbft for backward compatibility + // it should not be used by other components + if mod, ok := component.(interface{ WriteCustomConfigAt(string) error }); ok { + if err := mod.WriteCustomConfigAt(configPath); err != nil { + return err + } + } + } + + return nil +} + +// StartFlags returns all flags of all server components. +func (s *Server[T]) StartFlags() []*pflag.FlagSet { + flags := []*pflag.FlagSet{} + + // add server component flags + flags = append(flags, s.StartCmdFlags()) + + // add other components' start cmd flags + for _, mod := range s.components { + if startmod, ok := mod.(HasStartFlags); ok { + flags = append(flags, startmod.StartCmdFlags()) + } + } + + return flags +} diff --git a/server/v2/server_test.go b/server/v2/server_test.go new file mode 100644 index 000000000000..572d91272062 --- /dev/null +++ b/server/v2/server_test.go @@ -0,0 +1,99 @@ +package serverv2_test + +import ( + "context" + "os" + "path/filepath" + "testing" + "time" + + gogoproto "github.com/cosmos/gogoproto/proto" + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + + coreserver "cosmossdk.io/core/server" + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" + serverv2 "cosmossdk.io/server/v2" + grpc "cosmossdk.io/server/v2/api/grpc" + "cosmossdk.io/server/v2/appmanager" +) + +type mockInterfaceRegistry struct{} + +func (*mockInterfaceRegistry) Resolve(typeUrl string) (gogoproto.Message, error) { + panic("not implemented") +} + +func (*mockInterfaceRegistry) ListImplementations(ifaceTypeURL string) []string { + panic("not implemented") +} +func (*mockInterfaceRegistry) ListAllInterfaces() []string { panic("not implemented") } + +type mockApp[T transaction.Tx] struct { + serverv2.AppI[T] +} + +func (*mockApp[T]) GetGPRCMethodsToMessageMap() map[string]func() gogoproto.Message { + return map[string]func() gogoproto.Message{} +} + +func (*mockApp[T]) GetAppManager() *appmanager.AppManager[T] { + return nil +} + +func (*mockApp[T]) InterfaceRegistry() coreserver.InterfaceRegistry { + return &mockInterfaceRegistry{} +} + +func TestServer(t *testing.T) { + currentDir, err := os.Getwd() + require.NoError(t, err) + configPath := filepath.Join(currentDir, "testdata") + + v, err := serverv2.ReadConfig(configPath) + if err != nil { + v = viper.New() + } + + logger := log.NewLogger(os.Stdout) + grpcServer := grpc.New[transaction.Tx]() + err = grpcServer.Init(&mockApp[transaction.Tx]{}, v, logger) + require.NoError(t, err) + + mockServer := &mockServer{name: "mock-server-1", ch: make(chan string, 100)} + + server := serverv2.NewServer( + logger, + serverv2.DefaultServerConfig(), + grpcServer, + mockServer, + ) + + serverCfgs := server.Configs() + require.Equal(t, serverCfgs[grpcServer.Name()].(*grpc.Config).Address, grpc.DefaultConfig().Address) + require.Equal(t, serverCfgs[mockServer.Name()].(*mockServerConfig).MockFieldOne, MockServerDefaultConfig().MockFieldOne) + + // write config + err = server.WriteConfig(configPath) + require.NoError(t, err) + + v, err = serverv2.ReadConfig(configPath) + require.NoError(t, err) + + require.Equal(t, v.GetString(grpcServer.Name()+".address"), grpc.DefaultConfig().Address) + + // start empty + ctx, cancelFn := context.WithCancel(context.TODO()) + go func() { + // wait 5sec and cancel context + <-time.After(5 * time.Second) + cancelFn() + + err = server.Stop(ctx) + require.NoError(t, err) + }() + + err = server.Start(ctx) + require.NoError(t, err) +} diff --git a/server/v2/testdata/app.toml b/server/v2/testdata/app.toml new file mode 100644 index 000000000000..192dc8d67865 --- /dev/null +++ b/server/v2/testdata/app.toml @@ -0,0 +1,51 @@ +[grpc] +# Enable defines if the gRPC server should be enabled. +enable = false +# 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 + +[server] +# minimum-gas-prices defines the price which 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' + +[store] +# The type of database for application and snapshots databases. +app-db-backend = 'goleveldb' + +[store.options] +# State storage database type. Currently we support: 0 for SQLite, 1 for Pebble +ss-type = 0 +# State commitment database type. Currently we support:0 for iavl, 1 for iavl v2 +sc-type = 0 + +# Pruning options for state storage +[store.options.ss-pruning-option] +# Number of recent heights to keep on disk. +keep-recent = 2 +# Height interval at which pruned heights are removed from disk. +interval = 100 + +# Pruning options for state commitment +[store.options.sc-pruning-option] +# Number of recent heights to keep on disk. +keep-recent = 2 +# Height interval at which pruned heights are removed from disk. +interval = 100 + +[store.options.iavl-config] +# CacheSize set the size of the iavl tree cache. +cache-size = 100000 +# If true, the tree will work like no fast storage and always not upgrade fast storage. +skip-fast-storage-upgrade = true + +[mock-server-1] +# Mock field +mock_field = 'default' +# Mock field two +mock_field_two = 1 diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index b4d13aa7a78c..d9fa1fa54983 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -75,6 +75,7 @@ func initRootCmd[T transaction.Tx]( rootCmd, newApp, logger, + initServerConfig(), cometbft.New(&genericTxDecoder[T]{txConfig}, cometbft.DefaultServerOptions[T]()), grpc.New[T](), store.New[T](newApp), diff --git a/simapp/v2/simdv2/cmd/config.go b/simapp/v2/simdv2/cmd/config.go index 0794a8a42a79..c7f6b707c89c 100644 --- a/simapp/v2/simdv2/cmd/config.go +++ b/simapp/v2/simdv2/cmd/config.go @@ -3,6 +3,8 @@ package cmd import ( "strings" + serverv2 "cosmossdk.io/server/v2" + clientconfig "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/crypto/keyring" ) @@ -49,3 +51,20 @@ gas-adjustment = {{ .GasConfig.GasAdjustment }} return customClientConfigTemplate, customClientConfig } + +// Allow the chain developer to overwrite the server default app toml config. +func initServerConfig() serverv2.ServerConfig { + serverCfg := serverv2.DefaultServerConfig() + // The server's default minimum gas price is set to "0stake" inside + // app.toml. However, the chain developer can set a default app.toml value for their + // validators here. Please update value based on chain denom. + // + // In summary: + // - if you set serverCfg.MinGasPrices value, validators CAN tweak their + // own app.toml to override, or use this default value. + // + // In simapp, we set the min gas prices to 0. + serverCfg.MinGasPrices = "0stake" + + return serverCfg +} diff --git a/simapp/v2/simdv2/cmd/testnet.go b/simapp/v2/simdv2/cmd/testnet.go index 91c1a30a12a6..5ec782389036 100644 --- a/simapp/v2/simdv2/cmd/testnet.go +++ b/simapp/v2/simdv2/cmd/testnet.go @@ -41,7 +41,6 @@ import ( ) var ( - flagMinGasPrices = "minimum-gas-prices" flagNodeDirPrefix = "node-dir-prefix" flagNumValidators = "validator-count" flagOutputDir = "output-dir" @@ -72,7 +71,7 @@ func addTestnetFlagsToCmd(cmd *cobra.Command) { cmd.Flags().IntP(flagNumValidators, "n", 4, "Number of validators to initialize the testnet with") cmd.Flags().StringP(flagOutputDir, "o", "./.testnets", "Directory to store initialization data for the testnet") cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") - cmd.Flags().String(flagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)") + cmd.Flags().String(serverv2.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)") cmd.Flags().String(flags.FlagKeyType, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") // support old flags name for backwards compatibility @@ -129,7 +128,7 @@ Example: args.outputDir, _ = cmd.Flags().GetString(flagOutputDir) args.keyringBackend, _ = cmd.Flags().GetString(flags.FlagKeyringBackend) args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID) - args.minGasPrices, _ = cmd.Flags().GetString(flagMinGasPrices) + args.minGasPrices, _ = cmd.Flags().GetString(serverv2.FlagMinGasPrices) args.nodeDirPrefix, _ = cmd.Flags().GetString(flagNodeDirPrefix) args.nodeDaemonHome, _ = cmd.Flags().GetString(flagNodeDaemonHome) args.startingIPAddress, _ = cmd.Flags().GetString(flagStartingIPAddress) @@ -337,6 +336,9 @@ func initTestnetFiles[T transaction.Tx]( return err } + serverCfg := serverv2.DefaultServerConfig() + serverCfg.MinGasPrices = args.minGasPrices + // Write server config cometServer := cometbft.New[T]( &genericTxDecoder[T]{clientCtx.TxConfig}, @@ -345,7 +347,7 @@ func initTestnetFiles[T transaction.Tx]( ) storeServer := store.New[T](newApp) grpcServer := grpc.New[T](grpc.OverwriteDefaultConfig(grpcConfig)) - server := serverv2.NewServer(log.NewNopLogger(), cometServer, grpcServer, storeServer) + server := serverv2.NewServer(log.NewNopLogger(), serverCfg, cometServer, grpcServer, storeServer) err = server.WriteConfig(filepath.Join(nodeDir, "config")) if err != nil { return err diff --git a/tests/systemtests/staking_test.go b/tests/systemtests/staking_test.go index 0b18408410df..f197bff1a0ac 100644 --- a/tests/systemtests/staking_test.go +++ b/tests/systemtests/staking_test.go @@ -10,7 +10,6 @@ import ( ) func TestStakeUnstake(t *testing.T) { - t.Skip("The fee deduction is not yet implemented in v2") // Scenario: // delegate tokens to validator // undelegate some tokens diff --git a/tools/confix/data/v2-app.toml b/tools/confix/data/v2-app.toml index 6a93006eccfb..8f7f7f9940d2 100644 --- a/tools/confix/data/v2-app.toml +++ b/tools/confix/data/v2-app.toml @@ -28,6 +28,10 @@ max-recv-msg-size = 10485760 # The default value is math.MaxInt32. max-send-msg-size = 2147483647 +[server] +# minimum-gas-prices defines the price which 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' + [store] # The type of database for application and snapshots databases. app-db-backend = 'goleveldb' diff --git a/tools/confix/migrations.go b/tools/confix/migrations.go index 4a500898bc04..437c628d7b25 100644 --- a/tools/confix/migrations.go +++ b/tools/confix/migrations.go @@ -39,11 +39,12 @@ type v2KeyChangesMap map[string][]string // list all the keys which are need to be modified in v2 var v2KeyChanges = v2KeyChangesMap{ - "min-retain-blocks": []string{"comet.min-retain-blocks"}, - "index-events": []string{"comet.index-events"}, - "halt-height": []string{"comet.halt-height"}, - "halt-time": []string{"comet.halt-time"}, - "app-db-backend": []string{"store.app-db-backend"}, + "minimum-gas-prices": []string{"server.minimum-gas-prices"}, + "min-retain-blocks": []string{"comet.min-retain-blocks"}, + "index-events": []string{"comet.index-events"}, + "halt-height": []string{"comet.halt-height"}, + "halt-time": []string{"comet.halt-time"}, + "app-db-backend": []string{"store.app-db-backend"}, "pruning-keep-recent": []string{ "store.options.ss-pruning-option.keep-recent", "store.options.sc-pruning-option.keep-recent", diff --git a/x/auth/ante/fee.go b/x/auth/ante/fee.go index 298fae30a4cc..248d7163471b 100644 --- a/x/auth/ante/fee.go +++ b/x/auth/ante/fee.go @@ -2,8 +2,10 @@ package ante import ( "bytes" + "context" "fmt" + "cosmossdk.io/core/event" "cosmossdk.io/core/transaction" errorsmod "cosmossdk.io/errors" "cosmossdk.io/x/auth/types" @@ -14,7 +16,7 @@ import ( // TxFeeChecker checks if the provided fee is enough and returns the effective fee and tx priority. // The effective fee should be deducted later, and the priority should be returned in the ABCI response. -type TxFeeChecker func(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) +type TxFeeChecker func(ctx context.Context, tx transaction.Tx) (sdk.Coins, int64, error) // DeductFeeDecorator deducts fees from the fee payer. The fee payer is the fee granter (if specified) or first signer of the tx. // If the fee payer does not have the funds to pay for the fees, return an InsufficientFunds error. @@ -25,60 +27,78 @@ type DeductFeeDecorator struct { bankKeeper types.BankKeeper feegrantKeeper FeegrantKeeper txFeeChecker TxFeeChecker + minGasPrices sdk.DecCoins } -func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) DeductFeeDecorator { - if tfc == nil { - tfc = checkTxFeeWithValidatorMinGasPrices - } - - return DeductFeeDecorator{ +func NewDeductFeeDecorator(ak AccountKeeper, bk types.BankKeeper, fk FeegrantKeeper, tfc TxFeeChecker) *DeductFeeDecorator { + dfd := &DeductFeeDecorator{ accountKeeper: ak, bankKeeper: bk, feegrantKeeper: fk, txFeeChecker: tfc, + minGasPrices: sdk.NewDecCoins(), + } + + if tfc == nil { + dfd.txFeeChecker = dfd.checkTxFeeWithValidatorMinGasPrices } + + return dfd } -func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, next sdk.AnteHandler) (sdk.Context, error) { +// SetMinGasPrices sets the minimum-gas-prices value in the state of DeductFeeDecorator +func (dfd *DeductFeeDecorator) SetMinGasPrices(minGasPrices sdk.DecCoins) { + dfd.minGasPrices = minGasPrices +} + +// AnteHandle implements an AnteHandler decorator for the DeductFeeDecorator +func (dfd *DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, _ bool, next sdk.AnteHandler) (sdk.Context, error) { + dfd.minGasPrices = ctx.MinGasPrices() + txPriority, err := dfd.innerValidateTx(ctx, tx) + if err != nil { + return ctx, err + } + + newCtx := ctx.WithPriority(txPriority) + return next(newCtx, tx, false) +} + +func (dfd *DeductFeeDecorator) innerValidateTx(ctx context.Context, tx transaction.Tx) (priority int64, err error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { - return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the FeeTx interface") + return 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the FeeTx interface") } - txService := dfd.accountKeeper.GetEnvironment().TransactionService - execMode := txService.ExecMode(ctx) - if execMode != transaction.ExecModeSimulate && ctx.BlockHeight() > 0 && feeTx.GetGas() == 0 { - return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") - } + execMode := dfd.accountKeeper.GetEnvironment().TransactionService.ExecMode(ctx) + headerInfo := dfd.accountKeeper.GetEnvironment().HeaderService.HeaderInfo(ctx) - var ( - priority int64 - err error - ) + if execMode != transaction.ExecModeSimulate && headerInfo.Height > 0 && feeTx.GetGas() == 0 { + return 0, errorsmod.Wrap(sdkerrors.ErrInvalidGasLimit, "must provide positive gas") + } fee := feeTx.GetFee() if execMode != transaction.ExecModeSimulate { fee, priority, err = dfd.txFeeChecker(ctx, tx) if err != nil { - return ctx, err + return 0, err } } - if err := dfd.checkDeductFee(ctx, tx, fee); err != nil { - return ctx, err - } - newCtx := ctx.WithPriority(priority) + if err := dfd.checkDeductFee(ctx, feeTx, fee); err != nil { + return 0, err + } - return next(newCtx, tx, false) + return priority, nil } -func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee sdk.Coins) error { - feeTx, ok := sdkTx.(sdk.FeeTx) - if !ok { - return errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must implement the FeeTx interface") - } +// ValidateTx implements an TxValidator for DeductFeeDecorator +// Note: This method is applicable only for transactions that implement the sdk.FeeTx interface. +func (dfd *DeductFeeDecorator) ValidateTx(ctx context.Context, tx transaction.Tx) error { + _, err := dfd.innerValidateTx(ctx, tx) + return err +} +func (dfd *DeductFeeDecorator) checkDeductFee(ctx context.Context, feeTx sdk.FeeTx, fee sdk.Coins) error { addr := dfd.accountKeeper.GetModuleAddress(types.FeeCollectorName) if len(addr) == 0 { return fmt.Errorf("fee collector module account (%s) has not been set", types.FeeCollectorName) @@ -91,12 +111,10 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee // if feegranter set, deduct fee from feegranter account. // this works only when feegrant is enabled. if feeGranter != nil { - feeGranterAddr := sdk.AccAddress(feeGranter) - if dfd.feegrantKeeper == nil { return sdkerrors.ErrInvalidRequest.Wrap("fee grants are not enabled") - } else if !bytes.Equal(feeGranterAddr, feePayer) { - err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranterAddr, feePayer, fee, sdkTx.GetMsgs()) + } else if !bytes.Equal(feeGranter, feePayer) { + err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, feeTx.GetMsgs()) if err != nil { granterAddr, acErr := dfd.accountKeeper.AddressCodec().BytesToString(feeGranter) if acErr != nil { @@ -109,38 +127,34 @@ func (dfd DeductFeeDecorator) checkDeductFee(ctx sdk.Context, sdkTx sdk.Tx, fee return errorsmod.Wrapf(err, "%s does not allow to pay fees for %s", granterAddr, payerAddr) } } - - deductFeesFrom = feeGranterAddr + deductFeesFrom = feeGranter } // deduct the fees if !fee.IsZero() { - err := DeductFees(dfd.bankKeeper, ctx, deductFeesFrom, fee) - if err != nil { + if err := DeductFees(dfd.bankKeeper, ctx, deductFeesFrom, fee); err != nil { return err } } - events := sdk.Events{ - sdk.NewEvent( - sdk.EventTypeTx, - sdk.NewAttribute(sdk.AttributeKeyFee, fee.String()), - sdk.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()), - ), + if err := dfd.accountKeeper.GetEnvironment().EventService.EventManager(ctx).EmitKV( + sdk.EventTypeTx, + event.NewAttribute(sdk.AttributeKeyFee, fee.String()), + event.NewAttribute(sdk.AttributeKeyFeePayer, sdk.AccAddress(deductFeesFrom).String()), + ); err != nil { + return err } - ctx.EventManager().EmitEvents(events) return nil } // DeductFees deducts fees from the given account. -func DeductFees(bankKeeper types.BankKeeper, ctx sdk.Context, acc []byte, fees sdk.Coins) error { +func DeductFees(bankKeeper types.BankKeeper, ctx context.Context, acc []byte, fees sdk.Coins) error { if !fees.IsValid() { return errorsmod.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } - err := bankKeeper.SendCoinsFromAccountToModule(ctx, sdk.AccAddress(acc), types.FeeCollectorName, fees) - if err != nil { + if err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc, types.FeeCollectorName, fees); err != nil { return fmt.Errorf("failed to deduct fees: %w", err) } diff --git a/x/auth/ante/fee_test.go b/x/auth/ante/fee_test.go index 0c9fa299a5e4..6736f17aed99 100644 --- a/x/auth/ante/fee_test.go +++ b/x/auth/ante/fee_test.go @@ -41,6 +41,11 @@ func TestDeductFeeDecorator_ZeroGas(t *testing.T) { // Set IsCheckTx to true s.ctx = s.ctx.WithIsCheckTx(true) + // Set current block height in headerInfo + headerInfo := s.ctx.HeaderInfo() + headerInfo.Height = s.ctx.BlockHeight() + s.ctx = s.ctx.WithHeaderInfo(headerInfo) + _, err = antehandler(s.ctx, tx, false) require.Error(t, err) diff --git a/x/auth/ante/validator_tx_fee.go b/x/auth/ante/validator_tx_fee.go index af4f02fed05f..421068175bea 100644 --- a/x/auth/ante/validator_tx_fee.go +++ b/x/auth/ante/validator_tx_fee.go @@ -1,8 +1,10 @@ package ante import ( + "context" "math" + "cosmossdk.io/core/transaction" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" @@ -12,7 +14,7 @@ import ( // checkTxFeeWithValidatorMinGasPrices implements the default fee logic, where the minimum price per // unit of gas is fixed and set by each validator, can the tx priority is computed from the gas price. -func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { +func (dfd *DeductFeeDecorator) checkTxFeeWithValidatorMinGasPrices(ctx context.Context, tx transaction.Tx) (sdk.Coins, int64, error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { return nil, 0, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx") @@ -24,8 +26,8 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, // Ensure that the provided fees meet a minimum threshold for the validator, // if this is a CheckTx. This is only for local mempool purposes, and thus // is only ran on check tx. - if ctx.ExecMode() == sdk.ExecModeCheck { // NOTE: using environment here breaks the API of fee logic, an alternative must be found for server/v2. ref: https://github.com/cosmos/cosmos-sdk/issues/19640 - minGasPrices := ctx.MinGasPrices() + if dfd.accountKeeper.GetEnvironment().TransactionService.ExecMode(ctx) == transaction.ExecModeCheck { + minGasPrices := dfd.minGasPrices if !minGasPrices.IsZero() { requiredFees := make(sdk.Coins, len(minGasPrices)) diff --git a/x/auth/tx/config/depinject.go b/x/auth/tx/config/depinject.go index bb573f044f6a..e4e43ac3d80f 100644 --- a/x/auth/tx/config/depinject.go +++ b/x/auth/tx/config/depinject.go @@ -6,6 +6,7 @@ import ( "fmt" gogoproto "github.com/cosmos/gogoproto/proto" + "github.com/spf13/viper" "google.golang.org/grpc" "google.golang.org/grpc/codes" grpcstatus "google.golang.org/grpc/status" @@ -34,6 +35,9 @@ import ( signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" ) +// flagMinGasPricesV2 is the flag name for the minimum gas prices in the main server v2 component. +const flagMinGasPricesV2 = "server.minimum-gas-prices" + func init() { appconfig.RegisterModule(&txconfigv1.Config{}, appconfig.Provide(ProvideModule), @@ -50,7 +54,7 @@ type ModuleInputs struct { Codec codec.Codec ProtoFileResolver txsigning.ProtoFileResolver Environment appmodule.Environment - // BankKeeper is the expected bank keeper to be passed to AnteHandlers + // BankKeeper is the expected bank keeper to be passed to AnteHandlers / Tx Validators BankKeeper authtypes.BankKeeper `optional:"true"` MetadataBankKeeper BankKeeper `optional:"true"` AccountKeeper ante.AccountKeeper `optional:"true"` @@ -58,8 +62,10 @@ type ModuleInputs struct { AccountAbstractionKeeper ante.AccountAbstractionKeeper `optional:"true"` CustomSignModeHandlers func() []txsigning.SignModeHandler `optional:"true"` CustomGetSigners []txsigning.CustomGetSigner `optional:"true"` - UnorderedTxManager *unorderedtx.Manager `optional:"true"` ExtraTxValidators []appmodule.TxValidator[transaction.Tx] `optional:"true"` + UnorderedTxManager *unorderedtx.Manager `optional:"true"` + TxFeeChecker ante.TxFeeChecker `optional:"true"` + Viper *viper.Viper `optional:"true"` // server v2 } type ModuleOutputs struct { @@ -107,7 +113,40 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { panic(err) } - baseAppOption := func(app *baseapp.BaseApp) { + svd := ante.NewSigVerificationDecorator( + in.AccountKeeper, + txConfig.SignModeHandler(), + ante.DefaultSigVerificationGasConsumer, + in.AccountAbstractionKeeper, + ) + + var ( + minGasPrices sdk.DecCoins + feeTxValidator *ante.DeductFeeDecorator + ) + if in.AccountKeeper != nil && in.BankKeeper != nil && in.Viper != nil { + minGasPricesStr := in.Viper.GetString(flagMinGasPricesV2) + minGasPrices, err = sdk.ParseDecCoins(minGasPricesStr) + if err != nil { + panic(fmt.Sprintf("invalid minimum gas prices: %v", err)) + } + + feeTxValidator = ante.NewDeductFeeDecorator(in.AccountKeeper, in.BankKeeper, in.FeeGrantKeeper, in.TxFeeChecker) + feeTxValidator.SetMinGasPrices(minGasPrices) // set min gas price in deduct fee decorator + } + + return ModuleOutputs{ + Module: NewAppModule(svd, feeTxValidator, in.ExtraTxValidators...), + BaseAppOption: newBaseAppOption(txConfig, in), + TxConfig: txConfig, + TxConfigOptions: txConfigOptions, + } +} + +// newBaseAppOption returns baseapp option that sets the ante handler and post handler +// and set the tx encoder and decoder on baseapp. +func newBaseAppOption(txConfig client.TxConfig, in ModuleInputs) func(app *baseapp.BaseApp) { + return func(app *baseapp.BaseApp) { // AnteHandlers if !in.Config.SkipAnteHandler { anteHandler, err := newAnteHandler(txConfig, in) @@ -145,20 +184,6 @@ func ProvideModule(in ModuleInputs) ModuleOutputs { app.SetTxDecoder(txConfig.TxDecoder()) app.SetTxEncoder(txConfig.TxEncoder()) } - - svd := ante.NewSigVerificationDecorator( - in.AccountKeeper, - txConfig.SignModeHandler(), - ante.DefaultSigVerificationGasConsumer, - in.AccountAbstractionKeeper, - ) - - return ModuleOutputs{ - Module: NewAppModule(svd, in.ExtraTxValidators...), - TxConfig: txConfig, - TxConfigOptions: txConfigOptions, - BaseAppOption: baseAppOption, - } } func newAnteHandler(txConfig client.TxConfig, in ModuleInputs) (sdk.AnteHandler, error) { diff --git a/x/auth/tx/config/module.go b/x/auth/tx/config/module.go index 6e94e0e8cfac..f4a1207fa7b1 100644 --- a/x/auth/tx/config/module.go +++ b/x/auth/tx/config/module.go @@ -19,6 +19,7 @@ var ( // This module is only useful for chains using server/v2. Ante/Post handlers are setup via baseapp options in depinject. type AppModule struct { sigVerification ante.SigVerificationDecorator + feeTxValidator *ante.DeductFeeDecorator // txValidators contains tx validator that can be injected into the module via depinject. // tx validators should be module based, but it can happen that you do not want to create a new module // and simply depinject-it. @@ -28,10 +29,12 @@ type AppModule struct { // NewAppModule creates a new AppModule object. func NewAppModule( sigVerification ante.SigVerificationDecorator, + feeTxValidator *ante.DeductFeeDecorator, txValidators ...appmodulev2.TxValidator[transaction.Tx], ) AppModule { return AppModule{ sigVerification: sigVerification, + feeTxValidator: feeTxValidator, txValidators: txValidators, } } @@ -50,5 +53,9 @@ func (a AppModule) TxValidator(ctx context.Context, tx transaction.Tx) error { } } + if err := a.feeTxValidator.ValidateTx(ctx, tx); err != nil { + return err + } + return a.sigVerification.ValidateTx(ctx, tx) } From f9806f1ade593015b3ae326cc2dd575a05570f3a Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 29 Aug 2024 10:13:09 +0200 Subject: [PATCH 2/2] remove server/v2 and bump using main --- server/v2/cometbft/go.mod | 4 +- server/v2/cometbft/go.sum | 8 +- server/v2/commands.go | 213 ----------------------------- server/v2/config.go | 73 ---------- server/v2/flags.go | 25 ---- server/v2/server.go | 263 ------------------------------------ server/v2/server_test.go | 99 -------------- server/v2/testdata/app.toml | 51 ------- simapp/v2/go.mod | 4 +- simapp/v2/go.sum | 8 +- 10 files changed, 12 insertions(+), 736 deletions(-) delete mode 100644 server/v2/commands.go delete mode 100644 server/v2/config.go delete mode 100644 server/v2/flags.go delete mode 100644 server/v2/server.go delete mode 100644 server/v2/server_test.go delete mode 100644 server/v2/testdata/app.toml diff --git a/server/v2/cometbft/go.mod b/server/v2/cometbft/go.mod index 7f131220d4df..e67c8dc473a8 100644 --- a/server/v2/cometbft/go.mod +++ b/server/v2/cometbft/go.mod @@ -23,7 +23,7 @@ require ( cosmossdk.io/core v1.0.0 // main cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.4.1 - cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e // main + cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b // main cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e // main cosmossdk.io/store/v2 v2.0.0-20240731205446-aee9803a0af6 // main cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000 @@ -135,7 +135,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.57.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect diff --git a/server/v2/cometbft/go.sum b/server/v2/cometbft/go.sum index 64b4795ec574..bc6f46513293 100644 --- a/server/v2/cometbft/go.sum +++ b/server/v2/cometbft/go.sum @@ -24,8 +24,8 @@ cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA= cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= -cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e h1:5B5vereMsxfQsk8eXchBQPB1sc5POgYxZOBaUlST6WQ= -cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e/go.mod h1:rUve692/2QXV8ulpAG1mlytqiyW5nhZySY4ngmgJyQA= +cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b h1:FFixNVq2SbtRlYvr1fB/WikfYTRrA0o/35ImIhhZzrE= +cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b/go.mod h1:MgjYKtPEW4FPEYxh1h0idVBjgblFgdrAWkeqn7UOrVA= cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e h1:9eB2si1gT6c5ea8Jsh498Ei6E3Th1yMyuJgSLiT6D4Y= cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20= cosmossdk.io/store v1.0.0-rc.0.0.20240815194237-858ec2fcb897 h1:o024zaPHYtmUGL2BCX1ns9rfZmMc19U4hQ2CAPt2Xgg= @@ -415,8 +415,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= +github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= diff --git a/server/v2/commands.go b/server/v2/commands.go deleted file mode 100644 index 101a23d3983e..000000000000 --- a/server/v2/commands.go +++ /dev/null @@ -1,213 +0,0 @@ -package serverv2 - -import ( - "context" - "errors" - "os" - "os/signal" - "path/filepath" - "strings" - "syscall" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "cosmossdk.io/core/transaction" - "cosmossdk.io/log" -) - -// Execute executes the root command of an application. -// It handles adding core CLI flags, specifically the logging flags. -func Execute(rootCmd *cobra.Command, envPrefix, defaultHome string) error { - rootCmd.PersistentFlags().String(FlagLogLevel, "info", "The logging level (trace|debug|info|warn|error|fatal|panic|disabled or '*:,:')") - rootCmd.PersistentFlags().String(FlagLogFormat, "plain", "The logging format (json|plain)") - rootCmd.PersistentFlags().Bool(FlagLogNoColor, false, "Disable colored logs") - rootCmd.PersistentFlags().StringP(FlagHome, "", defaultHome, "directory for config and data") - - // update the global viper with the root command's configuration - viper.SetEnvPrefix(envPrefix) - viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) - viper.AutomaticEnv() - - return rootCmd.Execute() -} - -// AddCommands add the server commands to the root command -// It configure the config handling and the logger handling -func AddCommands[T transaction.Tx]( - rootCmd *cobra.Command, - newApp AppCreator[T], - logger log.Logger, - serverCfg ServerConfig, - components ...ServerComponent[T], -) error { - if len(components) == 0 { - return errors.New("no components provided") - } - - server := NewServer(logger, serverCfg, components...) - originalPersistentPreRunE := rootCmd.PersistentPreRunE - rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { - // set the default command outputs - cmd.SetOut(cmd.OutOrStdout()) - cmd.SetErr(cmd.ErrOrStderr()) - - if err := configHandle(server, cmd); err != nil { - return err - } - - // call the original PersistentPreRun(E) if it exists - if rootCmd.PersistentPreRun != nil { - rootCmd.PersistentPreRun(cmd, args) - return nil - } - - return originalPersistentPreRunE(cmd, args) - } - - cmds := server.CLICommands() - startCmd := createStartCommand(server, newApp) - startCmd.SetContext(rootCmd.Context()) - cmds.Commands = append(cmds.Commands, startCmd) - rootCmd.AddCommand(cmds.Commands...) - - if len(cmds.Queries) > 0 { - if queryCmd := findSubCommand(rootCmd, "query"); queryCmd != nil { - queryCmd.AddCommand(cmds.Queries...) - } else { - queryCmd := topLevelCmd(rootCmd.Context(), "query", "Querying subcommands") - queryCmd.Aliases = []string{"q"} - queryCmd.AddCommand(cmds.Queries...) - rootCmd.AddCommand(queryCmd) - } - } - - if len(cmds.Txs) > 0 { - if txCmd := findSubCommand(rootCmd, "tx"); txCmd != nil { - txCmd.AddCommand(cmds.Txs...) - } else { - txCmd := topLevelCmd(rootCmd.Context(), "tx", "Transactions subcommands") - txCmd.AddCommand(cmds.Txs...) - rootCmd.AddCommand(txCmd) - } - } - - return nil -} - -// createStartCommand creates the start command for the application. -func createStartCommand[T transaction.Tx]( - server *Server[T], - newApp AppCreator[T], -) *cobra.Command { - flags := server.StartFlags() - - cmd := &cobra.Command{ - Use: "start", - Short: "Run the application", - RunE: func(cmd *cobra.Command, args []string) error { - v := GetViperFromCmd(cmd) - l := GetLoggerFromCmd(cmd) - if err := v.BindPFlags(cmd.Flags()); err != nil { - return err - } - - if err := server.Init(newApp(l, v), v, l); err != nil { - return err - } - - ctx, cancelFn := context.WithCancel(cmd.Context()) - 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 err - } - - return nil - }, - } - - // add the start flags to the command - for _, startFlags := range flags { - cmd.Flags().AddFlagSet(startFlags) - } - - return cmd -} - -// configHandle writes the default config to the home directory if it does not exist and sets the server context -func configHandle[T transaction.Tx](s *Server[T], cmd *cobra.Command) error { - home, err := cmd.Flags().GetString(FlagHome) - if err != nil { - return err - } - - configDir := filepath.Join(home, "config") - - // we need to check app.toml as the config folder can already exist for the client.toml - if _, err := os.Stat(filepath.Join(configDir, "app.toml")); os.IsNotExist(err) { - if err = s.WriteConfig(configDir); err != nil { - return err - } - } - - v, err := ReadConfig(configDir) - if err != nil { - return err - } - - if err := v.BindPFlags(cmd.Flags()); err != nil { - return err - } - - log, err := NewLogger(v, cmd.OutOrStdout()) - if err != nil { - return err - } - - return SetCmdServerContext(cmd, v, log) -} - -// findSubCommand finds a sub-command of the provided command whose Use -// string is or begins with the provided subCmdName. -// It verifies the command's aliases as well. -func findSubCommand(cmd *cobra.Command, subCmdName string) *cobra.Command { - for _, subCmd := range cmd.Commands() { - use := subCmd.Use - if use == subCmdName || strings.HasPrefix(use, subCmdName+" ") { - return subCmd - } - - for _, alias := range subCmd.Aliases { - if alias == subCmdName || strings.HasPrefix(alias, subCmdName+" ") { - return subCmd - } - } - } - return nil -} - -// topLevelCmd creates a new top-level command with the provided name and -// description. The command will have DisableFlagParsing set to false and -// SuggestionsMinimumDistance set to 2. -func topLevelCmd(ctx context.Context, use, short string) *cobra.Command { - cmd := &cobra.Command{ - Use: use, - Short: short, - DisableFlagParsing: false, - SuggestionsMinimumDistance: 2, - } - cmd.SetContext(ctx) - - return cmd -} diff --git a/server/v2/config.go b/server/v2/config.go deleted file mode 100644 index b5c525fdf682..000000000000 --- a/server/v2/config.go +++ /dev/null @@ -1,73 +0,0 @@ -package serverv2 - -import ( - "fmt" - - "github.com/mitchellh/mapstructure" - "github.com/spf13/viper" -) - -// ServerConfig defines configuration for the server component. -type ServerConfig struct { - MinGasPrices string `mapstructure:"minimum-gas-prices" toml:"minimum-gas-prices" comment:"minimum-gas-prices defines the price which 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)."` -} - -// DefaultServerConfig returns the default config of server component -func DefaultServerConfig() ServerConfig { - return ServerConfig{ - MinGasPrices: "0stake", - } -} - -// ReadConfig returns a viper instance of the config file -func ReadConfig(configPath string) (*viper.Viper, error) { - v := viper.New() - v.SetConfigType("toml") - v.SetConfigName("config") - v.AddConfigPath(configPath) - if err := v.ReadInConfig(); err != nil { - return nil, fmt.Errorf("failed to read config: %s: %w", configPath, err) - } - - v.SetConfigName("app") - if err := v.MergeInConfig(); err != nil { - return nil, fmt.Errorf("failed to merge configuration: %w", err) - } - - v.WatchConfig() - - return v, nil -} - -// UnmarshalSubConfig unmarshals the given subconfig from the viper instance. -// It unmarshals the config, env, flags into the target struct. -// Use this instead of viper.Sub because viper does not unmarshal flags. -func UnmarshalSubConfig(v *viper.Viper, subName string, target any) error { - var sub any - for k, val := range v.AllSettings() { - if k == subName { - sub = val - break - } - } - - // Create a new decoder with custom decoding options - decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - DecodeHook: mapstructure.ComposeDecodeHookFunc( - mapstructure.StringToTimeDurationHookFunc(), - mapstructure.StringToSliceHookFunc(","), - ), - Result: target, - WeaklyTypedInput: true, - }) - if err != nil { - return fmt.Errorf("failed to create decoder: %w", err) - } - - // Decode the sub-configuration - if err := decoder.Decode(sub); err != nil { - return fmt.Errorf("failed to decode sub-configuration: %w", err) - } - - return nil -} diff --git a/server/v2/flags.go b/server/v2/flags.go deleted file mode 100644 index fc36cdcf2b4c..000000000000 --- a/server/v2/flags.go +++ /dev/null @@ -1,25 +0,0 @@ -// Package serverv2 defines constants for server configuration flags and output formats. -package serverv2 - -import "fmt" - -// start flags are prefixed with the server name -// this allows viper to properly bind the flags -func prefix(f string) string { - return fmt.Sprintf("%s.%s", serverName, f) -} - -var FlagMinGasPrices = prefix("minimum-gas-prices") - -const ( - // FlagHome specifies the home directory flag. - FlagHome = "home" - - FlagLogLevel = "log_level" // Sets the logging level - FlagLogFormat = "log_format" // Specifies the log output format - FlagLogNoColor = "log_no_color" // Disables colored log output - FlagTrace = "trace" // Enables trace-level logging - - // OutputFormatJSON defines the JSON output format option. - OutputFormatJSON = "json" -) diff --git a/server/v2/server.go b/server/v2/server.go deleted file mode 100644 index 08ae9a6a06fa..000000000000 --- a/server/v2/server.go +++ /dev/null @@ -1,263 +0,0 @@ -package serverv2 - -import ( - "context" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/pelletier/go-toml/v2" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/spf13/viper" - "golang.org/x/sync/errgroup" - - "cosmossdk.io/core/transaction" - "cosmossdk.io/log" -) - -// ServerComponent is a server module that can be started and stopped. -type ServerComponent[T transaction.Tx] interface { - Name() string - - Start(context.Context) error - Stop(context.Context) error - Init(AppI[T], *viper.Viper, log.Logger) error -} - -// HasStartFlags is a server module that has start flags. -type HasStartFlags interface { - // StartCmdFlags returns server start flags. - // Those flags should be prefixed with the server name. - // They are then merged with the server config in one viper instance. - StartCmdFlags() *pflag.FlagSet -} - -// HasConfig is a server module that has a config. -type HasConfig interface { - Config() any -} - -// HasCLICommands is a server module that has CLI commands. -type HasCLICommands interface { - CLICommands() CLIConfig -} - -// CLIConfig defines the CLI configuration for a module server. -type CLIConfig struct { - // Commands defines the main command of a module server. - Commands []*cobra.Command - // Queries defines the query commands of a module server. - // Those commands are meant to be added in the root query command. - Queries []*cobra.Command - // Txs defines the tx commands of a module server. - // Those commands are meant to be added in the root tx command. - Txs []*cobra.Command -} - -const ( - serverName = "server" -) - -var _ ServerComponent[transaction.Tx] = (*Server[transaction.Tx])(nil) - -type Server[T transaction.Tx] struct { - logger log.Logger - components []ServerComponent[T] - config ServerConfig -} - -func NewServer[T transaction.Tx]( - logger log.Logger, - config ServerConfig, - components ...ServerComponent[T], -) *Server[T] { - return &Server[T]{ - logger: logger, - config: config, - components: components, - } -} - -func (s *Server[T]) Name() string { - return serverName -} - -// Start starts all components concurrently. -func (s *Server[T]) Start(ctx context.Context) error { - s.logger.Info("starting servers...") - - g, ctx := errgroup.WithContext(ctx) - for _, mod := range s.components { - mod := mod - g.Go(func() error { - return mod.Start(ctx) - }) - } - - if err := g.Wait(); err != nil { - return fmt.Errorf("failed to start servers: %w", err) - } - - <-ctx.Done() - - return nil -} - -// Stop stops all components concurrently. -func (s *Server[T]) Stop(ctx context.Context) error { - s.logger.Info("stopping servers...") - - g, ctx := errgroup.WithContext(ctx) - for _, mod := range s.components { - mod := mod - g.Go(func() error { - return mod.Stop(ctx) - }) - } - - return g.Wait() -} - -// CLICommands returns all CLI commands of all components. -func (s *Server[T]) CLICommands() CLIConfig { - compart := func(name string, cmds ...*cobra.Command) *cobra.Command { - if len(cmds) == 1 && strings.HasPrefix(cmds[0].Use, name) { - return cmds[0] - } - - subCmd := &cobra.Command{ - Use: name, - Short: fmt.Sprintf("Commands from the %s server component", name), - } - subCmd.AddCommand(cmds...) - - return subCmd - } - - commands := CLIConfig{} - for _, mod := range s.components { - if climod, ok := mod.(HasCLICommands); ok { - srvCmd := climod.CLICommands() - - if len(srvCmd.Commands) > 0 { - commands.Commands = append(commands.Commands, compart(mod.Name(), srvCmd.Commands...)) - } - - if len(srvCmd.Txs) > 0 { - commands.Txs = append(commands.Txs, compart(mod.Name(), srvCmd.Txs...)) - } - - if len(srvCmd.Queries) > 0 { - commands.Queries = append(commands.Queries, compart(mod.Name(), srvCmd.Queries...)) - } - } - } - - return commands -} - -// Config returns config of the server component -func (s *Server[T]) Config() ServerConfig { - return s.config -} - -// Configs returns all configs of all server components. -func (s *Server[T]) Configs() map[string]any { - cfgs := make(map[string]any) - - // add server component config - cfgs[s.Name()] = s.config - - // add other components' config - for _, mod := range s.components { - if configmod, ok := mod.(HasConfig); ok { - cfg := configmod.Config() - cfgs[mod.Name()] = cfg - } - } - - return cfgs -} - -func (s *Server[T]) StartCmdFlags() *pflag.FlagSet { - flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError) - flags.String(FlagMinGasPrices, "", "Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)") - return flags -} - -// Init initializes all server components with the provided application, configuration, and logger. -// It returns an error if any component fails to initialize. -func (s *Server[T]) Init(appI AppI[T], v *viper.Viper, logger log.Logger) error { - cfg := s.config - if v != nil { - if err := UnmarshalSubConfig(v, s.Name(), &cfg); err != nil { - return fmt.Errorf("failed to unmarshal config: %w", err) - } - } - - var components []ServerComponent[T] - for _, mod := range s.components { - mod := mod - if err := mod.Init(appI, v, logger); err != nil { - return err - } - - components = append(components, mod) - } - - s.config = cfg - s.components = components - return nil -} - -// WriteConfig writes the config to the given path. -// Note: it does not use viper.WriteConfigAs because we do not want to store flag values in the config. -func (s *Server[T]) WriteConfig(configPath string) error { - cfgs := s.Configs() - b, err := toml.Marshal(cfgs) - if err != nil { - return err - } - - if _, err := os.Stat(configPath); os.IsNotExist(err) { - if err := os.MkdirAll(configPath, os.ModePerm); err != nil { - return err - } - } - - if err := os.WriteFile(filepath.Join(configPath, "app.toml"), b, 0o600); err != nil { - return fmt.Errorf("failed to write config: %w", err) - } - - for _, component := range s.components { - // undocumented interface to write the component default config in another file than app.toml - // it is used by cometbft for backward compatibility - // it should not be used by other components - if mod, ok := component.(interface{ WriteCustomConfigAt(string) error }); ok { - if err := mod.WriteCustomConfigAt(configPath); err != nil { - return err - } - } - } - - return nil -} - -// StartFlags returns all flags of all server components. -func (s *Server[T]) StartFlags() []*pflag.FlagSet { - flags := []*pflag.FlagSet{} - - // add server component flags - flags = append(flags, s.StartCmdFlags()) - - // add other components' start cmd flags - for _, mod := range s.components { - if startmod, ok := mod.(HasStartFlags); ok { - flags = append(flags, startmod.StartCmdFlags()) - } - } - - return flags -} diff --git a/server/v2/server_test.go b/server/v2/server_test.go deleted file mode 100644 index 572d91272062..000000000000 --- a/server/v2/server_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package serverv2_test - -import ( - "context" - "os" - "path/filepath" - "testing" - "time" - - gogoproto "github.com/cosmos/gogoproto/proto" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" - - coreserver "cosmossdk.io/core/server" - "cosmossdk.io/core/transaction" - "cosmossdk.io/log" - serverv2 "cosmossdk.io/server/v2" - grpc "cosmossdk.io/server/v2/api/grpc" - "cosmossdk.io/server/v2/appmanager" -) - -type mockInterfaceRegistry struct{} - -func (*mockInterfaceRegistry) Resolve(typeUrl string) (gogoproto.Message, error) { - panic("not implemented") -} - -func (*mockInterfaceRegistry) ListImplementations(ifaceTypeURL string) []string { - panic("not implemented") -} -func (*mockInterfaceRegistry) ListAllInterfaces() []string { panic("not implemented") } - -type mockApp[T transaction.Tx] struct { - serverv2.AppI[T] -} - -func (*mockApp[T]) GetGPRCMethodsToMessageMap() map[string]func() gogoproto.Message { - return map[string]func() gogoproto.Message{} -} - -func (*mockApp[T]) GetAppManager() *appmanager.AppManager[T] { - return nil -} - -func (*mockApp[T]) InterfaceRegistry() coreserver.InterfaceRegistry { - return &mockInterfaceRegistry{} -} - -func TestServer(t *testing.T) { - currentDir, err := os.Getwd() - require.NoError(t, err) - configPath := filepath.Join(currentDir, "testdata") - - v, err := serverv2.ReadConfig(configPath) - if err != nil { - v = viper.New() - } - - logger := log.NewLogger(os.Stdout) - grpcServer := grpc.New[transaction.Tx]() - err = grpcServer.Init(&mockApp[transaction.Tx]{}, v, logger) - require.NoError(t, err) - - mockServer := &mockServer{name: "mock-server-1", ch: make(chan string, 100)} - - server := serverv2.NewServer( - logger, - serverv2.DefaultServerConfig(), - grpcServer, - mockServer, - ) - - serverCfgs := server.Configs() - require.Equal(t, serverCfgs[grpcServer.Name()].(*grpc.Config).Address, grpc.DefaultConfig().Address) - require.Equal(t, serverCfgs[mockServer.Name()].(*mockServerConfig).MockFieldOne, MockServerDefaultConfig().MockFieldOne) - - // write config - err = server.WriteConfig(configPath) - require.NoError(t, err) - - v, err = serverv2.ReadConfig(configPath) - require.NoError(t, err) - - require.Equal(t, v.GetString(grpcServer.Name()+".address"), grpc.DefaultConfig().Address) - - // start empty - ctx, cancelFn := context.WithCancel(context.TODO()) - go func() { - // wait 5sec and cancel context - <-time.After(5 * time.Second) - cancelFn() - - err = server.Stop(ctx) - require.NoError(t, err) - }() - - err = server.Start(ctx) - require.NoError(t, err) -} diff --git a/server/v2/testdata/app.toml b/server/v2/testdata/app.toml deleted file mode 100644 index 192dc8d67865..000000000000 --- a/server/v2/testdata/app.toml +++ /dev/null @@ -1,51 +0,0 @@ -[grpc] -# Enable defines if the gRPC server should be enabled. -enable = false -# 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 - -[server] -# minimum-gas-prices defines the price which 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' - -[store] -# The type of database for application and snapshots databases. -app-db-backend = 'goleveldb' - -[store.options] -# State storage database type. Currently we support: 0 for SQLite, 1 for Pebble -ss-type = 0 -# State commitment database type. Currently we support:0 for iavl, 1 for iavl v2 -sc-type = 0 - -# Pruning options for state storage -[store.options.ss-pruning-option] -# Number of recent heights to keep on disk. -keep-recent = 2 -# Height interval at which pruned heights are removed from disk. -interval = 100 - -# Pruning options for state commitment -[store.options.sc-pruning-option] -# Number of recent heights to keep on disk. -keep-recent = 2 -# Height interval at which pruned heights are removed from disk. -interval = 100 - -[store.options.iavl-config] -# CacheSize set the size of the iavl tree cache. -cache-size = 100000 -# If true, the tree will work like no fast storage and always not upgrade fast storage. -skip-fast-storage-upgrade = true - -[mock-server-1] -# Mock field -mock_field = 'default' -# Mock field two -mock_field_two = 1 diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index 5e65823aa15a..8ac8d316af90 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -11,7 +11,7 @@ require ( cosmossdk.io/log v1.4.1 cosmossdk.io/math v1.3.0 cosmossdk.io/runtime/v2 v2.0.0-20240827121911-e98b8e96174f // main - cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e // main + cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b // main cosmossdk.io/server/v2/cometbft v0.0.0-00010101000000-000000000000 cosmossdk.io/store/v2 v2.0.0-20240815194237-858ec2fcb897 // main cosmossdk.io/tools/confix v0.0.0-00010101000000-000000000000 @@ -185,7 +185,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.57.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.2.0 // indirect diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 9a7fe1c7a7dc..8c6a0793eafc 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -214,8 +214,8 @@ cosmossdk.io/runtime/v2 v2.0.0-20240827121911-e98b8e96174f h1:k/naA1PbdzhQ6EdiPh cosmossdk.io/runtime/v2 v2.0.0-20240827121911-e98b8e96174f/go.mod h1:SoCx1xyZn+tVPAtTAuLSEYjocVtZips+O2QLGBj99/c= cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA= cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= -cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e h1:5B5vereMsxfQsk8eXchBQPB1sc5POgYxZOBaUlST6WQ= -cosmossdk.io/server/v2 v2.0.0-20240827095516-355f748add9e/go.mod h1:rUve692/2QXV8ulpAG1mlytqiyW5nhZySY4ngmgJyQA= +cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b h1:FFixNVq2SbtRlYvr1fB/WikfYTRrA0o/35ImIhhZzrE= +cosmossdk.io/server/v2 v2.0.0-20240829074658-81a225e6a29b/go.mod h1:MgjYKtPEW4FPEYxh1h0idVBjgblFgdrAWkeqn7UOrVA= cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e h1:9eB2si1gT6c5ea8Jsh498Ei6E3Th1yMyuJgSLiT6D4Y= cosmossdk.io/server/v2/appmanager v0.0.0-20240827095516-355f748add9e/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20= cosmossdk.io/server/v2/stf v0.0.0-20240827095516-355f748add9e h1:A2JxCwJuoMRiBF8ZjpxRf+JO5cTSYw8Vc2iHImfHoKg= @@ -764,8 +764,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY= +github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=