Gaia Lite Generate Only Support (w/o Keybase) (#3396)
This commit is contained in:
committed by
Jack Zampolin
parent
1a656e7023
commit
90797f5e09
+54
-42
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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))
|
||||
|
||||
Vendored
+662
-723
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user