add /accounts endpoints but failing

This commit is contained in:
Fabian 2018-03-10 18:33:05 +01:00 committed by Ethan Buchman
parent 0d423ae066
commit 0121c98a1e
8 changed files with 329 additions and 47 deletions

View File

@ -127,8 +127,8 @@ func TestVersion(t *testing.T) {
}
func TestNodeStatus(t *testing.T) {
ch := server.StartServer(t)
defer close(ch)
_, _ = startServer(t)
// TODO need to kill server after
prepareClient(t)
cdc := app.MakeCodec()
@ -153,8 +153,8 @@ func TestNodeStatus(t *testing.T) {
}
func TestBlock(t *testing.T) {
ch := server.StartServer(t)
defer close(ch)
_, _ = startServer(t)
// TODO need to kill server after
prepareClient(t)
cdc := app.MakeCodec()
@ -184,9 +184,8 @@ func TestBlock(t *testing.T) {
}
func TestValidators(t *testing.T) {
ch := server.StartServer(t)
defer close(ch)
_, _ = startServer(t)
// TODO need to kill server after
prepareClient(t)
cdc := app.MakeCodec()
r := initRouter(cdc)
@ -214,6 +213,67 @@ func TestValidators(t *testing.T) {
require.Equal(t, http.StatusNotFound, res.Code)
}
func TestCoinSend(t *testing.T) {
addr, seed := startServer(t)
// TODO need to kill server after
prepareClient(t)
cdc := app.MakeCodec()
r := initRouter(cdc)
// query empty
res := request(t, r, "GET", "/accounts/1234567890123456789012345678901234567890", nil)
require.Equal(t, http.StatusNoContent, res.Code, res.Body.String())
// query
res = request(t, r, "GET", "/accounts/"+addr.String(), nil)
require.Equal(t, http.StatusOK, res.Code, res.Body.String())
assert.Equal(t, `{
"coins": [
{
"denom": "mycoin",
"amount": 9007199254740992
}
]
}`, res.Body.String())
// create account for default coins
var jsonStr = []byte(fmt.Sprintf(`{"name":"test", "password":"1234567890", "seed": "%s"}`, seed))
res = request(t, r, "POST", "/keys", jsonStr)
require.Equal(t, http.StatusOK, res.Code, res.Body.String())
// create random account
res = request(t, r, "GET", "/keys/seed", nil)
require.Equal(t, http.StatusOK, res.Code, res.Body.String())
receiveSeed := res.Body.String()
jsonStr = []byte(fmt.Sprintf(`{"name":"receive", "password":"1234567890", "seed": "%s"}`, receiveSeed))
res = request(t, r, "POST", "/keys", jsonStr)
require.Equal(t, http.StatusOK, res.Code, res.Body.String())
receiveAddr := res.Body.String()
// send
jsonStr = []byte(`{"name":"test", "password":"1234567890", "amount":[{
"denom": "mycoin",
"amount": 1
}]}`)
res = request(t, r, "POST", "/accounts/"+receiveAddr+"/send", jsonStr)
require.Equal(t, http.StatusOK, res.Code, res.Body.String())
// check if received
res = request(t, r, "GET", "/accounts/"+receiveAddr, nil)
require.Equal(t, http.StatusOK, res.Code, res.Body.String())
assert.Equal(t, `{
"coins": [
{
"denom": "mycoin",
"amount": 1
}
]
}`, res.Body.String())
}
//__________________________________________________________
// helpers
@ -226,6 +286,8 @@ func prepareClient(t *testing.T) {
app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db)
viper.Set(client.FlagNode, "localhost:46657")
_ = client.GetKeyBase(db)
header := abci.Header{Height: 1}
app.BeginBlock(abci.RequestBeginBlock{Header: header})
app.Commit()
@ -244,11 +306,31 @@ func setupViper() func() {
}
}
func startServer(t *testing.T) {
// from baseoind.main
func defaultOptions(addr string) func(args []string) (json.RawMessage, error) {
return func(args []string) (json.RawMessage, error) {
opts := fmt.Sprintf(`{
"accounts": [{
"address": "%s",
"coins": [
{
"denom": "mycoin",
"amount": 9007199254740992
}
]
}]
}`, addr)
return json.RawMessage(opts), nil
}
}
func startServer(t *testing.T) (types.Address, string) {
defer setupViper()()
// init server
initCmd := server.InitCmd(mock.GenInitOptions, log.NewNopLogger())
err := initCmd.RunE(nil, nil)
addr, secret, err := server.GenerateCoinKey()
require.NoError(t, err)
initCmd := server.InitCmd(defaultOptions(addr.String()), log.NewNopLogger())
err = initCmd.RunE(nil, nil)
require.NoError(t, err)
// start server
@ -258,6 +340,8 @@ func startServer(t *testing.T) {
err = runOrTimeout(startCmd, timeout)
require.NoError(t, err)
return addr, secret
}
// copied from server/start_test.go
@ -281,16 +365,6 @@ func runOrTimeout(cmd *cobra.Command, timeout time.Duration) error {
}
}
func createKey(t *testing.T, r http.Handler) string {
var jsonStr = []byte(`{"name":"test", "password":"1234567890"}`)
res := request(t, r, "POST", "/keys", jsonStr)
assert.Equal(t, http.StatusOK, res.Code, res.Body.String())
addr := res.Body.String()
return addr
}
func request(t *testing.T, r http.Handler, method string, path string, payload []byte) *httptest.ResponseRecorder {
req, err := http.NewRequest(method, path, bytes.NewBuffer(payload))
require.Nil(t, err)

View File

@ -13,6 +13,8 @@ import (
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/rest"
bank "github.com/cosmos/cosmos-sdk/x/bank/rest"
)
const (
@ -52,5 +54,7 @@ func initRouter(cdc *wire.Codec) http.Handler {
keys.RegisterRoutes(r)
rpc.RegisterRoutes(r)
tx.RegisterRoutes(r, cdc)
auth.RegisterRoutes(r, cdc, "main")
bank.RegisterRoutes(r, cdc)
return r
}

View File

@ -16,10 +16,10 @@ import (
// GetAccountCmd for the auth.BaseAccount type
func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command {
return GetAccountCmd(storeName, cdc, getParseAccount(cdc))
return GetAccountCmd(storeName, cdc, GetParseAccount(cdc))
}
func getParseAccount(cdc *wire.Codec) sdk.ParseAccount {
func GetParseAccount(cdc *wire.Codec) sdk.ParseAccount {
return func(accBytes []byte) (sdk.Account, error) {
acct := new(auth.BaseAccount)
err := cdc.UnmarshalBinary(accBytes, &acct)

66
x/auth/rest/query.go Normal file
View File

@ -0,0 +1,66 @@
package rest
import (
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
type commander struct {
storeName string
cdc *wire.Codec
parser sdk.ParseAccount
}
func QueryAccountRequestHandler(storeName string, cdc *wire.Codec, parser sdk.ParseAccount) func(http.ResponseWriter, *http.Request) {
c := commander{storeName, cdc, parser}
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
addr := vars["address"]
bz, err := hex.DecodeString(addr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
key := sdk.Address(bz)
res, err := client.Query(key, c.storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't query account. Error: %s", err.Error())))
return
}
// the query will return empty if there is no data for this account
if len(res) == 0 {
w.WriteHeader(http.StatusNoContent)
return
}
// parse out the value
account, err := c.parser(res)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't parse query result. Result: %s. Error: %s", res, err.Error())))
return
}
// print out whole account
output, err := json.MarshalIndent(account, "", " ")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't marshall query result. Error: %s", err.Error())))
return
}
w.Write(output)
}
}

11
x/auth/rest/root.go Normal file
View File

@ -0,0 +1,11 @@
package rest
import (
"github.com/cosmos/cosmos-sdk/wire"
auth "github.com/cosmos/cosmos-sdk/x/auth/commands"
"github.com/gorilla/mux"
)
func RegisterRoutes(r *mux.Router, cdc *wire.Codec, storeName string) {
r.HandleFunc("/accounts/{address}", QueryAccountRequestHandler(storeName, cdc, auth.GetParseAccount(cdc))).Methods("GET")
}

View File

@ -10,8 +10,8 @@ import (
"github.com/cosmos/cosmos-sdk/client/builder"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/bank"
cryptokeys "github.com/tendermint/go-crypto/keys"
)
const (
@ -20,8 +20,8 @@ const (
)
// SendTxCommand will create a send tx and sign it with the given key
func SendTxCmd(cdc *wire.Codec) *cobra.Command {
cmdr := commander{cdc}
func SendTxCmd(Cdc *wire.Codec) *cobra.Command {
cmdr := Commander{Cdc}
cmd := &cobra.Command{
Use: "send",
Short: "Create and sign a send tx",
@ -32,18 +32,32 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
return cmd
}
type commander struct {
cdc *wire.Codec
type Commander struct {
Cdc *wire.Codec
}
func (c commander) sendTxCmd(cmd *cobra.Command, args []string) error {
func (c Commander) sendTxCmd(cmd *cobra.Command, args []string) error {
// get the from address
from, err := builder.GetFromAddress()
if err != nil {
return err
}
// parse coins
amount := viper.GetString(flagAmount)
coins, err := sdk.ParseCoins(amount)
if err != nil {
return err
}
// parse destination address
dest := viper.GetString(flagTo)
bz, err := hex.DecodeString(dest)
if err != nil {
return err
}
to := sdk.Address(bz)
// build send msg
msg, err := buildMsg(from)
if err != nil {
@ -60,25 +74,32 @@ func (c commander) sendTxCmd(cmd *cobra.Command, args []string) error {
return nil
}
func buildMsg(from sdk.Address) (sdk.Msg, error) {
// parse coins
amount := viper.GetString(flagAmount)
coins, err := sdk.ParseCoins(amount)
if err != nil {
return nil, err
}
// parse destination address
dest := viper.GetString(flagTo)
bz, err := hex.DecodeString(dest)
if err != nil {
return nil, err
}
to := sdk.Address(bz)
func BuildMsg(from sdk.Address, to sdk.Address, coins sdk.Coins) sdk.Msg {
input := bank.NewInput(from, coins)
output := bank.NewOutput(to, coins)
msg := bank.NewSendMsg([]bank.Input{input}, []bank.Output{output})
return msg, nil
return msg
}
func (c Commander) SignMessage(msg sdk.Msg, kb cryptokeys.Keybase, accountName string, password string) ([]byte, error) {
// sign and build
bz := msg.GetSignBytes()
sig, pubkey, err := kb.Sign(accountName, password, bz)
if err != nil {
return nil, err
}
sigs := []sdk.StdSignature{{
PubKey: pubkey,
Signature: sig,
Sequence: viper.GetInt64(flagSequence),
}}
// marshal bytes
tx := sdk.NewStdTx(msg, sigs)
txBytes, err := c.Cdc.MarshalBinary(tx)
if err != nil {
return nil, err
}
return txBytes, nil
}

10
x/bank/rest/root.go Normal file
View File

@ -0,0 +1,10 @@
package rest
import (
"github.com/cosmos/cosmos-sdk/wire"
"github.com/gorilla/mux"
)
func RegisterRoutes(r *mux.Router, cdc *wire.Codec) {
r.HandleFunc("/accounts/{address}/send", SendRequestHandler(cdc)).Methods("POST")
}

96
x/bank/rest/sendtx.go Normal file
View File

@ -0,0 +1,96 @@
package rest
import (
"encoding/hex"
"encoding/json"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/bank/commands"
)
type SendBody struct {
// fees is not used currently
// Fees sdk.Coin `json="fees"`
Amount sdk.Coins `json="amount"`
LocalAccountName string `json="account"`
Password string `json="password"`
}
func SendRequestHandler(cdc *wire.Codec) func(http.ResponseWriter, *http.Request) {
c := commands.Commander{cdc}
return func(w http.ResponseWriter, r *http.Request) {
// collect data
vars := mux.Vars(r)
address := vars["address"]
var m SendBody
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
kb, err := keys.GetKeyBase()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
info, err := kb.Get(m.LocalAccountName)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
return
}
bz, err := hex.DecodeString(address)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
to := sdk.Address(bz)
// build
msg := commands.BuildMsg(info.Address(), to, m.Amount)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
// sign
txBytes, err := c.SignMessage(msg, kb, m.LocalAccountName, m.Password)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
return
}
// send
res, err := client.BroadcastTx(txBytes)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(res, "", " ")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}