diff --git a/example-config.yml b/example-config.yml index c261f6f..b0b9a1c 100644 --- a/example-config.yml +++ b/example-config.yml @@ -67,7 +67,7 @@ chains: chain_id: osmosis-1 # Hooray, in v2 we derive the valcons from abci queries so you don't have to jump through hoops to figure out how # to convert ed25519 keys to the appropriate bech32 address. - # Use valcons address if using ICS + # Use valcons address if using ICS or tendermint/PubKeyBn254 valoper_address: osmovaloper1xxxxxxx... # Should the monitor revert to using public API endpoints if all supplied RCP nodes fail? # This isn't always reliable, not all public nodes have websocket proxying setup correctly. diff --git a/td2/rpc.go b/td2/rpc.go index b3429fe..5f61687 100644 --- a/td2/rpc.go +++ b/td2/rpc.go @@ -2,6 +2,7 @@ package tenderduty import ( "context" + "encoding/json" "errors" "fmt" "io" @@ -39,20 +40,28 @@ func (cc *ChainConfig) newRpc() error { down = true return } + var network string + var catching_up bool status, err := cc.client.Status(ctx) if err != nil { - msg = fmt.Sprintf("❌ could not get status for %s: (%s) %s", cc.name, u, err) - down = true - l(msg) - return + n, c, err := getStatusWithEndpoint(ctx, u) + if err != nil { + msg = fmt.Sprintf("❌ could not get status for %s: (%s) %s", cc.name, u, err) + down = true + l(msg) + return + } + network, catching_up = n, c + } else { + network, catching_up = status.NodeInfo.Network, status.SyncInfo.CatchingUp } - if status.NodeInfo.Network != cc.ChainId { - msg = fmt.Sprintf("chain id %s on %s does not match, expected %s, skipping", status.NodeInfo.Network, u, cc.ChainId) + if network != cc.ChainId { + msg = fmt.Sprintf("chain id %s on %s does not match, expected %s, skipping", network, u, cc.ChainId) down = true l(msg) return } - if status.SyncInfo.CatchingUp { + if catching_up { msg = fmt.Sprint("🐢 node is not synced, skipping ", u) syncing = true down = true @@ -261,3 +270,51 @@ func guessPublicEndpoint(u string) string { } return proto + matches[1] + port } + +func getStatusWithEndpoint(ctx context.Context, u string) (string, bool, error) { + // Parse the URL + parsedURL, err := url.Parse(u) + if err != nil { + return "", false, err + } + + // Check if the scheme is 'tcp' and modify to 'http' + if parsedURL.Scheme == "tcp" { + parsedURL.Scheme = "http" + } + + queryPath := fmt.Sprintf("%s/status", parsedURL.String()) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, queryPath, nil) + if err != nil { + return "", false, err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return "", false, err + } + defer resp.Body.Close() + + b, err := io.ReadAll(resp.Body) + if err != nil { + return "", false, err + } + + type tendermintStatus struct { + JsonRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result struct { + NodeInfo struct { + Network string `json:"network"` + } `json:"node_info"` + SyncInfo struct { + CatchingUp bool `json:"catching_up"` + } `json:"sync_info"` + } `json:"result"` + } + var status tendermintStatus + if err := json.Unmarshal(b, &status); err != nil { + return "", false, err + } + return status.Result.NodeInfo.Network, status.Result.SyncInfo.CatchingUp, nil +}