diff --git a/.gitignore b/.gitignore index b7142e8..149d9a7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,12 @@ *.so *.dylib +# vscode +.vscode + +# direnv +.envrc + # Test binary, built with `go test -c` *.test diff --git a/cmd/relayer_exporter/relayer_exporter.go b/cmd/relayer_exporter/relayer_exporter.go index 4176d73..567eaad 100644 --- a/cmd/relayer_exporter/relayer_exporter.go +++ b/cmd/relayer_exporter/relayer_exporter.go @@ -8,6 +8,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" + "go.uber.org/zap" "github.com/archway-network/relayer_exporter/pkg/collector" "github.com/archway-network/relayer_exporter/pkg/config" @@ -45,11 +46,12 @@ func main() { log.Info( fmt.Sprintf( - "Getting IBC paths from %s/%s/%s on GitHub", + "Github IBC registry: %s/%s", cfg.GitHub.Org, cfg.GitHub.Repo, - cfg.GitHub.IBCDir, ), + zap.String("Mainnet Directory", cfg.GitHub.IBCDir), + zap.String("Testnet Directory", cfg.GitHub.TestnetsIBCDir), ) // TODO: Add a feature to refresh paths at configured interval @@ -58,7 +60,10 @@ func main() { log.Fatal(err.Error()) } - rpcs := cfg.GetRPCsMap() + rpcs, err := cfg.GetRPCsMap(paths) + if err != nil { + log.Fatal(err.Error()) + } ibcCollector := collector.IBCCollector{ RPCs: rpcs, diff --git a/config.yaml b/config.yaml index 5eb3574..a9ce3db 100644 --- a/config.yaml +++ b/config.yaml @@ -1,26 +1,28 @@ ---- +github: + org: archway-network + repo: networks + dir: _IBC + testnetsDir: testnets/_IBC rpc: + # mainnets - chainName: archway chainId: archway-1 url: https://rpc.mainnet.archway.io:443 - chainName: agoric chainId: agoric-3 - url: https://main.rpc.agoric.net:443 + url: https://agoric.rpc.kjnodes.com:443 - chainName: axelar chainId: axelar-dojo-1 - url: https://axelar-rpc.polkachu.com:443 - - chainName: axelartestnet - chainId: axelar-testnet-lisbon-3 - url: https://rpc-axelar-testnet.imperator.co:443 - - chainName: archwaytestnet - chainId: constantine-3 - url: https://rpc.constantine.archway.tech:443 + url: https://rpc-1.axelar.nodes.guru:443 - chainName: bitcanna chainId: bitcanna-1 url: https://rpc.bitcanna.io:443 - chainName: cosmoshub chainId: cosmoshub-4 url: https://cosmoshub-rpc.stakely.io:443 + - chainName: decentr + chainId: mainnet-3 + url: https://poseidon.mainnet.decentr.xyz:443 - chainName: jackal chainId: jackal-1 url: https://jackal-rpc.polkachu.com:443 @@ -29,45 +31,61 @@ rpc: url: https://juno-rpc.publicnode.com:443 - chainName: kujira chainId: kaiyo-1 - url: https://kujira-rpc.polkachu.com:443 + url: https://kujira-rpc.publicnode.com:443 - chainName: noble chainId: noble-1 url: https://noble-rpc.polkachu.com:443 - chainName: nois chainId: nois-1 url: https://nois.rpc.kjnodes.com:443 - - chainName: osmosistestnet - chainId: osmo-test-5 - url: https://rpc.osmotest5.osmosis.zone:443 + - chainName: omniflixhub + chainId: omniflixhub-1 + url: https://omniflix.kingnodes.com:443 - chainName: osmosis chainId: osmosis-1 url: https://osmosis-rpc.stakely.io:443 - chainName: quicksilver chainId: quicksilver-2 url: https://rpc.quicksilver.zone:443 - - chainName: akashtestnet - chainId: sandbox-01 - url: https://rpc.sandbox-01.aksh.pw:443 - chainName: umee chainId: umee-1 url: https://rpc-umee.mzonder.com:443 - chainName: gravitybridge chainId: gravity-bridge-3 url: https://gravitychain.io:26657 - - chainName: omniflixhub - chainId: omniflixhub-1 - url: https://rpc-omniflix.mzonder.com:443 - - chainName: decentr - chainId: mainnet-3 - url: https://poseidon.mainnet.decentr.xyz:443 + - chainName: secretnetwork + chainId: secret-4 + url: https://rpc.secret.express:443 + - chainName: terra2 + chainId: phoenix-1 + url: https://terra-rpc.stakely.io:443 + - chainName: comdex + chainId: comdex-1 + url: https://rpc.comdex.one:443 + - chainName: neutron + chainId: neutron-1 + url: https://rpc-kralum.neutron-1.neutron.org:443 + - chainName: stargaze + chainId: stargaze-1 + url: https://rpc.stargaze-apis.com:443 -github: - org: archway-network - repo: networks - dir: _IBC - testnetsDir: testnets/_IBC + # testnets + - chainName: archwaytestnet + chainId: constantine-3 + url: https://rpc.constantine.archway.tech:443 + - chainName: axelartestnet + chainId: axelar-testnet-lisbon-3 + url: https://axelar-testnet-rpc.qubelabs.io:443 + - chainName: osmosistestnet + chainId: osmo-test-5 + url: https://rpc.osmotest5.osmosis.zone:443 accounts: - - address: archway1l2al7y78500h5akvgt8exwnkpmf2zmk8ky9ht3 - chainName: archwaytestnet - denom: aconst + # Foundation + - address: archway1gpyqzc0aerc85cpk2cm8ec6zkc95x5yqrakskv + chainName: archway + denom: aarch + # PhiLabs + - address: archway1ktka5q3cnsy3ar7qwj2huzz6qj9q4ys7h74l9y + chainName: archway + denom: aarch \ No newline at end of file diff --git a/pkg/chain/chain.go b/pkg/chain/chain.go index 224179f..4219d09 100644 --- a/pkg/chain/chain.go +++ b/pkg/chain/chain.go @@ -2,6 +2,7 @@ package chain import ( "context" + "fmt" "github.com/cosmos/relayer/v2/relayer" "github.com/cosmos/relayer/v2/relayer/chains/cosmos" @@ -54,3 +55,19 @@ func PrepChain(info Info) (*relayer.Chain, error) { return chain, nil } + +func ValidateChainInfo(info Info) error { + if info.ChainID == "" { + return fmt.Errorf("missing chain ID: %v", info) + } + + if info.RPCAddr == "" { + return fmt.Errorf("missing RPC address: %v", info) + } + + if info.ClientID == "" { + return fmt.Errorf("missing client ID: %v", info) + } + + return nil +} diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 5cd6ddd..7b55480 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -1,229 +1,17 @@ package collector import ( - "fmt" - "math/big" - "reflect" "regexp" "strings" - "sync" - - "github.com/prometheus/client_golang/prometheus" - "go.uber.org/zap" "github.com/archway-network/relayer_exporter/pkg/config" - "github.com/archway-network/relayer_exporter/pkg/ibc" - log "github.com/archway-network/relayer_exporter/pkg/logger" ) const ( - successStatus = "success" - errorStatus = "error" - clientExpiryMetricName = "cosmos_ibc_client_expiry" - walletBalanceMetricName = "cosmos_wallet_balance" - channelStuckPacketsMetricName = "cosmos_ibc_stuck_packets" -) - -var ( - clientExpiry = prometheus.NewDesc( - clientExpiryMetricName, - "Returns light client expiry in unixtime.", - []string{ - "host_chain_id", - "client_id", - "target_chain_id", - "discord_ids", - "status", - }, - nil, - ) - channelStuckPackets = prometheus.NewDesc( - channelStuckPacketsMetricName, - "Returns stuck packets for a channel.", - []string{ - "src_channel_id", - "dst_channel_id", - "src_chain_id", - "dst_chain_id", - "src_chain_name", - "dst_chain_name", - "discord_ids", - "status", - }, - nil, - ) - walletBalance = prometheus.NewDesc( - walletBalanceMetricName, - "Returns wallet balance for an address on a chain.", - []string{"account", "chain_id", "denom", "status"}, nil, - ) + successStatus = "success" + errorStatus = "error" ) -type IBCCollector struct { - RPCs *map[string]config.RPC - Paths []*config.IBCData -} - -type WalletBalanceCollector struct { - RPCs *map[string]config.RPC - Accounts []config.Account -} - -func (cc IBCCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- clientExpiry - ch <- channelStuckPackets -} - -func (cc IBCCollector) Collect(ch chan<- prometheus.Metric) { - log.Debug( - "Start collecting", - zap.String( - "metrics", - fmt.Sprintf("%s, %s", clientExpiryMetricName, channelStuckPacketsMetricName), - ), - ) - - var wg sync.WaitGroup - - for _, p := range cc.Paths { - wg.Add(1) - - go func(path *config.IBCData) { - defer wg.Done() - - discordIDs := getDiscordIDs(path.Operators) - - // Client info - ci, err := ibc.GetClientsInfo(path, cc.RPCs) - status := successStatus - - if err != nil { - status = errorStatus - - log.Error(err.Error()) - } - - ch <- prometheus.MustNewConstMetric( - clientExpiry, - prometheus.GaugeValue, - float64(ci.ChainAClientExpiration.Unix()), - []string{ - (*cc.RPCs)[path.Chain1.ChainName].ChainID, - path.Chain1.ClientID, - (*cc.RPCs)[path.Chain2.ChainName].ChainID, - discordIDs, - status, - }..., - ) - - ch <- prometheus.MustNewConstMetric( - clientExpiry, - prometheus.GaugeValue, - float64(ci.ChainBClientExpiration.Unix()), - []string{ - (*cc.RPCs)[path.Chain2.ChainName].ChainID, - path.Chain2.ClientID, - (*cc.RPCs)[path.Chain1.ChainName].ChainID, - discordIDs, - status, - }..., - ) - - // Stuck packets - status = successStatus - - stuckPackets, err := ibc.GetChannelsInfo(path, cc.RPCs) - if err != nil { - status = errorStatus - - log.Error(err.Error()) - } - - if !reflect.DeepEqual(stuckPackets, ibc.ChannelsInfo{}) { - for _, sp := range stuckPackets.Channels { - ch <- prometheus.MustNewConstMetric( - channelStuckPackets, - prometheus.GaugeValue, - float64(sp.StuckPackets.Source), - []string{ - sp.Source, - sp.Destination, - (*cc.RPCs)[path.Chain1.ChainName].ChainID, - (*cc.RPCs)[path.Chain2.ChainName].ChainID, - path.Chain1.ChainName, - path.Chain2.ChainName, - discordIDs, - status, - }..., - ) - - ch <- prometheus.MustNewConstMetric( - channelStuckPackets, - prometheus.GaugeValue, - float64(sp.StuckPackets.Destination), - []string{ - sp.Destination, - sp.Source, - (*cc.RPCs)[path.Chain2.ChainName].ChainID, - (*cc.RPCs)[path.Chain1.ChainName].ChainID, - path.Chain2.ChainName, - path.Chain1.ChainName, - discordIDs, - status, - }..., - ) - } - } - }(p) - } - - wg.Wait() - - log.Debug("Stop collecting", zap.String("metric", clientExpiryMetricName)) -} - -func (wb WalletBalanceCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- walletBalance -} - -func (wb WalletBalanceCollector) Collect(ch chan<- prometheus.Metric) { - log.Debug("Start collecting", zap.String("metric", walletBalanceMetricName)) - - var wg sync.WaitGroup - - for _, a := range wb.Accounts { - wg.Add(1) - - go func(account config.Account) { - defer wg.Done() - - balance := 0.0 - status := successStatus - - err := account.GetBalance(wb.RPCs) - if err != nil { - status = errorStatus - - log.Error(err.Error(), zap.Any("account", account)) - } else { - // Convert to a big float to get a float64 for metrics - balance, _ = big.NewFloat(0.0).SetInt(account.Balance.BigInt()).Float64() - } - - ch <- prometheus.MustNewConstMetric( - walletBalance, - prometheus.GaugeValue, - balance, - []string{account.Address, (*wb.RPCs)[account.ChainName].ChainID, account.Denom, status}..., - ) - }(a) - } - - wg.Wait() - - log.Debug("Stop collecting", zap.String("metric", walletBalanceMetricName)) -} - func getDiscordIDs(ops []config.Operator) string { var ids []string diff --git a/pkg/collector/ibc_collector.go b/pkg/collector/ibc_collector.go new file mode 100644 index 0000000..53edd74 --- /dev/null +++ b/pkg/collector/ibc_collector.go @@ -0,0 +1,167 @@ +package collector + +import ( + "fmt" + "reflect" + "sync" + + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/zap" + + "github.com/archway-network/relayer_exporter/pkg/config" + "github.com/archway-network/relayer_exporter/pkg/ibc" + log "github.com/archway-network/relayer_exporter/pkg/logger" +) + +const ( + clientExpiryMetricName = "cosmos_ibc_client_expiry" + channelStuckPacketsMetricName = "cosmos_ibc_stuck_packets" +) + +var ( + clientExpiry = prometheus.NewDesc( + clientExpiryMetricName, + "Returns light client expiry in unixtime.", + []string{ + "host_chain_id", + "client_id", + "target_chain_id", + "discord_ids", + "status", + }, + nil, + ) + channelStuckPackets = prometheus.NewDesc( + channelStuckPacketsMetricName, + "Returns stuck packets for a channel.", + []string{ + "src_channel_id", + "dst_channel_id", + "src_chain_id", + "dst_chain_id", + "src_chain_name", + "dst_chain_name", + "discord_ids", + "status", + }, + nil, + ) +) + +type IBCCollector struct { + RPCs *map[string]config.RPC + Paths []*config.IBCData +} + +func (cc IBCCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- clientExpiry + ch <- channelStuckPackets +} + +func (cc IBCCollector) Collect(ch chan<- prometheus.Metric) { + log.Debug( + "Start collecting", + zap.String( + "metrics", + fmt.Sprintf("%s, %s", clientExpiryMetricName, channelStuckPacketsMetricName), + ), + ) + + var wg sync.WaitGroup + + for _, p := range cc.Paths { + wg.Add(1) + + go func(path *config.IBCData) { + defer wg.Done() + + discordIDs := getDiscordIDs(path.Operators) + + // Client info + ci, err := ibc.GetClientsInfo(path, cc.RPCs) + status := successStatus + + if err != nil { + status = errorStatus + + log.Error(err.Error()) + } + + ch <- prometheus.MustNewConstMetric( + clientExpiry, + prometheus.GaugeValue, + float64(ci.ChainAClientExpiration.Unix()), + []string{ + (*cc.RPCs)[path.Chain1.ChainName].ChainID, + path.Chain1.ClientID, + (*cc.RPCs)[path.Chain2.ChainName].ChainID, + discordIDs, + status, + }..., + ) + + ch <- prometheus.MustNewConstMetric( + clientExpiry, + prometheus.GaugeValue, + float64(ci.ChainBClientExpiration.Unix()), + []string{ + (*cc.RPCs)[path.Chain2.ChainName].ChainID, + path.Chain2.ClientID, + (*cc.RPCs)[path.Chain1.ChainName].ChainID, + discordIDs, + status, + }..., + ) + + // Stuck packets + status = successStatus + + stuckPackets, err := ibc.GetChannelsInfo(path, cc.RPCs) + if err != nil { + status = errorStatus + + log.Error(err.Error()) + } + + if !reflect.DeepEqual(stuckPackets, ibc.ChannelsInfo{}) { + for _, sp := range stuckPackets.Channels { + ch <- prometheus.MustNewConstMetric( + channelStuckPackets, + prometheus.GaugeValue, + float64(sp.StuckPackets.Source), + []string{ + sp.Source, + sp.Destination, + (*cc.RPCs)[path.Chain1.ChainName].ChainID, + (*cc.RPCs)[path.Chain2.ChainName].ChainID, + path.Chain1.ChainName, + path.Chain2.ChainName, + discordIDs, + status, + }..., + ) + + ch <- prometheus.MustNewConstMetric( + channelStuckPackets, + prometheus.GaugeValue, + float64(sp.StuckPackets.Destination), + []string{ + sp.Destination, + sp.Source, + (*cc.RPCs)[path.Chain2.ChainName].ChainID, + (*cc.RPCs)[path.Chain1.ChainName].ChainID, + path.Chain2.ChainName, + path.Chain1.ChainName, + discordIDs, + status, + }..., + ) + } + } + }(p) + } + + wg.Wait() + + log.Debug("Stop collecting", zap.String("metric", clientExpiryMetricName)) +} diff --git a/pkg/collector/wallet_balance_collector.go b/pkg/collector/wallet_balance_collector.go new file mode 100644 index 0000000..91d2f3b --- /dev/null +++ b/pkg/collector/wallet_balance_collector.go @@ -0,0 +1,71 @@ +package collector + +import ( + "math/big" + "sync" + + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/zap" + + "github.com/archway-network/relayer_exporter/pkg/config" + log "github.com/archway-network/relayer_exporter/pkg/logger" +) + +const ( + walletBalanceMetricName = "cosmos_wallet_balance" +) + +var ( + walletBalance = prometheus.NewDesc( + walletBalanceMetricName, + "Returns wallet balance for an address on a chain.", + []string{"account", "chain_id", "denom", "status"}, nil, + ) +) + +type WalletBalanceCollector struct { + RPCs *map[string]config.RPC + Accounts []config.Account +} + +func (wb WalletBalanceCollector) Describe(ch chan<- *prometheus.Desc) { + ch <- walletBalance +} + +func (wb WalletBalanceCollector) Collect(ch chan<- prometheus.Metric) { + log.Debug("Start collecting", zap.String("metric", walletBalanceMetricName)) + + var wg sync.WaitGroup + + for _, a := range wb.Accounts { + wg.Add(1) + + go func(account config.Account) { + defer wg.Done() + + balance := 0.0 + status := successStatus + + err := account.GetBalance(wb.RPCs) + if err != nil { + status = errorStatus + + log.Error(err.Error(), zap.Any("account", account)) + } else { + // Convert to a big float to get a float64 for metrics + balance, _ = big.NewFloat(0.0).SetInt(account.Balance.BigInt()).Float64() + } + + ch <- prometheus.MustNewConstMetric( + walletBalance, + prometheus.GaugeValue, + balance, + []string{account.Address, (*wb.RPCs)[account.ChainName].ChainID, account.Denom, status}..., + ) + }(a) + } + + wg.Wait() + + log.Debug("Stop collecting", zap.String("metric", walletBalanceMetricName)) +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 34b2dbe..91324bf 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "os" "strings" @@ -19,6 +20,7 @@ import ( const ibcPathSuffix = ".json" var ErrGitHubClient = errors.New("GitHub client not provided") +var ErrMissingRPCConfigMsg = "missing RPC config for chain: %s" type Account struct { Address string `yaml:"address"` @@ -47,37 +49,29 @@ type Config struct { } `yaml:"github"` } -type IBCData struct { - Schema string `json:"$schema"` +type IBCChainMeta struct { + ChainName string `json:"chain_name"` + ClientID string `json:"client_id"` + ConnectionID string `json:"connection_id"` +} + +type Channel struct { Chain1 struct { - ChainName string `json:"chain_name"` - ClientID string `json:"client_id"` - ConnectionID string `json:"connection_id"` + ChannelID string `json:"channel_id"` + PortID string `json:"port_id"` } `json:"chain_1"` Chain2 struct { - ChainName string `json:"chain_name"` - ClientID string `json:"client_id"` - ConnectionID string `json:"connection_id"` + ChannelID string `json:"channel_id"` + PortID string `json:"port_id"` } `json:"chain_2"` - Channels []struct { - Chain1 struct { - ChannelID string `json:"channel_id"` - PortID string `json:"port_id"` - } `json:"chain_1"` - Chain2 struct { - ChannelID string `json:"channel_id"` - PortID string `json:"port_id"` - } `json:"chain_2"` - Ordering string `json:"ordering"` - Version string `json:"version"` - Tags struct { - Status string `json:"status"` - Preferred bool `json:"preferred"` - Dex string `json:"dex"` - Properties string `json:"properties"` - } `json:"tags,omitempty"` - } `json:"channels"` - Operators []Operator `json:"operators"` + Ordering string `json:"ordering"` + Version string `json:"version"` + Tags struct { + Status string `json:"status"` + Preferred bool `json:"preferred"` + Dex string `json:"dex"` + Properties string `json:"properties"` + } `json:"tags,omitempty"` } type Operator struct { @@ -92,6 +86,14 @@ type Operator struct { Discord Discord `json:"discord"` } +type IBCData struct { + Schema string `json:"$schema"` + Chain1 IBCChainMeta `json:"chain_1"` + Chain2 IBCChainMeta `json:"chain_2"` + Channels []Channel `json:"channels"` + Operators []Operator `json:"operators"` +} + type Discord struct { Handle string `json:"handle"` ID string `json:"id"` @@ -119,7 +121,11 @@ func (a *Account) GetBalance(rpcs *map[string]RPC) error { return nil } -func (c *Config) GetRPCsMap() *map[string]RPC { +// GetRPCsMap uses the provided config file to return a map of chain +// chain_names to RPCs. It uses IBCData already extracted from +// github IBC registry to validate config for missing RPCs and raises +// an error if any are missing. +func (c *Config) GetRPCsMap(ibcPaths []*IBCData) (*map[string]RPC, error) { rpcs := map[string]RPC{} for _, rpc := range c.RPCs { @@ -130,7 +136,20 @@ func (c *Config) GetRPCsMap() *map[string]RPC { rpcs[rpc.ChainName] = rpc } - return &rpcs + // Validate RPCs exist for each IBC path + for _, ibcPath := range ibcPaths { + // Check RPC for chain 1 + if _, ok := rpcs[ibcPath.Chain1.ChainName]; !ok { + return &rpcs, fmt.Errorf("missing RPC config for chain: %s", ibcPath.Chain1.ChainName) + } + + // Check RPC for chain 2 + if _, ok := rpcs[ibcPath.Chain2.ChainName]; !ok { + return &rpcs, fmt.Errorf(ErrMissingRPCConfigMsg, ibcPath.Chain2.ChainName) + } + } + + return &rpcs, nil } func (c *Config) IBCPaths() ([]*IBCData, error) { @@ -176,6 +195,7 @@ func (c *Config) getPaths(dir string, client *github.Client) ([]*IBCData, error) for _, file := range ibcDir { if strings.HasSuffix(*file.Path, ibcPathSuffix) { + log.Debug(fmt.Sprintf("Fetching IBC data for %s/%s/%s", c.GitHub.Org, c.GitHub.Repo, *file.Path)) content, _, _, err := client.Repositories.GetContents( ctx, c.GitHub.Org, diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 61e1588..d5348b0 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -2,49 +2,101 @@ package config import ( "errors" + "fmt" "testing" "github.com/stretchr/testify/assert" ) -func TestGetRPCsMap(t *testing.T) { - rpcs := []RPC{ +func TestGetRPC(t *testing.T) { + testCases := []struct { + name string + rpcs []RPC + paths []*IBCData + resp map[string]RPC + err error + }{ { - ChainName: "archway", - ChainID: "archway-1", - URL: "https://rpc.mainnet.archway.io:443", + name: "No Missing or Invalid RPCs", + rpcs: []RPC{ + { + ChainName: "archway", + ChainID: "archway-1", + URL: "https://rpc.mainnet.archway.io:443", + }, + { + ChainName: "archwaytestnet", + ChainID: "constantine-3", + URL: "https://rpc.constantine.archway.tech:443", + Timeout: "2s", + }, + }, + paths: []*IBCData{}, + resp: map[string]RPC{ + "archway": { + ChainName: "archway", + ChainID: "archway-1", + URL: "https://rpc.mainnet.archway.io:443", + Timeout: "5s", + }, + "archwaytestnet": { + ChainName: "archwaytestnet", + ChainID: "constantine-3", + URL: "https://rpc.constantine.archway.tech:443", + Timeout: "2s", + }, + }, + err: nil, }, { - ChainName: "archwaytestnet", - ChainID: "constantine-3", - URL: "https://rpc.constantine.archway.tech:443", - Timeout: "2s", + name: "Missing RPCs", + rpcs: []RPC{ + { + ChainName: "archway", + ChainID: "archway-1", + URL: "https://rpc.mainnet.archway.io:443", + }, + }, + paths: []*IBCData{ + { + Schema: "$schema", + Chain1: IBCChainMeta{ + ChainName: "archway", + ClientID: "Client1", + ConnectionID: "Connection1", + }, + Chain2: IBCChainMeta{ + ChainName: "archwaytestnet", + ClientID: "Client2", + ConnectionID: "Connection2", + }, + Channels: []Channel{}, + Operators: []Operator{}, + }, + }, + resp: map[string]RPC{ + "archway": { + ChainName: "archway", + ChainID: "archway-1", + URL: "https://rpc.mainnet.archway.io:443", + Timeout: "5s", + }, + }, + err: fmt.Errorf(ErrMissingRPCConfigMsg, "archwaytestnet"), }, } - cfg := Config{ - GlobalRPCTimeout: "5s", - RPCs: rpcs, + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cfg := Config{ + GlobalRPCTimeout: "5s", + RPCs: tc.rpcs, + } + res, err := cfg.GetRPCsMap(tc.paths) + assert.ErrorIs(t, err, tc.err) + assert.Equal(t, &tc.resp, res) + }) } - - exp := map[string]RPC{ - "archway": { - ChainName: "archway", - ChainID: "archway-1", - URL: "https://rpc.mainnet.archway.io:443", - Timeout: "5s", - }, - "archwaytestnet": { - ChainName: "archwaytestnet", - ChainID: "constantine-3", - URL: "https://rpc.constantine.archway.tech:443", - Timeout: "2s", - }, - } - - res := cfg.GetRPCsMap() - - assert.Equal(t, &exp, res) } func TestGetPaths(t *testing.T) { diff --git a/pkg/ibc/ibc.go b/pkg/ibc/ibc.go index 2c26c1b..d3d6050 100644 --- a/pkg/ibc/ibc.go +++ b/pkg/ibc/ibc.go @@ -72,6 +72,7 @@ func GetClientsInfo(ibc *config.IBCData, rpcs *map[string]config.RPC) (ClientsIn ctx := context.Background() + fmt.Sprintf("Querying client expiration for %v <-> %v", cdA, cdB) clientsInfo.ChainAClientExpiration, clientsInfo.ChainAClientInfo, err = relayer.QueryClientExpiration( ctx, chainA,