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
+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
}