feat(hubl): support keyring (#17107)
This commit is contained in:
parent
2f8247d2d5
commit
7c10b2482c
@ -90,7 +90,7 @@ modules:
|
||||
"@type": cosmos.staking.module.v1.Module
|
||||
- name: tx
|
||||
config:
|
||||
"@type": cosmos.tx.module.v1.Module
|
||||
"@type": cosmos.tx.config.v1.Config
|
||||
```
|
||||
|
||||
A more complete example of `app.yaml` can be found [here](https://github.com/cosmos/cosmos-sdk/blob/91b1d83f1339e235a1dfa929ecc00084101a19e3/simapp/app.yaml).
|
||||
|
||||
@ -7,7 +7,7 @@ require (
|
||||
cosmossdk.io/client/v2 v2.0.0-20230815130322-dded2e9921f0
|
||||
cosmossdk.io/errors v1.0.0
|
||||
github.com/cockroachdb/errors v1.10.0
|
||||
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230815152400-f42d52f7e531
|
||||
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230823104347-c6b0bb62ac70
|
||||
github.com/manifoldco/promptui v0.9.0
|
||||
github.com/pelletier/go-toml/v2 v2.0.9
|
||||
github.com/spf13/cobra v1.7.0
|
||||
|
||||
@ -184,8 +184,8 @@ github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0
|
||||
github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U=
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o=
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I=
|
||||
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230815152400-f42d52f7e531 h1:wMqsKQzHof2ikpTlM5O1PZG4yr+15am+0ROtD/5wJLA=
|
||||
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230815152400-f42d52f7e531/go.mod h1:yQzBSxaplSkNZd34HOEqF4NhOHikbpFwWhWAQSteXrw=
|
||||
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230823104347-c6b0bb62ac70 h1:sK7w1WJAThRUXXtnpn7B8dBoSG8yFbYeuXNC+S69ANI=
|
||||
github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230823104347-c6b0bb62ac70/go.mod h1:lUps0DsgRmykXPyjoEBIkJa0Ybq666DFdubg6AB+WCg=
|
||||
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
|
||||
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
|
||||
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
|
||||
"cosmossdk.io/errors"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Chains map[string]*ChainConfig `toml:"chains"`
|
||||
}
|
||||
|
||||
type ChainConfig struct {
|
||||
GRPCEndpoints []GRPCEndpoint `toml:"trusted-grpc-endpoints"`
|
||||
Bech32Prefix string `toml:"bech32-prefix"`
|
||||
}
|
||||
|
||||
type GRPCEndpoint struct {
|
||||
Endpoint string `toml:"endpoint"`
|
||||
Insecure bool `toml:"insecure"`
|
||||
}
|
||||
|
||||
func LoadConfig(configDir string) (*Config, error) {
|
||||
configPath := configFilename(configDir)
|
||||
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
return &Config{Chains: map[string]*ChainConfig{}}, nil
|
||||
}
|
||||
|
||||
bz, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't read config file: %s", configPath)
|
||||
}
|
||||
|
||||
config := &Config{}
|
||||
if err = toml.Unmarshal(bz, config); err != nil {
|
||||
return nil, errors.Wrapf(err, "can't load config file: %s", configPath)
|
||||
}
|
||||
|
||||
return config, err
|
||||
}
|
||||
|
||||
func SaveConfig(configDir string, config *Config) error {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := toml.NewEncoder(buf)
|
||||
if err := enc.Encode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(configDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configPath := configFilename(configDir)
|
||||
if err := os.WriteFile(configPath, buf.Bytes(), 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func configFilename(configDir string) string {
|
||||
return path.Join(configDir, "config.toml")
|
||||
}
|
||||
108
tools/hubl/internal/config/config.go
Normal file
108
tools/hubl/internal/config/config.go
Normal file
@ -0,0 +1,108 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
|
||||
"cosmossdk.io/errors"
|
||||
"cosmossdk.io/tools/hubl/internal/flags"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultConfigDirName = ".hubl"
|
||||
GlobalKeyringDirName = "global"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Chains map[string]*ChainConfig `toml:"chains"`
|
||||
KeyringBackend string `toml:"keyring-backend"`
|
||||
}
|
||||
|
||||
type ChainConfig struct {
|
||||
GRPCEndpoints []GRPCEndpoint `toml:"trusted-grpc-endpoints"`
|
||||
AddressPrefix string `toml:"address-prefix"`
|
||||
KeyringBackend string `toml:"keyring-backend"`
|
||||
}
|
||||
|
||||
type GRPCEndpoint struct {
|
||||
Endpoint string `toml:"endpoint"`
|
||||
Insecure bool `toml:"insecure"`
|
||||
}
|
||||
|
||||
var EmptyConfig = &Config{
|
||||
Chains: map[string]*ChainConfig{},
|
||||
KeyringBackend: flags.DefaultKeyringBackend,
|
||||
}
|
||||
|
||||
func (cfg *Config) GetKeyringBackend(chainName string) (string, error) {
|
||||
if chainName == GlobalKeyringDirName {
|
||||
return cfg.KeyringBackend, nil
|
||||
} else {
|
||||
chainCfg, ok := cfg.Chains[chainName]
|
||||
if ok {
|
||||
return chainCfg.KeyringBackend, nil
|
||||
}
|
||||
}
|
||||
|
||||
return flags.DefaultKeyringBackend, nil
|
||||
}
|
||||
|
||||
func GetConfigDir() (string, error) {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
configDir := path.Join(homeDir, DefaultConfigDirName)
|
||||
if _, err := os.Stat(configDir); os.IsNotExist(err) {
|
||||
return configDir, os.MkdirAll(configDir, 0o750)
|
||||
}
|
||||
|
||||
return configDir, nil
|
||||
}
|
||||
|
||||
func Load(configDir string) (*Config, error) {
|
||||
configPath := configFilename(configDir)
|
||||
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
return EmptyConfig, nil
|
||||
}
|
||||
|
||||
bz, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't read config file: %s", configPath)
|
||||
}
|
||||
|
||||
config := &Config{}
|
||||
if err = toml.Unmarshal(bz, config); err != nil {
|
||||
return nil, errors.Wrapf(err, "can't load config file: %s", configPath)
|
||||
}
|
||||
|
||||
return config, err
|
||||
}
|
||||
|
||||
func Save(configDir string, config *Config) error {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := toml.NewEncoder(buf)
|
||||
if err := enc.Encode(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(configDir, 0o750); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configPath := configFilename(configDir)
|
||||
if err := os.WriteFile(configPath, buf.Bytes(), 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func configFilename(configDir string) string {
|
||||
return path.Join(configDir, "config.toml")
|
||||
}
|
||||
18
tools/hubl/internal/flags/flags.go
Normal file
18
tools/hubl/internal/flags/flags.go
Normal file
@ -0,0 +1,18 @@
|
||||
package flags
|
||||
|
||||
const (
|
||||
FlagInsecure = "insecure"
|
||||
FlagUpdate = "update"
|
||||
FlagConfig = "config"
|
||||
FlagLong = "long"
|
||||
FlagOutput = "output"
|
||||
|
||||
FlagKeyringBackend = "keyring-backend"
|
||||
)
|
||||
|
||||
const (
|
||||
OutputFormatText = "text"
|
||||
OutputFormatJSON = "json"
|
||||
|
||||
DefaultKeyringBackend = "os"
|
||||
)
|
||||
109
tools/hubl/internal/keyring.go
Normal file
109
tools/hubl/internal/keyring.go
Normal file
@ -0,0 +1,109 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
_ "cosmossdk.io/api/cosmos/crypto/ed25519"
|
||||
_ "cosmossdk.io/api/cosmos/crypto/secp256k1"
|
||||
_ "cosmossdk.io/api/cosmos/crypto/secp256r1"
|
||||
"cosmossdk.io/tools/hubl/internal/config"
|
||||
"cosmossdk.io/tools/hubl/internal/flags"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
)
|
||||
|
||||
func KeyringCmd(chainName string) *cobra.Command {
|
||||
shortDesc := fmt.Sprintf("Keyring management for %s", chainName)
|
||||
if chainName == "" {
|
||||
chainName = config.GlobalKeyringDirName
|
||||
shortDesc = "Global keyring management for Hubl"
|
||||
}
|
||||
|
||||
keyringCmd := &cobra.Command{
|
||||
Use: "keys",
|
||||
Short: shortDesc,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
registry := codectypes.NewInterfaceRegistry()
|
||||
cryptocodec.RegisterInterfaces(registry)
|
||||
cdc := codec.NewProtoCodec(registry)
|
||||
|
||||
configDir, err := config.GetConfigDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfg, err := config.Load(configDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
backend, err := cfg.GetKeyringBackend(chainName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if changed := cmd.Flags().Changed(flags.FlagKeyringBackend); changed {
|
||||
b, err := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
backend = b
|
||||
}
|
||||
|
||||
keyringDir := path.Join(configDir, "keyring", chainName)
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
kr, err := keyring.New(chainName, backend, keyringDir, inBuf, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addressCodec, validatorAddressCodec, consensusAddressCodec, err := getAddressCodecFromConfig(cfg, chainName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientCtx := client.Context{}.
|
||||
WithKeyring(kr).
|
||||
WithCodec(cdc).
|
||||
WithKeyringDir(keyringDir).
|
||||
WithInput(inBuf).
|
||||
WithAddressCodec(addressCodec).
|
||||
WithValidatorAddressCodec(validatorAddressCodec).
|
||||
WithConsensusAddressCodec(consensusAddressCodec)
|
||||
|
||||
cmd.SetContext(context.WithValue(context.Background(), client.ClientContextKey, &clientCtx))
|
||||
if err := client.SetCmdClientContext(cmd, clientCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
keyringCmd.AddCommand(
|
||||
keys.AddKeyCommand(),
|
||||
keys.DeleteKeyCommand(),
|
||||
keys.ExportKeyCommand(),
|
||||
keys.ImportKeyCommand(),
|
||||
keys.ImportKeyHexCommand(),
|
||||
keys.ListKeysCmd(),
|
||||
keys.ParseKeyStringCommand(),
|
||||
keys.RenameKeyCommand(),
|
||||
keys.ShowKeysCmd(),
|
||||
)
|
||||
keyringCmd.PersistentFlags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test|memory)")
|
||||
keyringCmd.PersistentFlags().String(flags.FlagOutput, flags.OutputFormatText, "Output format (text|json)")
|
||||
|
||||
return keyringCmd
|
||||
}
|
||||
@ -20,23 +20,22 @@ import (
|
||||
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
|
||||
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
|
||||
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
|
||||
"cosmossdk.io/tools/hubl/internal/config"
|
||||
)
|
||||
|
||||
const DefaultConfigDirName = ".hubl"
|
||||
|
||||
type ChainInfo struct {
|
||||
client *grpc.ClientConn
|
||||
|
||||
Context context.Context
|
||||
ConfigDir string
|
||||
Chain string
|
||||
Config *ChainConfig
|
||||
Config *config.ChainConfig
|
||||
|
||||
ProtoFiles *protoregistry.Files
|
||||
ModuleOptions map[string]*autocliv1.ModuleOptions
|
||||
}
|
||||
|
||||
func NewChainInfo(configDir, chain string, config *ChainConfig) *ChainInfo {
|
||||
func NewChainInfo(configDir, chain string, config *config.ChainConfig) *ChainInfo {
|
||||
return &ChainInfo{
|
||||
Context: context.Background(),
|
||||
Config: config,
|
||||
@ -47,7 +46,7 @@ func NewChainInfo(configDir, chain string, config *ChainConfig) *ChainInfo {
|
||||
|
||||
func (c *ChainInfo) getCacheDir() (string, error) {
|
||||
cacheDir := path.Join(c.ConfigDir, "cache")
|
||||
return cacheDir, os.MkdirAll(cacheDir, 0o755)
|
||||
return cacheDir, os.MkdirAll(cacheDir, 0o750)
|
||||
}
|
||||
|
||||
func (c *ChainInfo) fdsCacheFilename() (string, error) {
|
||||
|
||||
@ -11,11 +11,9 @@ import (
|
||||
)
|
||||
|
||||
type ChainRegistryEntry struct {
|
||||
APIs ChainRegistryAPIs `json:"apis"`
|
||||
}
|
||||
|
||||
type ChainRegistryAPIs struct {
|
||||
GRPC []*APIEntry `json:"grpc"`
|
||||
APIs struct {
|
||||
GRPC []*APIEntry `json:"grpc"`
|
||||
} `json:"apis"`
|
||||
}
|
||||
|
||||
type APIEntry struct {
|
||||
|
||||
@ -3,8 +3,6 @@ package internal
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@ -15,74 +13,33 @@ import (
|
||||
|
||||
"cosmossdk.io/client/v2/autocli"
|
||||
"cosmossdk.io/client/v2/autocli/flag"
|
||||
"cosmossdk.io/tools/hubl/internal/config"
|
||||
"cosmossdk.io/tools/hubl/internal/flags"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
|
||||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
)
|
||||
|
||||
var (
|
||||
flagInsecure = "insecure"
|
||||
flagUpdate = "update"
|
||||
flagConfig = "config"
|
||||
flagLong = "long"
|
||||
)
|
||||
|
||||
func RootCommand() (*cobra.Command, error) {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
configDir := path.Join(homeDir, DefaultConfigDirName)
|
||||
config, err := LoadConfig(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "hubl",
|
||||
Short: "Hubl is a CLI for interacting with Cosmos SDK chains",
|
||||
Long: "Hubl is a CLI for interacting with Cosmos SDK chains",
|
||||
}
|
||||
|
||||
// add commands
|
||||
commands, err := RemoteCommand(config, configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commands = append(
|
||||
commands,
|
||||
InitCommand(config, configDir),
|
||||
VersionCmd(),
|
||||
)
|
||||
|
||||
cmd.AddCommand(commands...)
|
||||
return cmd, nil
|
||||
}
|
||||
|
||||
func InitCommand(config *Config, configDir string) *cobra.Command {
|
||||
func InitCmd(config *config.Config, configDir string) *cobra.Command {
|
||||
var insecure bool
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "init [foochain]",
|
||||
Short: "Initialize a new chain",
|
||||
Long: `To configure a new chain just run this command using the --init flag and the name of the chain as it's listed in the chain registry (https://github.com/cosmos/chain-registry).
|
||||
Long: `To configure a new chain, run this command using the --init flag and the name of the chain as it's listed in the chain registry (https://github.com/cosmos/chain-registry).
|
||||
If the chain is not listed in the chain registry, you can use any unique name.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
chainName := strings.ToLower(args[0])
|
||||
|
||||
return reconfigure(cmd, config, configDir, chainName)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().BoolVar(&insecure, flagInsecure, false, "allow setting up insecure gRPC connection")
|
||||
cmd.Flags().BoolVar(&insecure, flags.FlagInsecure, false, "allow setting up insecure gRPC connection")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RemoteCommand(config *Config, configDir string) ([]*cobra.Command, error) {
|
||||
func RemoteCommand(config *config.Config, configDir string) ([]*cobra.Command, error) {
|
||||
commands := []*cobra.Command{}
|
||||
|
||||
for chain, chainConfig := range config.Chains {
|
||||
@ -103,11 +60,16 @@ func RemoteCommand(config *Config, configDir string) ([]*cobra.Command, error) {
|
||||
ModuleOptions: chainInfo.ModuleOptions,
|
||||
}
|
||||
|
||||
addressCodec, validatorAddressCodec, consensusAddressCodec, err := getAddressCodecFromConfig(config, chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
builder := &autocli.Builder{
|
||||
Builder: flag.Builder{
|
||||
AddressCodec: addresscodec.NewBech32Codec(chainConfig.Bech32Prefix),
|
||||
ValidatorAddressCodec: addresscodec.NewBech32Codec(fmt.Sprintf("%svaloper", chainConfig.Bech32Prefix)),
|
||||
ConsensusAddressCodec: addresscodec.NewBech32Codec(fmt.Sprintf("%svalcons", chainConfig.Bech32Prefix)),
|
||||
AddressCodec: addressCodec,
|
||||
ValidatorAddressCodec: validatorAddressCodec,
|
||||
ConsensusAddressCodec: consensusAddressCodec,
|
||||
TypeResolver: &dynamicTypeResolver{chainInfo},
|
||||
FileResolver: chainInfo.ProtoFiles,
|
||||
},
|
||||
@ -132,17 +94,20 @@ func RemoteCommand(config *Config, configDir string) ([]*cobra.Command, error) {
|
||||
case reconfig:
|
||||
return reconfigure(cmd, config, configDir, chain)
|
||||
case update:
|
||||
cmd.Printf("Updating autocli data for %s\n", chain)
|
||||
cmd.Printf("Updating AutoCLI data for %s\n", chain)
|
||||
return chainInfo.Load(true)
|
||||
default:
|
||||
return cmd.Help()
|
||||
}
|
||||
},
|
||||
}
|
||||
chainCmd.Flags().BoolVar(&update, flagUpdate, false, "update the CLI commands for the selected chain (should be used after every chain upgrade)")
|
||||
chainCmd.Flags().BoolVar(&reconfig, flagConfig, false, "re-configure the selected chain (allows choosing a new gRPC endpoint and refreshes data")
|
||||
chainCmd.Flags().BoolVar(&insecure, flagInsecure, false, "allow re-configuring the selected chain using an insecure gRPC connection")
|
||||
chainCmd.PersistentFlags().StringVar(&output, flags.FlagOutput, flags.OutputFormatJSON, "output format (text|json)")
|
||||
chainCmd.Flags().BoolVar(&update, flags.FlagUpdate, false, "update the CLI commands for the selected chain (should be used after every chain upgrade)")
|
||||
chainCmd.Flags().BoolVar(&reconfig, flags.FlagConfig, false, "re-configure the selected chain (allows choosing a new gRPC endpoint and refreshes data")
|
||||
chainCmd.Flags().BoolVar(&insecure, flags.FlagInsecure, false, "allow re-configuring the selected chain using an insecure gRPC connection")
|
||||
chainCmd.PersistentFlags().StringVar(&output, flags.FlagOutput, flags.OutputFormatJSON, fmt.Sprintf("output format (%s|%s)", flags.OutputFormatText, flags.OutputFormatJSON))
|
||||
|
||||
// add chain specific keyring
|
||||
chainCmd.AddCommand(KeyringCmd(chainInfo.Chain))
|
||||
|
||||
if err := appOpts.EnhanceRootCommandWithBuilder(chainCmd, builder); err != nil {
|
||||
return nil, err
|
||||
@ -154,25 +119,24 @@ func RemoteCommand(config *Config, configDir string) ([]*cobra.Command, error) {
|
||||
return commands, nil
|
||||
}
|
||||
|
||||
func RemoteErrorCommand(config *Config, configDir, chain string, chainConfig *ChainConfig, err error) *cobra.Command {
|
||||
func RemoteErrorCommand(cfg *config.Config, configDir, chain string, chainConfig *config.ChainConfig, err error) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: chain,
|
||||
Short: "Unable to load data",
|
||||
Long: "Unable to load data, reconfiguration needed.",
|
||||
Short: fmt.Sprintf("Unable to load %s data", chain),
|
||||
Long: fmt.Sprintf("Unable to load %s data, reconfiguration needed.", chain),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cmd.Printf("Error loading chain data for %s: %+v\n", chain, err)
|
||||
|
||||
return reconfigure(cmd, config, configDir, chain)
|
||||
return reconfigure(cmd, cfg, configDir, chain)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Bool(flagInsecure, chainConfig.GRPCEndpoints[0].Insecure, "allow setting up insecure gRPC connection")
|
||||
cmd.Flags().Bool(flags.FlagInsecure, chainConfig.GRPCEndpoints[0].Insecure, "allow setting up insecure gRPC connection")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func reconfigure(cmd *cobra.Command, config *Config, configDir, chain string) error {
|
||||
insecure, _ := cmd.Flags().GetBool(flagInsecure)
|
||||
func reconfigure(cmd *cobra.Command, cfg *config.Config, configDir, chain string) error {
|
||||
insecure, _ := cmd.Flags().GetBool(flags.FlagInsecure)
|
||||
|
||||
cmd.Printf("Configuring %s\n", chain)
|
||||
endpoint, err := SelectGRPCEndpoints(chain)
|
||||
@ -181,8 +145,8 @@ func reconfigure(cmd *cobra.Command, config *Config, configDir, chain string) er
|
||||
}
|
||||
|
||||
cmd.Printf("%s endpoint selected\n", endpoint)
|
||||
chainConfig := &ChainConfig{
|
||||
GRPCEndpoints: []GRPCEndpoint{
|
||||
chainConfig := &config.ChainConfig{
|
||||
GRPCEndpoints: []config.GRPCEndpoint{
|
||||
{
|
||||
Endpoint: endpoint,
|
||||
Insecure: insecure,
|
||||
@ -205,10 +169,11 @@ func reconfigure(cmd *cobra.Command, config *Config, configDir, chain string) er
|
||||
return err
|
||||
}
|
||||
|
||||
chainConfig.Bech32Prefix = addressPrefix
|
||||
config.Chains[chain] = chainConfig
|
||||
chainConfig.KeyringBackend = flags.DefaultKeyringBackend
|
||||
chainConfig.AddressPrefix = addressPrefix
|
||||
cfg.Chains[chain] = chainConfig
|
||||
|
||||
if err := SaveConfig(configDir, config); err != nil {
|
||||
if err := config.Save(configDir, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
39
tools/hubl/internal/root.go
Normal file
39
tools/hubl/internal/root.go
Normal file
@ -0,0 +1,39 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"cosmossdk.io/tools/hubl/internal/config"
|
||||
)
|
||||
|
||||
func RootCommand() (*cobra.Command, error) {
|
||||
configDir, err := config.GetConfigDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg, err := config.Load(configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "hubl",
|
||||
Short: "Hubl is a CLI for interacting with Cosmos SDK chains",
|
||||
}
|
||||
|
||||
// add commands
|
||||
commands, err := RemoteCommand(cfg, configDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commands = append(
|
||||
commands,
|
||||
InitCmd(cfg, configDir),
|
||||
KeyringCmd(""),
|
||||
VersionCmd(),
|
||||
)
|
||||
|
||||
cmd.AddCommand(commands...)
|
||||
return cmd, nil
|
||||
}
|
||||
29
tools/hubl/internal/util.go
Normal file
29
tools/hubl/internal/util.go
Normal file
@ -0,0 +1,29 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/tools/hubl/internal/config"
|
||||
|
||||
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
|
||||
)
|
||||
|
||||
// getAddressCodecFromConfig returns the address codecs for the given chain name
|
||||
func getAddressCodecFromConfig(cfg *config.Config, chainName string) (address.Codec, address.Codec, address.Codec, error) {
|
||||
addressPrefix := "cosmos"
|
||||
|
||||
if chainName != config.GlobalKeyringDirName {
|
||||
chainConfig, ok := cfg.Chains[chainName]
|
||||
if !ok {
|
||||
return nil, nil, nil, fmt.Errorf("chain %s not found in config", chainName)
|
||||
}
|
||||
|
||||
addressPrefix = chainConfig.AddressPrefix
|
||||
}
|
||||
|
||||
return addresscodec.NewBech32Codec(addressPrefix),
|
||||
addresscodec.NewBech32Codec(fmt.Sprintf("%svaloper", addressPrefix)),
|
||||
addresscodec.NewBech32Codec(fmt.Sprintf("%svalcons", addressPrefix)),
|
||||
nil
|
||||
}
|
||||
@ -6,6 +6,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"cosmossdk.io/tools/hubl/internal/flags"
|
||||
)
|
||||
|
||||
func VersionCmd() *cobra.Command {
|
||||
@ -34,7 +36,7 @@ func VersionCmd() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
versionCmd.Flags().BoolVar(&long, flagLong, false, "display long version information")
|
||||
versionCmd.Flags().BoolVar(&long, flags.FlagLong, false, "display long version information")
|
||||
|
||||
return versionCmd
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user