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

This commit is contained in:
Alexander Bezobchuk
2019-01-29 11:22:47 -08:00
committed by Jack Zampolin
parent 1a656e7023
commit 90797f5e09
23 changed files with 1138 additions and 1011 deletions
+54 -42
View File
@@ -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"
@@ -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.
@@ -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
}
@@ -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 {
@@ -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),
}
}
@@ -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
@@ -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
@@ -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
}
+5 -9
View File
@@ -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
@@ -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
+64 -9
View File
@@ -2,7 +2,6 @@ package lcd
import (
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"os"
@@ -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"
@@ -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)
@@ -235,15 +236,67 @@ 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)
@@ -251,6 +304,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
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()
@@ -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))
+662 -723
View File
File diff suppressed because it is too large Load Diff
+49 -7
View File
@@ -688,23 +688,32 @@ func doTransfer(t *testing.T, port, seed, name, memo, password string, addr sdk.
return receiveAddr, resultTx
}
func doTransferWithGas(t *testing.T, port, seed, name, memo, password string, addr sdk.AccAddress, gas string,
gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins) (
res *http.Response, body string, receiveAddr sdk.AccAddress) {
func doTransferWithGas(
t *testing.T, port, seed, from, memo, password string, addr sdk.AccAddress,
gas string, gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins,
) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
// create receive address
kb := client.MockKeyBase()
receiveInfo, _, err := kb.CreateMnemonic("receive_address", cryptoKeys.English, gapp.DefaultKeyPass, cryptoKeys.SigningAlgo("secp256k1"))
require.Nil(t, err)
receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address())
receiveInfo, _, err := kb.CreateMnemonic(
"receive_address", cryptoKeys.English, gapp.DefaultKeyPass, cryptoKeys.SigningAlgo("secp256k1"),
)
require.Nil(t, err)
receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address())
acc := getAccount(t, port, addr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
if generateOnly {
// generate only txs do not use a Keybase so the address must be used
from = addr.String()
}
baseReq := utils.NewBaseReq(
name, password, memo, chainID, gas,
from, password, memo, chainID, gas,
fmt.Sprintf("%f", gasAdjustment), accnum, sequence, fees, nil,
generateOnly, simulate,
)
@@ -721,6 +730,39 @@ func doTransferWithGas(t *testing.T, port, seed, name, memo, password string, ad
return
}
func doTransferWithGasAccAuto(
t *testing.T, port, seed, from, memo, password string, gas string,
gasAdjustment float64, simulate, generateOnly bool, fees sdk.Coins,
) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
// create receive address
kb := client.MockKeyBase()
receiveInfo, _, err := kb.CreateMnemonic(
"receive_address", cryptoKeys.English, gapp.DefaultKeyPass, cryptoKeys.SigningAlgo("secp256k1"),
)
require.Nil(t, err)
receiveAddr = sdk.AccAddress(receiveInfo.GetPubKey().Address())
chainID := viper.GetString(client.FlagChainID)
baseReq := utils.NewBaseReq(
from, password, memo, chainID, gas,
fmt.Sprintf("%f", gasAdjustment), 0, 0, fees, nil, generateOnly, simulate,
)
sr := sendReq{
Amount: sdk.Coins{sdk.NewInt64Coin(stakingTypes.DefaultBondDenom, 1)},
BaseReq: baseReq,
}
req, err := cdc.MarshalJSON(sr)
require.NoError(t, err)
res, body = Request(t, port, "POST", fmt.Sprintf("/bank/accounts/%s/transfers", receiveAddr), req)
return
}
type sendReq struct {
Amount sdk.Coins `json:"amount"`
BaseReq utils.BaseReq `json:"base_req"`
+85 -48
View File
@@ -16,7 +16,12 @@ import (
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
//----------------------------------------
// GasEstimateResponse defines a response definition for tx gas estimation.
type GasEstimateResponse struct {
GasEstimate uint64 `json:"gas_estimate"`
}
//-----------------------------------------------------------------------------
// Basic HTTP utilities
// WriteErrorResponse prepares and writes a HTTP error
@@ -28,9 +33,17 @@ func WriteErrorResponse(w http.ResponseWriter, status int, err string) {
// WriteSimulationResponse prepares and writes an HTTP
// response for transactions simulations.
func WriteSimulationResponse(w http.ResponseWriter, gas uint64) {
func WriteSimulationResponse(w http.ResponseWriter, cdc *codec.Codec, gas uint64) {
gasEst := GasEstimateResponse{GasEstimate: gas}
resp, err := cdc.MarshalJSON(gasEst)
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas)))
w.Write(resp)
}
// ParseInt64OrReturnBadRequest converts s to a int64 value.
@@ -77,31 +90,13 @@ func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEm
return n, true
}
// WriteGenerateStdTxResponse writes response for the generate_only mode.
func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, txBldr authtxb.TxBuilder, msgs []sdk.Msg) {
stdMsg, err := txBldr.Build(msgs)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
output, err := cdc.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo))
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
return
}
//----------------------------------------
//-----------------------------------------------------------------------------
// Building / Sending utilities
// BaseReq defines a structure that can be embedded in other request structures
// that all share common "base" fields.
type BaseReq struct {
Name string `json:"name"`
From string `json:"from"`
Password string `json:"password"`
Memo string `json:"memo"`
ChainID string `json:"chain_id"`
@@ -117,12 +112,12 @@ type BaseReq struct {
// NewBaseReq creates a new basic request instance and sanitizes its values
func NewBaseReq(
name, password, memo, chainID string, gas, gasAdjustment string,
from, password, memo, chainID string, gas, gasAdjustment string,
accNumber, seq uint64, fees sdk.Coins, gasPrices sdk.DecCoins, genOnly, simulate bool,
) BaseReq {
return BaseReq{
Name: strings.TrimSpace(name),
From: strings.TrimSpace(from),
Password: password,
Memo: strings.TrimSpace(memo),
ChainID: strings.TrimSpace(chainID),
@@ -140,7 +135,7 @@ func NewBaseReq(
// Sanitize performs basic sanitization on a BaseReq object.
func (br BaseReq) Sanitize() BaseReq {
return NewBaseReq(
br.Name, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment,
br.From, br.Password, br.Memo, br.ChainID, br.Gas, br.GasAdjustment,
br.AccountNumber, br.Sequence, br.Fees, br.GasPrices, br.GenerateOnly, br.Simulate,
)
}
@@ -171,8 +166,8 @@ func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
}
}
if len(br.Name) == 0 {
WriteErrorResponse(w, http.StatusUnauthorized, "name required but not specified")
if len(br.From) == 0 {
WriteErrorResponse(w, http.StatusUnauthorized, "name or address required but not specified")
return false
}
@@ -209,59 +204,65 @@ func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req i
}
// CompleteAndBroadcastTxREST implements a utility function that facilitates
// sending a series of messages in a signed transaction given a TxBuilder and a
// QueryContext. It ensures that the account exists, has a proper number and
// sequence set. In addition, it builds and signs a transaction with the
// supplied messages. Finally, it broadcasts the signed transaction to a node.
// sending a series of messages in a signed tx. In addition, it will handle
// tx gas simulation and estimation.
//
// NOTE: Also see CompleteAndBroadcastTxCli.
// NOTE: Also see x/stake/client/rest/tx.go delegationsRequestHandlerFn.
// NOTE: Also see CompleteAndBroadcastTxCLI.
func CompleteAndBroadcastTxREST(
w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext,
baseReq BaseReq, msgs []sdk.Msg, cdc *codec.Codec,
) {
gasAdjustment, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
gasAdj, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
simulateAndExecute, gas, err := client.ParseGas(baseReq.Gas)
simAndExec, gas, err := client.ParseGas(baseReq.Gas)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
// derive the from account address and name from the Keybase
fromAddress, fromName, err := context.GetFromFields(baseReq.From)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
cliCtx = cliCtx.WithFromName(fromName).WithFromAddress(fromAddress)
txBldr := authtxb.NewTxBuilder(
GetTxEncoder(cdc), baseReq.AccountNumber,
baseReq.Sequence, gas, gasAdjustment, baseReq.Simulate,
baseReq.Sequence, gas, gasAdj, baseReq.Simulate,
baseReq.ChainID, baseReq.Memo, baseReq.Fees, baseReq.GasPrices,
)
if baseReq.Simulate || simulateAndExecute {
if gasAdjustment < 0 {
txBldr, err = prepareTxBuilder(txBldr, cliCtx)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
if baseReq.Simulate || simAndExec {
if gasAdj < 0 {
WriteErrorResponse(w, http.StatusBadRequest, "gas adjustment must be a positive float")
return
}
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, msgs)
txBldr, err = EnrichWithGas(txBldr, cliCtx, cliCtx.GetFromName(), msgs)
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if baseReq.Simulate {
WriteSimulationResponse(w, txBldr.GetGas())
WriteSimulationResponse(w, cdc, txBldr.GetGas())
return
}
}
if baseReq.GenerateOnly {
WriteGenerateStdTxResponse(w, cdc, txBldr, msgs)
return
}
txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, msgs)
txBytes, err := txBldr.BuildAndSign(cliCtx.GetFromName(), baseReq.Password, msgs)
if keyerror.IsErrKeyNotFound(err) {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
@@ -282,9 +283,10 @@ func CompleteAndBroadcastTxREST(
PostProcessResponse(w, cdc, res, cliCtx.Indent)
}
// PostProcessResponse performs post process for rest response
// PostProcessResponse performs post processing for a REST response.
func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response interface{}, indent bool) {
var output []byte
switch response.(type) {
default:
var err error
@@ -300,6 +302,41 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter
case []byte:
output = response.([]byte)
}
w.Header().Set("Content-Type", "application/json")
w.Write(output)
}
// WriteGenerateStdTxResponse writes response for the generate only mode.
func WriteGenerateStdTxResponse(w http.ResponseWriter, cdc *codec.Codec, br BaseReq, msgs []sdk.Msg) {
gasAdj, ok := ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
_, gas, err := client.ParseGas(br.Gas)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
txBldr := authtxb.NewTxBuilder(
GetTxEncoder(cdc), br.AccountNumber, br.Sequence, gas, gasAdj,
br.Simulate, br.ChainID, br.Memo, br.Fees, br.GasPrices,
)
stdMsg, err := txBldr.Build(msgs)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
output, err := cdc.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo))
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
return
}
+13 -19
View File
@@ -18,26 +18,23 @@ import (
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
// CompleteAndBroadcastTxCli implements a utility function that facilitates
// CompleteAndBroadcastTxCLI implements a utility function that facilitates
// sending a series of messages in a signed transaction given a TxBuilder and a
// QueryContext. It ensures that the account exists, has a proper number and
// sequence set. In addition, it builds and signs a transaction with the
// supplied messages. Finally, it broadcasts the signed transaction to a node.
//
// NOTE: Also see CompleteAndBroadcastTxREST.
func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error {
func CompleteAndBroadcastTxCLI(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error {
txBldr, err := prepareTxBuilder(txBldr, cliCtx)
if err != nil {
return err
}
name, err := cliCtx.GetFromName()
if err != nil {
return err
}
name := cliCtx.GetFromName()
if txBldr.GetSimulateAndExecute() || cliCtx.Simulate {
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs)
txBldr, err = EnrichWithGas(txBldr, cliCtx, name, msgs)
if err != nil {
return err
}
@@ -63,9 +60,9 @@ func CompleteAndBroadcastTxCli(txBldr authtxb.TxBuilder, cliCtx context.CLIConte
return err
}
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
// EnrichWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly.
func EnrichCtxWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authtxb.TxBuilder, error) {
func EnrichWithGas(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authtxb.TxBuilder, error) {
_, adjusted, err := simulateMsgs(txBldr, cliCtx, name, msgs)
if err != nil {
return txBldr, err
@@ -236,10 +233,7 @@ func prepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth
return txBldr, err
}
from, err := cliCtx.GetFromAddress()
if err != nil {
return txBldr, err
}
from := cliCtx.GetFromAddress()
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
@@ -275,22 +269,21 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg
func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
if txBldr.GetSimulateAndExecute() {
var name string
name, err = cliCtx.GetFromName()
name := cliCtx.GetFromName()
txBldr, err = EnrichWithGas(txBldr, cliCtx, name, msgs)
if err != nil {
return
}
txBldr, err = EnrichCtxWithGas(txBldr, cliCtx, name, msgs)
if err != nil {
return
}
fmt.Fprintf(os.Stderr, "estimated gas = %v\n", txBldr.GetGas())
}
stdSignMsg, err := txBldr.Build(msgs)
if err != nil {
return
}
return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
}
@@ -300,5 +293,6 @@ func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
return true
}
}
return false
}