diff --git a/CHANGELOG.md b/CHANGELOG.md index b37db2292..f7d4b3c85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ BREAKING CHANGES FEATURES * [x/auth] Added AccountNumbers to BaseAccount and StdTxs to allow for replay protection with account pruning +* [lcd] added an endpoint to query for the SDK version of the connected node IMPROVEMENTS * export command now writes current validator set for Tendermint diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 93ea6ae03..3265a870f 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" ) @@ -338,6 +339,11 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { } else { result = app.Simulate(tx) } + case "version": + return abci.ResponseQuery{ + Code: uint32(sdk.ABCICodeOK), + Value: []byte(version.GetVersion()), + } default: result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result() } diff --git a/client/context/helpers.go b/client/context/helpers.go index 0e28f5fd0..5449afa97 100644 --- a/client/context/helpers.go +++ b/client/context/helpers.go @@ -3,6 +3,8 @@ package context import ( "fmt" + "github.com/tendermint/tmlibs/common" + "github.com/pkg/errors" "github.com/cosmos/cosmos-sdk/wire" @@ -42,14 +44,19 @@ func (ctx CoreContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, return res, err } -// Query from Tendermint with the provided key and storename -func (ctx CoreContext) Query(key cmn.HexBytes, storeName string) (res []byte, err error) { - return ctx.query(key, storeName, "key") +// Query information about the connected node +func (ctx CoreContext) Query(path string) (res []byte, err error) { + return ctx.query(path, nil) +} + +// QueryStore from Tendermint with the provided key and storename +func (ctx CoreContext) QueryStore(key cmn.HexBytes, storeName string) (res []byte, err error) { + return ctx.queryStore(key, storeName, "key") } // Query from Tendermint with the provided storename and subspace func (ctx CoreContext) QuerySubspace(cdc *wire.Codec, subspace []byte, storeName string) (res []sdk.KVPair, err error) { - resRaw, err := ctx.query(subspace, storeName, "subspace") + resRaw, err := ctx.queryStore(subspace, storeName, "subspace") if err != nil { return res, err } @@ -58,8 +65,7 @@ func (ctx CoreContext) QuerySubspace(cdc *wire.Codec, subspace []byte, storeName } // Query from Tendermint with the provided storename and path -func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) { - path := fmt.Sprintf("/store/%s/%s", storeName, endPath) +func (ctx CoreContext) query(path string, key common.HexBytes) (res []byte, err error) { node, err := ctx.GetNode() if err != nil { return res, err @@ -80,6 +86,12 @@ func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res [ return resp.Value, nil } +// Query from Tendermint with the provided storename and path +func (ctx CoreContext) queryStore(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) { + path := fmt.Sprintf("/store/%s/%s", storeName, endPath) + return ctx.query(path, key) +} + // Get the from address from the name flag func (ctx CoreContext) GetFromAddress() (from sdk.Address, err error) { @@ -177,7 +189,7 @@ func (ctx CoreContext) GetAccountNumber(address []byte) (int64, error) { return 0, errors.New("accountDecoder required but not provided") } - res, err := ctx.Query(auth.AddressStoreKey(address), ctx.AccountStore) + res, err := ctx.QueryStore(auth.AddressStoreKey(address), ctx.AccountStore) if err != nil { return 0, err } @@ -201,7 +213,7 @@ func (ctx CoreContext) NextSequence(address []byte) (int64, error) { return 0, errors.New("accountDecoder required but not provided") } - res, err := ctx.Query(auth.AddressStoreKey(address), ctx.AccountStore) + res, err := ctx.QueryStore(auth.AddressStoreKey(address), ctx.AccountStore) if err != nil { return 0, err } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index ba2937e05..0bacbee20 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -116,6 +116,15 @@ func TestVersion(t *testing.T) { require.Nil(t, err) match := reg.MatchString(body) assert.True(t, match, body) + + // node info + res, body = Request(t, port, "GET", "/node_version", nil) + require.Equal(t, http.StatusOK, res.StatusCode, body) + + reg, err = regexp.Compile(`\d+\.\d+\.\d+(-dev)?`) + require.Nil(t, err) + match = reg.MatchString(body) + assert.True(t, match, body) } func TestNodeStatus(t *testing.T) { diff --git a/client/lcd/root.go b/client/lcd/root.go index 7d819740c..4af034297 100644 --- a/client/lcd/root.go +++ b/client/lcd/root.go @@ -17,7 +17,6 @@ import ( keys "github.com/cosmos/cosmos-sdk/client/keys" rpc "github.com/cosmos/cosmos-sdk/client/rpc" tx "github.com/cosmos/cosmos-sdk/client/tx" - version "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/wire" auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest" bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest" @@ -63,7 +62,6 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command { func createHandler(cdc *wire.Codec) http.Handler { r := mux.NewRouter() - r.HandleFunc("/version", version.RequestHandler).Methods("GET") kb, err := keys.GetKeyBase() //XXX if err != nil { @@ -73,6 +71,8 @@ func createHandler(cdc *wire.Codec) http.Handler { ctx := context.NewCoreContextFromViper() // TODO make more functional? aka r = keys.RegisterRoutes(r) + r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET") + r.HandleFunc("/node_version", NodeVersionRequestHandler(cdc, ctx)).Methods("GET") keys.RegisterRoutes(r) rpc.RegisterRoutes(ctx, r) tx.RegisterRoutes(ctx, r, cdc) diff --git a/client/lcd/version.go b/client/lcd/version.go new file mode 100644 index 000000000..0c8ef4ef6 --- /dev/null +++ b/client/lcd/version.go @@ -0,0 +1,29 @@ +package lcd + +import ( + "fmt" + "net/http" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/wire" +) + +// cli version REST handler endpoint +func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) { + v := version.GetVersion() + w.Write([]byte(v)) +} + +// connected node version REST handler endpoint +func NodeVersionRequestHandler(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + version, err := ctx.Query("/app/version") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Could't query version. Error: %s", err.Error()))) + return + } + w.Write([]byte(version)) + } +} diff --git a/docs/sdk/lcd-rest-api.yaml b/docs/sdk/lcd-rest-api.yaml index 6a5be2394..a39b7bf08 100644 --- a/docs/sdk/lcd-rest-api.yaml +++ b/docs/sdk/lcd-rest-api.yaml @@ -17,6 +17,13 @@ paths: responses: 200: description: Plaintext version i.e. "v0.5.0" + /node_version: + get: + summary: Version of the connected node + description: Get the version of the SDK running on the connected node to compare against expected + responses: + 200: + description: Plaintext version i.e. "v0.5.0" /node_info: get: description: Only the node info. Block information can be queried via /block/latest diff --git a/version/command.go b/version/command.go index b505414b1..2cff1bbe9 100644 --- a/version/command.go +++ b/version/command.go @@ -2,7 +2,6 @@ package version import ( "fmt" - "net/http" "github.com/spf13/cobra" ) @@ -16,7 +15,8 @@ var ( } ) -func getVersion() string { +// return version of CLI/node and commit hash +func GetVersion() string { v := Version if GitCommit != "" { v = v + "-" + GitCommit @@ -26,12 +26,6 @@ func getVersion() string { // CMD func printVersion(cmd *cobra.Command, args []string) { - v := getVersion() + v := GetVersion() fmt.Println(v) } - -// version REST handler endpoint -func RequestHandler(w http.ResponseWriter, r *http.Request) { - v := getVersion() - w.Write([]byte(v)) -} diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index a3265a78c..ccc1e277b 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -47,7 +47,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode // perform query ctx := context.NewCoreContextFromViper() - res, err := ctx.Query(auth.AddressStoreKey(key), storeName) + res, err := ctx.QueryStore(auth.AddressStoreKey(key), storeName) if err != nil { return err } diff --git a/x/auth/client/rest/query.go b/x/auth/client/rest/query.go index 1f68a69e5..a5d6f328c 100644 --- a/x/auth/client/rest/query.go +++ b/x/auth/client/rest/query.go @@ -34,7 +34,7 @@ func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder aut return } - res, err := ctx.Query(auth.AddressStoreKey(addr), storeName) + res, err := ctx.QueryStore(auth.AddressStoreKey(addr), storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("couldn't query account. Error: %s", err.Error()))) diff --git a/x/ibc/client/cli/relay.go b/x/ibc/client/cli/relay.go index 9742f83f9..90ea74b77 100644 --- a/x/ibc/client/cli/relay.go +++ b/x/ibc/client/cli/relay.go @@ -151,7 +151,7 @@ OUTER: } func query(node string, key []byte, storeName string) (res []byte, err error) { - return context.NewCoreContextFromViper().WithNodeURI(node).Query(key, storeName) + return context.NewCoreContextFromViper().WithNodeURI(node).QueryStore(key, storeName) } func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error { diff --git a/x/slashing/client/cli/query.go b/x/slashing/client/cli/query.go index 948e75667..c1b16eb3a 100644 --- a/x/slashing/client/cli/query.go +++ b/x/slashing/client/cli/query.go @@ -27,7 +27,7 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command { } key := slashing.GetValidatorSigningInfoKey(pk.Address()) ctx := context.NewCoreContextFromViper() - res, err := ctx.Query(key, storeName) + res, err := ctx.QueryStore(key, storeName) if err != nil { return err } diff --git a/x/stake/client/cli/query.go b/x/stake/client/cli/query.go index eac39b9ef..727cddcde 100644 --- a/x/stake/client/cli/query.go +++ b/x/stake/client/cli/query.go @@ -27,7 +27,7 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command { } key := stake.GetValidatorKey(addr) ctx := context.NewCoreContextFromViper() - res, err := ctx.Query(key, storeName) + res, err := ctx.QueryStore(key, storeName) if err != nil { return err } @@ -124,7 +124,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command { key := stake.GetDelegationKey(delAddr, addr, cdc) ctx := context.NewCoreContextFromViper() - res, err := ctx.Query(key, storeName) + res, err := ctx.QueryStore(key, storeName) if err != nil { return err } diff --git a/x/stake/client/rest/query.go b/x/stake/client/rest/query.go index d9288fb11..ec0e81330 100644 --- a/x/stake/client/rest/query.go +++ b/x/stake/client/rest/query.go @@ -48,7 +48,7 @@ func bondingStatusHandlerFn(ctx context.CoreContext, storeName string, cdc *wire key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) - res, err := ctx.Query(key, storeName) + res, err := ctx.QueryStore(key, storeName) if err != nil { w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("couldn't query bond. Error: %s", err.Error())))