feat: create config fix tool (#14342)

This commit is contained in:
Julien Robert 2023-01-10 11:28:41 +01:00 committed by GitHub
parent edae9b99ab
commit 9742029158
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 3363 additions and 173 deletions

2
.github/labeler.yml vendored
View File

@ -44,6 +44,8 @@
"C:Rosetta":
- contrib/rosetta/**/*
- tools/rosetta/**/*
"C:Confix":
- tools/confix/**/*
"C:Keys":
- client/keys/**/*
"Type: Build":

View File

@ -35,15 +35,24 @@ jobs:
**/go.sum
**/Makefile
Makefile
###################
#### Build App ####
###################
- name: Build
if: env.GIT_DIFF
run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false make build
- name: Build Legacy
if: env.GIT_DIFF
run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false COSMOS_BUILD_OPTIONS=legacy make build
###################
## Build Tooling ##
###################
- name: Build Cosmovisor
if: env.GIT_DIFF
run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false make cosmovisor
- name: Build Rosetta
if: env.GIT_DIFF
run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false make rosetta
- name: Build Confix
if: env.GIT_DIFF
run: GOARCH=${{ matrix.go-arch }} LEDGER_ENABLED=false make confix

38
.github/workflows/release-confix.yml vendored Normal file
View File

@ -0,0 +1,38 @@
name: Release Confix
on:
push:
tags:
- "tools/confix/v*.*.*"
permissions:
contents: read
jobs:
goreleaser:
permissions:
contents: write # for goreleaser/goreleaser-action to create a GitHub release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: 1.19.4
# get 'v*.*.*' part from 'confix/v*.*.*' and save to $GITHUB_ENV
- name: Set env
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/confix/}" >> $GITHUB_ENV
# remove the possible pre-existing same tag for cosmos-sdk related tags instead of confix tags
# Because goreleaser enforces semantic versioning and will error on non compliant tags.(https://goreleaser.com/limitations/semver/)
- name: Tag without prefix locally to avoid error in goreleaser
run: |-
git tag -d ${{ env.RELEASE_VERSION }} || echo "No such a tag exists before"
git tag ${{ env.RELEASE_VERSION }} HEAD
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v3
with:
# stick to version v0.179.0(https://github.com/cosmos/cosmos-sdk/issues/11125)
version: v0.179.0
args: release --rm-dist --skip-validate --release-notes ./RELEASE_NOTES.md
workdir: tools/confix
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_CURRENT_TAG: confix/${{ env.RELEASE_VERSION }}

View File

@ -581,3 +581,33 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN_X_NFT }}
with:
projectBaseDir: x/nft/
test-confix:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: 1.19.4
cache: true
cache-dependency-path: tools/confix/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
tools/confix/**/*.go
tools/confix/go.mod
tools/confix/go.sum
- name: tests
if: env.GIT_DIFF
run: |
cd tools/confix
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock rocksdb_build' ./...
- name: sonarcloud
if: env.GIT_DIFF
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN_CONFIX }}
with:
projectBaseDir: tools/confix/

View File

@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
* (client) [#14342](https://github.com/cosmos/cosmos-sdk/pull/14342) Add `simd config` command is now a sub-command, for setting, getting and migrating Cosmos SDK configuration files.
* (query) [#14468](https://github.com/cosmos/cosmos-sdk/pull/14468) Implement pagination for collections.
* (x/bank) [#14045](https://github.com/cosmos/cosmos-sdk/pull/14045) Add CLI command `spendable-balances`, which also accepts the flag `--denom`.
* (x/slashing, x/staking) [#14363](https://github.com/cosmos/cosmos-sdk/pull/14363) Add the infraction a validator commited type as an argument to a `SlashWithInfractionReason` keeper method.
@ -117,10 +118,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#13881](https://github.com/cosmos/cosmos-sdk/pull/13881) Optimize iteration on nested cached KV stores and other operations in general.
* (x/gov) [#14347](https://github.com/cosmos/cosmos-sdk/pull/14347) Support `v1.Proposal` message in `v1beta1.Proposal.Content`.
* (x/gov) [#14390](https://github.com/cosmos/cosmos-sdk/pull/14390) Add title, proposer and summary to proposal struct
* (baseapp) [#14417](https://github.com/cosmos/cosmos-sdk/pull/14417) `SetStreamingService` accepts appOptions, AppCodec and Storekeys needed to set streamers.
* Store pacakge no longer has a dependency on baseapp.
* (store) [#14438](https://github.com/cosmos/cosmos-sdk/pull/14438) Pass logger from baseapp to store.
* (store) [#14439](https://github.com/cosmos/cosmos-sdk/pull/14439) Remove global metric gatherer from store.
* (baseapp) [#14417](https://github.com/cosmos/cosmos-sdk/pull/14417) `SetStreamingService` accepts appOptions, AppCodec and Storekeys needed to set streamers.
* Store pacakge no longer has a dependency on baseapp.
* (store) [#14438](https://github.com/cosmos/cosmos-sdk/pull/14438) Pass logger from baseapp to store.
* (store) [#14439](https://github.com/cosmos/cosmos-sdk/pull/14439) Remove global metric gatherer from store.
* By default store has a no op metric gatherer, the application developer must set another metric gatherer or us the provided one in `store/metrics`.
### State Machine Breaking
@ -212,6 +213,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf
### CLI Breaking Changes
* (client) [#14342](https://github.com/cosmos/cosmos-sdk/pull/14342) `simd config` command is now a sub-command. Use `simd config --help` to learn more.
* (x/genutil) [#13535](https://github.com/cosmos/cosmos-sdk/pull/13535) Replace in `simd init`, the `--staking-bond-denom` flag with `--default-denom` which is used for all default denomination in the genesis, instead of only staking.
* (tx) [#12659](https://github.com/cosmos/cosmos-sdk/pull/12659) Remove broadcast mode `block`.
* (genesis) [#14149](https://github.com/cosmos/cosmos-sdk/pull/14149) Add `simd genesis` command, which contains all genesis-related sub-commands.

View File

@ -140,7 +140,10 @@ cosmovisor:
rosetta:
$(MAKE) -C tools/rosetta rosetta
.PHONY: build build-linux-amd64 build-linux-arm64 cosmovisor rosetta
confix:
$(MAKE) -C tools/confix confix
.PHONY: build build-linux-amd64 build-linux-arm64 cosmovisor rosetta confix
mocks: $(MOCKS_DIR)

View File

@ -1,97 +0,0 @@
package config
import (
"encoding/json"
"fmt"
"path/filepath"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
)
// Cmd returns a CLI command to interactively create an application CLI
// config file.
func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "config <key> [value]",
Short: "Create or query an application CLI configuration file",
RunE: runConfigCmd,
Args: cobra.RangeArgs(0, 2),
}
return cmd
}
func runConfigCmd(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
configPath := filepath.Join(clientCtx.HomeDir, "config")
conf, err := getClientConfig(configPath, clientCtx.Viper)
if err != nil {
return fmt.Errorf("couldn't get client config: %v", err)
}
switch len(args) {
case 0:
// print all client config fields to stdout
s, err := json.MarshalIndent(conf, "", "\t")
if err != nil {
return err
}
cmd.Println(string(s))
case 1:
// it's a get
key := args[0]
switch key {
case flags.FlagChainID:
cmd.Println(conf.ChainID)
case flags.FlagKeyringBackend:
cmd.Println(conf.KeyringBackend)
case flags.FlagOutput:
cmd.Println(conf.Output)
case flags.FlagNode:
cmd.Println(conf.Node)
case flags.FlagBroadcastMode:
cmd.Println(conf.BroadcastMode)
default:
err := errUnknownConfigKey(key)
return fmt.Errorf("couldn't get the value for the key: %v, error: %v", key, err)
}
case 2:
// it's set
key, value := args[0], args[1]
switch key {
case flags.FlagChainID:
conf.SetChainID(value)
case flags.FlagKeyringBackend:
conf.SetKeyringBackend(value)
case flags.FlagOutput:
conf.SetOutput(value)
case flags.FlagNode:
conf.SetNode(value)
case flags.FlagBroadcastMode:
conf.SetBroadcastMode(value)
default:
return errUnknownConfigKey(key)
}
confFile := filepath.Join(configPath, "client.toml")
if err := writeConfigToFile(confFile, conf); err != nil {
return fmt.Errorf("could not write client config to the file: %v", err)
}
default:
panic("cound not execute config command")
}
return nil
}
func errUnknownConfigKey(key string) error {
return fmt.Errorf("unknown configuration key: %q", key)
}

View File

@ -8,14 +8,15 @@ import (
"github.com/cosmos/cosmos-sdk/client"
)
// Default constants
const (
chainID = ""
keyringBackend = "os"
output = "text"
node = "tcp://localhost:26657"
broadcastMode = "sync"
)
func DefaultConfig() *ClientConfig {
return &ClientConfig{
ChainID: "",
KeyringBackend: "os",
Output: "text",
Node: "tcp://localhost:26657",
BroadcastMode: "sync",
}
}
type ClientConfig struct {
ChainID string `mapstructure:"chain-id" json:"chain-id"`
@ -25,11 +26,6 @@ type ClientConfig struct {
BroadcastMode string `mapstructure:"broadcast-mode" json:"broadcast-mode"`
}
// defaultClientConfig returns the reference to ClientConfig with default values.
func defaultClientConfig() *ClientConfig {
return &ClientConfig{chainID, keyringBackend, output, node, broadcastMode}
}
func (c *ClientConfig) SetChainID(chainID string) {
c.ChainID = chainID
}
@ -54,11 +50,11 @@ func (c *ClientConfig) SetBroadcastMode(broadcastMode string) {
func ReadFromClientConfig(ctx client.Context) (client.Context, error) {
configPath := filepath.Join(ctx.HomeDir, "config")
configFilePath := filepath.Join(configPath, "client.toml")
conf := defaultClientConfig()
conf := DefaultConfig()
// if config.toml file does not exist we create it and write default ClientConfig values into it.
// when config.toml does not exist create and init with default values
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
if err := ensureConfigPath(configPath); err != nil {
if err := os.MkdirAll(configPath, os.ModePerm); err != nil {
return ctx, fmt.Errorf("couldn't make client config: %v", err)
}

View File

@ -1,9 +1,7 @@
package config_test
import (
"bytes"
"fmt"
"io"
"os"
"testing"
@ -13,7 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
"github.com/spf13/cobra"
"github.com/stretchr/testify/require"
)
@ -45,68 +43,52 @@ func initClientContext(t *testing.T, envVar string) (client.Context, func()) {
return clientCtx, func() { _ = os.RemoveAll(home) }
}
func TestConfigCmd(t *testing.T) {
clientCtx, cleanup := initClientContext(t, testNode1)
defer func() {
_ = os.Unsetenv(nodeEnv)
cleanup()
}()
// NODE=http://localhost:1 ./build/simd config node http://localhost:2
cmd := config.Cmd()
args := []string{"node", testNode2}
_, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, args)
require.NoError(t, err)
// ./build/simd config node //http://localhost:1
b := bytes.NewBufferString("")
cmd.SetOut(b)
cmd.SetArgs([]string{"node"})
require.NoError(t, cmd.Execute())
out, err := io.ReadAll(b)
require.NoError(t, err)
require.Equal(t, string(out), testNode1+"\n")
}
func TestConfigCmdEnvFlag(t *testing.T) {
const (
defaultNode = "http://localhost:26657"
)
tt := []struct {
name string
envVar string
args []string
expNode string
}{
{"env var is set with no flag", testNode1, []string{"validators"}, testNode1},
{"env var is set with a flag", testNode1, []string{"validators", fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2},
{"env var is not set with no flag", "", []string{"validators"}, defaultNode},
{"env var is not set with a flag", "", []string{"validators", fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2},
{"env var is set with no flag", testNode1, []string{}, testNode1},
{"env var is set with a flag", testNode1, []string{fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2},
{"env var is not set with no flag", "", []string{}, "tcp://localhost:26657"},
{"env var is not set with a flag", "", []string{fmt.Sprintf("--%s=%s", flags.FlagNode, testNode2)}, testNode2},
}
for _, tc := range tt {
tc := tc
t.Run(tc.name, func(t *testing.T) {
testCmd := &cobra.Command{
Use: "test",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
return fmt.Errorf("%s", clientCtx.NodeURI)
},
}
flags.AddQueryFlagsToCmd(testCmd)
clientCtx, cleanup := initClientContext(t, tc.envVar)
defer func() {
if tc.envVar != "" {
_ = os.Unsetenv(nodeEnv)
}
cleanup()
_ = os.Unsetenv(nodeEnv)
}()
/*
env var is set with a flag
NODE=http://localhost:1 ./build/simd q staking validators --node http://localhost:2
Error: post failed: Post "http://localhost:2": dial tcp 127.0.0.1:2: connect: connection refused
NODE=http://localhost:1 test-cmd --node http://localhost:2
Prints "http://localhost:2"
We dial http://localhost:2 cause a flag has the higher priority than env variable.
It prints http://localhost:2 cause a flag has the higher priority than env variable.
*/
cmd := cli.GetQueryCmd()
_, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
_, err := clitestutil.ExecTestCLICmd(clientCtx, testCmd, tc.args)
require.Error(t, err)
require.Contains(t, err.Error(), tc.expNode, "Output does not contain expected Node")
require.Contains(t, err.Error(), tc.expNode)
})
}
}

View File

@ -45,11 +45,6 @@ func writeConfigToFile(configFilePath string, config *ClientConfig) error {
return os.WriteFile(configFilePath, buffer.Bytes(), 0o600)
}
// ensureConfigPath creates a directory configPath if it does not exist
func ensureConfigPath(configPath string) error {
return os.MkdirAll(configPath, os.ModePerm)
}
// getClientConfig reads values from client.toml file and unmarshalls them into ClientConfig
func getClientConfig(configPath string, v *viper.Viper) (*ClientConfig, error) {
v.AddConfigPath(configPath)
@ -60,7 +55,7 @@ func getClientConfig(configPath string, v *viper.Viper) (*ClientConfig, error) {
return nil, err
}
conf := new(ClientConfig)
conf := DefaultConfig()
if err := v.Unmarshal(conf); err != nil {
return nil, err
}

1
docs/.gitignore vendored
View File

@ -15,6 +15,7 @@ docs/docs/spec
docs/docs/architecture
docs/docs/tooling/01-cosmovisor.md
docs/docs/tooling/02-depinject.md
docs/docs/tooling/03-confix.md
docs/run-node/04-rosetta.md
# Misc

View File

@ -9,3 +9,4 @@ This section provides documentation on various tooling used in development of a
* [Protocol Buffers](./00-protobuf.md)
* [Cosmovisor](./01-cosmovisor.md)
* [Depinject](./02-depinject.md)
* [Confix](./03-confix.md)

View File

@ -3,6 +3,7 @@
find docs/modules ! -name '_category_.json' -type f -exec rm -rf {} +
rm -rf docs/tooling/01-cosmovisor.md
rm -rf docs/tooling/02-depinject.md
rm -rf docs/tooling/03-confix.md
rm -rf docs/run-node/04-rosetta.md
rm -rf docs/architecture
rm -rf docs/spec

View File

@ -17,10 +17,9 @@ cp ../x/auth/tx/README.md ./docs/modules/auth/2-tx.md
## Add modules page list
cat ../x/README.md | sed 's/\.\.\/docs\/building-modules\/README\.md/\/building-modules\/intro\.html/g' > ./docs/modules/README.md
## Add cosmovisor documentation
## Add tooling documentation
cp ../tools/cosmovisor/README.md ./docs/tooling/01-cosmovisor.md
## Add depinject documentation
cp ../tools/confix/README.md ./docs/tooling/03-confix.md
cp ../depinject/README.md ./docs/tooling/02-depinject.md
## Add rosetta documentation

View File

@ -15,5 +15,6 @@ use (
./tests
./tools/rosetta
./tools/cosmovisor
./tools/confix
./x/nft
)

View File

@ -8,10 +8,11 @@ require (
cosmossdk.io/core v0.4.0
cosmossdk.io/depinject v1.0.0-alpha.3
cosmossdk.io/math v1.0.0-beta.4
cosmossdk.io/tools/confix v0.0.0-00010101000000-000000000000
cosmossdk.io/tools/rosetta v0.2.0
github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32
// this version is not used as it is always replaced by the latest cosmos-sdk version
github.com/cosmos/cosmos-sdk v0.47.0-alpha2.0.20221219231612-5ed4075ba219
github.com/cosmos/cosmos-sdk v0.47.0-rc1
github.com/cosmos/cosmos-sdk/x/nft v0.1.0-alpha1
github.com/golang/mock v1.6.0
github.com/spf13/cast v1.5.0
@ -62,7 +63,9 @@ require (
github.com/cosmos/iavl v0.20.0-alpha1 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect
github.com/cosmos/rosetta-sdk-go v0.9.0 // indirect
github.com/creachadair/atomicfile v0.2.7 // indirect
github.com/creachadair/taskgroup v0.3.2 // indirect
github.com/creachadair/tomledit v0.0.24 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
@ -181,6 +184,8 @@ require (
)
replace (
// todo remove at pseudo version of confix
cosmossdk.io/tools/confix => ../tools/confix
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// Simapp always use the latest version of the cosmos-sdk
github.com/cosmos/cosmos-sdk => ../.

View File

@ -218,8 +218,12 @@ github.com/cosmos/rosetta-sdk-go v0.9.0/go.mod h1:2v41yXL25xxAXrczVSnbDHcQH9Cgil
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creachadair/atomicfile v0.2.7 h1:LiL/QmAUO7ZDsjSJ6xj3PlsXaYXYKMS8g/Po5S9IIk4=
github.com/creachadair/atomicfile v0.2.7/go.mod h1:BRq8Une6ckFneYXZQ+kO7p1ZZP3I2fzVzf28JxrIkBc=
github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM=
github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk=
github.com/creachadair/tomledit v0.0.24 h1:5Xjr25R2esu1rKCbQEmjZYlrhFkDspoAbAKb6QKQDhQ=
github.com/creachadair/tomledit v0.0.24/go.mod h1:9qHbShRWQzSCcn617cMzg4eab1vbLCOjOshAWSzWr8U=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0=

View File

@ -15,6 +15,7 @@ import (
"cosmossdk.io/simapp"
"cosmossdk.io/simapp/params"
confixcmd "cosmossdk.io/tools/confix/cmd"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
@ -174,7 +175,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome),
NewTestnetCmd(simapp.ModuleBasics, banktypes.GenesisBalancesIterator{}),
debug.Cmd(),
config.Cmd(),
confixcmd.ConfigCommand(),
pruning.Cmd(newApp),
)

View File

@ -9,7 +9,7 @@ require (
cosmossdk.io/simapp v0.0.0-00010101000000-000000000000
github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32
// this version is not used as it is always replaced by the latest cosmos-sdk version
github.com/cosmos/cosmos-sdk v0.47.0-alpha2.0.20221219231612-5ed4075ba219
github.com/cosmos/cosmos-sdk v0.47.0-rc1
github.com/cosmos/cosmos-sdk/x/nft v0.1.0-alpha1
github.com/cosmos/gogoproto v1.4.3
github.com/golang/mock v1.6.0

2
tools/confix/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/confix
/condiff

View File

@ -0,0 +1,34 @@
project_name: confix
release:
disable: false
name_template: "{{.Tag}}"
before:
hooks:
- go mod tidy
builds:
- main: ./cmd/confix
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
env:
- CGO_ENABLED=0
archives:
- name_template: '{{ replace .Version "confix/" "confix-" }}-{{ .Os }}-{{ .Arch }}'
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'SHA256SUMS-{{ replace .Version "confix/" "confix-" }}.txt'
algorithm: sha256
changelog:
skip: false

34
tools/confix/CHANGELOG.md Normal file
View File

@ -0,0 +1,34 @@
<!--
Guiding Principles:
Changelogs are for humans, not machines.
There should be an entry for every single version.
The same types of changes should be grouped.
Versions and sections should be linkable.
The latest version comes first.
The release date of each version is displayed.
Mention whether you follow Semantic Versioning.
Usage:
Change log entries are to be added to the Unreleased section under the
appropriate stanza (see below). Each entry should ideally include a tag and
the Github issue reference in the following format:
* (<tag>) [#<issue-number>] Changelog message.
Types of changes (Stanzas):
"Features" for new features.
"Improvements" for changes in existing functionality.
"Deprecated" for soon-to-be removed features.
"Bug Fixes" for any bug fixes.
"API Breaking" for breaking exported APIs used by developers building on SDK.
Ref: https://keepachangelog.com/en/1.0.0/
-->
# Changelog
## [Unreleased]
* [#14342](https://github.com/cosmos/cosmos-sdk/pull/14342) Add `confix` tool to manage configuration files.

14
tools/confix/Makefile Normal file
View File

@ -0,0 +1,14 @@
#!/usr/bin/make -f
all: confix condiff test
confix:
go build -mod=readonly ./cmd/confix
condiff:
go build -mod=readonly ./cmd/condiff
test:
go test -mod=readonly -race ./...
.PHONY: all confix condiff test

74
tools/confix/README.md Normal file
View File

@ -0,0 +1,74 @@
---
sidebar_position: 1
---
# Confix
`Confix` is a configuration management tool that allows you to manage your configuration via CLI.
It is based on the [Tendermint RFC 019](https://github.com/tendermint/tendermint/blob/5013bc3f4a6d64dcc2bf02ccc002ebc9881c62e4/docs/rfc/rfc-019-config-version.md).
## Installation
## Usage
Use standalone:
```shell
confix --help
```
Use in simd:
```shell
simd config fix --help
```
### Get
Get a configuration value, e.g.:
```shell
simd config get app pruning # gets the value pruning from app.toml
simd config get client chain-id # gets the value chain-id from client.toml
```
```shell
confix get ~/.simapp/config/app.toml pruning # gets the value pruning from app.toml
confix get ~/.simapp/config/client.toml chain-id # gets the value chain-id from client.toml
```
### Set
Set a configuration value, e.g.:
```shell
simd config set app pruning "enabled" # sets the value pruning from app.toml
simd config set client chain-id "foo-1" # sets the value chain-id from client.toml
```
```shell
confix set ~/.simapp/config/app.toml pruning "enabled" # sets the value pruning from app.toml
confix set ~/.simapp/config/client.toml chain-id "foo-1" # sets the value chain-id from client.toml
```
### Migrate
Migrate a configuration file to a new version, e.g.:
```shell
simd config migrate v0.47 # migrates defaultHome/config/app.toml to the latest v0.47 config
```
```shell
confix migrate v0.47 ~/.simapp/config/app.toml # migrate ~/.simapp/config/app.toml to the latest v0.47 config
```
### Maintainer
At each SDK modification of the default configuration, add the default SDK config under `data/v0.XX-app.toml`.
This allows users to use the tool standalone.
## Credits
This project is based on the [Tendermint RFC 019](https://github.com/tendermint/tendermint/blob/5013bc3f4a6d64dcc2bf02ccc002ebc9881c62e4/docs/rfc/rfc-019-config-version.md) and their own implementation of [confix](https://github.com/tendermint/tendermint/blob/v0.36.x/scripts/confix/confix.go).

View File

@ -0,0 +1,43 @@
package main
import (
"os"
"cosmossdk.io/tools/confix"
"github.com/spf13/cobra"
)
func main() {
cmd := &cobra.Command{
Use: "condiff f1 f2",
Short: "Diff the keyspaces of the TOML documents in files f1 and f2",
Long: `Diff the keyspaces of the TOML documents in files f1 and f2.
The output prints one line per key that differs:
-S name -- section exists in f1 but not f2
+S name -- section exists in f2 but not f1
-M name -- mapping exists in f1 but not f2
+M name -- mapping exists in f2 but not f1
Comments, order, and values are ignored for comparison purposes.`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
lhs, err := confix.LoadConfig(args[0])
if err != nil {
return err
}
rhs, err := confix.LoadConfig(args[1])
if err != nil {
return err
}
confix.PrintDiff(cmd.OutOrStdout(), confix.DiffKeys(lhs, rhs))
return nil
},
}
if err := cmd.Execute(); err != nil {
os.Exit(1)
}
}

View File

@ -0,0 +1,23 @@
package cmd
import (
"github.com/spf13/cobra"
)
// ConfigComamnd contains all the confix commands
// These command can be used to interactively update an application config value.
func ConfigCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "Utilities for managing application configuration",
}
cmd.AddCommand(
MigrateCommand(),
DiffCommand(),
GetCommand(),
SetCommand(),
)
return cmd
}

View File

@ -0,0 +1,13 @@
package main
import (
"os"
confixcmd "cosmossdk.io/tools/confix/cmd"
)
func main() {
if err := confixcmd.ConfigCommand().Execute(); err != nil {
os.Exit(1)
}
}

17
tools/confix/cmd/diff.go Normal file
View File

@ -0,0 +1,17 @@
package cmd
import (
"github.com/spf13/cobra"
)
func DiffCommand() *cobra.Command {
return &cobra.Command{
Use: "diff [config]",
Short: "Display the diff between the current config and the SDK default config",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
// TODO to implement in the next PR
return nil
},
}
}

View File

@ -0,0 +1,73 @@
package cmd
import (
"context"
"fmt"
"cosmossdk.io/tools/confix"
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
"golang.org/x/exp/maps"
)
var (
FlagStdOut bool
FlagVerbose bool
FlagSkipValidate bool
)
func MigrateCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "migrate [target-version] <app-toml-path> (options)",
Short: "Migrate Cosmos SDK app configuration file to the specified version",
Long: `Migrate the contents of the Cosmos SDK app configuration (app.toml) to the specified version.
The output is written in-place unless --stdout is provided.
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 filename string
targetVersion := args[0]
clientCtx := client.GetClientContextFromCmd(cmd)
if len(args) > 1 {
filename = args[1]
} else if clientCtx.HomeDir != "" {
filename = fmt.Sprintf("%s/config/app.toml", clientCtx.HomeDir)
} else {
return fmt.Errorf("must provide a path to the app.toml file")
}
plan, ok := confix.Migrations[targetVersion]
if !ok {
return fmt.Errorf("unknown version %q, supported versions are: %q", targetVersion, maps.Keys(confix.Migrations))
}
rawFile, err := confix.LoadConfig(filename)
if err != nil {
return fmt.Errorf("failed to load config: %v", err)
}
ctx := context.Background()
if FlagVerbose {
ctx = confix.WithLogWriter(ctx, cmd.ErrOrStderr())
}
outputPath := filename
if FlagStdOut {
outputPath = ""
}
if err := confix.Upgrade(ctx, plan(rawFile, targetVersion), filename, outputPath, FlagSkipValidate); err != nil {
return fmt.Errorf("failed to migrate config: %w", err)
}
return nil
},
}
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)")
return cmd
}

View File

@ -0,0 +1,36 @@
package cmd_test
import (
"fmt"
"strings"
"testing"
"cosmossdk.io/tools/confix/cmd"
"github.com/cosmos/cosmos-sdk/client"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"gotest.tools/v3/assert"
)
func TestMigradeCmd(t *testing.T) {
clientCtx, cleanup := initClientContext(t)
defer cleanup()
_, err := clitestutil.ExecTestCLICmd(client.Context{}, cmd.MigrateCommand(), []string{"v0.0"})
assert.ErrorContains(t, err, "must provide a path to the app.toml file")
_, 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"})
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", fmt.Sprintf("%s/config/client.toml", clientCtx.HomeDir)})
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", fmt.Sprintf("%s/config/client.toml", clientCtx.HomeDir), "--skip-validate", "--verbose"})
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "add app-db-backend key"))
}

119
tools/confix/cmd/mutate.go Normal file
View File

@ -0,0 +1,119 @@
package cmd
import (
"context"
"errors"
"fmt"
"strings"
"cosmossdk.io/tools/confix"
"github.com/creachadair/tomledit"
"github.com/creachadair/tomledit/parser"
"github.com/creachadair/tomledit/transform"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
)
// SetCommand returns a CLI command to interactively update an application config value.
func SetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "set [config] [key] [value]",
Short: "Set an application config value",
Long: "Set an application config value. The [config] argument must be the path of the file when using the too standalone, otherwise it must be the name of the config file without the .toml extension.",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
filename, inputValue := args[0], args[2]
// parse key e.g mempool.size -> [mempool, size]
key := strings.Split(args[1], ".")
clientCtx := client.GetClientContextFromCmd(cmd)
if clientCtx.HomeDir != "" {
filename = fmt.Sprintf("%s/config/%s.toml", clientCtx.HomeDir, filename)
}
plan := transform.Plan{
{
Desc: fmt.Sprintf("update %q=%q in %s", key, inputValue, filename),
T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
results := doc.Find(key...)
if len(results) == 0 {
return fmt.Errorf("key %q not found", key)
} else if len(results) > 1 {
return fmt.Errorf("key %q is ambiguous", key)
}
value, err := parser.ParseValue(inputValue)
if err != nil {
value = parser.MustValue(`"` + inputValue + `"`)
}
if ok := transform.InsertMapping(results[0].Section, &parser.KeyValue{
Block: results[0].Block,
Name: key,
Value: value,
}, true); !ok {
return errors.New("failed to set value")
}
return nil
}),
},
}
outputPath := filename
if FlagStdOut {
outputPath = ""
}
ctx := cmd.Context()
if FlagVerbose {
ctx = confix.WithLogWriter(ctx, cmd.ErrOrStderr())
}
return confix.Upgrade(ctx, plan, filename, outputPath, FlagSkipValidate)
},
}
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 mutate unknown configurations)")
return cmd
}
// GetCommand returns a CLI command to interactively get an application config value.
func GetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "get [config] [key]",
Short: "Get an application config value",
Long: "Get an application config value. The [config] argument must be the path of the file when using the too standalone, otherwise it must be the name of the config file without the .toml extension.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
filename, key := args[0], args[1]
// parse key e.g mempool.size -> [mempool, size]
keys := strings.Split(key, ".")
clientCtx := client.GetClientContextFromCmd(cmd)
if clientCtx.HomeDir != "" {
filename = fmt.Sprintf("%s/config/%s.toml", clientCtx.HomeDir, filename)
}
doc, err := confix.LoadConfig(filename)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
results := doc.Find(keys...)
if len(results) == 0 {
return fmt.Errorf("key %q not found", key)
} else if len(results) > 1 {
return fmt.Errorf("key %q is ambiguous", key)
}
return clientCtx.PrintString(fmt.Sprintf("%s\n", results[0].Value.String()))
},
}
return cmd
}

View File

@ -0,0 +1,63 @@
package cmd_test
import (
"fmt"
"os"
"strings"
"testing"
"cosmossdk.io/tools/confix/cmd"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"gotest.tools/v3/assert"
)
// initClientContext initiates client Context for tests
func initClientContext(t *testing.T) (client.Context, func()) {
home := t.TempDir()
chainId := "test-chain" //nolint:revive
clientCtx := client.Context{}.
WithHomeDir(home).
WithViper("").
WithChainID(chainId)
clientCtx, err := config.ReadFromClientConfig(clientCtx)
assert.NilError(t, err)
assert.Equal(t, clientCtx.ChainID, chainId)
return clientCtx, func() { _ = os.RemoveAll(home) }
}
func TestSetCmd(t *testing.T) {
clientCtx, cleanup := initClientContext(t)
defer cleanup()
_, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.SetCommand(), []string{"unexisting", "foo", "foo"})
assert.ErrorContains(t, err, "no such file or directory")
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.GetCommand(), []string{"client", "chain-id"})
assert.NilError(t, err)
assert.Equal(t, strings.TrimSpace(out.String()), `"test-chain"`)
newValue := "new-chain"
_, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.SetCommand(), []string{"client", "chain-id", newValue})
assert.NilError(t, err)
out, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.GetCommand(), []string{"client", "chain-id"})
assert.NilError(t, err)
assert.Equal(t, strings.TrimSpace(out.String()), fmt.Sprintf(`"%s"`, newValue))
}
func TestGetCmd(t *testing.T) {
clientCtx, cleanup := initClientContext(t)
defer cleanup()
out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd.GetCommand(), []string{"client", "chain-id"})
assert.NilError(t, err)
assert.Equal(t, strings.TrimSpace(out.String()), `"test-chain"`)
_, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.GetCommand(), []string{"client", "foo"})
assert.Error(t, err, `key "foo" not found`)
_, err = clitestutil.ExecTestCLICmd(clientCtx, cmd.GetCommand(), []string{"unexisting", "foo"})
assert.ErrorContains(t, err, "no such file or directory")
}

View File

@ -0,0 +1,230 @@
# 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"
# default: the last 100 states are kept in addition to every 500th state; pruning at 10 block intervals
# nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
# everything: all saved states will be deleted, storing only the current and previous state; pruning at 10 block intervals
# custom: allow pruning options to be manually specified through 'pruning-keep-recent', 'pruning-keep-every', and 'pruning-interval'
pruning = "default"
# These are applied if and only if the pruning strategy is custom.
pruning-keep-recent = "0"
pruning-keep-every = "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 Tendermint. 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 Tendermint blocks.
# It has no bearing on application state pruning which is determined by the
# "pruning-*" configurations.
#
# Note: Tendermint block pruning is dependant on this parameter in conunction
# 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 Tendermint 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.
# Default cache size is 50mb.
iavl-cache-size = 781250
# IAVLDisableFastNode enables or disables the fast node feature of IAVL.
# Default is true.
iavl-disable-fastnode = true
###############################################################################
### 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 = false
# Swagger defines if swagger documentation should automatically be registered.
swagger = false
# Address defines the API server to listen on.
address = "tcp://0.0.0.0:1317"
# MaxOpenConnections defines the number of maximum open connections.
max-open-connections = 1000
# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds).
rpc-read-timeout = 10
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds).
rpc-write-timeout = 0
# RPCMaxBodyBytes defines the Tendermint maximum response 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
###############################################################################
### Rosetta Configuration ###
###############################################################################
[rosetta]
# Enable defines if the Rosetta API server should be enabled.
enable = false
# Address defines the Rosetta API server to listen on.
address = ":8080"
# Network defines the name of the blockchain that will be returned by Rosetta.
blockchain = "app"
# Network defines the name of the network that will be returned by Rosetta.
network = "network"
# Retries defines the number of retries when connecting to the node before failing.
retries = 3
# Offline defines if Rosetta server should run in offline mode.
offline = 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 = "0.0.0.0:9090"
###############################################################################
### 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.
enable = true
# Address defines the gRPC-web server address to bind to.
address = "0.0.0.0:9091"
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
enable-unsafe-cors = false
###############################################################################
### 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). Must be a multiple of pruning-keep-every.
snapshot-interval = 0
# snapshot-keep-recent specifies the number of recent snapshots to keep and serve (0 to keep all).
snapshot-keep-recent = 2
###############################################################################
### Store / State Streaming ###
###############################################################################
[store]
streamers = []
[streamers]
[streamers.file]
keys = ["*", ]
write_dir = ""
prefix = ""
# output-metadata specifies if output the metadata file which includes the abci request/responses
# during processing the block.
output-metadata = "true"
# stop-node-on-error specifies if propagate the file streamer errors to consensus state machine.
stop-node-on-error = "true"
# fsync specifies if call fsync after writing the files.
fsync = "false"
[wasm]
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
query_gas_limit = 300000
# This is the number of wasm vm instances we keep cached in memory for speed-up
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
lru_size = 0

View File

@ -0,0 +1,255 @@
# 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"
# 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 Tendermint. 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 Tendermint blocks.
# It has no bearing on application state pruning which is determined by the
# "pruning-*" configurations.
#
# Note: Tendermint block pruning is dependant on this parameter in conunction
# 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 Tendermint 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.
# Default cache size is 50mb.
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.
# First fallback is the deprecated compile-time types.DBBackend value.
# Second fallback (if the types.DBBackend also isn't set), is the db-backend value set in Tendermint'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 = false
# Swagger defines if swagger documentation should automatically be registered.
swagger = false
# Address defines the API server to listen on.
address = "tcp://0.0.0.0:1317"
# MaxOpenConnections defines the number of maximum open connections.
max-open-connections = 1000
# RPCReadTimeout defines the Tendermint RPC read timeout (in seconds).
rpc-read-timeout = 10
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds).
rpc-write-timeout = 0
# RPCMaxBodyBytes defines the Tendermint maximum response 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
###############################################################################
### Rosetta Configuration ###
###############################################################################
[rosetta]
# Enable defines if the Rosetta API server should be enabled.
enable = false
# Address defines the Rosetta API server to listen on.
address = ":8080"
# Network defines the name of the blockchain that will be returned by Rosetta.
blockchain = "app"
# Network defines the name of the network that will be returned by Rosetta.
network = "network"
# Retries defines the number of retries when connecting to the node before failing.
retries = 3
# Offline defines if Rosetta server should run in offline mode.
offline = false
# EnableDefaultSuggestedFee defines if the server should suggest fee by default.
# If 'construction/medata' is called without gas limit and gas price,
# suggested fee based on gas-to-suggest and denom-to-suggest will be given.
enable-fee-suggestion = false
# GasToSuggest defines gas limit when calculating the fee
gas-to-suggest = 200000
# DenomToSuggest defines the defult denom for fee suggestion.
# Price must be in minimum-gas-prices.
denom-to-suggest = "uatom"
###############################################################################
### gRPC Configuration ###
###############################################################################
[grpc]
# Enable defines if the gRPC server should be enabled.
enable = true
# Address defines the gRPC server address to bind to.
address = "0.0.0.0: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.
enable = true
# Address defines the gRPC-web server address to bind to.
address = "0.0.0.0:9091"
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
enable-unsafe-cors = false
###############################################################################
### 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
###############################################################################
### Store / State Streaming ###
###############################################################################
[store]
streamers = []
[streamers]
[streamers.file]
keys = ["*", ]
write_dir = ""
prefix = ""
# output-metadata specifies if output the metadata file which includes the abci request/responses
# during processing the block.
output-metadata = "true"
# stop-node-on-error specifies if propagate the file streamer errors to consensus state machine.
stop-node-on-error = "true"
# fsync specifies if call fsync after writing the files.
fsync = "false"
[wasm]
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
query_gas_limit = 300000
# This is the number of wasm vm instances we keep cached in memory for speed-up
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
lru_size = 0

View File

@ -0,0 +1,232 @@
# 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"
# 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 Tendermint. 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 Tendermint blocks.
# It has no bearing on application state pruning which is determined by the
# "pruning-*" configurations.
#
# Note: Tendermint block pruning is dependant on this parameter in conunction
# 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 Tendermint 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.
# Default cache size is 50mb.
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.
# First fallback is the deprecated compile-time types.DBBackend value.
# Second fallback (if the types.DBBackend also isn't set), is the db-backend value set in Tendermint'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 = false
# 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 Tendermint RPC read timeout (in seconds).
rpc-read-timeout = 10
# RPCWriteTimeout defines the Tendermint RPC write timeout (in seconds).
rpc-write-timeout = 0
# RPCMaxBodyBytes defines the Tendermint maximum response 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.
enable = true
# Address defines the gRPC-web server address to bind to.
address = "localhost:9091"
# EnableUnsafeCORS defines if CORS should be enabled (unsafe - use it at your own risk).
enable-unsafe-cors = false
###############################################################################
### 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
###############################################################################
### Store / State Streaming ###
###############################################################################
[store]
streamers = []
[streamers]
[streamers.file]
keys = ["*", ]
write_dir = ""
prefix = ""
# output-metadata specifies if output the metadata file which includes the abci request/responses
# during processing the block.
output-metadata = "true"
# stop-node-on-error specifies if propagate the file streamer errors to consensus state machine.
stop-node-on-error = "true"
# fsync specifies if call fsync after writing the files.
fsync = "false"
###############################################################################
### 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"
[wasm]
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
query_gas_limit = 300000
# This is the number of wasm vm instances we keep cached in memory for speed-up
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
lru_size = 0

140
tools/confix/diff.go Normal file
View File

@ -0,0 +1,140 @@
package confix
import (
"fmt"
"io"
"sort"
"github.com/creachadair/tomledit"
"github.com/creachadair/tomledit/parser"
"github.com/creachadair/tomledit/transform"
)
const (
Section = "S"
Mapping = "M"
)
type KV struct {
Key string
Value string
Block []string // comment block
}
type Diff struct {
Type string // "section" or "mapping"
Deleted bool
KV KV
}
// DiffKeys diffs the keyspaces of the TOML documents in files lhs and rhs.
// Comments, order, and values are ignored for comparison purposes.
func DiffKeys(lhs, rhs *tomledit.Document) []Diff {
diff := diffSections(lhs.Global, rhs.Global)
lsec, rsec := lhs.Sections, rhs.Sections
transform.SortSectionsByName(lsec)
transform.SortSectionsByName(rsec)
i, j := 0, 0
for i < len(lsec) && j < len(rsec) {
if lsec[i].Name.Before(rsec[j].Name) {
diff = append(diff, Diff{Type: Section, Deleted: true, KV: KV{Key: lsec[i].Name.String()}})
for _, kv := range allKVs(lsec[i]) {
diff = append(diff, Diff{Type: Mapping, Deleted: true, KV: kv})
}
i++
} else if rsec[j].Name.Before(lsec[i].Name) {
diff = append(diff, Diff{Type: Section, KV: KV{Key: rsec[j].Name.String()}})
for _, kv := range allKVs(rsec[j]) {
diff = append(diff, Diff{Type: Mapping, KV: kv})
}
j++
} else {
diff = append(diff, diffSections(lsec[i], rsec[j])...)
i++
j++
}
}
for ; i < len(lsec); i++ {
diff = append(diff, Diff{Type: Section, Deleted: true, KV: KV{Key: lsec[i].Name.String()}})
for _, kv := range allKVs(lsec[i]) {
diff = append(diff, Diff{Type: Mapping, Deleted: true, KV: kv})
}
}
for ; j < len(rsec); j++ {
diff = append(diff, Diff{Type: Section, KV: KV{Key: rsec[j].Name.String()}})
for _, kv := range allKVs(rsec[j]) {
diff = append(diff, Diff{Type: Mapping, KV: kv})
}
}
return diff
}
func allKVs(s *tomledit.Section) []KV {
keys := []KV{}
s.Scan(func(key parser.Key, entry *tomledit.Entry) bool {
keys = append(keys, KV{
Key: key.String(),
Value: entry.Value.String(),
Block: entry.Block,
})
return true
})
return keys
}
func diffSections(lhs, rhs *tomledit.Section) []Diff {
return diffKeys(allKVs(lhs), allKVs(rhs))
}
func diffKeys(lhs, rhs []KV) []Diff {
diff := []Diff{}
sort.Slice(lhs, func(i, j int) bool {
return lhs[i].Key < lhs[j].Key
})
sort.Slice(rhs, func(i, j int) bool {
return rhs[i].Key < rhs[j].Key
})
i, j := 0, 0
for i < len(lhs) && j < len(rhs) {
if lhs[i].Key < rhs[j].Key {
diff = append(diff, Diff{Type: Mapping, Deleted: true, KV: lhs[i]})
i++
} else if lhs[i].Key > rhs[j].Key {
diff = append(diff, Diff{Type: Mapping, KV: rhs[j]})
j++
} else {
i++
j++
}
}
for ; i < len(lhs); i++ {
diff = append(diff, Diff{Type: Mapping, Deleted: true, KV: lhs[i]})
}
for ; j < len(rhs); j++ {
diff = append(diff, Diff{Type: Mapping, KV: rhs[j]})
}
return diff
}
// PrintDiff output prints one line per key that differs:
// -S name -- section exists in f1 but not f2
// +S name -- section exists in f2 but not f1
// -M name -- mapping exists in f1 but not f2
// +M name -- mapping exists in f2 but not f1
func PrintDiff(w io.Writer, diffs []Diff) {
for _, diff := range diffs {
if diff.Deleted {
fmt.Fprintln(w, fmt.Sprintf("-%s", diff.Type), fmt.Sprintf("%s=%s", diff.KV.Key, diff.KV.Value))
} else {
fmt.Fprintln(w, fmt.Sprintf("+%s", diff.Type), fmt.Sprintf("%s=%s", diff.KV.Key, diff.KV.Value))
}
}
}

4
tools/confix/doc.go Normal file
View File

@ -0,0 +1,4 @@
// Package confix applies changes to a Cosmos SDK TOML configuration file, to
// update configurations created with an older version of Cosmos SDK to a
// compatible format for a newer version.
package confix

144
tools/confix/go.mod Normal file
View File

@ -0,0 +1,144 @@
module cosmossdk.io/tools/confix
go 1.19
require (
github.com/cosmos/cosmos-sdk v0.47.0-rc1
github.com/creachadair/atomicfile v0.2.7
github.com/creachadair/tomledit v0.0.24
github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.14.0
golang.org/x/exp v0.0.0-20221019170559-20944726eadf
gotest.tools/v3 v3.4.0
)
require (
cosmossdk.io/api v0.2.6 // indirect
cosmossdk.io/core v0.3.2 // indirect
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
cosmossdk.io/errors v1.0.0-beta.7 // indirect
cosmossdk.io/math v1.0.0-beta.4 // indirect
cosmossdk.io/tools/rosetta v0.2.0 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/confio/ics23/go v0.9.0 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.1 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/gogoproto v1.4.3 // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/iavl v0.19.4 // indirect
github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect
github.com/cosmos/rosetta-sdk-go v0.9.0 // indirect
github.com/creachadair/taskgroup v0.3.2 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/felixge/httpsnoop v1.0.2 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/improbable-eng/grpc-web v0.15.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.15.12 // indirect
github.com/lib/pq v1.10.7 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rakyll/statik v0.1.7 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rs/cors v1.8.2 // indirect
github.com/rs/zerolog v1.28.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/spf13/afero v1.9.2 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tendermint/btcd v0.1.1 // indirect
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tendermint/tendermint v0.37.0-rc2 // indirect
github.com/tendermint/tm-db v0.6.7 // indirect
github.com/tidwall/btree v1.5.2 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.0 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/net v0.3.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/term v0.3.0 // indirect
golang.org/x/text v0.5.0 // indirect
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v0.5.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
// TODO investigate if we can outright delete this dependency, otherwise go install won't work :(
replace github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.8.1

1210
tools/confix/go.sum Normal file

File diff suppressed because it is too large Load Diff

14
tools/confix/log.go Normal file
View File

@ -0,0 +1,14 @@
package confix
import (
"context"
"io"
"github.com/creachadair/tomledit/transform"
)
// WithLogWriter returns a child of ctx with a logger attached that sends
// output to w. This is a convenience wrapper for transform.WithLogWriter.
func WithLogWriter(ctx context.Context, w io.Writer) context.Context {
return transform.WithLogWriter(ctx, w)
}

125
tools/confix/migrations.go Normal file
View File

@ -0,0 +1,125 @@
package confix
import (
"context"
"embed"
"fmt"
"strings"
"github.com/creachadair/tomledit"
"github.com/creachadair/tomledit/parser"
"github.com/creachadair/tomledit/transform"
)
const (
AppConfig = "app.toml"
ClientConfig = "client.toml"
TMConfig = "config.toml"
)
// MigrationMap defines a mapping from a version to a transformation plan.
type MigrationMap map[string]func(from *tomledit.Document, to 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.
"v0.46": PlanBuilder,
"v0.47": PlanBuilder,
// "v0.47.x": PlanBuilder, // add specific migration in case of configuration changes in minor versions
// "v0.48": PlanBuilder,
}
//go:embed data
data embed.FS
)
// PlanBuilder is a function that returns a transformation plan for a given diff between two files.
func PlanBuilder(from *tomledit.Document, to string) transform.Plan {
plan := transform.Plan{}
file, err := data.Open(fmt.Sprintf("data/%s-app.toml", to))
if err != nil {
panic(fmt.Errorf("failed to read file: %w. This file should have been included in confix", err))
}
target, err := tomledit.Parse(file)
if err != nil {
panic(fmt.Errorf("failed to parse file: %w. This file should have been valid", err))
}
deletedSections := map[string]bool{}
diffs := DiffKeys(from, target)
for _, diff := range diffs {
diff := diff
kv := diff.KV
var step transform.Step
keys := strings.Split(kv.Key, ".")
if !diff.Deleted {
switch diff.Type {
case Section:
step = transform.Step{
Desc: fmt.Sprintf("add %s section", kv.Key),
T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
doc.Sections = append(doc.Sections, &tomledit.Section{
Heading: &parser.Heading{
Block: parser.Comments{
"###############################################################################",
fmt.Sprintf("### %s Configuration ###", strings.Title(kv.Key)),
"###############################################################################"},
Name: keys,
},
})
return nil
}),
}
case Mapping:
if len(keys) == 1 { // top-level key
step = transform.Step{
Desc: fmt.Sprintf("add %s key", kv.Key),
T: transform.EnsureKey(nil, &parser.KeyValue{
Block: kv.Block,
Name: parser.Key{keys[0]},
Value: parser.MustValue(kv.Value),
})}
} else if len(keys) > 1 {
step = transform.Step{
Desc: fmt.Sprintf("add %s key", kv.Key),
T: transform.EnsureKey(parser.Key{keys[0]}, &parser.KeyValue{
Block: kv.Block,
Name: parser.Key{keys[1]},
Value: parser.MustValue(kv.Value),
})}
}
default:
panic(fmt.Errorf("unknown diff type: %s", diff.Type))
}
} else {
if diff.Type == Section {
deletedSections[kv.Key] = true
}
// when the whole section is deleted we don't need to remove the keys
if len(keys) > 1 && deletedSections[keys[0]] {
continue
}
step = transform.Step{
Desc: fmt.Sprintf("remove %s key", kv.Key),
T: transform.Remove(keys),
}
}
plan = append(plan, step)
}
return plan
}
// NoPlan returns a no-op plan.
func NoPlan(_ *tomledit.Document, to string) transform.Plan {
fmt.Printf("no migration needed to %s\n", to)
return transform.Plan{}
}

View File

@ -0,0 +1,15 @@
sonar.projectKey=cosmos-sdk-tools-confix
sonar.organization=cosmos
sonar.projectName=Cosmos SDK - Confix
sonar.project.monorepo.enabled=true
sonar.sources=.
sonar.exclusions=**/*_test.go
sonar.tests=.
sonar.test.inclusions=**/*_test.go
sonar.go.coverage.reportPaths=coverage.out
sonar.sourceEncoding=UTF-8
sonar.scm.provider=git
sonar.pullrequest.github.summary_comment=true

43
tools/confix/testdata/README.md vendored Normal file
View File

@ -0,0 +1,43 @@
# Test data for `confix` and `condiff`
The files in this directory are stock Cosmos SDK configuration files generated
by the last point release of each version series from v0.45 to present, along
with diffs between consecutive versions.
## Config Samples
The files named `vXX-app.toml` were generated by checking out and building
the corresponding version of Cosmos SDK v0.xx.y and initializing a new node in
an empty home directory. The resulting `app.toml` file was copied here.
The exact build instructions vary a bit, but a general repro looks like:
```shell
# This example uses v0.47, substitute the version of your choice.
git checkout release/v0.47.x
# Install dependencies
make install
# Confirm you go the version you expected, and generate the file.
simd version
simd init test --chain-id test
# Copy the file out.
cp ./.simapp/config/app.toml v47-app.toml
```
## Version Diffs
The files named `diff-XX-YY.txt` were generated by using the `condiff` tool on
the config samples for versions v0.XX and v0.YY:
```shell
condiff vXX-app.toml data/vYY-app.toml > testdata/diff-XX-YY.txt
```
The `baseline.txt` was computed in the same way, but using an empty starting
file so that we capture all the settings in the target:
```shell
condiff /dev/null data/v45-app.toml > testdata/baseline.txt
```

60
tools/confix/testdata/baseline.txt vendored Normal file
View File

@ -0,0 +1,60 @@
+M halt-height
+M halt-time
+M iavl-cache-size
+M iavl-disable-fastnode
+M index-events
+M inter-block-cache
+M min-retain-blocks
+M minimum-gas-prices
+M pruning
+M pruning-interval
+M pruning-keep-every
+M pruning-keep-recent
+S api
+M api.enable
+M api.swagger
+M api.address
+M api.max-open-connections
+M api.rpc-read-timeout
+M api.rpc-write-timeout
+M api.rpc-max-body-bytes
+M api.enabled-unsafe-cors
+S grpc
+M grpc.enable
+M grpc.address
+S grpc-web
+M grpc-web.enable
+M grpc-web.address
+M grpc-web.enable-unsafe-cors
+S rosetta
+M rosetta.enable
+M rosetta.address
+M rosetta.blockchain
+M rosetta.network
+M rosetta.retries
+M rosetta.offline
+S state-sync
+M state-sync.snapshot-interval
+M state-sync.snapshot-keep-recent
+S store
+M store.streamers
+S streamers
+M
+S streamers.file
+M streamers.file.keys
+M streamers.file.write_dir
+M streamers.file.prefix
+M streamers.file.output-metadata
+M streamers.file.stop-node-on-error
+M streamers.file.fsync
+S telemetry
+M telemetry.service-name
+M telemetry.enabled
+M telemetry.enable-hostname
+M telemetry.enable-hostname-label
+M telemetry.enable-service-label
+M telemetry.prometheus-retention-time
+M telemetry.global-labels
+S wasm
+M wasm.query_gas_limit
+M wasm.lru_size

17
tools/confix/testdata/client.toml vendored Normal file
View File

@ -0,0 +1,17 @@
# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
###############################################################################
### Client Configuration ###
###############################################################################
# The network chain ID
chain-id = "demo"
# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory)
keyring-backend = "test"
# CLI output format (text|json)
output = "text"
# <host>:<port> to Tendermint RPC interface for this chain
node = "tcp://localhost:26657"
# Transaction broadcasting mode (sync|async)
broadcast-mode = "sync"

7
tools/confix/testdata/diff-45-46.txt vendored Normal file
View File

@ -0,0 +1,7 @@
+M app-db-backend
-M pruning-keep-every
+M grpc.max-recv-msg-size
+M grpc.max-send-msg-size
+M rosetta.denom-to-suggest
+M rosetta.enable-fee-suggestion
+M rosetta.gas-to-suggest

12
tools/confix/testdata/diff-46-47.txt vendored Normal file
View File

@ -0,0 +1,12 @@
+S mempool
+M mempool.max-txs
-S rosetta
-M rosetta.enable
-M rosetta.address
-M rosetta.blockchain
-M rosetta.network
-M rosetta.retries
-M rosetta.offline
-M rosetta.enable-fee-suggestion
-M rosetta.gas-to-suggest
-M rosetta.denom-to-suggest

116
tools/confix/upgrade.go Normal file
View File

@ -0,0 +1,116 @@
package confix
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"strings"
"github.com/creachadair/atomicfile"
"github.com/creachadair/tomledit"
"github.com/creachadair/tomledit/transform"
"github.com/spf13/viper"
clientcfg "github.com/cosmos/cosmos-sdk/client/config"
srvcfg "github.com/cosmos/cosmos-sdk/server/config"
)
// Upgrade reads the configuration file at configPath and applies any
// transformations necessary to Upgrade it to the current version. If this
// succeeds, the transformed output is written to outputPath. As a special
// case, if outputPath == "" the output is written to stdout.
//
// It is safe if outputPath == inputPath. If a regular file outputPath already
// exists, it is overwritten. In case of error, the output is not written.
//
// Upgrade is a convenience wrapper for calls to LoadConfig, ApplyFixes, and
// CheckValid. If the caller requires more control over the behavior of the
// Upgrade, call those functions directly.
func Upgrade(ctx context.Context, plan transform.Plan, configPath, outputPath string, skipValidate bool) error {
if configPath == "" {
return errors.New("empty input configuration path")
}
doc, err := LoadConfig(configPath)
if err != nil {
return fmt.Errorf("loading config: %v", err)
}
// transforms doc and reports whether it succeeded.
if err := plan.Apply(ctx, doc); err != nil {
return fmt.Errorf("updating %q: %v", configPath, err)
}
var buf bytes.Buffer
if err := tomledit.Format(&buf, doc); err != nil {
return fmt.Errorf("formatting config: %v", err)
}
// allow to skip validation
if !skipValidate {
// verify that file is valid after applying fixes
if err := CheckValid(configPath, buf.Bytes()); err != nil {
return fmt.Errorf("updated config is invalid: %v", err)
}
}
if outputPath == "" {
_, err = os.Stdout.Write(buf.Bytes())
} else {
err = atomicfile.WriteData(outputPath, buf.Bytes(), 0600)
}
return err
}
// LoadConfig loads and parses the TOML document from path.
func LoadConfig(path string) (*tomledit.Document, error) {
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open %q: %v", path, err)
}
defer f.Close()
return tomledit.Parse(f)
}
// CheckValid checks whether the specified config appears to be a valid Cosmos SDK config file.
// It tries to unmarshal the config into both the server and client config structs.
func CheckValid(fileName string, data []byte) error {
v := viper.New()
v.SetConfigType("toml")
if err := v.ReadConfig(bytes.NewReader(data)); err != nil {
return fmt.Errorf("reading config: %w", err)
}
switch {
case strings.HasSuffix(fileName, AppConfig):
var cfg srvcfg.Config
if err := v.Unmarshal(&cfg); err != nil {
return fmt.Errorf("failed to unmarshal as server config: %w", err)
}
if err := cfg.ValidateBasic(); err != nil {
return fmt.Errorf("server config invalid : %w", err)
}
case strings.HasSuffix(fileName, ClientConfig):
var cfg clientcfg.ClientConfig
if err := v.Unmarshal(&cfg); err != nil {
return fmt.Errorf("failed to unmarshal as client config: %w", err)
}
if cfg.ChainID == "" {
return errors.New("client config invalid: chain-id is empty")
}
case strings.HasSuffix(fileName, TMConfig):
return errors.New("tendermint config is not supported")
default:
return fmt.Errorf("unknown config: %s", fileName)
}
return nil
}

View File

@ -0,0 +1,48 @@
package confix_test
import (
"os"
"testing"
"cosmossdk.io/tools/confix"
"gotest.tools/v3/assert"
)
func mustReadConfig(t *testing.T, path string) []byte {
f, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
return f
}
func TestUpgrade(t *testing.T) {
// TODO: add more test cases
}
func TestCheckValid(t *testing.T) {
err := confix.CheckValid("foo", []byte{})
assert.ErrorContains(t, err, "unknown config")
err = confix.CheckValid("client", mustReadConfig(t, "data/v0.45-app.toml"))
assert.ErrorContains(t, err, "unknown config")
err = confix.CheckValid("config.toml", mustReadConfig(t, "data/v0.45-app.toml"))
assert.Error(t, err, "tendermint config is not supported")
err = confix.CheckValid("client.toml", mustReadConfig(t, "data/v0.45-app.toml"))
assert.Error(t, err, "client config invalid: chain-id is empty")
err = confix.CheckValid("client.toml", []byte{})
assert.Error(t, err, "client config invalid: chain-id is empty")
err = confix.CheckValid("app.toml", []byte{})
assert.ErrorContains(t, err, "server config invalid")
err = confix.CheckValid("app.toml", mustReadConfig(t, "data/v0.45-app.toml"))
assert.NilError(t, err)
err = confix.CheckValid("client.toml", mustReadConfig(t, "testdata/client.toml"))
assert.NilError(t, err)
}