From e3852501462c8ac12431d5c98ce0b5ff02b45667 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Wed, 26 Jul 2023 13:38:56 -0700 Subject: [PATCH 1/7] extra client info --- cmd/query.go | 9 +++-- relayer/query.go | 36 +++++++++++++------ relayer/query_test.go | 83 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/cmd/query.go b/cmd/query.go index 5540fb916..5e47dde5f 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -1079,18 +1079,17 @@ $ %s query clients-expiration demo-path`, if err = c[dst].SetPath(path.Dst); err != nil { return err } - - srcExpiration, err := relayer.QueryClientExpiration(cmd.Context(), c[src], c[dst]) + srcExpiration, srcClientInfo, err := relayer.QueryClientExpiration(cmd.Context(), c[src], c[dst]) if err != nil { return err } - dstExpiration, err := relayer.QueryClientExpiration(cmd.Context(), c[dst], c[src]) + dstExpiration, dstClientInfo, err := relayer.QueryClientExpiration(cmd.Context(), c[dst], c[src]) if err != nil { return err } - fmt.Fprintf(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[src], srcExpiration)) - fmt.Fprintf(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[dst], dstExpiration)) + fmt.Fprintf(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[src], srcExpiration, srcClientInfo)) + fmt.Fprintf(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[dst], dstExpiration, dstClientInfo)) return nil }, diff --git a/relayer/query.go b/relayer/query.go index 24c40672a..b395c09a7 100644 --- a/relayer/query.go +++ b/relayer/query.go @@ -272,39 +272,53 @@ func QueryBalance(ctx context.Context, chain *Chain, address string, showDenoms return out, nil } -func QueryClientExpiration(ctx context.Context, src, dst *Chain) (time.Time, error) { +func QueryClientExpiration(ctx context.Context, src, dst *Chain) (time.Time, ClientStateInfo, error) { latestHeight, err := src.ChainProvider.QueryLatestHeight(ctx) if err != nil { - return time.Time{}, err + return time.Time{}, ClientStateInfo{}, err } clientStateRes, err := src.ChainProvider.QueryClientStateResponse(ctx, latestHeight, src.ClientID()) if err != nil { - return time.Time{}, err + return time.Time{}, ClientStateInfo{}, err } clientInfo, err := ClientInfoFromClientState(clientStateRes.ClientState) if err != nil { - return time.Time{}, err + return time.Time{}, ClientStateInfo{}, err } clientTime, err := dst.ChainProvider.BlockTime(ctx, int64(clientInfo.LatestHeight.GetRevisionHeight())) if err != nil { - return time.Time{}, err + return time.Time{}, ClientStateInfo{}, err } - return clientTime.Add(clientInfo.TrustingPeriod), nil + return clientTime.Add(clientInfo.TrustingPeriod), clientInfo, nil } -func SPrintClientExpiration(chain *Chain, expiration time.Time) string { +func SPrintClientExpiration(chain *Chain, expiration time.Time, clientInfo ClientStateInfo) string { now := time.Now() remainingTime := expiration.Sub(now) expirationFormatted := expiration.Format(time.RFC822) + var status string if remainingTime < 0 { - return fmt.Sprintf("client %s (%s) is already expired (%s)\n", - chain.ClientID(), chain.ChainID(), expirationFormatted) + status = "EXPIRED" + } else { + status = "GOOD" } - return fmt.Sprintf("client %s (%s) expires in %s (%s)\n", - chain.ClientID(), chain.ChainID(), remainingTime.Round(time.Second), expirationFormatted) + + // if remainingTime < 0 { + // return fmt.Sprintf("client %s (%s) is already expired (%s)\n", + // chain.ClientID(), chain.ChainID(), expirationFormatted) + // } + return fmt.Sprintf(` + client: %s (%s) + HEALTH: %s + TIME: %s (%s) + LAST UPDATE HEIGHT: %d + TRUSTING PERIOD: %s + + `, + chain.ClientID(), chain.ChainID(), status, expirationFormatted, remainingTime.Round(time.Second), clientInfo.LatestHeight.GetRevisionHeight(), clientInfo.TrustingPeriod.String()) } diff --git a/relayer/query_test.go b/relayer/query_test.go index fb67c60d1..39dc837b7 100644 --- a/relayer/query_test.go +++ b/relayer/query_test.go @@ -1,76 +1,124 @@ package relayer import ( - "github.com/cosmos/relayer/v2/relayer/chains/cosmos" "testing" "time" + "github.com/cosmos/relayer/v2/relayer/chains/cosmos" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" "github.com/stretchr/testify/require" ) func TestSPrintClientExpiration_PrintChainId(t *testing.T) { previousTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) chain := mockChain("expected-chain-id", "test-client-id") - expiration := SPrintClientExpiration(chain, previousTime) + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, previousTime, *clientStateInfo) require.Contains(t, expiration, "expected-chain-id") } func TestSPrintClientExpiration_PrintClientId(t *testing.T) { previousTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) chain := mockChain("test-chain-id", "expected-client-id") - expiration := SPrintClientExpiration(chain, previousTime) + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, previousTime, *clientStateInfo) require.Contains(t, expiration, "expected-client-id") } -func TestSPrintClientExpiration_PrintIsAlreadyExpired_WhenTimeIsInPast(t *testing.T) { +func TestSPrintClientExpiration_PrintExpired_WhenTimeIsInPast(t *testing.T) { previousTime := time.Now().Add(-10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) chain := mockChain("test-chain-id", "test-client-id") - expiration := SPrintClientExpiration(chain, previousTime) + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, previousTime, *clientStateInfo) - require.Contains(t, expiration, "is already expired") + require.Contains(t, expiration, "EXPIRED") } func TestSPrintClientExpiration_PrintRFC822FormattedTime_WhenTimeIsInPast(t *testing.T) { pastTime := time.Now().Add(-10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) - chain := mockChain("test-chain-id", "test-client-id") - expiration := SPrintClientExpiration(chain, pastTime) + chain := mockChain("expected-chain-id", "test-client-id") + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, pastTime, *clientStateInfo) require.Contains(t, expiration, pastTime.Format(time.RFC822)) } -func TestSPrintClientExpiration_PrintExpiresIn_WhenTimeIsInFuture(t *testing.T) { +func TestSPrintClientExpiration_PrintGood_WhenTimeIsInFuture(t *testing.T) { previousTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) chain := mockChain("test-chain-id", "test-client-id") - expiration := SPrintClientExpiration(chain, previousTime) + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, previousTime, *clientStateInfo) - require.Contains(t, expiration, "expires in") + require.Contains(t, expiration, "GOOD") } func TestSPrintClientExpiration_PrintRFC822FormattedTime_WhenTimeIsInFuture(t *testing.T) { futureTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) chain := mockChain("test-chain-id", "test-client-id") - expiration := SPrintClientExpiration(chain, futureTime) + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, futureTime, *clientStateInfo) require.Contains(t, expiration, futureTime.Format(time.RFC822)) } func TestSPrintClientExpiration_PrintRemainingTime_WhenTimeIsInFuture(t *testing.T) { futureTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) chain := mockChain("test-chain-id", "test-client-id") - expiration := SPrintClientExpiration(chain, futureTime) + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, futureTime, *clientStateInfo) require.Contains(t, expiration, "10h0m0s") } +func TestSPrintClientExpiration_TrustingPeriod(t *testing.T) { + previousTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) + + chain := mockChain("expected-chain-id", "test-client-id") + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, previousTime, *clientStateInfo) + + require.Contains(t, expiration, "1h0m0s") +} + +func TestSPrintClientExpiration_LastUpdateHeight(t *testing.T) { + previousTime := time.Now().Add(10 * time.Hour) + mockHeight := clienttypes.NewHeight(1, 100) + trustingPeriod := time.Duration(1 * time.Hour) + + chain := mockChain("expected-chain-id", "test-client-id") + clientStateInfo := mockClientStateInfo("test-chain-id", trustingPeriod, mockHeight) + expiration := SPrintClientExpiration(chain, previousTime, *clientStateInfo) + + require.Contains(t, expiration, "100") +} + func mockChain(chainId string, clientId string) *Chain { return &Chain{ Chainid: chainId, @@ -85,3 +133,12 @@ func mockChain(chainId string, clientId string) *Chain { }, } } + +func mockClientStateInfo(chainID string, trustingPeriod time.Duration, latestHeight ibcexported.Height) *ClientStateInfo { + mockHeight := clienttypes.NewHeight(1, 100) + return &ClientStateInfo{ + ChainID: chainID, + TrustingPeriod: time.Duration(1 * time.Hour), + LatestHeight: mockHeight, + } +} From 88717dcc23ed472636fc95a9e251dbdca3db16c9 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Wed, 26 Jul 2023 13:47:49 -0700 Subject: [PATCH 2/7] cleanup print --- cmd/query.go | 4 ++-- relayer/query.go | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/query.go b/cmd/query.go index 5e47dde5f..8cb6b13a4 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -1088,8 +1088,8 @@ $ %s query clients-expiration demo-path`, return err } - fmt.Fprintf(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[src], srcExpiration, srcClientInfo)) - fmt.Fprintf(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[dst], dstExpiration, dstClientInfo)) + fmt.Fprintln(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[src], srcExpiration, srcClientInfo)) + fmt.Fprintln(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[dst], dstExpiration, dstClientInfo)) return nil }, diff --git a/relayer/query.go b/relayer/query.go index b395c09a7..d662ee46d 100644 --- a/relayer/query.go +++ b/relayer/query.go @@ -314,11 +314,10 @@ func SPrintClientExpiration(chain *Chain, expiration time.Time, clientInfo Clien // } return fmt.Sprintf(` client: %s (%s) - HEALTH: %s - TIME: %s (%s) - LAST UPDATE HEIGHT: %d - TRUSTING PERIOD: %s - + HEALTH: %s + TIME: %s (%s) + LAST UPDATE HEIGHT: %d + TRUSTING PERIOD: %s `, chain.ClientID(), chain.ChainID(), status, expirationFormatted, remainingTime.Round(time.Second), clientInfo.LatestHeight.GetRevisionHeight(), clientInfo.TrustingPeriod.String()) } From aca6814d85189ca137d4eb683bce6f2a52de68e9 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Wed, 26 Jul 2023 13:49:26 -0700 Subject: [PATCH 3/7] remove extra comments --- relayer/query.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/relayer/query.go b/relayer/query.go index d662ee46d..005b700a0 100644 --- a/relayer/query.go +++ b/relayer/query.go @@ -308,10 +308,6 @@ func SPrintClientExpiration(chain *Chain, expiration time.Time, clientInfo Clien status = "GOOD" } - // if remainingTime < 0 { - // return fmt.Sprintf("client %s (%s) is already expired (%s)\n", - // chain.ClientID(), chain.ChainID(), expirationFormatted) - // } return fmt.Sprintf(` client: %s (%s) HEALTH: %s From 95b196824402e85f2469d72552ebc79456987037 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Wed, 26 Jul 2023 13:59:52 -0700 Subject: [PATCH 4/7] add alias --- cmd/query.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/query.go b/cmd/query.go index 8cb6b13a4..4da4f48cb 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -1055,9 +1055,10 @@ $ %s query unrelayed-acks demo-path channel-0`, func queryClientsExpiration(a *appState) *cobra.Command { cmd := &cobra.Command{ - Use: "clients-expiration path", - Short: "query for light clients expiration date", - Args: withUsage(cobra.ExactArgs(1)), + Use: "clients-expiration path", + Aliases: []string{"ce"}, + Short: "query for light clients expiration date", + Args: withUsage(cobra.ExactArgs(1)), Example: strings.TrimSpace(fmt.Sprintf(` $ %s query clients-expiration demo-path`, appName, From 27672de3f700b101b480e3885af48c19e4fcb653 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Wed, 26 Jul 2023 15:50:22 -0700 Subject: [PATCH 5/7] allow only one client --- cmd/query.go | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/cmd/query.go b/cmd/query.go index 4da4f48cb..71ef53eea 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -1080,13 +1080,26 @@ $ %s query clients-expiration demo-path`, if err = c[dst].SetPath(path.Dst); err != nil { return err } - srcExpiration, srcClientInfo, err := relayer.QueryClientExpiration(cmd.Context(), c[src], c[dst]) - if err != nil { - return err + + srcExpiration, srcClientInfo, errSrc := relayer.QueryClientExpiration(cmd.Context(), c[src], c[dst]) + if errSrc != nil && !strings.Contains(errSrc.Error(), "light client not found") { + return errSrc } - dstExpiration, dstClientInfo, err := relayer.QueryClientExpiration(cmd.Context(), c[dst], c[src]) - if err != nil { - return err + dstExpiration, dstClientInfo, errDst := relayer.QueryClientExpiration(cmd.Context(), c[dst], c[src]) + if errDst != nil && !strings.Contains(errDst.Error(), "light client not found") { + return errDst + } + + // if only the src light client is found, just print info for source light client + if errSrc == nil && errDst != nil { + fmt.Fprintln(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[src], srcExpiration, srcClientInfo)) + return nil + } + + // if only the dst light client is found, just print info for destinatino light client + if errDst == nil && errSrc != nil { + fmt.Fprintln(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[dst], dstExpiration, dstClientInfo)) + return nil } fmt.Fprintln(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[src], srcExpiration, srcClientInfo)) From 4e411adf2cfc4a62cc28facc0e8cf77da9422faa Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Wed, 26 Jul 2023 15:56:59 -0700 Subject: [PATCH 6/7] spelling --- cmd/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/query.go b/cmd/query.go index 71ef53eea..886b2f334 100644 --- a/cmd/query.go +++ b/cmd/query.go @@ -1096,7 +1096,7 @@ $ %s query clients-expiration demo-path`, return nil } - // if only the dst light client is found, just print info for destinatino light client + // if only the dst light client is found, just print info for destination light client if errDst == nil && errSrc != nil { fmt.Fprintln(cmd.OutOrStdout(), relayer.SPrintClientExpiration(c[dst], dstExpiration, dstClientInfo)) return nil From 75f4145ae2c41adc6ed243feeb039dbf594c4466 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Thu, 27 Jul 2023 13:58:41 -0700 Subject: [PATCH 7/7] remainingTime --- relayer/query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/query.go b/relayer/query.go index 005b700a0..08b2ec1b0 100644 --- a/relayer/query.go +++ b/relayer/query.go @@ -302,7 +302,7 @@ func SPrintClientExpiration(chain *Chain, expiration time.Time, clientInfo Clien expirationFormatted := expiration.Format(time.RFC822) var status string - if remainingTime < 0 { + if remainingTime <= 0 { status = "EXPIRED" } else { status = "GOOD"