diff --git a/local-interchain/chains/hub.yml b/local-interchain/chains/hub.yml new file mode 100644 index 000000000..8587fd593 --- /dev/null +++ b/local-interchain/chains/hub.yml @@ -0,0 +1,33 @@ +--- +chains: +- name: gaia + chain_id: localcosmos-1 + denom: uatom + binary: gaiad + bech32_prefix: cosmos + docker_image: + version: v10.0.1 + gas_prices: 0%DENOM% + chain_type: cosmos + coin_type: 118 + trusting_period: 112h + gas_adjustment: 2 + number_vals: 1 + number_node: 0 + debugging: true + block_time: 500ms + genesis: + modify: + - key: app_state.gov.voting_params.voting_period + value: 15s + - key: app_state.gov.deposit_params.max_deposit_period + value: 15s + - key: app_state.gov.deposit_params.min_deposit.0.denom + value: uatom + accounts: + - name: acc0 + address: cosmos1hj5fveer5cjtn4wd6wstzugjfdxzl0xpxvjjvr + amount: 10000000000%DENOM% + mnemonic: decorate bright ozone fork gallery riot bus exhaust worth way bone + indoor calm squirrel merry zero scheme cotton until shop any excess stage + laundry diff --git a/local-interchain/cmd/local-ic/chains.go b/local-interchain/cmd/local-ic/chains.go index 6b52894b3..acaa99d2d 100644 --- a/local-interchain/cmd/local-ic/chains.go +++ b/local-interchain/cmd/local-ic/chains.go @@ -10,11 +10,11 @@ import ( ) type chains struct { - Configs []string `json:"chain_configs"` + Configs []string `json:"chain_configs" yaml:"chain_configs"` } var chainsCmd = &cobra.Command{ - Use: "chains [config.json]", + Use: "chains [config.(json|yaml)]", Short: "List all current chains or outputs a current config information", Args: cobra.RangeArgs(0, 1), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { diff --git a/local-interchain/cmd/local-ic/interaction.go b/local-interchain/cmd/local-ic/interaction.go index 547bc3cb7..92009d396 100644 --- a/local-interchain/cmd/local-ic/interaction.go +++ b/local-interchain/cmd/local-ic/interaction.go @@ -14,19 +14,22 @@ import ( const ( FlagAPIEndpoint = "api-endpoint" + FlagNodeIndex = "node-index" ) func init() { interactCmd.Flags().String(FlagAPIAddressOverride, "http://127.0.0.1:8080", "override the default API address") + interactCmd.Flags().String(FlagAuthKey, "a", "auth key to use") + interactCmd.Flags().IntP(FlagNodeIndex, "n", 0, "node index to interact with") } var interactCmd = &cobra.Command{ Use: "interact [chain_id] [interaction] [arguments...]", Short: "Interact with a node", - Example: `local-ic interact localcosmos-1 bin 'status --node=%RPC%' --api-endpoint=http://127.0.0.1:8080 -local-ic interact localcosmos-1 query bank balances cosmos1hj5fveer5cjtn4wd6wstzugjfdxzl0xpxvjjvr -local-ic interact localcosmos-1 get_channels -local-ic interact localcosmos-1 relayer-exec rly q channels localcosmos-1 + Example: ` local-ic interact localcosmos-1 bin 'status --node=%RPC%' --api-endpoint=http://127.0.0.1:8080 + local-ic interact localcosmos-1 query bank balances cosmos1hj5fveer5cjtn4wd6wstzugjfdxzl0xpxvjjvr + local-ic interact localcosmos-1 get_channels + local-ic interact localcosmos-1 relayer-exec rly q channels localcosmos-1 `, Args: cobra.MinimumNArgs(2), Aliases: []string{"i"}, @@ -35,7 +38,7 @@ local-ic interact localcosmos-1 relayer-exec rly q channels localcosmos-1 }, Run: func(cmd *cobra.Command, args []string) { - ah := handlers.ActionHandler{ + ah := &handlers.ActionHandler{ ChainId: args[0], Action: args[1], } @@ -44,14 +47,30 @@ local-ic interact localcosmos-1 relayer-exec rly q channels localcosmos-1 ah.Cmd = strings.Join(args[2:], " ") } - apiAddr, _ := cmd.Flags().GetString(FlagAPIAddressOverride) + authKey, err := cmd.Flags().GetString(FlagAuthKey) + if err != nil { + panic(err) + } + + nodeIdx, err := cmd.Flags().GetInt(FlagNodeIndex) + if err != nil { + panic(err) + } + + ah.AuthKey = authKey + ah.NodeIndex = nodeIdx + + apiAddr, err := cmd.Flags().GetString(FlagAPIAddressOverride) + if err != nil { + panic(err) + } res := makeHttpReq(apiAddr, ah) fmt.Println(res) }, } -func makeHttpReq(apiEndpoint string, ah handlers.ActionHandler) string { +func makeHttpReq(apiEndpoint string, ah *handlers.ActionHandler) string { client := &http.Client{} // curl -X POST -H "Content-Type: application/json" -d '{ diff --git a/local-interchain/cmd/local-ic/new_chain.go b/local-interchain/cmd/local-ic/new_chain.go index 62c56132d..9740c6a2c 100644 --- a/local-interchain/cmd/local-ic/new_chain.go +++ b/local-interchain/cmd/local-ic/new_chain.go @@ -21,7 +21,7 @@ import ( var reader = bufio.NewReader(os.Stdin) type Chains struct { - Chains []ictypes.Chain `json:"chains"` + Chains []ictypes.Chain `json:"chains" yaml:"chains"` } var newChainCmd = &cobra.Command{ diff --git a/local-interchain/cmd/local-ic/start_chain.go b/local-interchain/cmd/local-ic/start_chain.go index e7255ca7c..6dce8a707 100644 --- a/local-interchain/cmd/local-ic/start_chain.go +++ b/local-interchain/cmd/local-ic/start_chain.go @@ -1,6 +1,8 @@ package main import ( + "fmt" + "os" "path" "path/filepath" "strings" @@ -57,13 +59,14 @@ local-ic start https://pastebin.com/raw/Ummk4DTM // last part of the URL to be the test name configPath = configPath[strings.LastIndex(configPath, "/")+1:] } else { + configPath, err = GetConfigWithExtension(parentDir, configPath) + if err != nil { + panic(err) + } + config, err = interchain.LoadConfig(parentDir, configPath) if err != nil { - // try again with .json, then if it still fails - panic - config, err = interchain.LoadConfig(parentDir, configPath+".json") - if err != nil { - panic(err) - } + panic(err) } } @@ -94,6 +97,27 @@ local-ic start https://pastebin.com/raw/Ummk4DTM }, } +// GetConfigWithExtension returns the config with the file extension attached if one was not provided. +// If "hub" is passed it, it will search for hub.yaml, hub.yml, or hub.json. +// If an extension is already applied, it will use that. +func GetConfigWithExtension(parentDir, config string) (string, error) { + if path.Ext(config) != "" { + return config, nil + } + + extensions := []string{".yaml", ".yml", ".json"} + for _, ext := range extensions { + fp := path.Join(parentDir, interchain.ChainDir, config+ext) + if _, err := os.Stat(fp); err != nil { + continue + } + + return config + ext, nil + } + + return "", fmt.Errorf("could not find a file with an accepted extension: %s. (%+v)", config, extensions) +} + func init() { startCmd.Flags().String(FlagAPIAddressOverride, "127.0.0.1", "override the default API address") startCmd.Flags().Uint16(FlagAPIPortOverride, 8080, "override the default API port") diff --git a/local-interchain/interchain/config.go b/local-interchain/interchain/config.go index 0154de080..90cab1c5a 100644 --- a/local-interchain/interchain/config.go +++ b/local-interchain/interchain/config.go @@ -3,7 +3,7 @@ package interchain import ( "encoding/json" "fmt" - "io/ioutil" + "io" "log" "net/http" "os" @@ -14,6 +14,7 @@ import ( types "github.com/strangelove-ventures/localinterchain/interchain/types" "github.com/strangelove-ventures/localinterchain/interchain/util" + "gopkg.in/yaml.v3" "github.com/strangelove-ventures/interchaintest/v8" "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" @@ -21,6 +22,8 @@ import ( "github.com/strangelove-ventures/interchaintest/v8/testutil" ) +const ChainDir = "chains" + func LoadConfig(installDir, chainCfgFile string) (*types.Config, error) { var config types.Config @@ -29,18 +32,23 @@ func LoadConfig(installDir, chainCfgFile string) (*types.Config, error) { configFile = chainCfgFile } - // Chains Folder - chainsDir := filepath.Join(installDir, "chains") + // A nested "chains" dir is required within the parent you specify. + chainsDir := filepath.Join(installDir, ChainDir) cfgFilePath := filepath.Join(chainsDir, configFile) - bytes, err := os.ReadFile(cfgFilePath) + bz, err := os.ReadFile(cfgFilePath) if err != nil { return nil, err } - err = json.Unmarshal(bytes, &config) - if err != nil { - return nil, err + if strings.HasSuffix(chainCfgFile, ".json") { + if err = json.Unmarshal(bz, &config); err != nil { + return nil, fmt.Errorf("error unmarshalling json config: %w", err) + } + } else { + if err := yaml.Unmarshal(bz, &config); err != nil { + return nil, fmt.Errorf("error unmarshalling yaml config: %w", err) + } } log.Println("Using directory:", installDir) @@ -56,7 +64,7 @@ func LoadConfigFromURL(url string) (*types.Config, error) { } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Fatalln(err) } diff --git a/local-interchain/interchain/handlers/info.go b/local-interchain/interchain/handlers/info.go index cf458ab22..c410a1e3a 100644 --- a/local-interchain/interchain/handlers/info.go +++ b/local-interchain/interchain/handlers/info.go @@ -57,9 +57,9 @@ func NewInfo( } type GetInfo struct { - Logs types.MainLogs `json:"logs"` - Chains []types.Chain `json:"chains"` - Relay types.Relayer `json:"relayer"` + Logs types.MainLogs `json:"logs" yaml:"logs"` + Chains []types.Chain `json:"chains" yaml:"chains"` + Relay types.Relayer `json:"relayer" yaml:"relayer"` } func (i *info) GetInfo(w http.ResponseWriter, r *http.Request) { diff --git a/local-interchain/interchain/handlers/types.go b/local-interchain/interchain/handlers/types.go index 754404034..8889b241a 100644 --- a/local-interchain/interchain/handlers/types.go +++ b/local-interchain/interchain/handlers/types.go @@ -7,16 +7,16 @@ import ( ) type IbcChainConfigAlias struct { - Type string `json:"type"` - Name string `json:"name"` - ChainID string `json:"chain_id"` - Bin string `json:"bin"` - Bech32Prefix string `json:"bech32_prefix"` - Denom string `json:"denom"` - CoinType string `json:"coin_type"` - GasPrices string `json:"gas_prices"` - GasAdjustment float64 `json:"gas_adjustment"` - TrustingPeriod string `json:"trusting_period"` + Type string `json:"type" yaml:"type"` + Name string `json:"name" yaml:"name"` + ChainID string `json:"chain_id" yaml:"chain_id"` + Bin string `json:"bin" yaml:"bin"` + Bech32Prefix string `json:"bech32_prefix" yaml:"bech32_prefix"` + Denom string `json:"denom" yaml:"denom"` + CoinType string `json:"coin_type" yaml:"coin_type"` + GasPrices string `json:"gas_prices" yaml:"gas_prices"` + GasAdjustment float64 `json:"gas_adjustment" yaml:"gas_adjustment"` + TrustingPeriod string `json:"trusting_period" yaml:"trusting_period"` } func (c *IbcChainConfigAlias) Marshal() ([]byte, error) { diff --git a/local-interchain/interchain/router/router.go b/local-interchain/interchain/router/router.go index 7ababa8e7..96fe233b9 100644 --- a/local-interchain/interchain/router/router.go +++ b/local-interchain/interchain/router/router.go @@ -16,8 +16,8 @@ import ( ) type Route struct { - Path string `json:"path"` - Methods []string `json:"methods"` + Path string `json:"path" yaml:"path"` + Methods []string `json:"methods" yaml:"methods"` } func NewRouter( diff --git a/local-interchain/interchain/start.go b/local-interchain/interchain/start.go index aa0a55a78..99ecb4b60 100644 --- a/local-interchain/interchain/start.go +++ b/local-interchain/interchain/start.go @@ -6,6 +6,7 @@ import ( "log" "math" "net/http" + "path" "strings" "github.com/strangelove-ventures/interchaintest/v8" @@ -77,9 +78,9 @@ func StartChain(installDir, chainCfgFile string, ac *types.AppStartConfig) { // Create chain factory for all the chains cf := interchaintest.NewBuiltinChainFactory(logger, chainSpecs) - // Get chains from the chain factory - name := strings.ReplaceAll(chainCfgFile, ".json", "") + "ic" - chains, err := cf.Chains(name) + testName := GetTestName(chainCfgFile) + + chains, err := cf.Chains(testName) if err != nil { log.Fatal("cf.Chains", err) } @@ -90,7 +91,7 @@ func StartChain(installDir, chainCfgFile string, ac *types.AppStartConfig) { ic.AdditionalGenesisWallets = SetupGenesisWallets(config, chains) fakeT := FakeTesting{ - FakeName: name, + FakeName: testName, } // Base setup @@ -125,7 +126,7 @@ func StartChain(installDir, chainCfgFile string, ac *types.AppStartConfig) { // Build all chains & begin. err = ic.Build(ctx, eRep, interchaintest.InterchainBuildOptions{ - TestName: name, + TestName: testName, Client: client, NetworkID: network, SkipPathCreation: false, @@ -197,3 +198,13 @@ func StartChain(installDir, chainCfgFile string, ac *types.AppStartConfig) { log.Fatal("WaitForBlocks StartChain: ", err) } } + +func GetTestName(chainCfgFile string) string { + name := chainCfgFile + fExt := path.Ext(name) + if fExt != "" { + name = strings.ReplaceAll(chainCfgFile, fExt, "") + } + + return name + "ic" +} diff --git a/local-interchain/interchain/types/chain.go b/local-interchain/interchain/types/chain.go index 854e1ccff..785182d9e 100644 --- a/local-interchain/interchain/types/chain.go +++ b/local-interchain/interchain/types/chain.go @@ -8,40 +8,36 @@ import ( // ConfigFileOverrides overrides app configuration files. type ConfigFileOverrides struct { - File string `json:"file"` - Paths testutil.Toml `json:"paths"` + File string `json:"file" yaml:"file"` + Paths testutil.Toml `json:"paths" yaml:"paths"` } type Chain struct { // ibc chain config (optional) - ChainType string `json:"chain_type" validate:"min=1"` - CoinType int `json:"coin_type" validate:"gt=0"` - Binary string `json:"binary" validate:"min=1"` - Bech32Prefix string `json:"bech32_prefix" validate:"min=1"` - Denom string `json:"denom" validate:"min=1"` - TrustingPeriod string `json:"trusting_period"` - Debugging bool `json:"debugging"` - BlockTime string `json:"block_time"` - - HostPortOverride map[string]string `json:"host_port_override"` + ChainType string `json:"chain_type" yaml:"chain_type" validate:"min=1"` + CoinType int `json:"coin_type" yaml:"coin_type" validate:"gt=0"` + Binary string `json:"binary" yaml:"binary" validate:"min=1"` + Bech32Prefix string `json:"bech32_prefix" yaml:"bech32_prefix" validate:"min=1"` + Denom string `json:"denom" yaml:"denom" validate:"min=1"` + TrustingPeriod string `json:"trusting_period" yaml:"trusting_period"` + Debugging bool `json:"debugging" yaml:"debugging"` + BlockTime string `json:"block_time" yaml:"block_time"` + HostPortOverride map[string]string `json:"host_port_override" yaml:"host_port_override"` // Required - Name string `json:"name" validate:"min=1"` - ChainID string `json:"chain_id" validate:"min=3"` - - DockerImage DockerImage `json:"docker_image" validate:"url"` - - GasPrices string `json:"gas_prices"` - GasAdjustment float64 `json:"gas_adjustment"` - NumberVals int `json:"number_vals" validate:"gte=1"` - NumberNode int `json:"number_node"` - IBCPaths []string `json:"ibc_paths"` - Genesis Genesis `json:"genesis"` - - ConfigFileOverrides []ConfigFileOverrides `json:"config_file_overrides,omitempty"` + Name string `json:"name" yaml:"name" validate:"min=1"` + ChainID string `json:"chain_id" yaml:"chain_id" validate:"min=3"` + DockerImage DockerImage `json:"docker_image" yaml:"docker_image" validate:"url"` + GasPrices string `json:"gas_prices" yaml:"gas_prices"` + GasAdjustment float64 `json:"gas_adjustment" yaml:"gas_adjustment"` + NumberVals int `json:"number_vals" yaml:"number_vals" validate:"gte=1"` + NumberNode int `json:"number_node" yaml:"number_node"` + IBCPaths []string `json:"ibc_paths" yaml:"ibc_paths"` + Genesis Genesis `json:"genesis" yaml:"genesis"` + ConfigFileOverrides []ConfigFileOverrides `json:"config_file_overrides,omitempty" yaml:"config_file_overrides,omitempty"` // EVM - EVMLoadStatePath string `json:"evm_load_state_path,omitempty"` + EVMLoadStatePath string `json:"evm_load_state_path,omitempty" yaml:"evm_load_state_path,omitempty"` } func (chain *Chain) Validate() error { diff --git a/local-interchain/interchain/types/genesis.go b/local-interchain/interchain/types/genesis.go index 9a5332ada..5e6535d74 100644 --- a/local-interchain/interchain/types/genesis.go +++ b/local-interchain/interchain/types/genesis.go @@ -11,12 +11,11 @@ type GenesisAccount struct { type Genesis struct { // Only apart of my fork for now. - Modify []cosmos.GenesisKV `json:"modify"` // 'key' & 'val' in the config. + Modify []cosmos.GenesisKV `json:"modify" yaml:"modify"` // 'key' & 'val' in the config. - Accounts []GenesisAccount `json:"accounts"` + Accounts []GenesisAccount `json:"accounts" yaml:"accounts"` // A list of commands which run after chains are good to go. // May need to move out of genesis into its own section? Seems silly though. - StartupCommands []string `json:"startup_commands"` + StartupCommands []string `json:"startup_commands" yaml:"startup_commands"` } - diff --git a/local-interchain/interchain/types/logs.go b/local-interchain/interchain/types/logs.go index 3ca43fb31..b6732d5e0 100644 --- a/local-interchain/interchain/types/logs.go +++ b/local-interchain/interchain/types/logs.go @@ -1,17 +1,17 @@ package types type MainLogs struct { - StartTime uint64 `json:"start_time"` - Chains []LogOutput `json:"chains"` - Channels []IBCChannel `json:"ibc_channels"` + StartTime uint64 `json:"start_time" yaml:"start_time"` + Chains []LogOutput `json:"chains" yaml:"chains"` + Channels []IBCChannel `json:"ibc_channels" yaml:"ibc_channels"` } type LogOutput struct { - ChainID string `json:"chain_id"` - ChainName string `json:"chain_name"` - RPCAddress string `json:"rpc_address"` - RESTAddress string `json:"rest_address"` - GRPCAddress string `json:"grpc_address"` - P2PAddress string `json:"p2p_address"` - IBCPath []string `json:"ibc_paths"` + ChainID string `json:"chain_id" yaml:"chain_id"` + ChainName string `json:"chain_name" yaml:"chain_name"` + RPCAddress string `json:"rpc_address" yaml:"rpc_address"` + RESTAddress string `json:"rest_address" yaml:"rest_address"` + GRPCAddress string `json:"grpc_address" yaml:"grpc_address"` + P2PAddress string `json:"p2p_address" yaml:"p2p_address"` + IBCPath []string `json:"ibc_paths" yaml:"ibc_paths"` } diff --git a/local-interchain/interchain/types/types.go b/local-interchain/interchain/types/types.go index 333c72159..786bdcfe1 100644 --- a/local-interchain/interchain/types/types.go +++ b/local-interchain/interchain/types/types.go @@ -5,9 +5,9 @@ import ( ) type Config struct { - Chains []Chain `json:"chains"` - Relayer Relayer `json:"relayer"` - Server RestServer `json:"server"` + Chains []Chain `json:"chains" yaml:"chains"` + Relayer Relayer `json:"relayer" yaml:"relayer"` + Server RestServer `json:"server" yaml:"server"` } type AppStartConfig struct { @@ -21,22 +21,22 @@ type AppStartConfig struct { } type RestServer struct { - Host string `json:"host"` - Port string `json:"port"` + Host string `json:"host" yaml:"host"` + Port string `json:"port" yaml:"port"` } type DockerImage struct { - Repository string `json:"repository"` - Version string `json:"version"` - UidGid string `json:"uid_gid"` + Repository string `json:"repository" yaml:"repository"` + Version string `json:"version" yaml:"version"` + UidGid string `json:"uid_gid" yaml:"uid_gid"` } type Relayer struct { - DockerImage DockerImage `json:"docker_image"` - StartupFlags []string `json:"startup_flags"` + DockerImage DockerImage `json:"docker_image" yaml:"docker_image"` + StartupFlags []string `json:"startup_flags" yaml:"startup_flags"` } type IBCChannel struct { - ChainID string `json:"chain_id"` - Channel *ibc.ChannelOutput `json:"channel"` + ChainID string `json:"chain_id" yaml:"chain_id"` + Channel *ibc.ChannelOutput `json:"channel" yaml:"channel"` }