Skip to content

Commit

Permalink
fix: handles SEI status
Browse files Browse the repository at this point in the history
  • Loading branch information
AntiTyping committed Nov 10, 2023
1 parent 57256cb commit 798d060
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 89 deletions.
108 changes: 69 additions & 39 deletions internal/cosmos/comet_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,68 @@ import (
"time"
)

// CometStatus is the response from the /status RPC endpoint.
type CometStatus struct {
type ValidatorInfo struct {
Address string `json:"address"`
PubKey struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"pub_key"`
VotingPower string `json:"voting_power"`
}

type NodeInfo struct {
ProtocolVersion struct {
P2P string `json:"p2p"`
Block string `json:"block"`
App string `json:"app"`
} `json:"protocol_version"`
ID string `json:"id"`
ListenAddr string `json:"listen_addr"`
Network string `json:"network"`
Version string `json:"version"`
Channels string `json:"channels"`
Moniker string `json:"moniker"`
Other struct {
TxIndex string `json:"tx_index"`
RPCAddress string `json:"rpc_address"`
} `json:"other"`
}

type SyncInfo struct {
LatestBlockHash string `json:"latest_block_hash"`
LatestAppHash string `json:"latest_app_hash"`
LatestBlockHeight string `json:"latest_block_height"`
LatestBlockTime time.Time `json:"latest_block_time"`
EarliestBlockHash string `json:"earliest_block_hash"`
EarliestAppHash string `json:"earliest_app_hash"`
EarliestBlockHeight string `json:"earliest_block_height"`
EarliestBlockTime time.Time `json:"earliest_block_time"`
CatchingUp bool `json:"catching_up"`
}

// rpcCometStatusResponse is the union of possible server response
type rpcCometStatusResponse struct {
JSONRPC string `json:"jsonrpc"`
ID int `json:"id"`
Result struct {
NodeInfo struct {
ProtocolVersion struct {
P2P string `json:"p2p"`
Block string `json:"block"`
App string `json:"app"`
} `json:"protocol_version"`
ID string `json:"id"`
ListenAddr string `json:"listen_addr"`
Network string `json:"network"`
Version string `json:"version"`
Channels string `json:"channels"`
Moniker string `json:"moniker"`
Other struct {
TxIndex string `json:"tx_index"`
RPCAddress string `json:"rpc_address"`
} `json:"other"`
} `json:"node_info"`
SyncInfo struct {
LatestBlockHash string `json:"latest_block_hash"`
LatestAppHash string `json:"latest_app_hash"`
LatestBlockHeight string `json:"latest_block_height"`
LatestBlockTime time.Time `json:"latest_block_time"`
EarliestBlockHash string `json:"earliest_block_hash"`
EarliestAppHash string `json:"earliest_app_hash"`
EarliestBlockHeight string `json:"earliest_block_height"`
EarliestBlockTime time.Time `json:"earliest_block_time"`
CatchingUp bool `json:"catching_up"`
} `json:"sync_info"`
ValidatorInfo struct {
Address string `json:"address"`
PubKey struct {
Type string `json:"type"`
Value string `json:"value"`
} `json:"pub_key"`
VotingPower string `json:"voting_power"`
} `json:"validator_info"`
NodeInfo *NodeInfo `json:"node_info"`
SyncInfo *SyncInfo `json:"sync_info"`
ValidatorInfo *ValidatorInfo `json:"validator_info"`
} `json:"result"`
NodeInfo *NodeInfo `json:"node_info"`
SyncInfo *SyncInfo `json:"sync_info"`
ValidatorInfo *ValidatorInfo `json:"validator_info"`
}

// CometStatus is the common response from the /status RPC endpoint.
type CometStatus struct {
JSONRPC string `json:"jsonrpc"`
ID int `json:"id"`
Result struct {
NodeInfo NodeInfo
SyncInfo SyncInfo
ValidatorInfo ValidatorInfo
}
}

// LatestBlockHeight parses the latest block height string. If the string is malformed, returns 0.
Expand Down Expand Up @@ -93,9 +113,19 @@ func (client *CometClient) Status(ctx context.Context, rpcHost string) (CometSta
if resp.StatusCode != http.StatusOK {
return status, errors.New(resp.Status)
}
err = json.NewDecoder(resp.Body).Decode(&status)
var rpcStatusResponse rpcCometStatusResponse
err = json.NewDecoder(resp.Body).Decode(&rpcStatusResponse)
if err != nil {
return status, fmt.Errorf("malformed json: %w", err)
}
if rpcStatusResponse.ValidatorInfo != nil {
status.Result.ValidatorInfo = *rpcStatusResponse.ValidatorInfo
status.Result.SyncInfo = *rpcStatusResponse.SyncInfo
status.Result.NodeInfo = *rpcStatusResponse.NodeInfo
} else {
status.Result.ValidatorInfo = *rpcStatusResponse.Result.ValidatorInfo
status.Result.SyncInfo = *rpcStatusResponse.Result.SyncInfo
status.Result.NodeInfo = *rpcStatusResponse.Result.NodeInfo
}
return status, err
}
185 changes: 135 additions & 50 deletions internal/cosmos/comet_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,61 +34,93 @@ func TestCometStatus_LatestBlockHeight(t *testing.T) {
func TestCometClient_Status(t *testing.T) {
t.Parallel()

t.Run("happy path", func(t *testing.T) {
// This context ensures we're not comparing instances of context.Background().
cctx, cancel := context.WithCancel(context.Background())
defer cancel()

client := NewCometClient(http.DefaultClient)
require.NotNil(t, client.httpDo)

client.httpDo = func(req *http.Request) (*http.Response, error) {
require.Same(t, cctx, req.Context())
require.Equal(t, "GET", req.Method)
require.Equal(t, "http://10.2.3.4:26657/status", req.URL.String())

return &http.Response{
StatusCode: 200,
Body: io.NopCloser(strings.NewReader(statusResponseFixture)),
}, nil
}

got, err := client.Status(cctx, "http://10.2.3.4:26657")
require.NoError(t, err)
require.Equal(t, "cosmoshub-testnet-fullnode-0", got.Result.NodeInfo.Moniker)
require.Equal(t, false, got.Result.SyncInfo.CatchingUp)
require.Equal(t, "13348657", got.Result.SyncInfo.LatestBlockHeight)
require.Equal(t, "9034670", got.Result.SyncInfo.EarliestBlockHeight)
t.Run("when there are no errors", func(t *testing.T) {
t.Run("happy path", func(t *testing.T) {
// This context ensures we're not comparing instances of context.Background().
cctx, cancel := context.WithCancel(context.Background())
defer cancel()

client := NewCometClient(http.DefaultClient)
require.NotNil(t, client.httpDo)

client.httpDo = func(req *http.Request) (*http.Response, error) {
require.Same(t, cctx, req.Context())
require.Equal(t, "GET", req.Method)
require.Equal(t, "http://10.2.3.4:26657/status", req.URL.String())

return &http.Response{
StatusCode: 200,
Body: io.NopCloser(strings.NewReader(statusResponseFixture)),
}, nil
}

got, err := client.Status(cctx, "http://10.2.3.4:26657")
require.NoError(t, err)
require.Equal(t, "cosmoshub-testnet-fullnode-0", got.Result.NodeInfo.Moniker)
require.Equal(t, false, got.Result.SyncInfo.CatchingUp)
require.Equal(t, "13348657", got.Result.SyncInfo.LatestBlockHeight)
require.Equal(t, "9034670", got.Result.SyncInfo.EarliestBlockHeight)
})

t.Run("given SEI RPC it returns the status", func(t *testing.T) {
// This context ensures we're not comparing instances of context.Background().
cctx, cancel := context.WithCancel(context.Background())
defer cancel()

client := NewCometClient(http.DefaultClient)
require.NotNil(t, client.httpDo)

client.httpDo = func(req *http.Request) (*http.Response, error) {
require.Same(t, cctx, req.Context())
require.Equal(t, "GET", req.Method)
require.Equal(t, "http://10.2.3.4:26657/status", req.URL.String())

return &http.Response{
StatusCode: 200,
Body: io.NopCloser(strings.NewReader(seiStatusResponseFixture)),
}, nil
}

got, err := client.Status(cctx, "http://10.2.3.4:26657")
require.NoError(t, err)
require.Equal(t, "hello-sei-relayer", got.Result.NodeInfo.Moniker)
require.Equal(t, false, got.Result.SyncInfo.CatchingUp)
require.Equal(t, "37909189", got.Result.SyncInfo.LatestBlockHeight)
require.Equal(t, "33517999", got.Result.SyncInfo.EarliestBlockHeight)
})
})

t.Run("non 200 response", func(t *testing.T) {
client := NewCometClient(http.DefaultClient)
client.httpDo = func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: 500,
Status: "internal server error",
Body: io.NopCloser(strings.NewReader("")),
}, nil
}

_, err := client.Status(context.Background(), "http://10.2.3.4:26657")
require.Error(t, err)
require.EqualError(t, err, "internal server error")
})

t.Run("http error", func(t *testing.T) {
client := NewCometClient(http.DefaultClient)
client.httpDo = func(req *http.Request) (*http.Response, error) {
return nil, errors.New("boom")
}

_, err := client.Status(context.Background(), "http://10.2.3.4:26657")
require.Error(t, err)
require.EqualError(t, err, "boom")
t.Run("when there is an error", func(t *testing.T) {
t.Run("non 200 response", func(t *testing.T) {
client := NewCometClient(http.DefaultClient)
client.httpDo = func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: 500,
Status: "internal server error",
Body: io.NopCloser(strings.NewReader("")),
}, nil
}

_, err := client.Status(context.Background(), "http://10.2.3.4:26657")
require.Error(t, err)
require.EqualError(t, err, "internal server error")
})

t.Run("http error", func(t *testing.T) {
client := NewCometClient(http.DefaultClient)
client.httpDo = func(req *http.Request) (*http.Response, error) {
return nil, errors.New("boom")
}

_, err := client.Status(context.Background(), "http://10.2.3.4:26657")
require.Error(t, err)
require.EqualError(t, err, "boom")
})
})
}

const statusResponseFixture = `{
const statusResponseFixture = `
{
"jsonrpc": "2.0",
"id": -1,
"result": {
Expand Down Expand Up @@ -131,3 +163,56 @@ const statusResponseFixture = `{
}
}
`
const seiStatusResponseFixture = `
{
"node_info": {
"protocol_version": {
"p2p": "8",
"block": "11",
"app": "0"
},
"id": "a08b049a9d1909252f96973c3038db88b4b12883",
"listen_addr": "65.109.78.7:11956",
"network": "pacific-1",
"version": "0.35.0-unreleased",
"channels": "40202122233038606162630070717273",
"moniker": "hello-sei-relayer",
"other": {
"tx_index": "on",
"rpc_address": "tcp://0.0.0.0:11957"
}
},
"application_info": {
"version": "9"
},
"sync_info": {
"latest_block_hash": "24F4FEF7C5B704C99B3C36964ECCA855B9480E07F711B0A5FB2C348A4CAC5D48",
"latest_app_hash": "65271A3CA49CDC29FDC3A33974C508626F47CA178BCEA9421275E752824BC107",
"latest_block_height": "37909189",
"latest_block_time": "2023-11-09T17:36:20.235115543Z",
"earliest_block_hash": "0127F5D1CF7B53007180EB11052BB2B54D06C75EDE94E0F6686EA1988464B5B9",
"earliest_app_hash": "643CB8B56EA1A5F58D12396D26D8D89C7F9601FC199C6ACF76569BFCEE8C548C",
"earliest_block_height": "33517999",
"earliest_block_time": "2023-10-20T18:56:19.244399909Z",
"max_peer_block_height": "37909188",
"catching_up": false,
"total_synced_time": "0",
"remaining_time": "0",
"total_snapshots": "0",
"chunk_process_avg_time": "0",
"snapshot_height": "0",
"snapshot_chunks_count": "0",
"snapshot_chunks_total": "0",
"backfilled_blocks": "0",
"backfill_blocks_total": "0"
},
"validator_info": {
"address": "FD7DCAA2E2C25770720E844E0FEA6D0004940B02",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "7znc+z+uh4QFjLHTQPgSrXZvUpFRNMM9hjQCXNZYtyA="
},
"voting_power": "0"
}
}
`

0 comments on commit 798d060

Please sign in to comment.