Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(client): allow overwritting client.toml #17513

Merged
merged 20 commits into from
Aug 29, 2023
Merged
64 changes: 44 additions & 20 deletions client/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"github.com/cosmos/cosmos-sdk/client"
)

func DefaultConfig() *ClientConfig {
return &ClientConfig{
func DefaultConfig() *Config {
return &Config{
ChainID: "",
KeyringBackend: "os",
Output: "text",
Expand All @@ -18,60 +18,84 @@
}
}

type ClientConfig struct {
type Config struct {
ChainID string `mapstructure:"chain-id" json:"chain-id"`
KeyringBackend string `mapstructure:"keyring-backend" json:"keyring-backend"`
Output string `mapstructure:"output" json:"output"`
Node string `mapstructure:"node" json:"node"`
BroadcastMode string `mapstructure:"broadcast-mode" json:"broadcast-mode"`
}

func (c *ClientConfig) SetChainID(chainID string) {
func (c *Config) SetChainID(chainID string) {
c.ChainID = chainID
}

func (c *ClientConfig) SetKeyringBackend(keyringBackend string) {
func (c *Config) SetKeyringBackend(keyringBackend string) {
c.KeyringBackend = keyringBackend
}

func (c *ClientConfig) SetOutput(output string) {
func (c *Config) SetOutput(output string) {
c.Output = output
}

func (c *ClientConfig) SetNode(node string) {
func (c *Config) SetNode(node string) {
c.Node = node
}

func (c *ClientConfig) SetBroadcastMode(broadcastMode string) {
func (c *Config) SetBroadcastMode(broadcastMode string) {
c.BroadcastMode = broadcastMode
}

// ReadFromClientConfig reads values from client.toml file and updates them in client Context
func ReadFromClientConfig(ctx client.Context) (client.Context, error) {
func ReadFromClientConfig(ctx client.Context, customClientTemplate string, customConfig interface{}) (client.Context, error) {
configPath := filepath.Join(ctx.HomeDir, "config")
configFilePath := filepath.Join(configPath, "client.toml")
conf := DefaultConfig()

// when config.toml does not exist create and init with default values
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
if err := os.MkdirAll(configPath, os.ModePerm); err != nil {
return ctx, fmt.Errorf("couldn't make client config: %w", err)
}

if ctx.ChainID != "" {
conf.ChainID = ctx.ChainID // chain-id will be written to the client.toml while initiating the chain.
}
if customClientTemplate != "" {
setConfigTemplate(customClientTemplate)
Fixed Show fixed Hide fixed

if err = ctx.Viper.Unmarshal(&customConfig); err != nil {
return ctx, fmt.Errorf("failed to parse custom client config: %w", err)
}

if ctx.ChainID != "" {
if cfg, ok := customConfig.(interface{ SetChainID(string) }); ok {
cfg.SetChainID(ctx.ChainID)
}
}

if err := writeConfigFile(configFilePath, customConfig); err != nil {
return ctx, fmt.Errorf("could not write client config to the file: %w", err)
}

if err := writeConfigToFile(configFilePath, conf); err != nil {
return ctx, fmt.Errorf("could not write client config to the file: %w", err)
} else {
config, err := parseConfig(ctx.Viper)
if err != nil {
return ctx, fmt.Errorf("couldn't parse config: %w", err)
}

if ctx.ChainID != "" {
config.ChainID = ctx.ChainID // chain-id will be written to the client.toml while initiating the chain.
}

if err := writeConfigFile(configFilePath, config); err != nil {
return ctx, fmt.Errorf("could not write client config to the file: %w", err)
}
}
}

conf, err := getClientConfig(configPath, ctx.Viper)
if err != nil {
return ctx, fmt.Errorf("couldn't get client config: %w", err)
}
// we need to update KeyringDir field on Client Context first cause it is used in NewKeyringFromBackend

// we need to update KeyringDir field on client.Context first cause it is used in NewKeyringFromBackend
ctx = ctx.WithOutputFormat(conf.Output).
WithChainID(conf.ChainID).
WithKeyringDir(ctx.HomeDir)
Expand All @@ -81,17 +105,17 @@
return ctx, fmt.Errorf("couldn't get keyring: %w", err)
}

ctx = ctx.WithKeyring(keyring)

// https://github.com/cosmos/cosmos-sdk/issues/8986
client, err := client.NewClientFromNode(conf.Node)
if err != nil {
return ctx, fmt.Errorf("couldn't get client from nodeURI: %w", err)
}

ctx = ctx.WithNodeURI(conf.Node).
ctx = ctx.
WithNodeURI(conf.Node).
WithBroadcastMode(conf.BroadcastMode).
WithClient(client).
WithBroadcastMode(conf.BroadcastMode)
WithKeyring(keyring)

return ctx, nil
}
2 changes: 1 addition & 1 deletion client/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func initClientContext(t *testing.T, envVar string) (client.Context, func()) {
require.NoError(t, os.Setenv(nodeEnv, envVar))
}

clientCtx, err := config.ReadFromClientConfig(clientCtx)
clientCtx, err := config.ReadFromClientConfig(clientCtx, "", nil)
require.NoError(t, err)
require.Equal(t, clientCtx.ChainID, chainID)

Expand Down
43 changes: 34 additions & 9 deletions client/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
"github.com/spf13/viper"
)

const defaultConfigTemplate = `# This is a TOML config file.
const DefaultClientConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

###############################################################################
### Client Configuration ###
### Client Configuration ###
###############################################################################

# The network chain ID
Expand All @@ -27,17 +27,42 @@ node = "{{ .Node }}"
broadcast-mode = "{{ .BroadcastMode }}"
`

// writeConfigToFile parses defaultConfigTemplate, renders config using the template and writes it to
// configFilePath.
func writeConfigToFile(configFilePath string, config *ClientConfig) error {
var buffer bytes.Buffer
var configTemplate *template.Template

func init() {
var err error

tmpl := template.New("clientConfigFileTemplate")
if configTemplate, err = tmpl.Parse(DefaultClientConfigTemplate); err != nil {
panic(err)
}
}

// parseConfig retrieves the default environment configuration for the client.
func parseConfig(v *viper.Viper) (*Config, error) {
conf := DefaultConfig()
err := v.Unmarshal(conf)

return conf, err
}

// setConfigTemplate sets the custom app config template for
// the application
func setConfigTemplate(customTemplate string) error {
tmpl := template.New("clientConfigFileTemplate")
configTemplate, err := tmpl.Parse(defaultConfigTemplate)
if err != nil {

var err error
if configTemplate, err = tmpl.Parse(customTemplate); err != nil {
return err
}

return nil
}

// writeConfigFile renders config using the template and writes it to
// configFilePath.
func writeConfigFile(configFilePath string, config interface{}) error {
var buffer bytes.Buffer
if err := configTemplate.Execute(&buffer, config); err != nil {
return err
}
Expand All @@ -46,7 +71,7 @@ func writeConfigToFile(configFilePath string, config *ClientConfig) error {
}

// getClientConfig reads values from client.toml file and unmarshalls them into ClientConfig
func getClientConfig(configPath string, v *viper.Viper) (*ClientConfig, error) {
func getClientConfig(configPath string, v *viper.Viper) (*Config, error) {
v.AddConfigPath(configPath)
v.SetConfigName("client")
v.SetConfigType("toml")
Expand Down
13 changes: 8 additions & 5 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,6 @@ func init() {
var err error

tmpl := template.New("appConfigFileTemplate")

if configTemplate, err = tmpl.Parse(DefaultConfigTemplate); err != nil {
panic(err)
}
Expand All @@ -260,26 +259,30 @@ func ParseConfig(v *viper.Viper) (*Config, error) {

// SetConfigTemplate sets the custom app config template for
// the application
func SetConfigTemplate(customTemplate string) {
func SetConfigTemplate(customTemplate string) error {
var err error

tmpl := template.New("appConfigFileTemplate")

if configTemplate, err = tmpl.Parse(customTemplate); err != nil {
panic(err)
return err
}

return nil
}

// WriteConfigFile renders config using the template and writes it to
// configFilePath.
func WriteConfigFile(configFilePath string, config interface{}) {
func WriteConfigFile(configFilePath string, config interface{}) error {
var buffer bytes.Buffer

if err := configTemplate.Execute(&buffer, config); err != nil {
panic(err)
return err
}

mustWriteFile(configFilePath, buffer.Bytes(), 0o644)

return nil
}

func mustWriteFile(filePath string, contents []byte, mode os.FileMode) {
Expand Down
40 changes: 40 additions & 0 deletions simapp/simd/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
confixcmd "cosmossdk.io/tools/confix/cmd"

"github.com/cosmos/cosmos-sdk/client"
clientconfig "github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/debug"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/keys"
Expand Down Expand Up @@ -46,6 +47,45 @@ func initCometBFTConfig() *cmtcfg.Config {
return cfg
}

// initAppConfig helps to override default client config template and configs.
// return "", nil if no custom configuration is required for the application.
func initClientConfig() (string, interface{}) {
type GasConfig struct {
GasAdjustment float64 `mapstructure:"gas_adjustment"`
}

type CustomClientConfig struct {
clientconfig.Config `mapstructure:",squash"`

GasConfig GasConfig `mapstructure:"gas"`
}

// Optionally allow the chain developer to overwrite the SDK's default client config.
clientCfg := clientconfig.DefaultConfig()
// The SDK's default keyring backend is set to "os".
// This is more secure than "test" and is the recommended value.
//
// In simapp, we set the default keyring backend to test, as SimApp is meant
// to be an example and testing application.
clientCfg.KeyringBackend = "test"

customClientConfig := CustomClientConfig{
Config: *clientCfg,
GasConfig: GasConfig{
GasAdjustment: 1.5,
},
}

customClientConfigTemplate := clientconfig.DefaultClientConfigTemplate + `
[gas]
# This is the gas adjustment factor used by the tx commands.
# It defaults to 1 and can be overridden by the --gas-adjustment flag or here.
gas-adjustment = 0
`

return customClientConfigTemplate, customClientConfig
}

// initAppConfig helps to override default appConfig template and configs.
// return "", nil if no custom configuration is required for the application.
func initAppConfig() (string, interface{}) {
Expand Down
8 changes: 5 additions & 3 deletions simapp/simd/cmd/root_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ func NewRootCmd() *cobra.Command {
return err
}

initClientCtx, err = config.ReadFromClientConfig(initClientCtx)
customClientTemplate, customClientConfig := initClientConfig()
initClientCtx, err = config.ReadFromClientConfig(initClientCtx, customClientTemplate, customClientConfig)
if err != nil {
return err
}
Expand Down Expand Up @@ -135,8 +136,9 @@ func ProvideClientContext(
WithHomeDir(simapp.DefaultNodeHome).
WithViper("") // In simapp, we don't use any prefix for env variables.

// Read the config again to overwrite the default values with the values from the config file
initClientCtx, _ = config.ReadFromClientConfig(initClientCtx)
// Read the config to overwrite the default values with the values from the config file
customClientTemplate, customClientConfig := initClientConfig()
initClientCtx, _ = config.ReadFromClientConfig(initClientCtx, customClientTemplate, customClientConfig)

return initClientCtx
}
Expand Down
2 changes: 1 addition & 1 deletion tools/confix/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func CheckValid(fileName string, data []byte) error {
return fmt.Errorf("server config invalid: %w", err)
}
case strings.HasSuffix(fileName, ClientConfig):
var cfg clientcfg.ClientConfig
var cfg clientcfg.Config
if err := v.Unmarshal(&cfg); err != nil {
return fmt.Errorf("failed to unmarshal as client config: %w", err)
}
Expand Down
Loading