package rpc import ( "context" "net/http" "github.com/spf13/cobra" "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/p2p" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/version" ) // ValidatorInfo is info about the node's validator, same as Tendermint, // except that we use our own PubKey. type validatorInfo struct { Address bytes.HexBytes PubKey cryptotypes.PubKey VotingPower int64 } // ResultStatus is node's info, same as Tendermint, except that we use our own // PubKey. type resultStatus struct { NodeInfo p2p.DefaultNodeInfo SyncInfo ctypes.SyncInfo ValidatorInfo validatorInfo } // StatusCommand returns the command to return the status of the network. func StatusCommand() *cobra.Command { cmd := &cobra.Command{ Use: "status", Short: "Query remote node for status", RunE: func(cmd *cobra.Command, _ []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } status, err := getNodeStatus(clientCtx) if err != nil { return err } // `status` has TM pubkeys, we need to convert them to our pubkeys. pk, err := cryptocodec.FromTmPubKeyInterface(status.ValidatorInfo.PubKey) if err != nil { return err } statusWithPk := resultStatus{ NodeInfo: status.NodeInfo, SyncInfo: status.SyncInfo, ValidatorInfo: validatorInfo{ Address: status.ValidatorInfo.Address, PubKey: pk, VotingPower: status.ValidatorInfo.VotingPower, }, } output, err := clientCtx.LegacyAmino.MarshalJSON(statusWithPk) if err != nil { return err } cmd.Println(string(output)) return nil }, } cmd.Flags().StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") return cmd } func getNodeStatus(clientCtx client.Context) (*ctypes.ResultStatus, error) { node, err := clientCtx.GetNode() if err != nil { return &ctypes.ResultStatus{}, err } return node.Status(context.Background()) } // NodeInfoResponse defines a response type that contains node status and version // information. type NodeInfoResponse struct { p2p.DefaultNodeInfo `json:"node_info"` ApplicationVersion version.Info `json:"application_version"` } // REST handler for node info func NodeInfoRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status, err := getNodeStatus(clientCtx) if rest.CheckInternalServerError(w, err) { return } resp := NodeInfoResponse{ DefaultNodeInfo: status.NodeInfo, ApplicationVersion: version.NewInfo(), } rest.PostProcessResponseBare(w, clientCtx, resp) } } // SyncingResponse defines a response type that contains node syncing information. type SyncingResponse struct { Syncing bool `json:"syncing"` } // REST handler for node syncing func NodeSyncingRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status, err := getNodeStatus(clientCtx) if rest.CheckInternalServerError(w, err) { return } rest.PostProcessResponseBare(w, clientCtx, SyncingResponse{Syncing: status.SyncInfo.CatchingUp}) } }