diff --git a/cmd/babylond/cmd/flags.go b/cmd/babylond/cmd/flags.go new file mode 100644 index 000000000..649ccc9a0 --- /dev/null +++ b/cmd/babylond/cmd/flags.go @@ -0,0 +1,56 @@ +package cmd + +import ( + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + tmrand "github.com/tendermint/tendermint/libs/rand" +) + +type GenesisCLIArgs struct { + ChainID string + MaxActiveValidators uint32 + BtcConfirmationDepth uint64 + BtcFinalizationTimeout uint64 + EpochInterval uint64 + BaseBtcHeaderHex string + BaseBtcHeaderHeight uint64 +} + +func addGenesisFlags(cmd *cobra.Command) { + cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + // staking flags + cmd.Flags().Uint32(flagMaxActiveValidators, 10, "Maximum number of validators.") + // btccheckpoint flags + cmd.Flags().Uint64(flagBtcConfirmationDepth, 6, "Confirmation depth for Bitcoin headers.") + cmd.Flags().Uint64(flagBtcFinalizationTimeout, 20, "Finalization timeout for Bitcoin headers.") + // epoch args + cmd.Flags().Uint64(flagEpochInterval, 400, "Number of blocks between epochs. Must be more than 0.") + // btclightclient args + // Genesis header for the simnet + cmd.Flags().String(flagBaseBtcHeaderHex, "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a45068653ffff7f2002000000", "Hex of the base Bitcoin header.") + cmd.Flags().Uint64(flagBaseBtcHeaderHeight, 0, "Height of the base Bitcoin header.") +} + +func parseGenesisFlags(cmd *cobra.Command) *GenesisCLIArgs { + chainID, _ := cmd.Flags().GetString(flags.FlagChainID) + maxActiveValidators, _ := cmd.Flags().GetUint32(flagMaxActiveValidators) + btcConfirmationDepth, _ := cmd.Flags().GetUint64(flagBtcConfirmationDepth) + btcFinalizationTimeout, _ := cmd.Flags().GetUint64(flagBtcFinalizationTimeout) + epochInterval, _ := cmd.Flags().GetUint64(flagEpochInterval) + baseBtcHeaderHex, _ := cmd.Flags().GetString(flagBaseBtcHeaderHex) + baseBtcHeaderHeight, _ := cmd.Flags().GetUint64(flagBaseBtcHeaderHeight) + + if chainID == "" { + chainID = "chain-" + tmrand.NewRand().Str(6) + } + + return &GenesisCLIArgs{ + ChainID: chainID, + MaxActiveValidators: maxActiveValidators, + BtcConfirmationDepth: btcConfirmationDepth, + BtcFinalizationTimeout: btcFinalizationTimeout, + EpochInterval: epochInterval, + BaseBtcHeaderHeight: baseBtcHeaderHeight, + BaseBtcHeaderHex: baseBtcHeaderHex, + } +} diff --git a/cmd/babylond/cmd/genesis.go b/cmd/babylond/cmd/genesis.go index efcc64ef7..a284b6208 100644 --- a/cmd/babylond/cmd/genesis.go +++ b/cmd/babylond/cmd/genesis.go @@ -10,21 +10,94 @@ import ( checkpointingtypes "github.com/babylonchain/babylon/x/checkpointing/types" epochingtypes "github.com/babylonchain/babylon/x/epoching/types" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/client/flags" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/spf13/cobra" + "github.com/tendermint/tendermint/types" ) -func PrepareGenesis(clientCtx client.Context, appState map[string]json.RawMessage, genesisParams GenesisParams) (map[string]json.RawMessage, error) { +func PrepareGenesisCmd(defaultNodeHome string, mbm module.BasicManager) *cobra.Command { + cmd := &cobra.Command{ + Use: "prepare-genesis ", + Args: cobra.ExactArgs(2), + Short: "Prepare a genesis file", + Long: `Prepare a genesis file. +Example: + babylond prepare-genesis testnet babylon-test-1 +`, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + serverCtx := server.GetServerContextFromCmd(cmd) + config := serverCtx.Config + + genesisCliArgs := parseGenesisFlags(cmd) + + genFile := config.GenesisFile() + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genFile) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %s", err) + } + + network := args[0] + chainID := args[1] + + var genesisParams GenesisParams + if network == "testnet" { + genesisParams = TestnetGenesisParams(genesisCliArgs.MaxActiveValidators, + genesisCliArgs.BtcConfirmationDepth, genesisCliArgs.BtcFinalizationTimeout, + genesisCliArgs.EpochInterval, genesisCliArgs.BaseBtcHeaderHex, + genesisCliArgs.BaseBtcHeaderHeight) + } else if network == "mainnet" { + // TODO: mainnet genesis params + } else { + return fmt.Errorf("please choose testnet or mainnet") + } + + appState, genDoc, err = PrepareGenesis(clientCtx, appState, genDoc, genesisParams, chainID) + + if err = mbm.ValidateGenesis(clientCtx.Codec, clientCtx.TxConfig, appState); err != nil { + return fmt.Errorf("error validating genesis file: %s", err) + } + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + genDoc.AppState = appStateJSON + return genutil.ExportGenesisFile(genDoc, genFile) + }, + } + + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The application home directory") + addGenesisFlags(cmd) + + return cmd +} + +func PrepareGenesis(clientCtx client.Context, appState map[string]json.RawMessage, + genDoc *types.GenesisDoc, genesisParams GenesisParams, chainID string) (map[string]json.RawMessage, *types.GenesisDoc, error) { + depCdc := clientCtx.Codec cdc := depCdc + // Add ChainID + genDoc.ChainID = chainID + // Set the confirmation and finalization parameters btccheckpointGenState := btccheckpointtypes.DefaultGenesis() btccheckpointGenState.Params = genesisParams.BtccheckpointParams @@ -85,7 +158,7 @@ func PrepareGenesis(clientCtx client.Context, appState map[string]json.RawMessag appState[banktypes.ModuleName] = cdc.MustMarshalJSON(bankGenState) // return appState - return appState, nil + return appState, genDoc, nil } type GenesisParams struct { @@ -97,7 +170,7 @@ type GenesisParams struct { GovParams govtypes.Params CrisisConstantFee sdk.Coin - AuthAccounts []*types.Any + AuthAccounts []*cdctypes.Any BankGenBalances []banktypes.Balance CheckpointingGenKeys []*checkpointingtypes.GenesisKey diff --git a/cmd/babylond/cmd/root.go b/cmd/babylond/cmd/root.go index 3f717342c..820595b49 100644 --- a/cmd/babylond/cmd/root.go +++ b/cmd/babylond/cmd/root.go @@ -124,6 +124,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { genutilcli.MigrateGenesisCmd(), genutilcli.GenTxCmd(app.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, app.DefaultNodeHome), genutilcli.ValidateGenesisCmd(app.ModuleBasics), + PrepareGenesisCmd(app.DefaultNodeHome, app.ModuleBasics), AddGenesisAccountCmd(app.DefaultNodeHome), tmcli.NewCompletionCmd(rootCmd, true), testnetCmd(app.ModuleBasics, banktypes.GenesisBalancesIterator{}), diff --git a/cmd/babylond/cmd/testnet.go b/cmd/babylond/cmd/testnet.go index 5488c7b83..7b36aac14 100644 --- a/cmd/babylond/cmd/testnet.go +++ b/cmd/babylond/cmd/testnet.go @@ -8,25 +8,24 @@ import ( "errors" "fmt" appparams "github.com/babylonchain/babylon/app/params" + txformat "github.com/babylonchain/babylon/btctxformatter" + bbn "github.com/babylonchain/babylon/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "net" "os" "path/filepath" "github.com/babylonchain/babylon/app" - txformat "github.com/babylonchain/babylon/btctxformatter" "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/babylonchain/babylon/privval" "github.com/babylonchain/babylon/testutil/datagen" - bbn "github.com/babylonchain/babylon/types" checkpointingtypes "github.com/babylonchain/babylon/x/checkpointing/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/spf13/cobra" tmconfig "github.com/tendermint/tendermint/config" tmos "github.com/tendermint/tendermint/libs/os" - tmrand "github.com/tendermint/tendermint/libs/rand" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" @@ -84,38 +83,30 @@ Example: serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config + genesisCliArgs := parseGenesisFlags(cmd) outputDir, _ := cmd.Flags().GetString(flagOutputDir) keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - chainID, _ := cmd.Flags().GetString(flags.FlagChainID) minGasPrices, _ := cmd.Flags().GetString(server.FlagMinGasPrices) nodeDirPrefix, _ := cmd.Flags().GetString(flagNodeDirPrefix) nodeDaemonHome, _ := cmd.Flags().GetString(flagNodeDaemonHome) startingIPAddress, _ := cmd.Flags().GetString(flagStartingIPAddress) numValidators, _ := cmd.Flags().GetInt(flagNumValidators) algo, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm) - // staking args - maxActiveValidators, _ := cmd.Flags().GetUint32(flagMaxActiveValidators) - // btccheckpoint args btcNetwork, _ := cmd.Flags().GetString(flagBtcNetwork) btcCheckpointTag, _ := cmd.Flags().GetString(flagBtcCheckpointTag) - btcConfirmationDepth, _ := cmd.Flags().GetUint64(flagBtcConfirmationDepth) - btcFinalizationTimeout, _ := cmd.Flags().GetUint64(flagBtcFinalizationTimeout) - // epoching args - epochInterval, _ := cmd.Flags().GetUint64(flagEpochInterval) - // btclightclient args - baseBtcHeaderHex, _ := cmd.Flags().GetString(flagBaseBtcHeaderHex) - baseBtcHeaderHeight, err := cmd.Flags().GetUint64(flagBaseBtcHeaderHeight) additionalAccount, _ := cmd.Flags().GetBool(flagAdditionalSenderAccount) if err != nil { return errors.New("base Bitcoin header height should be a uint64") } - genesisParams := TestnetGenesisParams(maxActiveValidators, btcConfirmationDepth, - btcFinalizationTimeout, epochInterval, baseBtcHeaderHex, baseBtcHeaderHeight) + genesisParams := TestnetGenesisParams(genesisCliArgs.MaxActiveValidators, + genesisCliArgs.BtcConfirmationDepth, genesisCliArgs.BtcFinalizationTimeout, + genesisCliArgs.EpochInterval, genesisCliArgs.BaseBtcHeaderHex, + genesisCliArgs.BaseBtcHeaderHeight) return InitTestnet( - clientCtx, cmd, config, mbm, genBalIterator, outputDir, chainID, minGasPrices, + clientCtx, cmd, config, mbm, genBalIterator, outputDir, genesisCliArgs.ChainID, minGasPrices, nodeDirPrefix, nodeDaemonHome, startingIPAddress, keyringBackend, algo, numValidators, btcNetwork, btcCheckpointTag, additionalAccount, genesisParams, ) @@ -127,23 +118,13 @@ Example: cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix the directory name for each node with (node results in node0, node1, ...)") cmd.Flags().String(flagNodeDaemonHome, "babylond", "Home directory of the node's daemon configuration") cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") - cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") cmd.Flags().String(server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", appparams.BaseCoinUnit), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.001bbn)") cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") cmd.Flags().String(flags.FlagKeyAlgorithm, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for") - // btccheckpoint args cmd.Flags().String(flagBtcNetwork, string(bbn.BtcSimnet), "Bitcoin network to use. Available networks: simnet, testnet, mainnet") cmd.Flags().String(flagBtcCheckpointTag, string(txformat.DefaultTestTagStr), "Tag to use for Bitcoin checkpoints.") - cmd.Flags().Uint64(flagBtcConfirmationDepth, 6, "Confirmation depth for Bitcoin headers.") - cmd.Flags().Uint64(flagBtcFinalizationTimeout, 20, "Finalization timeout for Bitcoin headers.") - // epoch args - cmd.Flags().Uint64(flagEpochInterval, 10, "Number of blocks between epochs. Must be more than 0.") - // btclightclient args - // Simnet genesis header - cmd.Flags().String(flagBaseBtcHeaderHex, "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a45068653ffff7f2002000000", "Hex of the base Bitcoin header.") - cmd.Flags().Uint64(flagBaseBtcHeaderHeight, 0, "Height of the base Bitcoin header.") - cmd.Flags().Uint32(flagMaxActiveValidators, 10, "Maximum number of validators.") cmd.Flags().Bool(flagAdditionalSenderAccount, false, "If there should be additional pre funded account per validator") + addGenesisFlags(cmd) return cmd } @@ -172,10 +153,6 @@ func InitTestnet( genesisParams GenesisParams, ) error { - if chainID == "" { - chainID = "chain-" + tmrand.NewRand().Str(6) - } - nodeIDs := make([]string, numValidators) valKeys := make([]*privval.ValidatorKeys, numValidators) @@ -413,7 +390,7 @@ func initGenFiles( // set the bls keys for the checkpointing module genesisParams.CheckpointingGenKeys = genKeys - appGenState, err = PrepareGenesis(clientCtx, appGenState, genesisParams) + appGenState, _, err = PrepareGenesis(clientCtx, appGenState, &types.GenesisDoc{}, genesisParams, chainID) if err != nil { return err }