From cf86c567c79768671673a4fd785206928441aae6 Mon Sep 17 00:00:00 2001 From: Amaury Date: Mon, 14 Dec 2020 23:51:23 +0100 Subject: [PATCH] Add msg on CLI for migrating GenesisDoc (#8164) * Add msg on CLI for migrating GenesisDoc * Fix build * Better indentation * Add table tests * typo * Rename variables * Fix validate tests * Add warning println Co-authored-by: Cory --- simapp/simd/cmd/root.go | 2 +- x/genutil/client/cli/migrate.go | 13 ++- x/genutil/client/cli/migrate_test.go | 67 +++++++++------ x/genutil/client/cli/validate_genesis.go | 33 ++++++-- x/genutil/client/cli/validate_genesis_test.go | 82 +++++++++++++++++++ 5 files changed, 157 insertions(+), 40 deletions(-) create mode 100644 x/genutil/client/cli/validate_genesis_test.go diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 469645019..dd33ea082 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -73,7 +73,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), genutilcli.MigrateGenesisCmd(), genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.ValidateGenesisCmd(simapp.ModuleBasics, encodingConfig.TxConfig), + genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), AddGenesisAccountCmd(simapp.DefaultNodeHome), tmcli.NewCompletionCmd(rootCmd, true), testnetCmd(simapp.ModuleBasics, banktypes.GenesisBalancesIterator{}), diff --git a/x/genutil/client/cli/migrate.go b/x/genutil/client/cli/migrate.go index ab1e65f04..483f4aaf1 100644 --- a/x/genutil/client/cli/migrate.go +++ b/x/genutil/client/cli/migrate.go @@ -9,7 +9,6 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" tmjson "github.com/tendermint/tendermint/libs/json" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -74,9 +73,17 @@ $ %s migrate v0.36 /path/to/genesis.json --chain-id=cosmoshub-3 --genesis-time=2 target := args[0] importGenesis := args[1] - genDoc, err := tmtypes.GenesisDocFromFile(importGenesis) + genDoc, err := validateGenDoc(importGenesis) if err != nil { - return errors.Wrapf(err, "failed to read genesis document from file %s", importGenesis) + return err + } + + // Since some default values are valid values, we just print to + // make sure the user didn't forget to update these values. + if genDoc.ConsensusParams.Evidence.MaxBytes == 0 { + fmt.Printf("Warning: consensus_params.evidence.max_bytes is set to 0. If this is"+ + " deliberate, feel free to ignore this warning. If not, please have a look at the chain"+ + " upgrade guide at %s.\n", chainUpgradeGuide) } var initialState types.AppMap diff --git a/x/genutil/client/cli/migrate_test.go b/x/genutil/client/cli/migrate_test.go index 807c0d32b..d31f8962a 100644 --- a/x/genutil/client/cli/migrate_test.go +++ b/x/genutil/client/cli/migrate_test.go @@ -1,15 +1,12 @@ package cli_test import ( - "context" - "io/ioutil" - "path" "testing" "github.com/stretchr/testify/require" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" ) @@ -19,29 +16,45 @@ func TestGetMigrationCallback(t *testing.T) { } } -func TestMigrateGenesis(t *testing.T) { - home := t.TempDir() +func (s *IntegrationTestSuite) TestMigrateGenesis() { + val0 := s.network.Validators[0] - cdc := makeCodec() + testCases := []struct { + name string + genesis string + target string + expErr bool + expErrMsg string + }{ + { + "migrate to 0.36", + `{"chain_id":"test","app_state":{}}`, + "v0.36", + false, "", + }, + { + "exported 0.37 genesis file", + v037Exported, + "v0.40", + true, "Make sure that you have correctly migrated all Tendermint consensus params", + }, + { + "valid 0.40 genesis file", + v040Valid, + "v0.40", + false, "", + }, + } - genesisPath := path.Join(home, "genesis.json") - target := "v0.36" - - cmd := cli.MigrateGenesisCmd() - _ = testutil.ApplyMockIODiscardOutErr(cmd) - - clientCtx := client.Context{}.WithLegacyAmino(cdc) - ctx := context.Background() - ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - - // Reject if we dont' have the right parameters or genesis does not exists - cmd.SetArgs([]string{target, genesisPath}) - require.Error(t, cmd.ExecuteContext(ctx)) - - // Noop migration with minimal genesis - emptyGenesis := []byte(`{"chain_id":"test","app_state":{}}`) - require.NoError(t, ioutil.WriteFile(genesisPath, emptyGenesis, 0644)) - - cmd.SetArgs([]string{target, genesisPath}) - require.NoError(t, cmd.ExecuteContext(ctx)) + for _, tc := range testCases { + s.Run(tc.name, func() { + genesisFile := testutil.WriteToNewTempFile(s.T(), tc.genesis) + _, err := clitestutil.ExecTestCLICmd(val0.ClientCtx, cli.MigrateGenesisCmd(), []string{tc.target, genesisFile.Name()}) + if tc.expErr { + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + } + }) + } } diff --git a/x/genutil/client/cli/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go index a2e148b24..0514cc66f 100644 --- a/x/genutil/client/cli/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -3,7 +3,6 @@ package cli import ( "encoding/json" "fmt" - "os" "github.com/spf13/cobra" tmtypes "github.com/tendermint/tendermint/types" @@ -13,8 +12,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" ) -// Validate genesis command takes -func ValidateGenesisCmd(mbm module.BasicManager, txEncCfg client.TxEncodingConfig) *cobra.Command { +const chainUpgradeGuide = "https://docs.cosmos.network/master/migrations/chain-upgrade-guide-040.html" + +// ValidateGenesisCmd takes a genesis file, and makes sure that it is valid. +func ValidateGenesisCmd(mbm module.BasicManager) *cobra.Command { return &cobra.Command{ Use: "validate-genesis [file]", Args: cobra.RangeArgs(0, 1), @@ -33,11 +34,9 @@ func ValidateGenesisCmd(mbm module.BasicManager, txEncCfg client.TxEncodingConfi genesis = args[0] } - fmt.Fprintf(os.Stderr, "validating genesis file at %s\n", genesis) - - var genDoc *tmtypes.GenesisDoc - if genDoc, err = tmtypes.GenesisDocFromFile(genesis); err != nil { - return fmt.Errorf("error loading genesis doc from %s: %s", genesis, err.Error()) + genDoc, err := validateGenDoc(genesis) + if err != nil { + return err } var genState map[string]json.RawMessage @@ -45,7 +44,7 @@ func ValidateGenesisCmd(mbm module.BasicManager, txEncCfg client.TxEncodingConfi return fmt.Errorf("error unmarshalling genesis doc %s: %s", genesis, err.Error()) } - if err = mbm.ValidateGenesis(cdc, txEncCfg, genState); err != nil { + if err = mbm.ValidateGenesis(cdc, clientCtx.TxConfig, genState); err != nil { return fmt.Errorf("error validating genesis file %s: %s", genesis, err.Error()) } @@ -54,3 +53,19 @@ func ValidateGenesisCmd(mbm module.BasicManager, txEncCfg client.TxEncodingConfi }, } } + +// validateGenDoc reads a genesis file and validates that it is a correct +// Tendermint GenesisDoc. This function does not do any cosmos-related +// validation. +func validateGenDoc(importGenesisFile string) (*tmtypes.GenesisDoc, error) { + genDoc, err := tmtypes.GenesisDocFromFile(importGenesisFile) + if err != nil { + return nil, fmt.Errorf("%s. Make sure that"+ + " you have correctly migrated all Tendermint consensus params, please see the"+ + " chain migration guide at %s for more info", + err.Error(), chainUpgradeGuide, + ) + } + + return genDoc, nil +} diff --git a/x/genutil/client/cli/validate_genesis_test.go b/x/genutil/client/cli/validate_genesis_test.go new file mode 100644 index 000000000..f62aa1b7a --- /dev/null +++ b/x/genutil/client/cli/validate_genesis_test.go @@ -0,0 +1,82 @@ +package cli_test + +import ( + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" +) + +// An example exported genesis file from a 0.37 chain. Note that evidence +// parameters only contains `max_age`. +var v037Exported = `{ + "app_hash": "", + "app_state": {}, + "chain_id": "test", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { "max_age": "100000" }, + "validator": { "pub_key_types": ["ed25519"] } + }, + "genesis_time": "2020-09-29T20:16:29.172362037Z", + "validators": [] +}` + +// An example exported genesis file that's 0.40 compatible. +var v040Valid = `{ + "app_hash": "", + "app_state": {}, + "chain_id": "test", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000", + "max_bytes": "0" + }, + "validator": { "pub_key_types": ["ed25519"] } + }, + "genesis_time": "2020-09-29T20:16:29.172362037Z", + "validators": [] +}` + +func (s *IntegrationTestSuite) TestValidateGenesis() { + val0 := s.network.Validators[0] + + testCases := []struct { + name string + genesis string + expErr bool + }{ + { + "exported 0.37 genesis file", + v037Exported, + true, + }, + { + "valid 0.40 genesis file", + v040Valid, + false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + genesisFile := testutil.WriteToNewTempFile(s.T(), tc.genesis) + _, err := clitestutil.ExecTestCLICmd(val0.ClientCtx, cli.ValidateGenesisCmd(nil), []string{genesisFile.Name()}) + if tc.expErr { + s.Require().Contains(err.Error(), "Make sure that you have correctly migrated all Tendermint consensus params") + + } else { + s.Require().NoError(err) + } + }) + } +}