Merge PR #2181: Implement a simulate-only CLI flag/field for REST endpoints
This commit is contained in:
commit
e1981d47e3
|
@ -40,6 +40,7 @@ FEATURES
|
|||
|
||||
* Gaia REST API (`gaiacli advanced rest-server`)
|
||||
* [lcd] Endpoints to query staking pool and params
|
||||
* [lcd] \#2110 Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
|
||||
|
||||
* Gaia CLI (`gaiacli`)
|
||||
* [cli] Cmds to query staking pool and params
|
||||
|
@ -48,6 +49,7 @@ FEATURES
|
|||
provide desired Bech32 prefix encoding
|
||||
* [cli] \#2047 Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
|
||||
* [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
|
||||
* [cli] \#2110 Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
|
||||
|
||||
* Gaia
|
||||
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
||||
|
|
|
@ -37,6 +37,7 @@ type CLIContext struct {
|
|||
JSON bool
|
||||
PrintResponse bool
|
||||
Certifier tmlite.Certifier
|
||||
DryRun bool
|
||||
}
|
||||
|
||||
// NewCLIContext returns a new initialized CLIContext with parameters from the
|
||||
|
@ -63,6 +64,7 @@ func NewCLIContext() CLIContext {
|
|||
JSON: viper.GetBool(client.FlagJson),
|
||||
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
||||
Certifier: createCertifier(),
|
||||
DryRun: viper.GetBool(client.FlagDryRun),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,3 +161,9 @@ func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext {
|
|||
ctx.Certifier = certifier
|
||||
return ctx
|
||||
}
|
||||
|
||||
// WithGasAdjustment returns a copy of the context with an updated GasAdjustment flag.
|
||||
func (ctx CLIContext) WithGasAdjustment(adjustment float64) CLIContext {
|
||||
ctx.GasAdjustment = adjustment
|
||||
return ctx
|
||||
}
|
||||
|
|
|
@ -4,8 +4,11 @@ import "github.com/spf13/cobra"
|
|||
|
||||
// nolint
|
||||
const (
|
||||
// DefaultGasAdjustment is applied to gas estimates to avoid tx
|
||||
// execution failures due to state changes that might
|
||||
// occur between the tx simulation and the actual run.
|
||||
DefaultGasAdjustment = 1.0
|
||||
DefaultGasLimit = 200000
|
||||
DefaultGasAdjustment = 1.2
|
||||
|
||||
FlagUseLedger = "ledger"
|
||||
FlagChainID = "chain-id"
|
||||
|
@ -23,6 +26,7 @@ const (
|
|||
FlagAsync = "async"
|
||||
FlagJson = "json"
|
||||
FlagPrintResponse = "print-response"
|
||||
FlagDryRun = "dry-run"
|
||||
)
|
||||
|
||||
// LineBreak can be included in a command list to provide a blank line
|
||||
|
@ -54,11 +58,12 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
|||
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
|
||||
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
|
||||
c.Flags().Int64(FlagGas, DefaultGasLimit, "gas limit to set per-transaction; set to 0 to calculate required gas automatically")
|
||||
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation")
|
||||
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
|
||||
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
|
||||
c.Flags().Bool(FlagJson, false, "return output in json format")
|
||||
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
|
||||
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
|
||||
c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package lcd
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
@ -265,11 +266,21 @@ func TestCoinSend(t *testing.T) {
|
|||
require.Equal(t, int64(1), mycoins.Amount.Int64())
|
||||
|
||||
// test failure with too little gas
|
||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100)
|
||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100, 0, "")
|
||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
|
||||
|
||||
// test success with just enough gas
|
||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 3000)
|
||||
// test failure with wrong adjustment
|
||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0.1, "")
|
||||
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
|
||||
|
||||
// run simulation and test success with estimated gas
|
||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0, "?simulate=true")
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var responseBody struct {
|
||||
GasEstimate int64 `json:"gas_estimate"`
|
||||
}
|
||||
require.Nil(t, json.Unmarshal([]byte(body), &responseBody))
|
||||
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, responseBody.GasEstimate, 0, "")
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
}
|
||||
|
||||
|
@ -720,7 +731,7 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account {
|
|||
return acc
|
||||
}
|
||||
|
||||
func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64, gasAdjustment float64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
|
||||
|
||||
// create receive address
|
||||
kb := client.MockKeyBase()
|
||||
|
@ -744,22 +755,28 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc
|
|||
"gas":"%v",
|
||||
`, gas)
|
||||
}
|
||||
gasAdjustmentStr := ""
|
||||
if gasAdjustment > 0 {
|
||||
gasStr = fmt.Sprintf(`
|
||||
"gas_adjustment":"%v",
|
||||
`, gasAdjustment)
|
||||
}
|
||||
jsonStr := []byte(fmt.Sprintf(`{
|
||||
%v
|
||||
%v%v
|
||||
"name":"%s",
|
||||
"password":"%s",
|
||||
"account_number":"%d",
|
||||
"sequence":"%d",
|
||||
"amount":[%s],
|
||||
"chain_id":"%s"
|
||||
}`, gasStr, name, password, accnum, sequence, coinbz, chainID))
|
||||
}`, gasStr, gasAdjustmentStr, name, password, accnum, sequence, coinbz, chainID))
|
||||
|
||||
res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send", receiveAddr), jsonStr)
|
||||
res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send%v", receiveAddr, queryStr), jsonStr)
|
||||
return
|
||||
}
|
||||
|
||||
func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) {
|
||||
res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0)
|
||||
res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0, 0, "")
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
|
||||
err := cdc.UnmarshalJSON([]byte(body), &resultTx)
|
||||
|
|
|
@ -1,12 +1,45 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
queryArgDryRun = "simulate"
|
||||
)
|
||||
|
||||
// WriteErrorResponse prepares and writes a HTTP error
|
||||
// given a status code and an error message.
|
||||
func WriteErrorResponse(w *http.ResponseWriter, status int, msg string) {
|
||||
(*w).WriteHeader(status)
|
||||
(*w).Write([]byte(msg))
|
||||
func WriteErrorResponse(w http.ResponseWriter, status int, msg string) {
|
||||
w.WriteHeader(status)
|
||||
w.Write([]byte(msg))
|
||||
}
|
||||
|
||||
// WriteGasEstimateResponse prepares and writes an HTTP
|
||||
// response for transactions simulations.
|
||||
func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas)))
|
||||
}
|
||||
|
||||
// HasDryRunArg returns true if the request's URL query contains
|
||||
// the dry run argument and its value is set to "true".
|
||||
func HasDryRunArg(r *http.Request) bool {
|
||||
return r.URL.Query().Get(queryArgDryRun) == "true"
|
||||
}
|
||||
|
||||
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default
|
||||
// value if the string is empty. Write
|
||||
func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) {
|
||||
if len(s) == 0 {
|
||||
return defaultIfEmpty, true
|
||||
}
|
||||
n, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return n, false
|
||||
}
|
||||
return n, true
|
||||
}
|
||||
|
|
|
@ -12,46 +12,26 @@ import (
|
|||
"github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// DefaultGasAdjustment is applied to gas estimates to avoid tx
|
||||
// execution failures due to state changes that might
|
||||
// occur between the tx simulation and the actual run.
|
||||
const DefaultGasAdjustment = 1.2
|
||||
|
||||
// SendTx implements a auxiliary handler that facilitates sending a series of
|
||||
// messages in a signed transaction given a TxContext 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.
|
||||
func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) error {
|
||||
if err := cliCtx.EnsureAccountExists(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
txCtx, err := prepareTxContext(txCtx, cliCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: (ref #1903) Allow for user supplied account number without
|
||||
// automatically doing a manual lookup.
|
||||
if txCtx.AccountNumber == 0 {
|
||||
accNum, err := cliCtx.GetAccountNumber(from)
|
||||
autogas := cliCtx.DryRun || (cliCtx.Gas == 0)
|
||||
if autogas {
|
||||
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txCtx = txCtx.WithAccountNumber(accNum)
|
||||
fmt.Fprintf(os.Stdout, "estimated gas = %v\n", txCtx.Gas)
|
||||
}
|
||||
|
||||
// TODO: (ref #1903) Allow for user supplied account sequence without
|
||||
// automatically doing a manual lookup.
|
||||
if txCtx.Sequence == 0 {
|
||||
accSeq, err := cliCtx.GetAccountSequence(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
txCtx = txCtx.WithSequence(accSeq)
|
||||
if cliCtx.DryRun {
|
||||
return nil
|
||||
}
|
||||
|
||||
passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName)
|
||||
|
@ -59,13 +39,6 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
|
|||
return err
|
||||
}
|
||||
|
||||
if cliCtx.Gas == 0 {
|
||||
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, passphrase, msgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// build and sign the transaction
|
||||
txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs)
|
||||
if err != nil {
|
||||
|
@ -75,24 +48,24 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
|
|||
return cliCtx.EnsureBroadcastTx(txBytes)
|
||||
}
|
||||
|
||||
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
|
||||
// transaction and set the transaction's respective value accordingly.
|
||||
func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) {
|
||||
txBytes, err := BuildAndSignTxWithZeroGas(txCtx, name, passphrase, msgs)
|
||||
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
|
||||
func SimulateMsgs(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg, gas int64) (estimated, adjusted int64, err error) {
|
||||
txBytes, err := txCtx.WithGas(gas).BuildWithPubKey(name, msgs)
|
||||
if err != nil {
|
||||
return txCtx, err
|
||||
return
|
||||
}
|
||||
estimate, adjusted, err := CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment)
|
||||
if err != nil {
|
||||
return txCtx, err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted)
|
||||
return txCtx.WithGas(adjusted), nil
|
||||
estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment)
|
||||
return
|
||||
}
|
||||
|
||||
// BuildAndSignTxWithZeroGas builds transactions with GasWanted set to 0.
|
||||
func BuildAndSignTxWithZeroGas(txCtx authctx.TxContext, name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
|
||||
return txCtx.WithGas(0).BuildAndSign(name, passphrase, msgs)
|
||||
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
|
||||
// transaction and set the transaction's respective value accordingly.
|
||||
func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authctx.TxContext, error) {
|
||||
_, adjusted, err := SimulateMsgs(txCtx, cliCtx, name, msgs, 0)
|
||||
if err != nil {
|
||||
return txCtx, err
|
||||
}
|
||||
return txCtx.WithGas(adjusted), nil
|
||||
}
|
||||
|
||||
// CalculateGas simulates the execution of a transaction and returns
|
||||
|
@ -109,14 +82,10 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
|
|||
return
|
||||
}
|
||||
adjusted = adjustGasEstimate(estimate, adjustment)
|
||||
fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted)
|
||||
return
|
||||
}
|
||||
|
||||
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
||||
if adjustment == 0 {
|
||||
return int64(DefaultGasAdjustment * float64(estimate))
|
||||
}
|
||||
return int64(adjustment * float64(estimate))
|
||||
}
|
||||
|
||||
|
@ -127,3 +96,35 @@ func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) {
|
|||
}
|
||||
return simulationResult.GasUsed, nil
|
||||
}
|
||||
|
||||
func prepareTxContext(txCtx authctx.TxContext, cliCtx context.CLIContext) (authctx.TxContext, error) {
|
||||
if err := cliCtx.EnsureAccountExists(); err != nil {
|
||||
return txCtx, err
|
||||
}
|
||||
|
||||
from, err := cliCtx.GetFromAddress()
|
||||
if err != nil {
|
||||
return txCtx, err
|
||||
}
|
||||
|
||||
// TODO: (ref #1903) Allow for user supplied account number without
|
||||
// automatically doing a manual lookup.
|
||||
if txCtx.AccountNumber == 0 {
|
||||
accNum, err := cliCtx.GetAccountNumber(from)
|
||||
if err != nil {
|
||||
return txCtx, err
|
||||
}
|
||||
txCtx = txCtx.WithAccountNumber(accNum)
|
||||
}
|
||||
|
||||
// TODO: (ref #1903) Allow for user supplied account sequence without
|
||||
// automatically doing a manual lookup.
|
||||
if txCtx.Sequence == 0 {
|
||||
accSeq, err := cliCtx.GetAccountSequence(from)
|
||||
if err != nil {
|
||||
return txCtx, err
|
||||
}
|
||||
txCtx = txCtx.WithSequence(accSeq)
|
||||
}
|
||||
return txCtx, nil
|
||||
}
|
||||
|
|
|
@ -58,6 +58,13 @@ func TestGaiaCLISend(t *testing.T) {
|
|||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
// Test --dry-run
|
||||
success := executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --dry-run", flags, barAddr), app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
// Check state didn't change
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
// test autosequencing
|
||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
@ -148,6 +155,10 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
|
||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1))
|
||||
|
||||
// Test --dry-run
|
||||
success := executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
|
||||
executeWrite(t, cvStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
@ -164,7 +175,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
unbondStr += fmt.Sprintf(" --validator=%s", sdk.ValAddress(barAddr))
|
||||
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
|
||||
|
||||
success := executeWrite(t, unbondStr, app.DefaultKeyPass)
|
||||
success = executeWrite(t, unbondStr, app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
@ -211,6 +222,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
spStr += fmt.Sprintf(" --title=%s", "Test")
|
||||
spStr += fmt.Sprintf(" --description=%s", "test")
|
||||
|
||||
// Test --dry-run
|
||||
success := executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
|
||||
require.True(t, success)
|
||||
|
||||
executeWrite(t, spStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ When you query an account balance with zero tokens, you will get this error: `No
|
|||
|
||||
### Send Tokens
|
||||
|
||||
The following command could be used to send coins from one account to another:
|
||||
|
||||
```bash
|
||||
gaiacli send \
|
||||
--amount=10faucetToken \
|
||||
|
@ -110,7 +112,7 @@ The `--amount` flag accepts the format `--amount=<value|coin_name>`.
|
|||
::: tip Note
|
||||
You may want to cap the maximum gas that can be consumed by the transaction via the `--gas` flag.
|
||||
If set to 0, the gas limit will be automatically estimated.
|
||||
Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.2.
|
||||
Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.0.
|
||||
:::
|
||||
|
||||
Now, view the updated balances of the origin and destination accounts:
|
||||
|
@ -126,6 +128,17 @@ You can also check your balance at a given block by using the `--block` flag:
|
|||
gaiacli account <account_cosmos> --block=<block_height>
|
||||
```
|
||||
|
||||
You can simulate a transaction without actually broadcasting it by appending the `--dry-run` flag to the command line:
|
||||
|
||||
```bash
|
||||
gaiacli send \
|
||||
--amount=10faucetToken \
|
||||
--chain-id=<chain_id> \
|
||||
--name=<key_name> \
|
||||
--to=<destination_cosmosaccaddr> \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
### Staking
|
||||
|
||||
#### Set up a Validator
|
||||
|
|
|
@ -88,17 +88,17 @@ func TestMsgQuiz(t *testing.T) {
|
|||
require.Equal(t, acc1, res1)
|
||||
|
||||
// Set the trend, submit a really cool quiz and check for reward
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, priv1) // result without reward
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, false, priv1) // result without reward
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, priv1) // reset the trend
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, priv1) // the same answer will nolonger do!
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, true, priv1) // reset the trend
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, false, priv1) // the same answer will nolonger do!
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, priv1) // earlier answer now relevant again
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, true, priv1) // earlier answer now relevant again
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", sdk.NewInt(69)}, {"icecold", sdk.NewInt(138)}})
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, priv1) // expect to fail to set the trend to something which is not cool
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, false, priv1) // expect to fail to set the trend to something which is not cool
|
||||
}
|
||||
|
|
|
@ -74,13 +74,13 @@ func TestMsgMine(t *testing.T) {
|
|||
|
||||
// Mine and check for reward
|
||||
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(1)}})
|
||||
// Mine again and check for reward
|
||||
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
|
||||
// Mine again - should be invalid
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, false, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
|||
return newCtx, err.Result(), true
|
||||
}
|
||||
|
||||
sigs := stdTx.GetSignatures()
|
||||
sigs := stdTx.GetSignatures() // When simulating, this would just be a 0-length slice.
|
||||
signerAddrs := stdTx.GetSigners()
|
||||
msgs := tx.GetMsgs()
|
||||
|
||||
|
@ -88,10 +88,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
|||
|
||||
// check signature, return account with incremented nonce
|
||||
signBytes := StdSignBytes(newCtx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo())
|
||||
signerAcc, res := processSig(
|
||||
newCtx, am,
|
||||
signerAddr, sig, signBytes,
|
||||
)
|
||||
signerAcc, res := processSig(newCtx, am, signerAddr, sig, signBytes, simulate)
|
||||
if !res.IsOK() {
|
||||
return newCtx, res, true
|
||||
}
|
||||
|
@ -149,24 +146,24 @@ func validateBasic(tx StdTx) (err sdk.Error) {
|
|||
// if the account doesn't have a pubkey, set it.
|
||||
func processSig(
|
||||
ctx sdk.Context, am AccountMapper,
|
||||
addr sdk.AccAddress, sig StdSignature, signBytes []byte) (
|
||||
addr sdk.AccAddress, sig StdSignature, signBytes []byte, simulate bool) (
|
||||
acc Account, res sdk.Result) {
|
||||
|
||||
// Get the account.
|
||||
acc = am.GetAccount(ctx, addr)
|
||||
if acc == nil {
|
||||
return nil, sdk.ErrUnknownAddress(addr.String()).Result()
|
||||
}
|
||||
|
||||
// Check account number.
|
||||
accnum := acc.GetAccountNumber()
|
||||
seq := acc.GetSequence()
|
||||
|
||||
// Check account number.
|
||||
if accnum != sig.AccountNumber {
|
||||
return nil, sdk.ErrInvalidSequence(
|
||||
fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result()
|
||||
}
|
||||
|
||||
// Check and increment sequence number.
|
||||
seq := acc.GetSequence()
|
||||
// Check sequence number.
|
||||
if seq != sig.Sequence {
|
||||
return nil, sdk.ErrInvalidSequence(
|
||||
fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result()
|
||||
|
@ -176,31 +173,48 @@ func processSig(
|
|||
// Handle w/ #870
|
||||
panic(err)
|
||||
}
|
||||
pubKey, res := processPubKey(acc, sig, simulate)
|
||||
if !res.IsOK() {
|
||||
return nil, res
|
||||
}
|
||||
err = acc.SetPubKey(pubKey)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrInternal("setting PubKey on signer's account").Result()
|
||||
}
|
||||
|
||||
consumeSignatureVerificationGas(ctx.GasMeter(), pubKey)
|
||||
if !simulate && !pubKey.VerifyBytes(signBytes, sig.Signature) {
|
||||
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func processPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, sdk.Result) {
|
||||
// If pubkey is not known for account,
|
||||
// set it from the StdSignature.
|
||||
pubKey := acc.GetPubKey()
|
||||
if simulate {
|
||||
// In simulate mode the transaction comes with no signatures, thus
|
||||
// if the account's pubkey is nil, both signature verification
|
||||
// and gasKVStore.Set() shall consume the largest amount, i.e.
|
||||
// it takes more gas to verifiy secp256k1 keys than ed25519 ones.
|
||||
if pubKey == nil {
|
||||
return secp256k1.GenPrivKey().PubKey(), sdk.Result{}
|
||||
}
|
||||
return pubKey, sdk.Result{}
|
||||
}
|
||||
if pubKey == nil {
|
||||
pubKey = sig.PubKey
|
||||
if pubKey == nil {
|
||||
return nil, sdk.ErrInvalidPubKey("PubKey not found").Result()
|
||||
}
|
||||
if !bytes.Equal(pubKey.Address(), addr) {
|
||||
if !bytes.Equal(pubKey.Address(), acc.GetAddress()) {
|
||||
return nil, sdk.ErrInvalidPubKey(
|
||||
fmt.Sprintf("PubKey does not match Signer address %v", addr)).Result()
|
||||
}
|
||||
err = acc.SetPubKey(pubKey)
|
||||
if err != nil {
|
||||
return nil, sdk.ErrInternal("setting PubKey on signer's account").Result()
|
||||
fmt.Sprintf("PubKey does not match Signer address %v", acc.GetAddress())).Result()
|
||||
}
|
||||
}
|
||||
|
||||
// Check sig.
|
||||
consumeSignatureVerificationGas(ctx.GasMeter(), pubKey)
|
||||
if !pubKey.VerifyBytes(signBytes, sig.Signature) {
|
||||
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
||||
}
|
||||
|
||||
return
|
||||
return pubKey, sdk.Result{}
|
||||
}
|
||||
|
||||
func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) {
|
||||
|
|
|
@ -4,14 +4,14 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
|
||||
|
@ -567,3 +567,63 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
|||
acc2 = mapper.GetAccount(ctx, addr2)
|
||||
require.Nil(t, acc2.GetPubKey())
|
||||
}
|
||||
|
||||
func TestProcessPubKey(t *testing.T) {
|
||||
ms, capKey, _ := setupMultiStore()
|
||||
cdc := wire.NewCodec()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
// keys
|
||||
_, addr1 := privAndAddr()
|
||||
priv2, _ := privAndAddr()
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
type args struct {
|
||||
acc Account
|
||||
sig StdSignature
|
||||
simulate bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
{"no sigs, simulate off", args{acc1, StdSignature{}, false}, true},
|
||||
{"no sigs, simulate on", args{acc1, StdSignature{}, true}, false},
|
||||
{"pubkey doesn't match addr, simulate off", args{acc1, StdSignature{PubKey: priv2.PubKey()}, false}, true},
|
||||
{"pubkey doesn't match addr, simulate on", args{acc1, StdSignature{PubKey: priv2.PubKey()}, true}, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := processPubKey(tt.args.acc, tt.args.sig, tt.args.simulate)
|
||||
require.Equal(t, tt.wantErr, !err.IsOK())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsumeSignatureVerificationGas(t *testing.T) {
|
||||
type args struct {
|
||||
meter sdk.GasMeter
|
||||
pubkey crypto.PubKey
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
gasConsumed int64
|
||||
wantPanic bool
|
||||
}{
|
||||
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), ed25519.GenPrivKey().PubKey()}, ed25519VerifyCost, false},
|
||||
{"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), secp256k1.GenPrivKey().PubKey()}, secp256k1VerifyCost, false},
|
||||
{"unknown key", args{sdk.NewInfiniteGasMeter(), nil}, 0, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.wantPanic {
|
||||
require.Panics(t, func() { consumeSignatureVerificationGas(tt.args.meter, tt.args.pubkey) })
|
||||
} else {
|
||||
consumeSignatureVerificationGas(tt.args.meter, tt.args.pubkey)
|
||||
require.Equal(t, tt.args.meter.GasConsumed(), tt.gasConsumed)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,3 +148,32 @@ func (ctx TxContext) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]by
|
|||
|
||||
return ctx.Sign(name, passphrase, msg)
|
||||
}
|
||||
|
||||
// BuildWithPubKey builds a single message to be signed from a TxContext given a set of
|
||||
// messages and attach the public key associated to the given name.
|
||||
// It returns an error if a fee is supplied but cannot be parsed or the key cannot be
|
||||
// retrieved.
|
||||
func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
|
||||
msg, err := ctx.Build(msgs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keybase, err := keys.GetKeyBase()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := keybase.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigs := []auth.StdSignature{{
|
||||
AccountNumber: msg.AccountNumber,
|
||||
Sequence: msg.Sequence,
|
||||
PubKey: info.GetPubKey(),
|
||||
}}
|
||||
|
||||
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
|
||||
}
|
||||
|
|
|
@ -33,13 +33,13 @@ func QueryAccountRequestHandlerFn(
|
|||
|
||||
addr, err := sdk.AccAddressFromBech32(bech32addr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryStore(auth.AddressStoreKey(addr), storeName)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't query account. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't query account. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -52,14 +52,14 @@ func QueryAccountRequestHandlerFn(
|
|||
// decode the value
|
||||
account, err := decoder(res)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// print out whole account
|
||||
output, err := cdc.MarshalJSON(account)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't marshall query result. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't marshall query result. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ type (
|
|||
}
|
||||
|
||||
appTestCase struct {
|
||||
expSimPass bool
|
||||
expPass bool
|
||||
msgs []sdk.Msg
|
||||
accNums []int64
|
||||
|
@ -107,27 +108,29 @@ func TestMsgSendWithAccounts(t *testing.T) {
|
|||
|
||||
testCases := []appTestCase{
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg1},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
msgs: []sdk.Msg{sendMsg1},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
expectedBalances: []expectedBalance{
|
||||
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}},
|
||||
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
|
||||
},
|
||||
},
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg1, sendMsg2},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expPass: false,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
msgs: []sdk.Msg{sendMsg1, sendMsg2},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expSimPass: false,
|
||||
expPass: false,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
@ -144,7 +147,7 @@ func TestMsgSendWithAccounts(t *testing.T) {
|
|||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
|
||||
|
||||
// resigning the tx with the bumped sequence should work
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, true, priv1)
|
||||
}
|
||||
|
||||
func TestMsgSendMultipleOut(t *testing.T) {
|
||||
|
@ -163,11 +166,12 @@ func TestMsgSendMultipleOut(t *testing.T) {
|
|||
|
||||
testCases := []appTestCase{
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg2},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
msgs: []sdk.Msg{sendMsg2},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
expectedBalances: []expectedBalance{
|
||||
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
|
||||
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}},
|
||||
|
@ -177,7 +181,7 @@ func TestMsgSendMultipleOut(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
@ -205,11 +209,12 @@ func TestSengMsgMultipleInOut(t *testing.T) {
|
|||
|
||||
testCases := []appTestCase{
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg3},
|
||||
accNums: []int64{0, 2},
|
||||
accSeqs: []int64{0, 0},
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1, priv4},
|
||||
msgs: []sdk.Msg{sendMsg3},
|
||||
accNums: []int64{0, 2},
|
||||
accSeqs: []int64{0, 0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1, priv4},
|
||||
expectedBalances: []expectedBalance{
|
||||
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
|
||||
{addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
|
||||
|
@ -220,7 +225,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
@ -240,22 +245,24 @@ func TestMsgSendDependent(t *testing.T) {
|
|||
|
||||
testCases := []appTestCase{
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg1},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
msgs: []sdk.Msg{sendMsg1},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv1},
|
||||
expectedBalances: []expectedBalance{
|
||||
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
|
||||
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
|
||||
},
|
||||
},
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg4},
|
||||
accNums: []int64{1},
|
||||
accSeqs: []int64{0},
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv2},
|
||||
msgs: []sdk.Msg{sendMsg4},
|
||||
accNums: []int64{1},
|
||||
accSeqs: []int64{0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
privKeys: []crypto.PrivKey{priv2},
|
||||
expectedBalances: []expectedBalance{
|
||||
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}},
|
||||
},
|
||||
|
@ -263,7 +270,7 @@ func TestMsgSendDependent(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
cliclient "github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -31,6 +32,7 @@ type sendBody struct {
|
|||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
||||
var msgCdc = wire.NewCodec()
|
||||
|
@ -40,6 +42,7 @@ func init() {
|
|||
}
|
||||
|
||||
// SendRequestHandlerFn - http request handler to send coins to a address
|
||||
// nolint: gocyclo
|
||||
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// collect data
|
||||
|
@ -48,32 +51,32 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
|
|||
|
||||
to, err := sdk.AccAddressFromBech32(bech32addr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var m sendBody
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
err = msgCdc.UnmarshalJSON(body, &m)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
info, err := kb.Get(m.LocalAccountName)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// build message
|
||||
msg := client.BuildMsg(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount)
|
||||
if err != nil { // XXX rechecking same error ?
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -85,10 +88,20 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
|
|||
Sequence: m.Sequence,
|
||||
}
|
||||
|
||||
if m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, cliclient.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txCtx.Gas)
|
||||
return
|
||||
}
|
||||
txCtx = newCtx
|
||||
|
@ -96,19 +109,19 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
|
|||
|
||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, res)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -77,11 +77,11 @@ func postProposalHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.Hand
|
|||
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, req.ProposalType, req.Proposer, req.InitialDeposit)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
|
||||
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu
|
|||
|
||||
if len(strProposalID) == 0 {
|
||||
err := errors.New("proposalId required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -114,11 +114,11 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu
|
|||
msg := gov.NewMsgDeposit(req.Depositer, proposalID, req.Amount)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
|
||||
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc
|
|||
|
||||
if len(strProposalID) == 0 {
|
||||
err := errors.New("proposalId required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -151,11 +151,11 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc
|
|||
msg := gov.NewMsgVote(req.Voter, proposalID, req.Option)
|
||||
err = msg.ValidateBasic()
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
|
||||
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
if len(strProposalID) == 0 {
|
||||
err := errors.New("proposalId required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -183,13 +183,13 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposal", bz)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
if len(strProposalID) == 0 {
|
||||
err := errors.New("proposalId required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -216,14 +216,14 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
if len(bechDepositerAddr) == 0 {
|
||||
err := errors.New("depositer address required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr)
|
||||
if err != nil {
|
||||
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -236,13 +236,13 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryWithData("custom/gov/deposit", bz)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -252,11 +252,11 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID}))
|
||||
if err != nil || len(res) == 0 {
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID)
|
||||
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
if len(strProposalID) == 0 {
|
||||
err := errors.New("proposalId required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -283,14 +283,14 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
if len(bechVoterAddr) == 0 {
|
||||
err := errors.New("voter address required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr)
|
||||
if err != nil {
|
||||
err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter)
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -302,13 +302,13 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
}
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryWithData("custom/gov/vote", bz)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -317,17 +317,17 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
if vote.Empty() {
|
||||
bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposal", bz)
|
||||
if err != nil || len(res) == 0 {
|
||||
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
|
||||
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
err = errors.Errorf("voter [%s] did not deposit on proposalID [%d]", bechVoterAddr, proposalID)
|
||||
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
w.Write(res)
|
||||
|
@ -343,7 +343,7 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
if len(strProposalID) == 0 {
|
||||
err := errors.New("proposalId required but not specified")
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -359,13 +359,13 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
}
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.QueryWithData("custom/gov/votes", bz)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -388,7 +388,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr)
|
||||
if err != nil {
|
||||
err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter)
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
params.Voter = voterAddr
|
||||
|
@ -398,7 +398,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr)
|
||||
if err != nil {
|
||||
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
params.Depositer = depositerAddr
|
||||
|
@ -408,7 +408,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus)
|
||||
if err != nil {
|
||||
err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus)
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
params.ProposalStatus = proposalStatus
|
||||
|
@ -423,7 +423,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
|
|||
|
||||
res, err := cliCtx.QueryWithData("custom/gov/proposals", bz)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -20,17 +21,18 @@ type baseReq struct {
|
|||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
||||
func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req interface{}) error {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return err
|
||||
}
|
||||
err = cdc.UnmarshalJSON(body, req)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -38,27 +40,27 @@ func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req inter
|
|||
|
||||
func (req baseReq) baseReqValidate(w http.ResponseWriter) bool {
|
||||
if len(req.Name) == 0 {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Name required but not specified")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Name required but not specified")
|
||||
return false
|
||||
}
|
||||
|
||||
if len(req.Password) == 0 {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Password required but not specified")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Password required but not specified")
|
||||
return false
|
||||
}
|
||||
|
||||
if len(req.ChainID) == 0 {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "ChainID required but not specified")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "ChainID required but not specified")
|
||||
return false
|
||||
}
|
||||
|
||||
if req.AccountNumber < 0 {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Account Number required but not specified")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Account Number required but not specified")
|
||||
return false
|
||||
}
|
||||
|
||||
if req.Sequence < 0 {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Sequence required but not specified")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Sequence required but not specified")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -66,7 +68,7 @@ func (req baseReq) baseReqValidate(w http.ResponseWriter) bool {
|
|||
|
||||
// TODO: Build this function out into a more generic base-request
|
||||
// (probably should live in client/lcd).
|
||||
func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
|
||||
func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
|
||||
var err error
|
||||
txCtx := authctx.TxContext{
|
||||
Codec: cdc,
|
||||
|
@ -76,29 +78,39 @@ func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq base
|
|||
Gas: baseReq.Gas,
|
||||
}
|
||||
|
||||
if baseReq.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, baseReq.Password, []sdk.Msg{msg})
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || baseReq.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txCtx.Gas)
|
||||
return
|
||||
}
|
||||
txCtx = newCtx
|
||||
}
|
||||
txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
output, err := wire.MarshalJSONIndent(cdc, res)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -70,10 +70,10 @@ func TestIBCMsgs(t *testing.T) {
|
|||
Sequence: 0,
|
||||
}
|
||||
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{0}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, emptyCoins)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{1}, false, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{1}, false, false, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, coins)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, false, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, false, false, priv1)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -29,10 +30,12 @@ type transferBody struct {
|
|||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
}
|
||||
|
||||
// TransferRequestHandler - http request handler to transfer coins to a address
|
||||
// on a different chain via IBC
|
||||
// nolint: gocyclo
|
||||
func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
@ -41,26 +44,26 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
|
|||
|
||||
to, err := sdk.AccAddressFromBech32(bech32addr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var m transferBody
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = cdc.UnmarshalJSON(body, &m)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
info, err := kb.Get(m.LocalAccountName)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -76,10 +79,20 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
|
|||
Gas: m.Gas,
|
||||
}
|
||||
|
||||
if m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txCtx.Gas)
|
||||
return
|
||||
}
|
||||
txCtx = newCtx
|
||||
|
@ -87,19 +100,19 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
|
|||
|
||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
output, err := cdc.MarshalJSON(res)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -61,14 +61,14 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
|
|||
SignCheckDeliver(
|
||||
t, mApp.BaseApp, []sdk.Msg{msg},
|
||||
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()},
|
||||
true, privKeys[0],
|
||||
true, true, privKeys[0],
|
||||
)
|
||||
|
||||
// Signing a tx with the wrong privKey should result in an auth error
|
||||
res := SignCheckDeliver(
|
||||
t, mApp.BaseApp, []sdk.Msg{msg},
|
||||
[]int64{accs[1].GetAccountNumber()}, []int64{accs[1].GetSequence() + 1},
|
||||
false, privKeys[1],
|
||||
true, false, privKeys[1],
|
||||
)
|
||||
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
|
||||
|
||||
|
@ -76,7 +76,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
|
|||
SignCheckDeliver(
|
||||
t, mApp.BaseApp, []sdk.Msg{msg},
|
||||
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence() + 1},
|
||||
true, privKeys[0],
|
||||
true, true, privKeys[0],
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -71,13 +71,13 @@ func CheckGenTx(
|
|||
// returned.
|
||||
func SignCheckDeliver(
|
||||
t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64,
|
||||
seq []int64, expPass bool, priv ...crypto.PrivKey,
|
||||
seq []int64, expSimPass, expPass bool, priv ...crypto.PrivKey,
|
||||
) sdk.Result {
|
||||
tx := GenTx(msgs, accNums, seq, priv...)
|
||||
// Must simulate now as CheckTx doesn't run Msgs anymore
|
||||
res := app.Simulate(tx)
|
||||
|
||||
if expPass {
|
||||
if expSimPass {
|
||||
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
|
||||
} else {
|
||||
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
|
||||
|
|
|
@ -102,7 +102,7 @@ func TestSlashingMsgs(t *testing.T) {
|
|||
createValidatorMsg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description,
|
||||
)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
|
@ -116,6 +116,6 @@ func TestSlashingMsgs(t *testing.T) {
|
|||
checkValidatorSigningInfo(t, mapp, keeper, sdk.ValAddress(addr1), false)
|
||||
|
||||
// unjail should fail with unknown validator
|
||||
res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, priv1)
|
||||
res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, false, priv1)
|
||||
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), res.Code)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -33,37 +34,39 @@ type UnjailBody struct {
|
|||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
ValidatorAddr string `json:"validator_addr"`
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var m UnjailBody
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &m)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
info, err := kb.Get(m.LocalAccountName)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(m.ValidatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), valAddr) {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -77,10 +80,20 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
|
|||
|
||||
msg := slashing.NewMsgUnjail(valAddr)
|
||||
|
||||
if m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txCtx.Gas)
|
||||
return
|
||||
}
|
||||
txCtx = newCtx
|
||||
|
@ -88,19 +101,19 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
|
|||
|
||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
|
||||
return
|
||||
}
|
||||
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
output, err := json.MarshalIndent(res, "", " ")
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ func TestStakeMsgs(t *testing.T) {
|
|||
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description,
|
||||
)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
|
@ -145,7 +145,7 @@ func TestStakeMsgs(t *testing.T) {
|
|||
addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description,
|
||||
)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, priv1, priv2)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, true, priv1, priv2)
|
||||
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)})
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
|
@ -161,7 +161,7 @@ func TestStakeMsgs(t *testing.T) {
|
|||
description = NewDescription("bar_moniker", "", "", "")
|
||||
editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, priv1)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, true, priv1)
|
||||
validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true)
|
||||
require.Equal(t, description, validator.Description)
|
||||
|
||||
|
@ -169,13 +169,13 @@ func TestStakeMsgs(t *testing.T) {
|
|||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
||||
delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, true, priv2)
|
||||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10))
|
||||
|
||||
// begin unbonding
|
||||
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, sdk.ValAddress(addr1), sdk.NewDec(10))
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, true, priv2)
|
||||
|
||||
// delegation should exist anymore
|
||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -60,6 +61,7 @@ type EditDelegationsBody struct {
|
|||
AccountNumber int64 `json:"account_number"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Gas int64 `json:"gas"`
|
||||
GasAdjustment string `json:"gas_adjustment"`
|
||||
Delegations []msgDelegationsInput `json:"delegations"`
|
||||
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
|
||||
CompleteUnbondings []msgCompleteUnbondingInput `json:"complete_unbondings"`
|
||||
|
@ -106,18 +108,18 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
for _, msg := range m.Delegations {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -133,29 +135,29 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
for _, msg := range m.BeginRedelegates {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
shares, err := sdk.NewDecFromStr(msg.SharesAmount)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -172,24 +174,24 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
for _, msg := range m.CompleteRedelegates {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -205,24 +207,24 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
for _, msg := range m.BeginUnbondings {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
shares, err := sdk.NewDecFromStr(msg.SharesAmount)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -238,18 +240,18 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
for _, msg := range m.CompleteUnbondings {
|
||||
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -276,10 +278,20 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
|
||||
m.Sequence++
|
||||
|
||||
if m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
cliCtx = cliCtx.WithGasAdjustment(adjustment)
|
||||
|
||||
if utils.HasDryRunArg(r) || m.Gas == 0 {
|
||||
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
if utils.HasDryRunArg(r) {
|
||||
utils.WriteSimulationResponse(w, txCtx.Gas)
|
||||
return
|
||||
}
|
||||
txCtx = newCtx
|
||||
|
@ -287,7 +299,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
|
||||
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -301,7 +313,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
for i, txBytes := range signedTxs {
|
||||
res, err := cliCtx.BroadcastTx(txBytes)
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -310,7 +322,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
|
|||
|
||||
output, err := wire.MarshalJSONIndent(cdc, results[:])
|
||||
if err != nil {
|
||||
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
|
||||
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue