Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Gaia Lite Generate Only Support (w/o Keybase) #3396

Merged
merged 28 commits into from
Jan 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
be414e8
update swagger from original pr
Jan 25, 2019
2c1a548
cleanup CLIContext and expose from fields/helpers
Jan 25, 2019
a495415
update utils and API
Jan 25, 2019
54c10c7
update rest utils
Jan 25, 2019
8405680
refactor WriteGenerateStdTxResponse and implement ToTxBuilder
Jan 25, 2019
64fa9f9
update CompleteAndBroadcastTxREST godoc
Jan 25, 2019
e2f3854
further refactor CompleteAndBroadcastTxREST
Jan 25, 2019
b7c8e4b
update bank transfer REST route to support gen only
Jan 25, 2019
7b2641c
add gen only comment on address validation
Jan 25, 2019
81e2408
update CLI commands to reflect new CLIContext APIs
Jan 28, 2019
d22d179
update sign REST endpoint to allow for address or key name
Jan 28, 2019
8028c14
allow for generate only in x/gov POST REST endpoints
Jan 28, 2019
acd4d01
remove ToTxBuilder
Jan 28, 2019
c1da687
allow for generate only in x/ibc POST REST endpoints
Jan 28, 2019
4fb8ae6
allow for generate only in x/slashing POST REST endpoints
Jan 28, 2019
c3f83a8
add ValidateBasic message call to slashing endpoint
Jan 28, 2019
197a023
allow for generate only in x/staking POST REST endpoints
Jan 28, 2019
6707014
fix x/ibc errors
Jan 28, 2019
69f488d
fix and update LCD tests to use gas estimation and generation only
Jan 28, 2019
e31f60c
update docs
Jan 28, 2019
db52973
update swagger docs
Jan 28, 2019
ea854aa
add pending log entry
Jan 28, 2019
c26e4bf
Merge branch 'develop' into bez/3284-gaia-lite-gen-only-tx
Jan 28, 2019
1328e0c
Update client/utils/rest.go
fedekunze Jan 28, 2019
01baa21
use Vue tip notes
Jan 28, 2019
4b06321
Merge remote-tracking branch 'origin/bez/3284-gaia-lite-gen-only-tx' …
Jan 28, 2019
9c892c9
implement TestCoinSendGenerateOnly
Jan 28, 2019
30aebc1
implement TestCoinSendAccAuto
Jan 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
BREAKING CHANGES

* Gaia REST API (`gaiacli advanced rest-server`)
* [\#3284](https://github.com/cosmos/cosmos-sdk/issues/3284) Rename the `name`
field to `from` in the `base_req` body.

* Gaia CLI (`gaiacli`)

Expand Down Expand Up @@ -31,6 +33,11 @@ FEATURES
IMPROVEMENTS

* Gaia REST API
* [\#3284](https://github.com/cosmos/cosmos-sdk/issues/3284) Update Gaia Lite
REST service to support the following:
* Automatic account number and sequence population when fields are omitted
* Generate only functionality no longer requires access to a local Keybase
* `from` field in the `base_req` body can be a Keybase name or account address

* Gaia CLI (`gaiacli`)

Expand Down
96 changes: 54 additions & 42 deletions client/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
"path/filepath"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/codec"
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/x/auth"

"github.com/spf13/viper"
Expand All @@ -19,14 +21,10 @@ import (
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"

"github.com/cosmos/cosmos-sdk/client/keys"
cskeys "github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

var (
verifier tmlite.Verifier
)
var verifier tmlite.Verifier

// CLIContext implements a typical CLI context created in SDK modules for
// transaction handling and queries.
Expand All @@ -47,8 +45,8 @@ type CLIContext struct {
Verifier tmlite.Verifier
Simulate bool
GenerateOnly bool
fromAddress types.AccAddress
fromName string
FromAddress sdk.AccAddress
FromName string
Indent bool
}

Expand All @@ -63,7 +61,11 @@ func NewCLIContext() CLIContext {
}

from := viper.GetString(client.FlagFrom)
fromAddress, fromName := fromFields(from)
fromAddress, fromName, err := GetFromFields(from)
if err != nil {
fmt.Printf("failed to get from fields: %v", err)
os.Exit(1)
}

// We need to use a single verifier for all contexts
if verifier == nil {
Expand All @@ -85,8 +87,8 @@ func NewCLIContext() CLIContext {
Verifier: verifier,
Simulate: viper.GetBool(client.FlagDryRun),
GenerateOnly: viper.GetBool(client.FlagGenerateOnly),
fromAddress: fromAddress,
fromName: fromName,
FromAddress: fromAddress,
FromName: fromName,
Indent: viper.GetBool(client.FlagIndentResponse),
}
}
Expand Down Expand Up @@ -137,37 +139,6 @@ func createVerifier() tmlite.Verifier {
return verifier
}

func fromFields(from string) (fromAddr types.AccAddress, fromName string) {
if from == "" {
return nil, ""
}

keybase, err := keys.GetKeyBase()
if err != nil {
fmt.Println("no keybase found")
os.Exit(1)
}

var info cskeys.Info
if addr, err := types.AccAddressFromBech32(from); err == nil {
info, err = keybase.GetByAddress(addr)
if err != nil {
fmt.Printf("could not find key %s\n", from)
os.Exit(1)
}
} else {
info, err = keybase.Get(from)
if err != nil {
fmt.Printf("could not find key %s\n", from)
os.Exit(1)
}
}

fromAddr = info.GetAddress()
fromName = info.GetName()
return
}

// WithCodec returns a copy of the context with an updated codec.
func (ctx CLIContext) WithCodec(cdc *codec.Codec) CLIContext {
ctx.Codec = cdc
Expand Down Expand Up @@ -255,6 +226,19 @@ func (ctx CLIContext) WithSimulation(simulate bool) CLIContext {
return ctx
}

// WithFromName returns a copy of the context with an updated from account name.
func (ctx CLIContext) WithFromName(name string) CLIContext {
ctx.FromName = name
return ctx
}

// WithFromAddress returns a copy of the context with an updated from account
// address.
func (ctx CLIContext) WithFromAddress(addr sdk.AccAddress) CLIContext {
ctx.FromAddress = addr
return ctx
}

// PrintOutput prints output while respecting output and indent flags
// NOTE: pass in marshalled structs that have been unmarshaled
// because this function will panic on marshaling errors
Expand All @@ -279,3 +263,31 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
fmt.Println(string(out))
return
}

// GetFromFields returns a from account address and Keybase name given either
// an address or key name.
func GetFromFields(from string) (sdk.AccAddress, string, error) {
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
if from == "" {
return nil, "", nil
}

keybase, err := keys.GetKeyBase()
if err != nil {
return nil, "", err
}

var info cryptokeys.Info
if addr, err := sdk.AccAddressFromBech32(from); err == nil {
info, err = keybase.GetByAddress(addr)
if err != nil {
return nil, "", err
}
} else {
info, err = keybase.Get(from)
if err != nil {
return nil, "", err
}
}

return info.GetAddress(), info.GetName(), nil
}
14 changes: 5 additions & 9 deletions client/context/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) {
}

// GetFromAddress returns the from address from the context's name.
func (ctx CLIContext) GetFromAddress() (sdk.AccAddress, error) {
return ctx.fromAddress, nil
func (ctx CLIContext) GetFromAddress() sdk.AccAddress {
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
return ctx.FromAddress
}

// GetFromName returns the key name for the current context.
func (ctx CLIContext) GetFromName() (string, error) {
return ctx.fromName, nil
func (ctx CLIContext) GetFromName() string {
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
return ctx.FromName
}

// GetAccountNumber returns the next account number for the given account
Expand Down Expand Up @@ -116,11 +116,7 @@ func (ctx CLIContext) GetAccountSequence(address []byte) (uint64, error) {
// EnsureAccountExists ensures that an account exists for a given context. An
// error is returned if it does not.
func (ctx CLIContext) EnsureAccountExists() error {
addr, err := ctx.GetFromAddress()
if err != nil {
return err
}

addr := ctx.GetFromAddress()
accountBytes, err := ctx.QueryStore(auth.AddressStoreKey(addr), ctx.AccountStore)
if err != nil {
return err
Expand Down
73 changes: 64 additions & 9 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package lcd

import (
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"os"
Expand All @@ -26,6 +25,7 @@ import (
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
Expand Down Expand Up @@ -211,16 +211,17 @@ func TestCoinSend(t *testing.T) {
// run simulation and test success with estimated gas
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, "10000", 1.0, true, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var responseBody struct {
GasEstimate int64 `json:"gas_estimate"`
}
require.Nil(t, json.Unmarshal([]byte(body), &responseBody))

var gasEstResp utils.GasEstimateResponse
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &gasEstResp))
require.NotZero(t, gasEstResp.GasEstimate)

acc = getAccount(t, port, addr)
require.Equal(t, expectedBalance.Amount, acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))

res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr,
fmt.Sprintf("%d", responseBody.GasEstimate), 1.0, false, false, fees)
// run successful tx
gas := fmt.Sprintf("%d", gasEstResp.GasEstimate)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, pw, addr, gas, 1.0, false, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)

err = cdc.UnmarshalJSON([]byte(body), &resultTx)
Expand All @@ -235,22 +236,75 @@ func TestCoinSend(t *testing.T) {
require.Equal(t, expectedBalance.Amount.SubRaw(1), acc.GetCoins().AmountOf(stakingTypes.DefaultBondDenom))
}

func TestCoinSendAccAuto(t *testing.T) {
addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t))
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()

acc := getAccount(t, port, addr)
initialBalance := acc.GetCoins()

// send a transfer tx without specifying account number and sequence
res, body, _ := doTransferWithGasAccAuto(t, port, seed, name1, memo, pw, "200000", 1.0, false, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)

// query sender
acc = getAccount(t, port, addr)
coins := acc.GetCoins()
expectedBalance := initialBalance[0].Minus(fees[0])

require.Equal(t, stakingTypes.DefaultBondDenom, coins[0].Denom)
require.Equal(t, expectedBalance.Amount.SubRaw(1), coins[0].Amount)
}

func TestCoinSendGenerateOnly(t *testing.T) {
addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t))
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()

// generate only
res, body, _ := doTransferWithGas(t, port, seed, "", memo, "", addr, "200000", 1, false, true, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var stdTx auth.StdTx
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &stdTx))
require.Equal(t, len(stdTx.Msgs), 1)
require.Equal(t, stdTx.GetMsgs()[0].Route(), "bank")
require.Equal(t, stdTx.GetMsgs()[0].GetSigners(), []sdk.AccAddress{addr})
require.Equal(t, 0, len(stdTx.Signatures))
require.Equal(t, memo, stdTx.Memo)
require.NotZero(t, stdTx.Fee.Gas)
require.IsType(t, stdTx.GetMsgs()[0], bank.MsgSend{})
require.Equal(t, addr, stdTx.GetMsgs()[0].(bank.MsgSend).Inputs[0].Address)
}

func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
addr, seed := CreateAddr(t, name1, pw, GetKeyBase(t))
cleanup, _, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
acc := getAccount(t, port, addr)

// generate TX
res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1, false, true, fees)
// simulate tx
res, body, _ := doTransferWithGas(t, port, seed, name1, memo, "", addr, client.GasFlagAuto, 1, true, false, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var gasEstResp utils.GasEstimateResponse
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &gasEstResp))
require.NotZero(t, gasEstResp.GasEstimate)

// generate tx
gas := fmt.Sprintf("%d", gasEstResp.GasEstimate)
res, body, _ = doTransferWithGas(t, port, seed, name1, memo, "", addr, gas, 1, false, true, fees)
require.Equal(t, http.StatusOK, res.StatusCode, body)

var msg auth.StdTx
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &msg))
require.Equal(t, len(msg.Msgs), 1)
require.Equal(t, msg.Msgs[0].Route(), "bank")
require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
require.Equal(t, 0, len(msg.Signatures))
require.Equal(t, memo, msg.Memo)
require.NotZero(t, msg.Fee.Gas)

gasEstimate := int64(msg.Fee.Gas)
accnum := acc.GetAccountNumber()
Expand All @@ -268,6 +322,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
}
json, err := cdc.MarshalJSON(payload)
require.Nil(t, err)

res, body = Request(t, port, "POST", "/tx/sign", json)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &signedMsg))
Expand Down
Loading