github.com/cosmos/cosmos-sdk@v0.50.10/x/genutil/client/cli/migrate.go (about)

     1  package cli
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/spf13/cobra"
    11  	"golang.org/x/exp/maps"
    12  
    13  	"github.com/cosmos/cosmos-sdk/client"
    14  	"github.com/cosmos/cosmos-sdk/client/flags"
    15  	"github.com/cosmos/cosmos-sdk/version"
    16  	v043 "github.com/cosmos/cosmos-sdk/x/genutil/migrations/v043"
    17  	v046 "github.com/cosmos/cosmos-sdk/x/genutil/migrations/v046"
    18  	v047 "github.com/cosmos/cosmos-sdk/x/genutil/migrations/v047"
    19  	"github.com/cosmos/cosmos-sdk/x/genutil/types"
    20  )
    21  
    22  const flagGenesisTime = "genesis-time"
    23  
    24  // MigrationMap is a map of SDK versions to their respective genesis migration functions.
    25  var MigrationMap = types.MigrationMap{
    26  	"v0.43": v043.Migrate, // NOTE: v0.43, v0.44 and v0.45 are genesis compatible.
    27  	"v0.46": v046.Migrate,
    28  	"v0.47": v047.Migrate,
    29  }
    30  
    31  // MigrateGenesisCmd returns a command to execute genesis state migration.
    32  // Applications should pass their own migration map to this function.
    33  // When the application migration includes a SDK migration, the Cosmos SDK migration function should as well be called.
    34  func MigrateGenesisCmd(migrations types.MigrationMap) *cobra.Command {
    35  	cmd := &cobra.Command{
    36  		Use:     "migrate [target-version] [genesis-file]",
    37  		Short:   "Migrate genesis to a specified target version",
    38  		Long:    "Migrate the source genesis into the target version and print to STDOUT",
    39  		Example: fmt.Sprintf("%s migrate v0.47 /path/to/genesis.json --chain-id=cosmoshub-3 --genesis-time=2019-04-22T17:00:00Z", version.AppName),
    40  		Args:    cobra.ExactArgs(2),
    41  		RunE: func(cmd *cobra.Command, args []string) error {
    42  			return MigrateHandler(cmd, args, migrations)
    43  		},
    44  	}
    45  
    46  	cmd.Flags().String(flagGenesisTime, "", "Override genesis_time with this flag")
    47  	cmd.Flags().String(flags.FlagChainID, "", "Override chain_id with this flag")
    48  	cmd.Flags().String(flags.FlagOutputDocument, "", "Exported state is written to the given file instead of STDOUT")
    49  
    50  	return cmd
    51  }
    52  
    53  // MigrateHandler handles the migration command with a migration map as input,
    54  // returning an error upon failure.
    55  func MigrateHandler(cmd *cobra.Command, args []string, migrations types.MigrationMap) error {
    56  	clientCtx := client.GetClientContextFromCmd(cmd)
    57  
    58  	target := args[0]
    59  	migrationFunc, ok := migrations[target]
    60  	if !ok || migrationFunc == nil {
    61  		versions := maps.Keys(migrations)
    62  		sort.Strings(versions)
    63  		return fmt.Errorf("unknown migration function for version: %s (supported versions %s)", target, strings.Join(versions, ", "))
    64  	}
    65  
    66  	importGenesis := args[1]
    67  	appGenesis, err := types.AppGenesisFromFile(importGenesis)
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	if err := appGenesis.ValidateAndComplete(); err != nil {
    73  		return fmt.Errorf("make sure that you have correctly migrated all CometBFT consensus params. Refer the UPGRADING.md (%s): %w", chainUpgradeGuide, err)
    74  	}
    75  
    76  	// Since some default values are valid values, we just print to
    77  	// make sure the user didn't forget to update these values.
    78  	if appGenesis.Consensus.Params.Evidence.MaxBytes == 0 {
    79  		fmt.Printf("Warning: consensus.params.evidence.max_bytes is set to 0. If this is"+
    80  			" deliberate, feel free to ignore this warning. If not, please have a look at the chain"+
    81  			" upgrade guide at %s.\n", chainUpgradeGuide)
    82  	}
    83  
    84  	var initialState types.AppMap
    85  	if err := json.Unmarshal(appGenesis.AppState, &initialState); err != nil {
    86  		return fmt.Errorf("failed to JSON unmarshal initial genesis state: %w", err)
    87  	}
    88  
    89  	newGenState, err := migrationFunc(initialState, clientCtx)
    90  	if err != nil {
    91  		return fmt.Errorf("failed to migrate genesis state: %w", err)
    92  	}
    93  
    94  	appGenesis.AppState, err = json.Marshal(newGenState)
    95  	if err != nil {
    96  		return fmt.Errorf("failed to JSON marshal migrated genesis state: %w", err)
    97  	}
    98  
    99  	genesisTime, _ := cmd.Flags().GetString(flagGenesisTime)
   100  	if genesisTime != "" {
   101  		var t time.Time
   102  
   103  		err := t.UnmarshalText([]byte(genesisTime))
   104  		if err != nil {
   105  			return fmt.Errorf("failed to unmarshal genesis time: %w", err)
   106  		}
   107  
   108  		appGenesis.GenesisTime = t
   109  	}
   110  
   111  	chainID, _ := cmd.Flags().GetString(flags.FlagChainID)
   112  	if chainID != "" {
   113  		appGenesis.ChainID = chainID
   114  	}
   115  
   116  	bz, err := json.Marshal(appGenesis)
   117  	if err != nil {
   118  		return fmt.Errorf("failed to marshal app genesis: %w", err)
   119  	}
   120  
   121  	outputDocument, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
   122  	if outputDocument == "" {
   123  		cmd.Println(string(bz))
   124  		return nil
   125  	}
   126  
   127  	if err = appGenesis.SaveAs(outputDocument); err != nil {
   128  		return err
   129  	}
   130  
   131  	return nil
   132  }