bump version
added rest server and status endpoint added get block endpoint added latest block endpoint add 404 if height is out of bounds add version endpoint add validators endpoint export GetBlockHeight add keys endpoints add txs endpoints added verb limiters to ednpoints only output node info + json structure improvement fixed wrong body parsing github PR template crypto.Address -> sdk.Address revert to old go-wire update glide remove print statement and update glide fix #554 add .DS_Store to .gitignore Massive consolidation: queue, data storage struct, store, logic, ... Small fixes
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -120,3 +123,76 @@ func printCreate(info keys.Info, seed string) {
|
||||
panic(fmt.Sprintf("I can't speak: %s", output))
|
||||
}
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
type NewKeyBody struct {
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
// TODO make seed mandatory
|
||||
// Seed string `json="seed"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var kb keys.Keybase
|
||||
var m NewKeyBody
|
||||
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err = decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
if m.Name == "" {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("You have to specify a name for the locally stored account."))
|
||||
return
|
||||
}
|
||||
|
||||
// algo type defaults to ed25519
|
||||
if m.Type == "" {
|
||||
m.Type = "ed25519"
|
||||
}
|
||||
algo := keys.CryptoAlgo(m.Type)
|
||||
|
||||
_, _, err = kb.Create(m.Name, m.Password, algo)
|
||||
// TODO handle different errors
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(200)
|
||||
}
|
||||
|
||||
// function to just a new seed to display in the UI before actually persisting it in the keybase
|
||||
func getSeed(algo keys.CryptoAlgo) string {
|
||||
kb := client.MockKeyBase()
|
||||
pass := "throwing-this-key-away"
|
||||
name := "inmemorykey"
|
||||
|
||||
_, seed, _ := kb.Create(name, pass, algo)
|
||||
return seed
|
||||
}
|
||||
|
||||
func SeedRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
algoType := vars["type"]
|
||||
// algo type defaults to ed25519
|
||||
if algoType == "" {
|
||||
algoType = "ed25519"
|
||||
}
|
||||
algo := keys.CryptoAlgo(algoType)
|
||||
|
||||
seed := getSeed(algo)
|
||||
w.Write([]byte(seed))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -43,3 +47,41 @@ func runDeleteCmd(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("Password deleted forever (uh oh!)")
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
type DeleteKeyBody struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
var kb keys.Keybase
|
||||
var m DeleteKeyBody
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
kb, err = GetKeyBase()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO handle error if key is not available or pass is wrong
|
||||
err = kb.Delete(name, m.Password)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(200)
|
||||
}
|
||||
|
||||
+41
-1
@@ -1,6 +1,13 @@
|
||||
package keys
|
||||
|
||||
import "github.com/spf13/cobra"
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// CMD
|
||||
|
||||
// listKeysCmd represents the list command
|
||||
var listKeysCmd = &cobra.Command{
|
||||
@@ -23,3 +30,36 @@ func runListCmd(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//REST
|
||||
|
||||
func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
infos, err := kb.List()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
// an empty list will be JSONized as null, but we want to keep the empty list
|
||||
if len(infos) == 0 {
|
||||
w.Write([]byte("[]"))
|
||||
return
|
||||
}
|
||||
keysOutput := make([]KeyOutput, len(infos))
|
||||
for i, info := range infos {
|
||||
keysOutput[i] = KeyOutput{Name: info.Name, Address: info.PubKey.Address().String()}
|
||||
}
|
||||
output, err := json.MarshalIndent(keysOutput, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
+42
-6
@@ -1,7 +1,12 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -13,20 +18,51 @@ var showKeysCmd = &cobra.Command{
|
||||
RunE: runShowCmd,
|
||||
}
|
||||
|
||||
func getKey(name string) (keys.Info, error) {
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
return keys.Info{}, err
|
||||
}
|
||||
|
||||
return kb.Get(name)
|
||||
}
|
||||
|
||||
// CMD
|
||||
|
||||
func runShowCmd(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 || len(args[0]) == 0 {
|
||||
return errors.New("You must provide a name for the key")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := kb.Get(name)
|
||||
info, err := getKey(name)
|
||||
if err == nil {
|
||||
printInfo(info)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
|
||||
info, err := getKey(name)
|
||||
// TODO check for the error if key actually does not exist, instead of assuming this as the reason
|
||||
if err != nil {
|
||||
w.WriteHeader(404)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
keyOutput := KeyOutput{Name: info.Name, Address: info.PubKey.Address().String()}
|
||||
output, err := json.MarshalIndent(keyOutput, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -48,3 +52,42 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("Password successfully updated!")
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
type UpdateKeyBody struct {
|
||||
NewPassword string `json:"new_password"`
|
||||
OldPassword string `json:"old_password"`
|
||||
}
|
||||
|
||||
func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
name := vars["name"]
|
||||
var kb keys.Keybase
|
||||
var m UpdateKeyBody
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
kb, err = GetKeyBase()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO check if account exists and if password is correct
|
||||
err = kb.Update(name, m.OldPassword, m.NewPassword)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(200)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,14 @@ var (
|
||||
keybase keys.Keybase
|
||||
)
|
||||
|
||||
// used for outputting keys.Info over REST
|
||||
type KeyOutput struct {
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
// TODO add pubkey?
|
||||
// Pubkey string `json:"pubkey"`
|
||||
}
|
||||
|
||||
// GetKeyBase initializes a keybase based on the configuration
|
||||
func GetKeyBase() (keys.Keybase, error) {
|
||||
if keybase == nil {
|
||||
|
||||
+41
-10
@@ -1,11 +1,18 @@
|
||||
package lcd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
client "github.com/cosmos/cosmos-sdk/client"
|
||||
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"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -13,19 +20,14 @@ const (
|
||||
flagCORS = "cors"
|
||||
)
|
||||
|
||||
// XXX: remove this when not needed
|
||||
func todoNotImplemented(_ *cobra.Command, _ []string) error {
|
||||
return errors.New("TODO: Command not yet implemented")
|
||||
}
|
||||
|
||||
// ServeCommand will generate a long-running rest server
|
||||
// (aka Light Client Daemon) that exposes functionality similar
|
||||
// to the cli, but over rest
|
||||
func ServeCommand() *cobra.Command {
|
||||
func ServeCommand(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "serve",
|
||||
Use: "rest-server",
|
||||
Short: "Start LCD (light-client daemon), a local REST server",
|
||||
RunE: todoNotImplemented,
|
||||
RunE: startRESTServer(cdc),
|
||||
}
|
||||
// TODO: handle unix sockets also?
|
||||
cmd.Flags().StringP(flagBind, "b", "localhost:1317", "Interface and port that server binds to")
|
||||
@@ -34,3 +36,32 @@ func ServeCommand() *cobra.Command {
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func startRESTServer(cdc *wire.Codec) func(cmd *cobra.Command, args []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
bind := viper.GetString(flagBind)
|
||||
r := initRouter(cdc)
|
||||
return http.ListenAndServe(bind, r)
|
||||
}
|
||||
}
|
||||
|
||||
func initRouter(cdc *wire.Codec) http.Handler {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/version", version.VersionRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/node_info", rpc.NodeStatusRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/keys", keys.QueryKeysRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/keys", keys.AddNewKeyRequestHandler).Methods("POST")
|
||||
r.HandleFunc("/keys/seed", keys.SeedRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/keys/{name}", keys.GetKeyRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/keys/{name}", keys.UpdateKeyRequestHandler).Methods("PUT")
|
||||
r.HandleFunc("/keys/{name}", keys.DeleteKeyRequestHandler).Methods("DELETE")
|
||||
r.HandleFunc("/txs", tx.SearchTxRequestHandler(cdc)).Methods("GET")
|
||||
r.HandleFunc("/txs/{hash}", tx.QueryTxRequestHandler(cdc)).Methods("GET")
|
||||
r.HandleFunc("/txs/sign", tx.SignTxRequstHandler).Methods("POST")
|
||||
r.HandleFunc("/txs/broadcast", tx.BroadcastTxRequestHandler).Methods("POST")
|
||||
r.HandleFunc("/blocks/latest", rpc.LatestBlockRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/blocks/{height}", rpc.BlockRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/validatorsets/latest", rpc.LatestValidatorsetRequestHandler).Methods("GET")
|
||||
r.HandleFunc("/validatorsets/{height}", rpc.ValidatorsetRequestHandler).Methods("GET")
|
||||
return r
|
||||
}
|
||||
|
||||
+87
-20
@@ -1,11 +1,13 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
)
|
||||
@@ -18,7 +20,7 @@ func blockCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "block [height]",
|
||||
Short: "Get verified data for a the block at given height",
|
||||
RunE: getBlock,
|
||||
RunE: printBlock,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
||||
// TODO: change this to false when we can
|
||||
@@ -27,7 +29,47 @@ func blockCommand() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getBlock(cmd *cobra.Command, args []string) error {
|
||||
func getBlock(height *int64) ([]byte, error) {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: actually honor the --select flag!
|
||||
// header -> BlockchainInfo
|
||||
// header, tx -> Block
|
||||
// results -> BlockResults
|
||||
res, err := node.Block(height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO move maarshalling into cmd/rest functions
|
||||
// output, err := tmwire.MarshalJSON(res)
|
||||
output, err := json.MarshalIndent(res, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func GetChainHeight() (int64, error) {
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
status, err := node.Status()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
height := status.LatestBlockHeight
|
||||
return height, nil
|
||||
}
|
||||
|
||||
// CMD
|
||||
|
||||
func printBlock(cmd *cobra.Command, args []string) error {
|
||||
var height *int64
|
||||
// optional height
|
||||
if len(args) > 0 {
|
||||
@@ -41,26 +83,51 @@ func getBlock(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: actually honor the --select flag!
|
||||
// header -> BlockchainInfo
|
||||
// header, tx -> Block
|
||||
// results -> BlockResults
|
||||
res, err := node.Block(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSON(res)
|
||||
// output, err := json.MarshalIndent(res, " ", "")
|
||||
output, err := getBlock(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
func BlockRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
height, err := strconv.ParseInt(vars["height"], 10, 64)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/block/{height}'."))
|
||||
return
|
||||
}
|
||||
chainHeight, err := GetChainHeight()
|
||||
if height > chainHeight {
|
||||
w.WriteHeader(404)
|
||||
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
|
||||
return
|
||||
}
|
||||
output, err := getBlock(&height)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
func LatestBlockRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
height, err := GetChainHeight()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
output, err := getBlock(&height)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
+35
-4
@@ -1,31 +1,40 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
)
|
||||
|
||||
func statusCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "status",
|
||||
Short: "Query remote node for status",
|
||||
RunE: checkStatus,
|
||||
RunE: printNodeStatus,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func checkStatus(cmd *cobra.Command, args []string) error {
|
||||
func getNodeStatus() (*ctypes.ResultStatus, error) {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return err
|
||||
return &ctypes.ResultStatus{}, err
|
||||
}
|
||||
res, err := node.Status()
|
||||
return node.Status()
|
||||
}
|
||||
|
||||
// CMD
|
||||
|
||||
func printNodeStatus(cmd *cobra.Command, args []string) error {
|
||||
status, err := getNodeStatus()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -35,6 +44,28 @@ func checkStatus(cmd *cobra.Command, args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
// TODO match desired spec output
|
||||
func NodeStatusRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
status, err := getNodeStatus()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
nodeInfo := status.NodeInfo
|
||||
output, err := json.MarshalIndent(nodeInfo, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
+68
-15
@@ -1,11 +1,13 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
)
|
||||
@@ -14,7 +16,7 @@ func validatorCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "validatorset <height>",
|
||||
Short: "Get the full validator set at given height",
|
||||
RunE: getValidators,
|
||||
RunE: printValidators,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
||||
// TODO: change this to false when we can
|
||||
@@ -22,7 +24,28 @@ func validatorCommand() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func getValidators(cmd *cobra.Command, args []string) error {
|
||||
func getValidators(height *int64) ([]byte, error) {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := node.Validators(height)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(res, "", " ")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// CMD
|
||||
|
||||
func printValidators(cmd *cobra.Command, args []string) error {
|
||||
var height *int64
|
||||
// optional height
|
||||
if len(args) > 0 {
|
||||
@@ -36,22 +59,52 @@ func getValidators(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
output, err := getValidators(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := node.Validators(height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSON(res)
|
||||
// output, err := json.MarshalIndent(res, " ", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
func ValidatorsetRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
height, err := strconv.ParseInt(vars["height"], 10, 64)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'."))
|
||||
return
|
||||
}
|
||||
chainHeight, err := GetChainHeight()
|
||||
if height > chainHeight {
|
||||
w.WriteHeader(404)
|
||||
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
|
||||
return
|
||||
}
|
||||
output, err := getValidators(&height)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
func LatestValidatorsetRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
height, err := GetChainHeight()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
output, err := getValidators(&height)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
|
||||
+40
-11
@@ -3,6 +3,7 @@ package tx
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
@@ -24,7 +25,7 @@ func SearchTxCmd(cmdr commander) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "txs",
|
||||
Short: "Search for all transactions that match the given tags",
|
||||
RunE: cmdr.searchTxCmd,
|
||||
RunE: cmdr.searchAndPrintTx,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
||||
// TODO: change this to false once proofs built in
|
||||
@@ -34,10 +35,9 @@ func SearchTxCmd(cmdr commander) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c commander) searchTxCmd(cmd *cobra.Command, args []string) error {
|
||||
tags := viper.GetStringSlice(flagTags)
|
||||
func (c commander) searchTx(tags []string) ([]byte, error) {
|
||||
if len(tags) == 0 {
|
||||
return errors.New("Must declare at least one tag to search")
|
||||
return nil, errors.New("Must declare at least one tag to search")
|
||||
}
|
||||
// XXX: implement ANY
|
||||
query := strings.Join(tags, " AND ")
|
||||
@@ -45,27 +45,25 @@ func (c commander) searchTxCmd(cmd *cobra.Command, args []string) error {
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prove := !viper.GetBool(client.FlagTrustNode)
|
||||
res, err := node.TxSearch(query, prove)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := formatTxResults(c.cdc, res)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output, err := c.cdc.MarshalJSON(info)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
|
||||
return nil
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error) {
|
||||
@@ -79,3 +77,34 @@ func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CMD
|
||||
|
||||
func (c commander) searchAndPrintTx(cmd *cobra.Command, args []string) error {
|
||||
tags := viper.GetStringSlice(flagTags)
|
||||
|
||||
output, err := c.searchTx(tags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
func SearchTxRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Request) {
|
||||
c := commander{cdc}
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
tag := r.FormValue("tag")
|
||||
tags := []string{tag}
|
||||
output, err := c.searchTx(tags)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
}
|
||||
|
||||
+124
-23
@@ -4,12 +4,20 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
keybase "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
keys "github.com/tendermint/go-crypto/keys"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
@@ -22,7 +30,7 @@ func QueryTxCmd(cmdr commander) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "tx [hash]",
|
||||
Short: "Matches this txhash over all committed blocks",
|
||||
RunE: cmdr.queryTxCmd,
|
||||
RunE: cmdr.queryAndPrintTx,
|
||||
}
|
||||
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:46657", "Node to connect to")
|
||||
// TODO: change this to false when we can
|
||||
@@ -30,42 +38,28 @@ func QueryTxCmd(cmdr commander) *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// command to query for a transaction
|
||||
func (c commander) queryTxCmd(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 || len(args[0]) == 0 {
|
||||
return errors.New("You must provide a tx hash")
|
||||
}
|
||||
|
||||
// find the key to look up the account
|
||||
hexStr := args[0]
|
||||
hash, err := hex.DecodeString(hexStr)
|
||||
func (c commander) queryTx(hashHexStr string, trustNode bool) ([]byte, error) {
|
||||
hash, err := hex.DecodeString(hashHexStr)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get the node
|
||||
node, err := client.GetNode()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
prove := !viper.GetBool(client.FlagTrustNode)
|
||||
|
||||
res, err := node.Tx(hash, prove)
|
||||
res, err := node.Tx(hash, !trustNode)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
info, err := formatTxResult(c.cdc, res)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(info, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
|
||||
return nil
|
||||
return json.MarshalIndent(info, "", " ")
|
||||
}
|
||||
|
||||
func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (txInfo, error) {
|
||||
@@ -98,3 +92,110 @@ func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) {
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
// CMD
|
||||
|
||||
// command to query for a transaction
|
||||
func (c commander) queryAndPrintTx(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 || len(args[0]) == 0 {
|
||||
return errors.New("You must provide a tx hash")
|
||||
}
|
||||
|
||||
// find the key to look up the account
|
||||
hashHexStr := args[0]
|
||||
trustNode := viper.GetBool(client.FlagTrustNode)
|
||||
|
||||
output, err := c.queryTx(hashHexStr, trustNode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// REST
|
||||
|
||||
func QueryTxRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Request) {
|
||||
c := commander{cdc}
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
hashHexStr := vars["hash"]
|
||||
trustNode, err := strconv.ParseBool(r.FormValue("trust_node"))
|
||||
// trustNode defaults to true
|
||||
if err != nil {
|
||||
trustNode = true
|
||||
}
|
||||
|
||||
output, err := c.queryTx(hashHexStr, trustNode)
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.Write(output)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO refactor into different files show, sign, broadcast
|
||||
|
||||
type SignTxBody struct {
|
||||
Name string `json="name"`
|
||||
Password string `json="password"`
|
||||
TxBytes string `json="tx"`
|
||||
}
|
||||
|
||||
func SignTxRequstHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var kb keys.Keybase
|
||||
var m SignTxBody
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
kb, err = keybase.GetKeyBase()
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
//TODO check if account exists
|
||||
sig, _, err := kb.Sign(m.Name, m.Password, []byte(m.TxBytes))
|
||||
if err != nil {
|
||||
w.WriteHeader(403)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(sig.Bytes())
|
||||
}
|
||||
|
||||
type BroadcastTxBody struct {
|
||||
TxBytes string `json="tx"`
|
||||
}
|
||||
|
||||
func BroadcastTxRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var m BroadcastTxBody
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&m)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
res, err := client.BroadcastTx([]byte(m.TxBytes))
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(string(res.Height)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user