Skip to content

Commit

Permalink
Gaia Lite Generate Only Support (w/o Keybase) (#3396)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored and jackzampolin committed Jan 29, 2019
1 parent 1a656e7 commit 90797f5
Show file tree
Hide file tree
Showing 23 changed files with 1,124 additions and 997 deletions.
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`)
- [#3399](https://github.com/cosmos/cosmos-sdk/pull/3399) Add `gaiad validate-genesis` command to facilitate checking of genesis files
Expand Down Expand Up @@ -32,6 +34,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) {
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 {
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 {
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

0 comments on commit 90797f5

Please sign in to comment.