This commit is contained in:
rigelrozanski 2018-09-27 19:54:41 -04:00
commit 0436f50c00
51 changed files with 1357 additions and 1227 deletions

View File

@ -159,9 +159,9 @@ test_sim_gaia_fast:
@echo "Running quick Gaia simulation. This may take several minutes..."
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=400 -SimulationBlockSize=200 -SimulationCommit=true -v -timeout 24h
test_sim_gaia_slow:
@echo "Running full Gaia simulation. This may take a while!"
@go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 -SimulationVerbose=true -SimulationCommit=true -v -timeout 24h
test_sim_gaia_full:
@echo "Running full multi-seed Gaia simulation. This may take awhile!"
@sh scripts/multisim.sh
SIM_NUM_BLOCKS ?= 210
SIM_BLOCK_SIZE ?= 200

View File

@ -19,7 +19,7 @@ BREAKING CHANGES
`cosmosvaloper`.
* [cli] [\#2190](https://github.com/cosmos/cosmos-sdk/issues/2190) `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
* [cli] \#2073 --from can now be either an address or a key name
* [cli] [\#1184](https://github.com/cosmos/cosmos-sdk/issues/1184) Subcommands reorganisation, see [\#2390](https://github.com/cosmos/cosmos-sdk/pull/2390) for a comprehensive list of changes.
* Gaia
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
@ -44,7 +44,8 @@ BREAKING CHANGES
* [core] [\#1807](https://github.com/cosmos/cosmos-sdk/issues/1807) Switch from use of rational to decimal
* [types] [\#1901](https://github.com/cosmos/cosmos-sdk/issues/1901) Validator interface's GetOwner() renamed to GetOperator()
* [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period
* [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable.
* [types] [\#2119](https://github.com/cosmos/cosmos-sdk/issues/2119) Parsed error messages and ABCI log errors to make them more human readable.
* [types] \#2407 MulInt method added to big decimal in order to improve efficiency of slashing
* [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
* [simulation] Remove log and testing.TB from Operation and Invariants, in favor of using errors \#2282
* [simulation] Remove usage of keys and addrs in the types, in favor of simulation.Account \#2384
@ -55,6 +56,7 @@ BREAKING CHANGES
* [codec] \#2324 All referrences to wire have been renamed to codec. Additionally, wire.NewCodec is now codec.New().
* [types] \#2343 Make sdk.Msg have a names field, to facilitate automatic tagging.
* [baseapp] \#2366 Automatically add action tags to all messages
* [x/auth] \#2377 auth.StdSignMsg -> txbuilder.StdSignMsg
* [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index
* [x/staking] \#2236 more distribution hooks for distribution
@ -88,6 +90,7 @@ FEATURES
* Gaia
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
* [simulation] #2313 Reworked `make test_sim_gaia_slow` to `make test_sim_gaia_full`, now simulates from multiple starting seeds in parallel
* [cli] [\#1921] (https://github.com/cosmos/cosmos-sdk/issues/1921)
* New configuration file `gaiad.toml` is now created to host Gaia-specific configuration.
* New --minimum_fees/minimum_fees flag/config option to set a minimum fee.
@ -135,7 +138,11 @@ IMPROVEMENTS
* [simulation] Logs get written to file if large, and also get printed on panics \#2285
* [gaiad] \#1992 Add optional flag to `gaiad testnet` to make config directory of daemon (default `gaiad`) and cli (default `gaiacli`) configurable
* [x/stake] Add stake `Queriers` for Gaia-lite endpoints. This increases the staking endpoints performance by reusing the staking `keeper` logic for queries. [#2249](https://github.com/cosmos/cosmos-sdk/pull/2149)
* [store] [\#2017](https://github.com/cosmos/cosmos-sdk/issues/2017) Refactor
gas iterator gas consumption to only consume gas for iterator creation and `Next`
calls which includes dynamic consumption of value length.
* [types/decimal] \#2378 - Added truncate functionality to decimal
* [client] [\#1184](https://github.com/cosmos/cosmos-sdk/issues/1184) Remove unused `client/tx/sign.go`.
* Tendermint

View File

@ -821,92 +821,3 @@ func TestTxGasLimits(t *testing.T) {
}
}
}
//-------------------------------------------------------------------------------------------
// Queries
// Test that we can only query from the latest committed state.
func TestQuery(t *testing.T) {
key, value := []byte("hello"), []byte("goodbye")
anteOpt := func(bapp *BaseApp) {
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
store := ctx.KVStore(capKey1)
store.Set(key, value)
return
})
}
routerOpt := func(bapp *BaseApp) {
bapp.Router().AddRoute(typeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
store := ctx.KVStore(capKey1)
store.Set(key, value)
return sdk.Result{}
})
}
app := setupBaseApp(t, anteOpt, routerOpt)
app.InitChain(abci.RequestInitChain{})
// NOTE: "/store/key1" tells us KVStore
// and the final "/key" says to use the data as the
// key in the given KVStore ...
query := abci.RequestQuery{
Path: "/store/key1/key",
Data: key,
}
tx := newTxCounter(0, 0)
// query is empty before we do anything
res := app.Query(query)
require.Equal(t, 0, len(res.Value))
// query is still empty after a CheckTx
resTx := app.Check(tx)
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
res = app.Query(query)
require.Equal(t, 0, len(res.Value))
// query is still empty after a DeliverTx before we commit
app.BeginBlock(abci.RequestBeginBlock{})
resTx = app.Deliver(tx)
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
res = app.Query(query)
require.Equal(t, 0, len(res.Value))
// query returns correct value after Commit
app.Commit()
res = app.Query(query)
require.Equal(t, value, res.Value)
}
// Test p2p filter queries
func TestP2PQuery(t *testing.T) {
addrPeerFilterOpt := func(bapp *BaseApp) {
bapp.SetAddrPeerFilter(func(addrport string) abci.ResponseQuery {
require.Equal(t, "1.1.1.1:8000", addrport)
return abci.ResponseQuery{Code: uint32(3)}
})
}
pubkeyPeerFilterOpt := func(bapp *BaseApp) {
bapp.SetPubKeyPeerFilter(func(pubkey string) abci.ResponseQuery {
require.Equal(t, "testpubkey", pubkey)
return abci.ResponseQuery{Code: uint32(4)}
})
}
app := setupBaseApp(t, addrPeerFilterOpt, pubkeyPeerFilterOpt)
addrQuery := abci.RequestQuery{
Path: "/p2p/filter/addr/1.1.1.1:8000",
}
res := app.Query(addrQuery)
require.Equal(t, uint32(3), res.Code)
pubkeyQuery := abci.RequestQuery{
Path: "/p2p/filter/pubkey/testpubkey",
}
res = app.Query(pubkeyQuery)
require.Equal(t, uint32(4), res.Code)
}

View File

@ -1,9 +1,12 @@
// nolint: golint
package baseapp
import (
"fmt"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
dbm "github.com/tendermint/tendermint/libs/db"
)
// File for storing in-package BaseApp optional functions,
@ -35,3 +38,85 @@ func SetMinimumFees(minFees string) func(*BaseApp) {
}
return func(bap *BaseApp) { bap.SetMinimumFees(fees) }
}
func (app *BaseApp) SetName(name string) {
if app.sealed {
panic("SetName() on sealed BaseApp")
}
app.name = name
}
func (app *BaseApp) SetDB(db dbm.DB) {
if app.sealed {
panic("SetDB() on sealed BaseApp")
}
app.db = db
}
func (app *BaseApp) SetCMS(cms store.CommitMultiStore) {
if app.sealed {
panic("SetEndBlocker() on sealed BaseApp")
}
app.cms = cms
}
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
if app.sealed {
panic("SetInitChainer() on sealed BaseApp")
}
app.initChainer = initChainer
}
func (app *BaseApp) SetBeginBlocker(beginBlocker sdk.BeginBlocker) {
if app.sealed {
panic("SetBeginBlocker() on sealed BaseApp")
}
app.beginBlocker = beginBlocker
}
func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) {
if app.sealed {
panic("SetEndBlocker() on sealed BaseApp")
}
app.endBlocker = endBlocker
}
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
if app.sealed {
panic("SetAnteHandler() on sealed BaseApp")
}
app.anteHandler = ah
}
func (app *BaseApp) SetAddrPeerFilter(pf sdk.PeerFilter) {
if app.sealed {
panic("SetAddrPeerFilter() on sealed BaseApp")
}
app.addrPeerFilter = pf
}
func (app *BaseApp) SetPubKeyPeerFilter(pf sdk.PeerFilter) {
if app.sealed {
panic("SetPubKeyPeerFilter() on sealed BaseApp")
}
app.pubkeyPeerFilter = pf
}
func (app *BaseApp) Router() Router {
if app.sealed {
panic("Router() on sealed BaseApp")
}
return app.router
}
func (app *BaseApp) QueryRouter() QueryRouter {
return app.queryRouter
}
func (app *BaseApp) Seal() { app.sealed = true }
func (app *BaseApp) IsSealed() bool { return app.sealed }
func (app *BaseApp) enforceSeal() {
if !app.sealed {
panic("enforceSeal() on BaseApp but not sealed")
}
}

96
baseapp/query_test.go Normal file
View File

@ -0,0 +1,96 @@
package baseapp
import (
"fmt"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
)
// Test that we can only query from the latest committed state.
func TestQuery(t *testing.T) {
key, value := []byte("hello"), []byte("goodbye")
anteOpt := func(bapp *BaseApp) {
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, res sdk.Result, abort bool) {
store := ctx.KVStore(capKey1)
store.Set(key, value)
return
})
}
routerOpt := func(bapp *BaseApp) {
bapp.Router().AddRoute(typeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
store := ctx.KVStore(capKey1)
store.Set(key, value)
return sdk.Result{}
})
}
app := setupBaseApp(t, anteOpt, routerOpt)
app.InitChain(abci.RequestInitChain{})
// NOTE: "/store/key1" tells us KVStore
// and the final "/key" says to use the data as the
// key in the given KVStore ...
query := abci.RequestQuery{
Path: "/store/key1/key",
Data: key,
}
tx := newTxCounter(0, 0)
// query is empty before we do anything
res := app.Query(query)
require.Equal(t, 0, len(res.Value))
// query is still empty after a CheckTx
resTx := app.Check(tx)
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
res = app.Query(query)
require.Equal(t, 0, len(res.Value))
// query is still empty after a DeliverTx before we commit
app.BeginBlock(abci.RequestBeginBlock{})
resTx = app.Deliver(tx)
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
res = app.Query(query)
require.Equal(t, 0, len(res.Value))
// query returns correct value after Commit
app.Commit()
res = app.Query(query)
require.Equal(t, value, res.Value)
}
// Test p2p filter queries
func TestP2PQuery(t *testing.T) {
addrPeerFilterOpt := func(bapp *BaseApp) {
bapp.SetAddrPeerFilter(func(addrport string) abci.ResponseQuery {
require.Equal(t, "1.1.1.1:8000", addrport)
return abci.ResponseQuery{Code: uint32(3)}
})
}
pubkeyPeerFilterOpt := func(bapp *BaseApp) {
bapp.SetPubKeyPeerFilter(func(pubkey string) abci.ResponseQuery {
require.Equal(t, "testpubkey", pubkey)
return abci.ResponseQuery{Code: uint32(4)}
})
}
app := setupBaseApp(t, addrPeerFilterOpt, pubkeyPeerFilterOpt)
addrQuery := abci.RequestQuery{
Path: "/p2p/filter/addr/1.1.1.1:8000",
}
res := app.Query(addrQuery)
require.Equal(t, uint32(3), res.Code)
pubkeyQuery := abci.RequestQuery{
Path: "/p2p/filter/pubkey/testpubkey",
}
res = app.Query(pubkeyQuery)
require.Equal(t, uint32(4), res.Code)
}

View File

@ -1,80 +0,0 @@
package baseapp
import (
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// nolint - Setter functions
func (app *BaseApp) SetName(name string) {
if app.sealed {
panic("SetName() on sealed BaseApp")
}
app.name = name
}
func (app *BaseApp) SetDB(db dbm.DB) {
if app.sealed {
panic("SetDB() on sealed BaseApp")
}
app.db = db
}
func (app *BaseApp) SetCMS(cms store.CommitMultiStore) {
if app.sealed {
panic("SetEndBlocker() on sealed BaseApp")
}
app.cms = cms
}
func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
if app.sealed {
panic("SetInitChainer() on sealed BaseApp")
}
app.initChainer = initChainer
}
func (app *BaseApp) SetBeginBlocker(beginBlocker sdk.BeginBlocker) {
if app.sealed {
panic("SetBeginBlocker() on sealed BaseApp")
}
app.beginBlocker = beginBlocker
}
func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) {
if app.sealed {
panic("SetEndBlocker() on sealed BaseApp")
}
app.endBlocker = endBlocker
}
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
if app.sealed {
panic("SetAnteHandler() on sealed BaseApp")
}
app.anteHandler = ah
}
func (app *BaseApp) SetAddrPeerFilter(pf sdk.PeerFilter) {
if app.sealed {
panic("SetAddrPeerFilter() on sealed BaseApp")
}
app.addrPeerFilter = pf
}
func (app *BaseApp) SetPubKeyPeerFilter(pf sdk.PeerFilter) {
if app.sealed {
panic("SetPubKeyPeerFilter() on sealed BaseApp")
}
app.pubkeyPeerFilter = pf
}
func (app *BaseApp) Router() Router {
if app.sealed {
panic("Router() on sealed BaseApp")
}
return app.router
}
func (app *BaseApp) QueryRouter() QueryRouter {
return app.queryRouter
}
func (app *BaseApp) Seal() { app.sealed = true }
func (app *BaseApp) IsSealed() bool { return app.sealed }
func (app *BaseApp) enforceSeal() {
if !app.sealed {
panic("enforceSeal() on BaseApp but not sealed")
}
}

158
client/context/broadcast.go Normal file
View File

@ -0,0 +1,158 @@
package context
import (
"fmt"
"io"
"github.com/pkg/errors"
abci "github.com/tendermint/tendermint/abci/types"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
// TODO: This should get deleted eventually, and perhaps
// ctypes.ResultBroadcastTx be stripped of unused fields, and
// ctypes.ResultBroadcastTxCommit returned for tendermint RPC BroadcastTxSync.
//
// The motivation is that we want a unified type to return, and the better
// option is the one that can hold CheckTx/DeliverTx responses optionally.
func resultBroadcastTxToCommit(res *ctypes.ResultBroadcastTx) *ctypes.ResultBroadcastTxCommit {
return &ctypes.ResultBroadcastTxCommit{
Hash: res.Hash,
// NOTE: other fields are unused for async.
}
}
// BroadcastTx broadcasts a transactions either synchronously or asynchronously
// based on the context parameters. The result of the broadcast is parsed into
// an intermediate structure which is logged if the context has a logger
// defined.
func (ctx CLIContext) BroadcastTx(txBytes []byte) (*ctypes.ResultBroadcastTxCommit, error) {
if ctx.Async {
res, err := ctx.broadcastTxAsync(txBytes)
if err != nil {
return nil, err
}
resCommit := resultBroadcastTxToCommit(res)
return resCommit, err
}
return ctx.broadcastTxCommit(txBytes)
}
// BroadcastTxAndAwaitCommit broadcasts transaction bytes to a Tendermint node
// and waits for a commit.
func (ctx CLIContext) BroadcastTxAndAwaitCommit(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
}
res, err := node.BroadcastTxCommit(tx)
if err != nil {
return res, err
}
if !res.CheckTx.IsOK() {
return res, errors.Errorf("checkTx failed: (%d) %s",
res.CheckTx.Code,
res.CheckTx.Log)
}
if !res.DeliverTx.IsOK() {
return res, errors.Errorf("deliverTx failed: (%d) %s",
res.DeliverTx.Code,
res.DeliverTx.Log)
}
return res, err
}
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
// asynchronously.
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (*ctypes.ResultBroadcastTx, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
}
res, err := node.BroadcastTxAsync(tx)
if err != nil {
return res, err
}
return res, err
}
func (ctx CLIContext) broadcastTxAsync(txBytes []byte) (*ctypes.ResultBroadcastTx, error) {
res, err := ctx.BroadcastTxAsync(txBytes)
if err != nil {
return res, err
}
if ctx.Logger != nil {
if ctx.JSON {
type toJSON struct {
TxHash string
}
resJSON := toJSON{res.Hash.String()}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return res, err
}
ctx.Logger.Write(bz)
io.WriteString(ctx.Logger, "\n")
} else {
io.WriteString(ctx.Logger, fmt.Sprintf("async tx sent (tx hash: %s)\n", res.Hash))
}
}
return res, nil
}
func (ctx CLIContext) broadcastTxCommit(txBytes []byte) (*ctypes.ResultBroadcastTxCommit, error) {
res, err := ctx.BroadcastTxAndAwaitCommit(txBytes)
if err != nil {
return res, err
}
if ctx.JSON {
// Since JSON is intended for automated scripts, always include response in
// JSON mode.
type toJSON struct {
Height int64
TxHash string
Response abci.ResponseDeliverTx
}
if ctx.Logger != nil {
resJSON := toJSON{res.Height, res.Hash.String(), res.DeliverTx}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return res, err
}
ctx.Logger.Write(bz)
io.WriteString(ctx.Logger, "\n")
}
return res, nil
}
if ctx.Logger != nil {
resStr := fmt.Sprintf("Committed at block %d (tx hash: %s)\n", res.Height, res.Hash.String())
if ctx.PrintResponse {
resStr = fmt.Sprintf("Committed at block %d (tx hash: %s, response: %+v)\n",
res.Height, res.Hash.String(), res.DeliverTx,
)
}
io.WriteString(ctx.Logger, resStr)
}
return res, nil
}

View File

@ -2,7 +2,6 @@ package context
import (
"fmt"
"io"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
@ -19,7 +18,6 @@ import (
tmliteErr "github.com/tendermint/tendermint/lite/errors"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
// GetNode returns an RPC client. If the context's client is not defined, an
@ -114,49 +112,6 @@ func (ctx CLIContext) GetAccountSequence(address []byte) (int64, error) {
return account.GetSequence(), nil
}
// BroadcastTx broadcasts transaction bytes to a Tendermint node.
func (ctx CLIContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
}
res, err := node.BroadcastTxCommit(tx)
if err != nil {
return res, err
}
if !res.CheckTx.IsOK() {
return res, errors.Errorf("checkTx failed: (%d) %s",
res.CheckTx.Code,
res.CheckTx.Log)
}
if !res.DeliverTx.IsOK() {
return res, errors.Errorf("deliverTx failed: (%d) %s",
res.DeliverTx.Code,
res.DeliverTx.Log)
}
return res, err
}
// BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
// asynchronously.
func (ctx CLIContext) BroadcastTxAsync(tx []byte) (*ctypes.ResultBroadcastTx, error) {
node, err := ctx.GetNode()
if err != nil {
return nil, err
}
res, err := node.BroadcastTxAsync(tx)
if err != nil {
return res, err
}
return res, err
}
// EnsureAccountExists ensures that an account exists for a given context. An
// error is returned if it does not.
func (ctx CLIContext) EnsureAccountExists() error {
@ -193,92 +148,6 @@ func (ctx CLIContext) EnsureAccountExistsFromAddr(addr sdk.AccAddress) error {
return nil
}
// EnsureBroadcastTx broadcasts a transactions either synchronously or
// asynchronously based on the context parameters. The result of the broadcast
// is parsed into an intermediate structure which is logged if the context has
// a logger defined.
func (ctx CLIContext) EnsureBroadcastTx(txBytes []byte) error {
if ctx.Async {
return ctx.ensureBroadcastTxAsync(txBytes)
}
return ctx.ensureBroadcastTx(txBytes)
}
func (ctx CLIContext) ensureBroadcastTxAsync(txBytes []byte) error {
res, err := ctx.BroadcastTxAsync(txBytes)
if err != nil {
return err
}
if ctx.JSON {
type toJSON struct {
TxHash string
}
if ctx.Logger != nil {
resJSON := toJSON{res.Hash.String()}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return err
}
ctx.Logger.Write(bz)
io.WriteString(ctx.Logger, "\n")
}
} else {
if ctx.Logger != nil {
io.WriteString(ctx.Logger, fmt.Sprintf("Async tx sent (tx hash: %s)\n", res.Hash))
}
}
return nil
}
func (ctx CLIContext) ensureBroadcastTx(txBytes []byte) error {
res, err := ctx.BroadcastTx(txBytes)
if err != nil {
return err
}
if ctx.JSON {
// since JSON is intended for automated scripts, always include
// response in JSON mode.
type toJSON struct {
Height int64
TxHash string
Response abci.ResponseDeliverTx
}
if ctx.Logger != nil {
resJSON := toJSON{res.Height, res.Hash.String(), res.DeliverTx}
bz, err := ctx.Codec.MarshalJSON(resJSON)
if err != nil {
return err
}
ctx.Logger.Write(bz)
io.WriteString(ctx.Logger, "\n")
}
return nil
}
if ctx.Logger != nil {
resStr := fmt.Sprintf("Committed at block %d (tx hash: %s)\n", res.Height, res.Hash.String())
if ctx.PrintResponse {
resStr = fmt.Sprintf("Committed at block %d (tx hash: %s, response: %+v)\n",
res.Height, res.Hash.String(), res.DeliverTx,
)
}
io.WriteString(ctx.Logger, resStr)
}
return nil
}
// query performs a query from a Tendermint node with the provided store name
// and path.
func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err error) {
@ -302,7 +171,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
}
// Data from trusted node or subspace query doesn't need verification.
// data from trusted node or subspace query doesn't need verification
if ctx.TrustNode || !isQueryStoreWithProof(path) {
return resp.Value, nil
}
@ -315,26 +184,26 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
return resp.Value, nil
}
// Certify verifies the consensus proof at given height
// Certify verifies the consensus proof at given height.
func (ctx CLIContext) Certify(height int64) (lite.Commit, error) {
check, err := tmliteProxy.GetCertifiedCommit(height, ctx.Client, ctx.Certifier)
if tmliteErr.IsCommitNotFoundErr(err) {
switch {
case tmliteErr.IsCommitNotFoundErr(err):
return lite.Commit{}, ErrVerifyCommit(height)
} else if err != nil {
case err != nil:
return lite.Commit{}, err
}
return check, nil
}
// verifyProof perform response proof verification
// nolint: unparam
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
// verifyProof perform response proof verification.
func (ctx CLIContext) verifyProof(_ string, resp abci.ResponseQuery) error {
if ctx.Certifier == nil {
return fmt.Errorf("missing valid certifier to verify data from untrusted node")
return fmt.Errorf("missing valid certifier to verify data from distrusted node")
}
// AppHash for height H is in header H+1
// the AppHash for height H is in header H+1
commit, err := ctx.Certify(resp.Height + 1)
if err != nil {
return err
@ -342,14 +211,16 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
var multiStoreProof store.MultiStoreProof
cdc := codec.New()
err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof)
if err != nil {
return errors.Wrap(err, "failed to unmarshalBinary rangeProof")
}
// Verify the substore commit hash against trusted appHash
// verify the substore commit hash against trusted appHash
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(
multiStoreProof.StoreName, multiStoreProof.StoreInfos, commit.Header.AppHash)
multiStoreProof.StoreName, multiStoreProof.StoreInfos, commit.Header.AppHash,
)
if err != nil {
return errors.Wrap(err, "failed in verifying the proof against appHash")
}
@ -370,11 +241,12 @@ func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([
}
// isQueryStoreWithProof expects a format like /<queryType>/<storeName>/<subpath>
// queryType can be app or store
// queryType can be app or store.
func isQueryStoreWithProof(path string) bool {
if !strings.HasPrefix(path, "/") {
return false
}
paths := strings.SplitN(path[1:], "/", 3)
if len(paths) != 3 {
return false
@ -383,5 +255,6 @@ func isQueryStoreWithProof(path string) bool {
if store.RequireProof("/" + paths[2]) {
return true
}
return false
}

View File

@ -838,14 +838,16 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc
`, gasAdjustment)
}
jsonStr := []byte(fmt.Sprintf(`{
%v%v
"name":"%s",
"password":"%s",
"account_number":"%d",
"sequence":"%d",
"amount":[%s],
"chain_id":"%s"
}`, gasStr, gasAdjustmentStr, name, password, accnum, sequence, coinbz, chainID))
"base_req": {
%v%v
"name": "%s",
"password": "%s",
"chain_id": "%s",
"account_number":"%d",
"sequence":"%d"
}
}`, coinbz, gasStr, gasAdjustmentStr, name, password, chainID, accnum, sequence))
res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send%v", receiveAddr, queryStr), jsonStr)
return
@ -877,18 +879,20 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc
// send
jsonStr := []byte(fmt.Sprintf(`{
"name":"%s",
"password": "%s",
"account_number":"%d",
"sequence": "%d",
"src_chain_id": "%s",
"amount":[
{
"denom": "%s",
"amount": "1"
}
]
}`, name, password, accnum, sequence, chainID, "steak"))
],
"base_req": {
"name": "%s",
"password": "%s",
"chain_id": "%s",
"account_number":"%d",
"sequence":"%d"
}
}`, "steak", name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", fmt.Sprintf("/ibc/testchain/%s/send", receiveAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -997,11 +1001,6 @@ func doDelegate(t *testing.T, port, seed, name, password string,
chainID := viper.GetString(client.FlagChainID)
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"account_number": "%d",
"sequence": "%d",
"chain_id": "%s",
"delegations": [
{
"delegator_addr": "%s",
@ -1012,8 +1011,15 @@ func doDelegate(t *testing.T, port, seed, name, password string,
"begin_unbondings": [],
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delAddr, valAddr, "steak", amount))
"complete_redelegates": [],
"base_req": {
"name": "%s",
"password": "%s",
"chain_id": "%s",
"account_number":"%d",
"sequence":"%d"
}
}`, delAddr, valAddr, "steak", amount, name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -1034,11 +1040,6 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
chainID := viper.GetString(client.FlagChainID)
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"account_number": "%d",
"sequence": "%d",
"chain_id": "%s",
"delegations": [],
"begin_unbondings": [
{
@ -1049,8 +1050,15 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
],
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delAddr, valAddr, amount))
"complete_redelegates": [],
"base_req": {
"name": "%s",
"password": "%s",
"chain_id": "%s",
"account_number":"%d",
"sequence":"%d"
}
}`, delAddr, valAddr, amount, name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
@ -1072,11 +1080,6 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
chainID := viper.GetString(client.FlagChainID)
jsonStr := []byte(fmt.Sprintf(`{
"name": "%s",
"password": "%s",
"account_number": "%d",
"sequence": "%d",
"chain_id": "%s",
"delegations": [],
"begin_unbondings": [],
"complete_unbondings": [],
@ -1088,8 +1091,15 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
"shares": "30"
}
],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delAddr, valSrcAddr, valDstAddr))
"complete_redelegates": [],
"base_req": {
"name": "%s",
"password": "%s",
"chain_id": "%s",
"account_number":"%d",
"sequence":"%d"
}
}`, delAddr, valSrcAddr, valDstAddr, name, password, chainID, accnum, sequence))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)

View File

@ -1,6 +1,7 @@
package rpc
import (
"bytes"
"fmt"
"net/http"
"strconv"
@ -8,7 +9,6 @@ import (
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"bytes"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -21,7 +21,7 @@ import (
//ValidatorCommand returns the validator set for a given height
func ValidatorCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "validator-set [height]",
Use: "tendermint-validator-set [height]",
Short: "Get the full tendermint validator set at given height",
Args: cobra.MaximumNArgs(1),
RunE: printValidators,

View File

@ -25,7 +25,7 @@ func BroadcastTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return
}
res, err := cliCtx.BroadcastTx([]byte(m.TxBytes))
res, err := cliCtx.BroadcastTxAndAwaitCommit([]byte(m.TxBytes))
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

View File

@ -1,48 +0,0 @@
package tx
import (
"encoding/json"
"net/http"
keybase "github.com/cosmos/cosmos-sdk/client/keys"
keys "github.com/cosmos/cosmos-sdk/crypto/keys"
)
// REST request body for signed txs
// TODO does this need to be exposed?
type SignTxBody struct {
Name string `json:"name"`
Password string `json:"password"`
TxBytes string `json:"tx"`
}
// sign transaction REST Handler
func SignTxRequstHandler(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase
var m SignTxBody
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&m)
if err != nil {
w.WriteHeader(400)
w.Write([]byte(err.Error()))
return
}
kb, err = keybase.GetKeyBase()
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
//TODO check if account exists
sig, _, err := kb.Sign(m.Name, m.Password, []byte(m.TxBytes))
if err != nil {
w.WriteHeader(403)
w.Write([]byte(err.Error()))
return
}
w.Write(sig)
}

View File

@ -2,10 +2,15 @@ package utils
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
client "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
auth "github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
@ -16,6 +21,9 @@ const (
queryArgGenerateOnly = "generate_only"
)
//----------------------------------------
// Basic HTTP utilities
// WriteErrorResponse prepares and writes a HTTP error
// given a status code and an error message.
func WriteErrorResponse(w http.ResponseWriter, status int, msg string) {
@ -30,24 +38,45 @@ func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
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 urlQueryHasArg(r.URL, queryArgDryRun) }
// 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 urlQueryHasArg(r.URL, queryArgDryRun)
}
// HasGenerateOnlyArg returns whether a URL's query "generate-only" parameter is set to "true".
func HasGenerateOnlyArg(r *http.Request) bool { return urlQueryHasArg(r.URL, queryArgGenerateOnly) }
// HasGenerateOnlyArg returns whether a URL's query "generate-only" parameter
// is set to "true".
func HasGenerateOnlyArg(r *http.Request) bool {
return urlQueryHasArg(r.URL, queryArgGenerateOnly)
}
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default
// value if the string is empty. Write
// ParseInt64OrReturnBadRequest converts s to a int64 value.
func ParseInt64OrReturnBadRequest(w http.ResponseWriter, s string) (n int64, ok bool) {
var err error
n, err = strconv.ParseInt(s, 10, 64)
if err != nil {
err := fmt.Errorf("'%s' is not a valid int64", s)
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return n, false
}
return n, true
}
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a
// default value, defaultIfEmpty, if the string is empty.
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
}
@ -58,13 +87,164 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, txBldr authtxb.TxBuilder,
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
output, err := txBldr.Codec.MarshalJSON(auth.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo))
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
return
}
func urlQueryHasArg(url *url.URL, arg string) bool { return url.Query().Get(arg) == "true" }
//----------------------------------------
// 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"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
}
// Sanitize performs basic sanitization on a BaseReq object.
func (br BaseReq) Sanitize() BaseReq {
return BaseReq{
Name: strings.TrimSpace(br.Name),
Password: strings.TrimSpace(br.Password),
ChainID: strings.TrimSpace(br.ChainID),
Gas: strings.TrimSpace(br.Gas),
GasAdjustment: strings.TrimSpace(br.GasAdjustment),
AccountNumber: br.AccountNumber,
Sequence: br.Sequence,
}
}
/*
ReadRESTReq is a simple convenience wrapper that reads the body and
unmarshals to the req interface.
Usage:
type SomeReq struct {
BaseReq `json:"base_req"`
CustomField string `json:"custom_field"`
}
req := new(SomeReq)
err := ReadRESTReq(w, r, cdc, req)
*/
func ReadRESTReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) error {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
}
err = cdc.UnmarshalJSON(body, req)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
}
return nil
}
// ValidateBasic performs basic validation of a BaseReq. If custom validation
// logic is needed, the implementing request handler should perform those
// checks manually.
func (br BaseReq) ValidateBasic(w http.ResponseWriter) bool {
switch {
case len(br.Name) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "name required but not specified")
return false
case len(br.Password) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "password required but not specified")
return false
case len(br.ChainID) == 0:
WriteErrorResponse(w, http.StatusUnauthorized, "chainID required but not specified")
return false
}
return true
}
// 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.
//
// NOTE: Also see CompleteAndBroadcastTxCli.
// NOTE: Also see x/stake/client/rest/tx.go delegationsRequestHandlerFn.
func CompleteAndBroadcastTxREST(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq BaseReq, msgs []sdk.Msg, cdc *codec.Codec) {
simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
adjustment, ok := ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.TxBuilder{
Codec: cdc,
Gas: gas,
GasAdjustment: adjustment,
SimulateGas: simulateGas,
ChainID: baseReq.ChainID,
AccountNumber: baseReq.AccountNumber,
Sequence: baseReq.Sequence,
}
if HasDryRunArg(r) || txBldr.SimulateGas {
newBldr, err := EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, msgs)
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if HasDryRunArg(r) {
WriteSimulationResponse(w, newBldr.Gas)
return
}
txBldr = newBldr
}
if HasGenerateOnlyArg(r) {
WriteGenerateStdTxResponse(w, txBldr, msgs)
return
}
txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, msgs)
if err != nil {
WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := codec.MarshalJSONIndent(cdc, res)
if err != nil {
WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
}

View File

@ -14,13 +14,16 @@ import (
"github.com/tendermint/tendermint/libs/common"
)
// SendTx implements a auxiliary handler 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.
func SendTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) error {
txBldr, err := prepareTxContext(txBldr, cliCtx)
// 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 {
txBldr, err := prepareTxBuilder(txBldr, cliCtx)
if err != nil {
return err
}
@ -52,7 +55,8 @@ func SendTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg)
return err
}
// broadcast to a Tendermint node
return cliCtx.EnsureBroadcastTx(txBytes)
_, err = cliCtx.BroadcastTx(txBytes)
return err
}
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
@ -161,7 +165,7 @@ func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) {
return simulationResult.GasUsed, nil
}
func prepareTxContext(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (authtxb.TxBuilder, error) {
func prepareTxBuilder(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (authtxb.TxBuilder, error) {
if err := cliCtx.EnsureAccountExists(); err != nil {
return txBldr, err
}
@ -196,7 +200,7 @@ func prepareTxContext(txBldr authtxb.TxBuilder, cliCtx context.CLIContext) (auth
// buildUnsignedStdTx builds a StdTx as per the parameters passed in the
// contexts. Gas is automatically estimated if gas wanted is set to 0.
func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
txBldr, err = prepareTxContext(txBldr, cliCtx)
txBldr, err = prepareTxBuilder(txBldr, cliCtx)
if err != nil {
return
}

View File

@ -51,11 +51,11 @@ func TestGaiaCLIMinimumFees(t *testing.T) {
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
success := executeWrite(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
"gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
tests.WaitForNextNBlocksTM(2, port)
@ -75,30 +75,30 @@ func TestGaiaCLIFeesDeduction(t *testing.T) {
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(1000), fooAcc.GetCoins().AmountOf("fooToken").Int64())
// test simulation
success := executeWrite(t, fmt.Sprintf(
"gaiacli send %v --amount=1000fooToken --to=%s --from=foo --fee=1fooToken --dry-run", flags, barAddr), app.DefaultKeyPass)
"gaiacli tx send %v --amount=1000fooToken --to=%s --from=foo --fee=1fooToken --dry-run", flags, barAddr), app.DefaultKeyPass)
require.True(t, success)
tests.WaitForNextNBlocksTM(2, port)
// ensure state didn't change
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(1000), fooAcc.GetCoins().AmountOf("fooToken").Int64())
// insufficient funds (coins + fees)
success = executeWrite(t, fmt.Sprintf(
"gaiacli send %v --amount=1000fooToken --to=%s --from=foo --fee=1fooToken", flags, barAddr), app.DefaultKeyPass)
"gaiacli tx send %v --amount=1000fooToken --to=%s --from=foo --fee=1fooToken", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
tests.WaitForNextNBlocksTM(2, port)
// ensure state didn't change
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(1000), fooAcc.GetCoins().AmountOf("fooToken").Int64())
// test success (transfer = coins + fees)
success = executeWrite(t, fmt.Sprintf(
"gaiacli send %v --fee=300fooToken --amount=500fooToken --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
"gaiacli tx send %v --fee=300fooToken --amount=500fooToken --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.True(t, success)
tests.WaitForNextNBlocksTM(2, port)
}
@ -117,40 +117,40 @@ func TestGaiaCLISend(t *testing.T) {
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query 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)
success := executeWrite(t, fmt.Sprintf("gaiacli tx 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))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query 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)
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
require.Equal(t, int64(20), barAcc.GetCoins().AmountOf("steak").Int64())
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64())
// test memo
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), app.DefaultKeyPass)
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
require.Equal(t, int64(30), barAcc.GetCoins().AmountOf("steak").Int64())
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(20), fooAcc.GetCoins().AmountOf("steak").Int64())
}
@ -168,27 +168,27 @@ func TestGaiaCLIGasAuto(t *testing.T) {
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
// Test failure with auto gas disabled and very little gas set by hand
success := executeWrite(t, fmt.Sprintf("gaiacli send %v --gas=10 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
success := executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=10 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
tests.WaitForNextNBlocksTM(2, port)
// Check state didn't change
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
// Test failure with negative gas
success = executeWrite(t, fmt.Sprintf("gaiacli send %v --gas=-100 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=-100 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
// Test failure with 0 gas
success = executeWrite(t, fmt.Sprintf("gaiacli send %v --gas=0 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
success = executeWrite(t, fmt.Sprintf("gaiacli tx send %v --gas=0 --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.False(t, success)
// Enable auto gas
success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli send %v --json --gas=simulate --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
success, stdout, _ := executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx send %v --json --gas=simulate --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
require.True(t, success)
// check that gas wanted == gas used
cdc := app.MakeCodec()
@ -201,7 +201,7 @@ func TestGaiaCLIGasAuto(t *testing.T) {
require.Equal(t, jsonOutput.Response.GasWanted, jsonOutput.Response.GasUsed)
tests.WaitForNextNBlocksTM(2, port)
// Check state has changed accordingly
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
}
@ -220,12 +220,12 @@ func TestGaiaCLICreateValidator(t *testing.T) {
barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
barCeshPubKey := sdk.MustBech32ifyConsPub(barPubKey)
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
executeWrite(t, fmt.Sprintf("gaiacli tx send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
defaultParams := stake.DefaultParams()
@ -234,7 +234,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
initialPool = initialPool.ProcessProvisions(defaultParams) // provisions are added to the pool every hour
// create validator
cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags)
cvStr := fmt.Sprintf("gaiacli tx create-validator %v", flags)
cvStr += fmt.Sprintf(" --from=%s", "bar")
cvStr += fmt.Sprintf(" --pubkey=%s", barCeshPubKey)
cvStr += fmt.Sprintf(" --amount=%v", "2steak")
@ -262,15 +262,15 @@ func TestGaiaCLICreateValidator(t *testing.T) {
executeWrite(t, cvStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
validator := executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
require.Equal(t, validator.OperatorAddr, sdk.ValAddress(barAddr))
require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens))
// unbond a single share
unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags)
unbondStr := fmt.Sprintf("gaiacli tx unbond begin %v", flags)
unbondStr += fmt.Sprintf(" --from=%s", "bar")
unbondStr += fmt.Sprintf(" --validator=%s", sdk.ValAddress(barAddr))
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
@ -280,16 +280,16 @@ func TestGaiaCLICreateValidator(t *testing.T) {
tests.WaitForNextNBlocksTM(2, port)
/* // this won't be what we expect because we've only started unbonding, haven't completed
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %v %v", barCech, flags))
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
*/
validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
validator = executeGetValidator(t, fmt.Sprintf("gaiacli query validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
require.Equal(t, "1.0000000000", validator.Tokens.String())
params := executeGetParams(t, fmt.Sprintf("gaiacli stake parameters --output=json %v", flags))
params := executeGetParams(t, fmt.Sprintf("gaiacli query parameters --output=json %v", flags))
require.True(t, defaultParams.Equal(params))
pool := executeGetPool(t, fmt.Sprintf("gaiacli stake pool --output=json %v", flags))
pool := executeGetPool(t, fmt.Sprintf("gaiacli query pool --output=json %v", flags))
require.Equal(t, initialPool.DateLastCommissionReset, pool.DateLastCommissionReset)
require.Equal(t, initialPool.PrevBondedShares, pool.PrevBondedShares)
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
@ -308,14 +308,14 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
proposalsQuery := tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals %v", flags), "")
proposalsQuery := tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
require.Equal(t, "No matching proposals found", proposalsQuery)
// submit a test proposal
spStr := fmt.Sprintf("gaiacli gov submit-proposal %v", flags)
spStr := fmt.Sprintf("gaiacli tx submit-proposal %v", flags)
spStr += fmt.Sprintf(" --from=%s", "foo")
spStr += fmt.Sprintf(" --deposit=%s", "5steak")
spStr += fmt.Sprintf(" --type=%s", "Text")
@ -339,17 +339,17 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
executeWrite(t, spStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64())
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposal-id=1 --output=json %v", flags))
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
require.Equal(t, int64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals %v", flags), "")
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
require.Equal(t, " 1 - Test", proposalsQuery)
depositStr := fmt.Sprintf("gaiacli gov deposit %v", flags)
depositStr := fmt.Sprintf("gaiacli tx deposit %v", flags)
depositStr += fmt.Sprintf(" --from=%s", "foo")
depositStr += fmt.Sprintf(" --deposit=%s", "10steak")
depositStr += fmt.Sprintf(" --proposal-id=%s", "1")
@ -367,13 +367,13 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
executeWrite(t, depositStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64())
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli gov query-proposal --proposal-id=1 --output=json %v", flags))
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
require.Equal(t, int64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
voteStr := fmt.Sprintf("gaiacli gov vote %v", flags)
voteStr := fmt.Sprintf("gaiacli tx vote %v", flags)
voteStr += fmt.Sprintf(" --from=%s", "foo")
voteStr += fmt.Sprintf(" --proposal-id=%s", "1")
voteStr += fmt.Sprintf(" --option=%s", "Yes")
@ -391,23 +391,23 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
executeWrite(t, voteStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags))
vote := executeGetVote(t, fmt.Sprintf("gaiacli query vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags))
require.Equal(t, int64(1), vote.ProposalID)
require.Equal(t, gov.OptionYes, vote.Option)
votes := executeGetVotes(t, fmt.Sprintf("gaiacli gov query-votes --proposal-id=1 --output=json %v", flags))
votes := executeGetVotes(t, fmt.Sprintf("gaiacli query votes --proposal-id=1 --output=json %v", flags))
require.Len(t, votes, 1)
require.Equal(t, int64(1), votes[0].ProposalID)
require.Equal(t, gov.OptionYes, votes[0].Option)
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --status=DepositPeriod %v", flags), "")
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "")
require.Equal(t, "No matching proposals found", proposalsQuery)
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --status=VotingPeriod %v", flags), "")
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=VotingPeriod %v", flags), "")
require.Equal(t, " 1 - Test", proposalsQuery)
// submit a second test proposal
spStr = fmt.Sprintf("gaiacli gov submit-proposal %v", flags)
spStr = fmt.Sprintf("gaiacli tx submit-proposal %v", flags)
spStr += fmt.Sprintf(" --from=%s", "foo")
spStr += fmt.Sprintf(" --deposit=%s", "5steak")
spStr += fmt.Sprintf(" --type=%s", "Text")
@ -417,7 +417,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
executeWrite(t, spStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --latest=1 %v", flags), "")
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --latest=1 %v", flags), "")
require.Equal(t, " 2 - Apples", proposalsQuery)
}
@ -437,7 +437,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
// Test generate sendTx with default gas
success, stdout, stderr := executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo --generate-only",
"gaiacli tx send %v --amount=10steak --to=%s --from=foo --generate-only",
flags, barAddr), []string{}...)
require.True(t, success)
require.Empty(t, stderr)
@ -448,7 +448,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
// Test generate sendTx with --gas=$amount
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo --gas=100 --generate-only",
"gaiacli tx send %v --amount=10steak --to=%s --from=foo --gas=100 --generate-only",
flags, barAddr), []string{}...)
require.True(t, success)
require.Empty(t, stderr)
@ -459,7 +459,7 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
// Test generate sendTx, estimate gas
success, stdout, stderr = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli send %v --amount=10steak --to=%s --from=foo --gas=simulate --generate-only",
"gaiacli tx send %v --amount=10steak --to=%s --from=foo --gas=simulate --generate-only",
flags, barAddr), []string{}...)
require.True(t, success)
require.NotEmpty(t, stderr)
@ -473,13 +473,13 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
// Test sign --print-sigs
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli sign %v --print-sigs %v", flags, unsignedTxFile.Name()))
"gaiacli tx sign %v --print-sigs %v", flags, unsignedTxFile.Name()))
require.True(t, success)
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n", fooAddr.String()), stdout)
// Test sign
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli sign %v --name=foo %v", flags, unsignedTxFile.Name()), app.DefaultKeyPass)
"gaiacli tx sign %v --name=foo %v", flags, unsignedTxFile.Name()), app.DefaultKeyPass)
require.True(t, success)
msg = unmarshalStdTx(t, stdout)
require.Equal(t, len(msg.Msgs), 1)
@ -492,15 +492,15 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
// Test sign --print-signatures
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
"gaiacli sign %v --print-sigs %v", flags, signedTxFile.Name()))
"gaiacli tx sign %v --print-sigs %v", flags, signedTxFile.Name()))
require.True(t, success)
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\n", fooAddr.String(), fooAddr.String()), stdout)
// Test broadcast
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli broadcast %v --json %v", flags, signedTxFile.Name()))
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf("gaiacli tx broadcast %v --json %v", flags, signedTxFile.Name()))
require.True(t, success)
var result struct {
Response abci.ResponseDeliverTx
@ -510,9 +510,9 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, msg.Fee.Gas, result.Response.GasWanted)
tests.WaitForNextNBlocksTM(2, port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", barAddr, flags))
require.Equal(t, int64(10), barAcc.GetCoins().AmountOf("steak").Int64())
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
}

View File

@ -18,12 +18,20 @@ import (
slashingcmd "github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"path"
"os"
"path"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/spf13/viper"
)
const (
storeAcc = "acc"
storeGov = "gov"
storeSlashing = "slashing"
storeStake = "stake"
)
// rootCmd is the entry point for this binary
var (
rootCmd = &cobra.Command{
@ -44,103 +52,73 @@ func main() {
// add standard rpc commands
rpc.AddCommands(rootCmd)
//Add state commands
tendermintCmd := &cobra.Command{
Use: "tendermint",
Short: "Tendermint state querying subcommands",
//Add query commands
queryCmd := &cobra.Command{
Use: "query",
Aliases: []string{"q"},
Short: "Querying subcommands",
}
tendermintCmd.AddCommand(
queryCmd.AddCommand(
rpc.BlockCommand(),
rpc.ValidatorCommand(),
)
tx.AddCommands(tendermintCmd, cdc)
tx.AddCommands(queryCmd, cdc)
queryCmd.AddCommand(client.LineBreak)
queryCmd.AddCommand(client.GetCommands(
authcmd.GetAccountCmd(storeAcc, cdc, authcmd.GetAccountDecoder(cdc)),
stakecmd.GetCmdQueryDelegation(storeStake, cdc),
stakecmd.GetCmdQueryDelegations(storeStake, cdc),
stakecmd.GetCmdQueryParams(storeStake, cdc),
stakecmd.GetCmdQueryPool(storeStake, cdc),
govcmd.GetCmdQueryProposal(storeGov, cdc),
govcmd.GetCmdQueryProposals(storeGov, cdc),
stakecmd.GetCmdQueryRedelegation(storeStake, cdc),
stakecmd.GetCmdQueryRedelegations(storeStake, cdc),
slashingcmd.GetCmdQuerySigningInfo(storeSlashing, cdc),
stakecmd.GetCmdQueryUnbondingDelegation(storeStake, cdc),
stakecmd.GetCmdQueryUnbondingDelegations(storeStake, cdc),
stakecmd.GetCmdQueryValidator(storeStake, cdc),
stakecmd.GetCmdQueryValidators(storeStake, cdc),
govcmd.GetCmdQueryVote(storeGov, cdc),
govcmd.GetCmdQueryVotes(storeGov, cdc),
)...)
rootCmd.AddCommand(
tendermintCmd,
lcd.ServeCommand(cdc),
client.LineBreak,
)
//Add stake commands
stakeCmd := &cobra.Command{
Use: "stake",
Short: "Stake and validation subcommands",
//Add query commands
txCmd := &cobra.Command{
Use: "tx",
Short: "Transactions subcommands",
}
stakeCmd.AddCommand(
client.GetCommands(
stakecmd.GetCmdQueryValidator("stake", cdc),
stakecmd.GetCmdQueryValidators("stake", cdc),
stakecmd.GetCmdQueryDelegation("stake", cdc),
stakecmd.GetCmdQueryDelegations("stake", cdc),
stakecmd.GetCmdQueryParams("stake", cdc),
stakecmd.GetCmdQueryPool("stake", cdc),
stakecmd.GetCmdQueryUnbondingDelegation("stake", cdc),
stakecmd.GetCmdQueryUnbondingDelegations("stake", cdc),
stakecmd.GetCmdQueryRedelegation("stake", cdc),
stakecmd.GetCmdQueryRedelegations("stake", cdc),
slashingcmd.GetCmdQuerySigningInfo("slashing", cdc),
//Add auth and bank commands
txCmd.AddCommand(
client.PostCommands(
bankcmd.GetBroadcastCommand(cdc),
authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc)),
)...)
stakeCmd.AddCommand(
txCmd.AddCommand(client.LineBreak)
txCmd.AddCommand(
client.PostCommands(
stakecmd.GetCmdCreateValidator(cdc),
stakecmd.GetCmdEditValidator(cdc),
stakecmd.GetCmdDelegate(cdc),
stakecmd.GetCmdUnbond("stake", cdc),
stakecmd.GetCmdRedelegate("stake", cdc),
slashingcmd.GetCmdUnjail(cdc),
)...)
rootCmd.AddCommand(
stakeCmd,
)
//Add distribution commands
distrCmd := &cobra.Command{
Use: "distribution",
Short: "withdraw rewards for delegation and validation",
}
distrCmd.AddCommand(
client.PostCommands(
stakecmd.GetCmdRedelegate(storeStake, cdc),
stakecmd.GetCmdUnbond(storeStake, cdc),
distrcmd.GetCmdWithdrawRewards(cdc),
distrcmd.GetCmdSetWithdrawAddr(cdc),
)...)
rootCmd.AddCommand(
distrCmd,
)
//Add stake commands
govCmd := &cobra.Command{
Use: "gov",
Short: "Governance and voting subcommands",
}
govCmd.AddCommand(
client.GetCommands(
govcmd.GetCmdQueryProposal("gov", cdc),
govcmd.GetCmdQueryVote("gov", cdc),
govcmd.GetCmdQueryVotes("gov", cdc),
govcmd.GetCmdQueryProposals("gov", cdc),
)...)
govCmd.AddCommand(
client.PostCommands(
govcmd.GetCmdSubmitProposal(cdc),
govcmd.GetCmdDeposit(cdc),
bankcmd.SendTxCmd(cdc),
govcmd.GetCmdSubmitProposal(cdc),
slashingcmd.GetCmdUnjail(cdc),
govcmd.GetCmdVote(cdc),
)...)
rootCmd.AddCommand(
govCmd,
queryCmd,
txCmd,
lcd.ServeCommand(cdc),
client.LineBreak,
)
//Add auth and bank commands
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc)),
)...)
rootCmd.AddCommand(
client.PostCommands(
bankcmd.SendTxCmd(cdc),
bankcmd.GetBroadcastCommand(cdc),
)...)
// add proxy, version and key info
rootCmd.AddCommand(
keys.Commands(),
@ -178,7 +156,7 @@ func initConfig(cmd *cobra.Command) error {
}
if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil {
return err
return err
}
return viper.BindPFlag(cli.OutputFlag, cmd.PersistentFlags().Lookup(cli.OutputFlag))
}

View File

@ -23,7 +23,7 @@ NAME: TYPE: ADDRESS: PUBKEY:
This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following:
```bash
$ gaiacli send --from {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000
$ gaiacli tx send --from {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000
```
You will be asked to review and confirm the transaction on the Ledger. Once you do this you should see the result in the console! Now you can use your Ledger to manage your Atoms and Stake!

View File

@ -62,7 +62,7 @@ gaiacli account <YOUR_ADDRESS>
Here is the command to send coins via the CLI:
```bash
gaiacli send --amount=10faucetToken --chain-id=<name_of_testnet_chain> --name=<key_name> --to=<destination_address>
gaiacli tx send --amount=10faucetToken --chain-id=<name_of_testnet_chain> --name=<key_name> --to=<destination_address>
```
Flags:
@ -88,7 +88,7 @@ The Rest Server acts as an intermediary between the front-end and the full-node.
To start the Rest server:
```bash
gaiacli advanced rest-server --trust-node=false --node=<full_node_address:full_node_port>
gaiacli rest-server --trust-node=false --node=<full_node_address:full_node_port>
```
Flags:
@ -108,4 +108,4 @@ The Rest API documents all the available endpoints that you can use to interract
The API is divided into ICS standards for each category of endpoints. For example, the [ICS20](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#ics20---tokenapi) describes the API to interact with tokens.
To give more flexibility to implementers, we have separated the different steps that are involved in the process of sending transactions. You will be able to generate unsigned transactions (example with [coin transfer](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-banktransfers)), [sign](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-authtxsign) and [broadcast](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-authtxbroadcast) them with different API endpoints. This allows service providers to use their own signing mechanism for instance.
To give more flexibility to implementers, we have separated the different steps that are involved in the process of sending transactions. You will be able to generate unsigned transactions (example with [coin transfer](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-banktransfers)), [sign](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-authtxsign) and [broadcast](https://github.com/cosmos/cosmos-sdk/blob/develop/docs/light/api.md#post-authtxbroadcast) them with different API endpoints. This allows service providers to use their own signing mechanism for instance.

View File

@ -98,7 +98,7 @@ When you query an account balance with zero tokens, you will get this error: `No
The following command could be used to send coins from one account to another:
```bash
gaiacli send \
gaiacli tx send \
--amount=10faucetToken \
--chain-id=<chain_id> \
--name=<key_name> \
@ -131,7 +131,7 @@ 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 \
gaiacli tx send \
--amount=10faucetToken \
--chain-id=<chain_id> \
--name=<key_name> \
@ -142,7 +142,7 @@ gaiacli send \
Furthermore, you can build a transaction and print its JSON format to STDOUT by appending `--generate-only` to the list of the command line arguments:
```bash
gaiacli send \
gaiacli tx send \
--amount=10faucetToken \
--chain-id=<chain_id> \
--name=<key_name> \
@ -153,7 +153,7 @@ gaiacli send \
You can now sign the transaction file generated through the `--generate-only` flag by providing your key to the following command:
```bash
gaiacli sign \
gaiacli tx sign \
--chain-id=<chain_id> \
--name=<key_name>
unsignedSendTx.json > signedSendTx.json
@ -162,7 +162,7 @@ gaiacli sign \
You can broadcast the signed transaction to a node by providing the JSON file to the following command:
```
gaiacli broadcast --node=<node> signedSendTx.json
gaiacli tx broadcast --node=<node> signedSendTx.json
```
### Staking
@ -180,13 +180,13 @@ On the upcoming mainnet, you can delegate `atom` to a validator. These [delegato
You can query the list of all validators of a specific chain:
```bash
gaiacli stake validators
gaiacli query validators
```
If you want to get the information of a single validator you can check it with:
```bash
gaiacli stake validator <account_cosmosval>
gaiacli query validator <account_cosmosval>
```
#### Bond Tokens
@ -194,7 +194,7 @@ gaiacli stake validator <account_cosmosval>
On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond tokens to a testnet validator (*i.e.* delegate):
```bash
gaiacli stake delegate \
gaiacli tx delegate \
--amount=10steak \
--validator=$(gaiad tendermint show-validator) \
--name=<key_name> \
@ -212,7 +212,7 @@ Don't use more `steak` thank you have! You can always get more by using the [Fau
Once submitted a delegation to a validator, you can see it's information by using the following command:
```bash
gaiacli stake delegation \
gaiacli query delegation \
--address-delegator=<account_cosmos> \
--validator=<account_cosmosval>
```
@ -220,7 +220,7 @@ gaiacli stake delegation \
Or if you want to check all your current delegations with disctinct validators:
```bash
gaiacli stake delegations <account_cosmos>
gaiacli query delegations <account_cosmos>
```
You can also get previous delegation(s) status by adding the `--height` flag.
@ -230,17 +230,17 @@ You can also get previous delegation(s) status by adding the `--height` flag.
If for any reason the validator misbehaves, or you just want to unbond a certain amount of tokens, use this following command. You can unbond a specific `shares-amount` (eg:`12.1`\) or a `shares-percent` (eg:`25`) with the corresponding flags.
```bash
gaiacli stake unbond begin \
gaiacli tx unbond begin \
--validator=<account_cosmosval> \
--shares-percent=100 \
--from=<key_name> \
--chain-id=<chain_id>
```
Later you must complete the unbonding process by using the `gaiacli stake unbond complete` command:
Later you must complete the unbonding process by using the `gaiacli tx unbond complete` command:
```bash
gaiacli stake unbond complete \
gaiacli tx unbond complete \
--validator=<account_cosmosval> \
--from=<key_name> \
--chain-id=<chain_id>
@ -251,7 +251,7 @@ gaiacli stake unbond complete \
Once you begin an unbonding-delegation, you can see it's information by using the following command:
```bash
gaiacli stake unbonding-delegation \
gaiacli query unbonding-delegation \
--address-delegator=<account_cosmos> \
--validator=<account_cosmosval> \
```
@ -259,7 +259,7 @@ gaiacli stake unbonding-delegation \
Or if you want to check all your current unbonding-delegations with disctinct validators:
```bash
gaiacli stake unbonding-delegations <account_cosmos>
gaiacli query unbonding-delegations <account_cosmos>
```
You can also get previous unbonding-delegation(s) status by adding the `--height` flag.
@ -269,7 +269,7 @@ You can also get previous unbonding-delegation(s) status by adding the `--height
A redelegation is a type delegation that allows you to bond illiquid tokens from one validator to another:
```bash
gaiacli stake redelegate begin \
gaiacli tx redelegate begin \
--address-validator-source=<account_cosmosval> \
--address-validator-dest=<account_cosmosval> \
--shares-percent=50 \
@ -279,10 +279,10 @@ gaiacli stake redelegate begin \
Here you can also redelegate a specific `shares-amount` or a `shares-percent` with the corresponding flags.
Later you must complete the redelegation process by using the `gaiacli stake redelegate complete` command:
Later you must complete the redelegation process by using the `gaiacli tx redelegate complete` command:
```bash
gaiacli stake unbond complete \
gaiacli tx unbond complete \
--validator=<account_cosmosval> \
--from=<key_name> \
--chain-id=<chain_id>
@ -293,7 +293,7 @@ gaiacli stake unbond complete \
Once you begin an redelegation, you can see it's information by using the following command:
```bash
gaiacli stake redelegation \
gaiacli query redelegation \
--address-delegator=<account_cosmos> \
--address-validator-source=<account_cosmosval> \
--address-validator-dest=<account_cosmosval> \
@ -302,7 +302,7 @@ gaiacli stake redelegation \
Or if you want to check all your current unbonding-delegations with disctinct validators:
```bash
gaiacli stake redelegations <account_cosmos>
gaiacli query redelegations <account_cosmos>
```
You can also get previous redelegation(s) status by adding the `--height` flag.
@ -331,7 +331,7 @@ In order to create a governance proposal, you must submit an initial deposit alo
- `type`: Type of proposal. Must be of value _Text_ (types _SoftwareUpgrade_ and _ParameterChange_ not supported yet).
```bash
gaiacli gov submit-proposal \
gaiacli tx submit-proposal \
--title=<title> \
--description=<description> \
--type=<Text/ParameterChange/SoftwareUpgrade> \
@ -346,14 +346,14 @@ gaiacli gov submit-proposal \
Once created, you can now query information of the proposal:
```bash
gaiacli gov query-proposal \
gaiacli query proposal \
--proposal-id=<proposal_id>
```
Or query all available proposals:
```bash
gaiacli gov query-proposals
gaiacli query proposals
```
You can also query proposals filtered by `voter` or `depositer` by using the corresponding flags.
@ -363,7 +363,7 @@ You can also query proposals filtered by `voter` or `depositer` by using the cor
In order for a proposal to be broadcasted to the network, the amount deposited must be above a `minDeposit` value (default: `10 steak`). If the proposal you previously created didn't meet this requirement, you can still increase the total amount deposited to activate it. Once the minimum deposit is reached, the proposal enters voting period:
```bash
gaiacli gov deposit \
gaiacli tx deposit \
--proposal-id=<proposal_id> \
--depositer=<account_cosmos> \
--deposit=<200steak> \
@ -378,7 +378,7 @@ gaiacli gov deposit \
After a proposal's deposit reaches the `MinDeposit` value, the voting period opens. Bonded `Atom` holders can then cast vote on it:
```bash
gaiacli gov vote \
gaiacli tx vote \
--proposal-id=<proposal_id> \
--voter=<account_cosmos> \
--option=<Yes/No/NoWithVeto/Abstain> \
@ -391,7 +391,7 @@ gaiacli gov vote \
Check the vote with the option you just submitted:
```bash
gaiacli gov query-vote \
gaiacli query vote \
--proposal-id=<proposal_id> \
--voter=<account_cosmos>
```
@ -401,7 +401,7 @@ gaiacli gov query-vote \
You can get the current parameters that define high level settings for staking:
```
gaiacli stake parameters
gaiacli query parameters
```
With the above command you will get the values for:
@ -420,7 +420,7 @@ All this values can be updated though a `governance` process by submitting a par
A staking `Pool` defines the dynamic parameters of the current state. You can query them with the following command:
```
gaiacli stake pool
gaiacli query pool
```
With the `pool` command you will get the values for:

View File

@ -22,14 +22,14 @@ Your `cosmosvalconspub` can be used to create a new validator by staking tokens.
gaiad tendermint show-validator
```
Next, craft your `gaiacli stake create-validator` command:
Next, craft your `gaiacli tx create-validator` command:
::: warning Note
Don't use more `steak` thank you have! You can always get more by using the [Faucet](https://faucetcosmos.network/)!
:::
```bash
gaiacli stake create-validator \
gaiacli tx create-validator \
--amount=5steak \
--pubkey=$(gaiad tendermint show-validator) \
--address-validator=<account_cosmosval>
@ -52,7 +52,7 @@ You can edit your validator's public description. This info is to identify your
The `--identity` can be used as to verify identity with systems like Keybase or UPort. When using with Keybase `--identity` should be populated with a 16-digit string that is generated with a [keybase.io](https://keybase.io) account. It's a cryptographically secure method of verifying your identity across multiple online networks. The Keybase API allows us to retrieve your Keybase avatar. This is how you can add a logo to your validator profile.
```bash
gaiacli stake edit-validator
gaiacli tx edit-validator
--validator=<account_cosmos>
--moniker="choose a moniker" \
--website="https://cosmos.network" \
@ -75,7 +75,7 @@ __Note__: The `commission-rate` value must adhere to the following invariants:
View the validator's information with this command:
```bash
gaiacli stake validator <account_cosmos>
gaiacli query validator <account_cosmos>
```
### Track Validator Signing Information
@ -83,7 +83,7 @@ gaiacli stake validator <account_cosmos>
In order to keep track of a validator's signatures in the past you can do so by using the `signing-info` command:
```bash
gaiacli stake signing-information <validator-pubkey>\
gaiacli query signing-information <validator-pubkey>\
--chain-id=<chain_id>
```
@ -92,7 +92,7 @@ gaiacli stake signing-information <validator-pubkey>\
When a validator is "jailed" for downtime, you must submit an `Unjail` transaction in order to be able to get block proposer rewards again (depends on the zone fee distribution).
```bash
gaiacli stake unjail \
gaiacli tx unjail \
--from=<key_name> \
--chain-id=<chain_id>
--validator=<account_cosmosval> \
@ -104,7 +104,7 @@ gaiacli stake unjail \
Your validator is active if the following command returns anything:
```bash
gaiacli tendermint validator-set | grep "$(gaiad tendermint show-validator)"
gaiacli query tendermint-validator-set | grep "$(gaiad tendermint show-validator)"
```
You should also be able to see your validator on the [Explorer](https://explorecosmos.network/validators). You are looking for the `bech32` encoded `address` in the `~/.gaiad/config/priv_validator.json` file.
@ -128,7 +128,7 @@ gaiad start
Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmos>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`.
```bash
gaiacli stake unjail <cosmos> --chain-id=<chain_id> --name=<name>
gaiacli tx unjail <cosmos> --chain-id=<chain_id> --name=<name>
```
::: danger Warning

View File

@ -48,6 +48,11 @@ func (v Validator) GetDelegatorShares() sdk.Dec {
return sdk.ZeroDec()
}
// Implements sdk.Validator
func (v Validator) GetCommission() sdk.Dec {
return sdk.ZeroDec()
}
// Implements sdk.Validator
func (v Validator) GetJailed() bool {
return false

View File

@ -34,7 +34,7 @@ func QuizTxCmd(cdc *codec.Codec) *cobra.Command {
msg := cool.NewMsgQuiz(from, args[0])
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}
@ -59,7 +59,7 @@ func SetTrendTxCmd(cdc *codec.Codec) *cobra.Command {
msg := cool.NewMsgSetTrend(from, args[0])
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -53,7 +53,7 @@ func MineCmd(cdc *codec.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -68,7 +68,7 @@ func BondTxCmd(cdc *codec.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -98,7 +98,7 @@ func UnbondTxCmd(cdc *codec.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}

48
scripts/multisim.sh Executable file
View File

@ -0,0 +1,48 @@
#!/bin/bash
seeds=(1 2 4 7 9 20 32 123 4728 37827 981928 87821 891823782 989182 89182391)
echo "Running multi-seed simulation with seeds: ${seeds[@]}"
echo "Edit scripts/multisim.sh to add new seeds. Keeping parameters in the file makes failures easy to reproduce."
echo "This script will kill all sub-simulations on SIGINT/SIGTERM/EXIT (i.e. Ctrl-C)."
trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT
tmpdir=$(mktemp -d)
echo "Using temporary log directory: $tmpdir"
sim() {
seed=$1
echo "Running full Gaia simulation with seed $seed. This may take awhile!"
file="$tmpdir/gaia-simulation-seed-$seed-date-$(date -Iseconds -u).stdout"
echo "Writing stdout to $file..."
go test ./cmd/gaia/app -run TestFullGaiaSimulation -SimulationEnabled=true -SimulationNumBlocks=1000 \
-SimulationVerbose=true -SimulationCommit=true -SimulationSeed=$seed -v -timeout 24h > $file
}
i=0
pids=()
for seed in ${seeds[@]}; do
sim $seed &
pids[${i}]=$!
i=$(($i+1))
sleep 0.1 # start in order, nicer logs
done
echo "Simulation processes spawned, waiting for completion..."
code=0
i=0
for pid in ${pids[*]}; do
wait $pid
last=$?
if [ $last -ne 0 ]; then
seed=${seeds[${i}]}
echo "Simulation with seed $seed failed!"
code=1
fi
i=$(($i+1))
done
exit $code

View File

@ -8,13 +8,15 @@ import (
var _ KVStore = &gasKVStore{}
// gasKVStore applies gas tracking to an underlying kvstore
// gasKVStore applies gas tracking to an underlying KVStore. It implements the
// KVStore interface.
type gasKVStore struct {
gasMeter sdk.GasMeter
gasConfig sdk.GasConfig
parent sdk.KVStore
}
// NewGasKVStore returns a reference to a new GasKVStore.
// nolint
func NewGasKVStore(gasMeter sdk.GasMeter, gasConfig sdk.GasConfig, parent sdk.KVStore) *gasKVStore {
kvs := &gasKVStore{
@ -26,83 +28,96 @@ func NewGasKVStore(gasMeter sdk.GasMeter, gasConfig sdk.GasConfig, parent sdk.KV
}
// Implements Store.
func (gi *gasKVStore) GetStoreType() sdk.StoreType {
return gi.parent.GetStoreType()
func (gs *gasKVStore) GetStoreType() sdk.StoreType {
return gs.parent.GetStoreType()
}
// Implements KVStore.
func (gi *gasKVStore) Get(key []byte) (value []byte) {
gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostFlat, "ReadFlat")
value = gi.parent.Get(key)
func (gs *gasKVStore) Get(key []byte) (value []byte) {
gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostFlat, sdk.GasReadCostFlatDesc)
value = gs.parent.Get(key)
// TODO overflow-safe math?
gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*sdk.Gas(len(value)), "ReadPerByte")
gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*sdk.Gas(len(value)), sdk.GasReadPerByteDesc)
return value
}
// Implements KVStore.
func (gi *gasKVStore) Set(key []byte, value []byte) {
gi.gasMeter.ConsumeGas(gi.gasConfig.WriteCostFlat, "WriteFlat")
func (gs *gasKVStore) Set(key []byte, value []byte) {
gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostFlat, sdk.GasWriteCostFlatDesc)
// TODO overflow-safe math?
gi.gasMeter.ConsumeGas(gi.gasConfig.WriteCostPerByte*sdk.Gas(len(value)), "WritePerByte")
gi.parent.Set(key, value)
gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*sdk.Gas(len(value)), sdk.GasWritePerByteDesc)
gs.parent.Set(key, value)
}
// Implements KVStore.
func (gi *gasKVStore) Has(key []byte) bool {
gi.gasMeter.ConsumeGas(gi.gasConfig.HasCost, "Has")
return gi.parent.Has(key)
func (gs *gasKVStore) Has(key []byte) bool {
gs.gasMeter.ConsumeGas(gs.gasConfig.HasCost, sdk.GasHasDesc)
return gs.parent.Has(key)
}
// Implements KVStore.
func (gi *gasKVStore) Delete(key []byte) {
// No gas costs for deletion
gi.parent.Delete(key)
func (gs *gasKVStore) Delete(key []byte) {
// charge gas to prevent certain attack vectors even though space is being freed
gs.gasMeter.ConsumeGas(gs.gasConfig.DeleteCost, sdk.GasDeleteDesc)
gs.parent.Delete(key)
}
// Implements KVStore
func (gi *gasKVStore) Prefix(prefix []byte) KVStore {
func (gs *gasKVStore) Prefix(prefix []byte) KVStore {
// Keep gasstore layer at the top
return &gasKVStore{
gasMeter: gi.gasMeter,
gasConfig: gi.gasConfig,
parent: prefixStore{gi.parent, prefix},
gasMeter: gs.gasMeter,
gasConfig: gs.gasConfig,
parent: prefixStore{gs.parent, prefix},
}
}
// Implements KVStore
func (gi *gasKVStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, gi)
func (gs *gasKVStore) Gas(meter GasMeter, config GasConfig) KVStore {
return NewGasKVStore(meter, config, gs)
}
// Iterator implements the KVStore interface. It returns an iterator which
// incurs a flat gas cost for seeking to the first key/value pair and a variable
// gas cost based on the current value's length if the iterator is valid.
func (gs *gasKVStore) Iterator(start, end []byte) sdk.Iterator {
return gs.iterator(start, end, true)
}
// ReverseIterator implements the KVStore interface. It returns a reverse
// iterator which incurs a flat gas cost for seeking to the first key/value pair
// and a variable gas cost based on the current value's length if the iterator
// is valid.
func (gs *gasKVStore) ReverseIterator(start, end []byte) sdk.Iterator {
return gs.iterator(start, end, false)
}
// Implements KVStore.
func (gi *gasKVStore) Iterator(start, end []byte) sdk.Iterator {
return gi.iterator(start, end, true)
}
// Implements KVStore.
func (gi *gasKVStore) ReverseIterator(start, end []byte) sdk.Iterator {
return gi.iterator(start, end, false)
}
// Implements KVStore.
func (gi *gasKVStore) CacheWrap() sdk.CacheWrap {
func (gs *gasKVStore) CacheWrap() sdk.CacheWrap {
panic("cannot CacheWrap a GasKVStore")
}
// CacheWrapWithTrace implements the KVStore interface.
func (gi *gasKVStore) CacheWrapWithTrace(_ io.Writer, _ TraceContext) CacheWrap {
func (gs *gasKVStore) CacheWrapWithTrace(_ io.Writer, _ TraceContext) CacheWrap {
panic("cannot CacheWrapWithTrace a GasKVStore")
}
func (gi *gasKVStore) iterator(start, end []byte, ascending bool) sdk.Iterator {
func (gs *gasKVStore) iterator(start, end []byte, ascending bool) sdk.Iterator {
var parent sdk.Iterator
if ascending {
parent = gi.parent.Iterator(start, end)
parent = gs.parent.Iterator(start, end)
} else {
parent = gi.parent.ReverseIterator(start, end)
parent = gs.parent.ReverseIterator(start, end)
}
return newGasIterator(gi.gasMeter, gi.gasConfig, parent)
gi := newGasIterator(gs.gasMeter, gs.gasConfig, parent)
if gi.Valid() {
gi.(*gasIterator).consumeSeekGas()
}
return gi
}
type gasIterator struct {
@ -120,36 +135,50 @@ func newGasIterator(gasMeter sdk.GasMeter, gasConfig sdk.GasConfig, parent sdk.I
}
// Implements Iterator.
func (g *gasIterator) Domain() (start []byte, end []byte) {
return g.parent.Domain()
func (gi *gasIterator) Domain() (start []byte, end []byte) {
return gi.parent.Domain()
}
// Implements Iterator.
func (g *gasIterator) Valid() bool {
return g.parent.Valid()
func (gi *gasIterator) Valid() bool {
return gi.parent.Valid()
}
// Implements Iterator.
func (g *gasIterator) Next() {
g.parent.Next()
// Next implements the Iterator interface. It seeks to the next key/value pair
// in the iterator. It incurs a flat gas cost for seeking and a variable gas
// cost based on the current value's length if the iterator is valid.
func (gi *gasIterator) Next() {
if gi.Valid() {
gi.consumeSeekGas()
}
gi.parent.Next()
}
// Implements Iterator.
func (g *gasIterator) Key() (key []byte) {
g.gasMeter.ConsumeGas(g.gasConfig.KeyCostFlat, "KeyFlat")
key = g.parent.Key()
// Key implements the Iterator interface. It returns the current key and it does
// not incur any gas cost.
func (gi *gasIterator) Key() (key []byte) {
key = gi.parent.Key()
return key
}
// Implements Iterator.
func (g *gasIterator) Value() (value []byte) {
value = g.parent.Value()
g.gasMeter.ConsumeGas(g.gasConfig.ValueCostFlat, "ValueFlat")
g.gasMeter.ConsumeGas(g.gasConfig.ValueCostPerByte*sdk.Gas(len(value)), "ValuePerByte")
// Value implements the Iterator interface. It returns the current value and it
// does not incur any gas cost.
func (gi *gasIterator) Value() (value []byte) {
value = gi.parent.Value()
return value
}
// Implements Iterator.
func (g *gasIterator) Close() {
g.parent.Close()
func (gi *gasIterator) Close() {
gi.parent.Close()
}
// consumeSeekGas consumes a flat gas cost for seeking and a variable gas cost
// based on the current value's length.
func (gi *gasIterator) consumeSeekGas() {
value := gi.Value()
gi.gasMeter.ConsumeGas(gi.gasConfig.ValueCostPerByte*sdk.Gas(len(value)), sdk.GasValuePerByteDesc)
gi.gasMeter.ConsumeGas(gi.gasConfig.IterNextCostFlat, sdk.GasIterNextCostFlatDesc)
}

View File

@ -25,7 +25,7 @@ func TestGasKVStoreBasic(t *testing.T) {
require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
st.Delete(keyFmt(1))
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
require.Equal(t, meter.GasConsumed(), sdk.Gas(183))
require.Equal(t, meter.GasConsumed(), sdk.Gas(193))
}
func TestGasKVStoreIterator(t *testing.T) {
@ -49,7 +49,7 @@ func TestGasKVStoreIterator(t *testing.T) {
iterator.Next()
require.False(t, iterator.Valid())
require.Panics(t, iterator.Next)
require.Equal(t, meter.GasConsumed(), sdk.Gas(356))
require.Equal(t, meter.GasConsumed(), sdk.Gas(384))
}
func TestGasKVStoreOutOfGasSet(t *testing.T) {

View File

@ -1,6 +1,7 @@
package types
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
@ -423,3 +424,55 @@ func TestAmountOf(t *testing.T) {
assert.Equal(t, NewInt(tc.amountOfTREE), tc.coins.AmountOf("TREE"))
}
}
func BenchmarkCoinsAdditionIntersect(b *testing.B) {
benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) {
return func(b *testing.B) {
coinsA := Coins(make([]Coin, numCoinsA))
coinsB := Coins(make([]Coin, numCoinsB))
for i := 0; i < numCoinsA; i++ {
coinsA[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
}
for i := 0; i < numCoinsB; i++ {
coinsB[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
coinsA.Plus(coinsB)
}
}
}
benchmarkSizes := [][]int{[]int{1, 1}, []int{5, 5}, []int{5, 20}, []int{1, 1000}, []int{2, 1000}}
for i := 0; i < len(benchmarkSizes); i++ {
sizeA := benchmarkSizes[i][0]
sizeB := benchmarkSizes[i][1]
b.Run(fmt.Sprintf("sizes: A_%d, B_%d", sizeA, sizeB), benchmarkingFunc(sizeA, sizeB))
}
}
func BenchmarkCoinsAdditionNoIntersect(b *testing.B) {
benchmarkingFunc := func(numCoinsA int, numCoinsB int) func(b *testing.B) {
return func(b *testing.B) {
coinsA := Coins(make([]Coin, numCoinsA))
coinsB := Coins(make([]Coin, numCoinsB))
for i := 0; i < numCoinsA; i++ {
coinsA[i] = NewCoin("COINZ_"+string(numCoinsB+i), NewInt(int64(i)))
}
for i := 0; i < numCoinsB; i++ {
coinsB[i] = NewCoin("COINZ_"+string(i), NewInt(int64(i)))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
coinsA.Plus(coinsB)
}
}
}
benchmarkSizes := [][]int{[]int{1, 1}, []int{5, 5}, []int{5, 20}, []int{1, 1000}, []int{2, 1000}, []int{1000, 2}}
for i := 0; i < len(benchmarkSizes); i++ {
sizeA := benchmarkSizes[i][0]
sizeB := benchmarkSizes[i][1]
b.Run(fmt.Sprintf("sizes: A_%d, B_%d", sizeA, sizeB), benchmarkingFunc(sizeA, sizeB))
}
}

View File

@ -215,6 +215,16 @@ func (d Dec) Mul(d2 Dec) Dec {
return Dec{chopped}
}
// multiplication
func (d Dec) MulInt(i Int) Dec {
mul := new(big.Int).Mul(d.Int, i.i)
if mul.BitLen() > 255+DecimalPrecisionBits {
panic("Int overflow")
}
return Dec{mul}
}
// quotient
func (d Dec) Quo(d2 Dec) Dec {

View File

@ -325,3 +325,20 @@ func TestStringOverflow(t *testing.T) {
dec3.String(),
)
}
func TestDecMulInt(t *testing.T) {
tests := []struct {
sdkDec Dec
sdkInt Int
want Dec
}{
{NewDec(10), NewInt(2), NewDec(20)},
{NewDec(1000000), NewInt(100), NewDec(100000000)},
{NewDecWithPrec(1, 1), NewInt(10), NewDec(1)},
{NewDecWithPrec(1, 5), NewInt(20), NewDecWithPrec(2, 4)},
}
for i, tc := range tests {
got := tc.sdkDec.MulInt(tc.sdkInt)
require.Equal(t, tc.want, got, "Incorrect result on test case %d", i)
}
}

View File

@ -1,9 +1,26 @@
package types
// Gas consumption descriptors.
const (
GasIterNextCostFlatDesc = "IterNextFlat"
GasValuePerByteDesc = "ValuePerByte"
GasWritePerByteDesc = "WritePerByte"
GasReadPerByteDesc = "ReadPerByte"
GasWriteCostFlatDesc = "WriteFlat"
GasReadCostFlatDesc = "ReadFlat"
GasHasDesc = "Has"
GasDeleteDesc = "Delete"
)
var (
cachedDefaultGasConfig = DefaultGasConfig()
cachedTransientGasConfig = TransientGasConfig()
)
// Gas measured by the SDK
type Gas = int64
// Error thrown when out of gas
// ErrorOutOfGas defines an error thrown when an action results in out of gas.
type ErrorOutOfGas struct {
Descriptor string
}
@ -19,6 +36,7 @@ type basicGasMeter struct {
consumed Gas
}
// NewGasMeter returns a reference to a new basicGasMeter.
func NewGasMeter(limit Gas) GasMeter {
return &basicGasMeter{
limit: limit,
@ -41,6 +59,7 @@ type infiniteGasMeter struct {
consumed Gas
}
// NewInfiniteGasMeter returns a reference to a new infiniteGasMeter.
func NewInfiniteGasMeter() GasMeter {
return &infiniteGasMeter{
consumed: 0,
@ -58,35 +77,30 @@ func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
// GasConfig defines gas cost for each operation on KVStores
type GasConfig struct {
HasCost Gas
DeleteCost Gas
ReadCostFlat Gas
ReadCostPerByte Gas
WriteCostFlat Gas
WriteCostPerByte Gas
KeyCostFlat Gas
ValueCostFlat Gas
ValueCostPerByte Gas
IterNextCostFlat Gas
}
var (
cachedDefaultGasConfig = DefaultGasConfig()
cachedTransientGasConfig = TransientGasConfig()
)
// Default gas config for KVStores
// DefaultGasConfig returns a default gas config for KVStores.
func DefaultGasConfig() GasConfig {
return GasConfig{
HasCost: 10,
DeleteCost: 10,
ReadCostFlat: 10,
ReadCostPerByte: 1,
WriteCostFlat: 10,
WriteCostPerByte: 10,
KeyCostFlat: 5,
ValueCostFlat: 10,
ValueCostPerByte: 1,
IterNextCostFlat: 15,
}
}
// Default gas config for TransientStores
// TransientGasConfig returns a default gas config for TransientStores.
func TransientGasConfig() GasConfig {
// TODO: define gasconfig for transient stores
return DefaultGasConfig()

View File

@ -25,7 +25,7 @@ const (
func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Command {
cmd := &cobra.Command{
Use: "sign <file>",
Short: "Sign transactions",
Short: "Sign transactions generated offline",
Long: `Sign transactions created with the --generate-only flag.
Read a transaction from <file>, sign it, and print its JSON encoding.`,
RunE: makeSignCmd(codec, decoder),

View File

@ -0,0 +1,23 @@
package context
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// StdSignMsg is a convenience structure for passing along
// a Msg with the other requirements for a StdSignDoc before
// it is signed. For use in the CLI.
type StdSignMsg struct {
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Fee auth.StdFee `json:"fee"`
Msgs []sdk.Msg `json:"msgs"`
Memo string `json:"memo"`
}
// get message bytes
func (msg StdSignMsg) Bytes() []byte {
return auth.StdSignBytes(msg.ChainID, msg.AccountNumber, msg.Sequence, msg.Fee, msg.Msgs, msg.Memo)
}

View File

@ -92,23 +92,23 @@ func (bldr TxBuilder) WithAccountNumber(accnum int64) TxBuilder {
// Build builds a single message to be signed from a TxBuilder given a set of
// messages. It returns an error if a fee is supplied but cannot be parsed.
func (bldr TxBuilder) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) {
func (bldr TxBuilder) Build(msgs []sdk.Msg) (StdSignMsg, error) {
chainID := bldr.ChainID
if chainID == "" {
return auth.StdSignMsg{}, errors.Errorf("chain ID required but not specified")
return StdSignMsg{}, errors.Errorf("chain ID required but not specified")
}
fee := sdk.Coin{}
if bldr.Fee != "" {
parsedFee, err := sdk.ParseCoin(bldr.Fee)
if err != nil {
return auth.StdSignMsg{}, err
return StdSignMsg{}, err
}
fee = parsedFee
}
return auth.StdSignMsg{
return StdSignMsg{
ChainID: bldr.ChainID,
AccountNumber: bldr.AccountNumber,
Sequence: bldr.Sequence,
@ -120,7 +120,7 @@ func (bldr TxBuilder) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) {
// Sign signs a transaction given a name, passphrase, and a single message to
// signed. An error is returned if signing fails.
func (bldr TxBuilder) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) {
func (bldr TxBuilder) Sign(name, passphrase string, msg StdSignMsg) ([]byte, error) {
sig, err := MakeSignature(name, passphrase, msg)
if err != nil {
return nil, err
@ -172,7 +172,7 @@ func (bldr TxBuilder) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, erro
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If append
// is false, it replaces the signatures already attached with the new signature.
func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx auth.StdTx, appendSig bool) (signedStdTx auth.StdTx, err error) {
stdSignature, err := MakeSignature(name, passphrase, auth.StdSignMsg{
stdSignature, err := MakeSignature(name, passphrase, StdSignMsg{
ChainID: bldr.ChainID,
AccountNumber: bldr.AccountNumber,
Sequence: bldr.Sequence,
@ -195,7 +195,7 @@ func (bldr TxBuilder) SignStdTx(name, passphrase string, stdTx auth.StdTx, appen
}
// MakeSignature builds a StdSignature given key name, passphrase, and a StdSignMsg.
func MakeSignature(name, passphrase string, msg auth.StdSignMsg) (sig auth.StdSignature, err error) {
func MakeSignature(name, passphrase string, msg StdSignMsg) (sig auth.StdSignature, err error) {
keybase, err := keys.GetKeyBase()
if err != nil {
return

View File

@ -0,0 +1,81 @@
package context
import (
"reflect"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/tendermint/tendermint/crypto/ed25519"
)
var (
priv = ed25519.GenPrivKey()
addr = sdk.AccAddress(priv.PubKey().Address())
)
func TestTxBuilderBuild(t *testing.T) {
type fields struct {
Codec *codec.Codec
AccountNumber int64
Sequence int64
Gas int64
GasAdjustment float64
SimulateGas bool
ChainID string
Memo string
Fee string
}
defaultMsg := []sdk.Msg{sdk.NewTestMsg(addr)}
tests := []struct {
fields fields
msgs []sdk.Msg
want StdSignMsg
wantErr bool
}{
{
fields{
Codec: codec.New(),
AccountNumber: 1,
Sequence: 1,
Gas: 100,
GasAdjustment: 1.1,
SimulateGas: false,
ChainID: "test-chain",
Memo: "hello",
Fee: "1steak",
},
defaultMsg,
StdSignMsg{
ChainID: "test-chain",
AccountNumber: 1,
Sequence: 1,
Memo: "hello",
Msgs: defaultMsg,
Fee: auth.NewStdFee(100, sdk.NewCoin("steak", sdk.NewInt(1))),
},
false,
},
}
for i, tc := range tests {
bldr := TxBuilder{
Codec: tc.fields.Codec,
AccountNumber: tc.fields.AccountNumber,
Sequence: tc.fields.Sequence,
Gas: tc.fields.Gas,
GasAdjustment: tc.fields.GasAdjustment,
SimulateGas: tc.fields.SimulateGas,
ChainID: tc.fields.ChainID,
Memo: tc.fields.Memo,
Fee: tc.fields.Fee,
}
got, err := bldr.Build(tc.msgs)
require.Equal(t, tc.wantErr, (err != nil), "TxBuilder.Build() error = %v, wantErr %v, tc %d", err, tc.wantErr, i)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("TxBuilder.Build() = %v, want %v", got, tc.want)
}
}
}

View File

@ -139,23 +139,6 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs
return sdk.MustSortJSON(bz)
}
// StdSignMsg is a convenience structure for passing along
// a Msg with the other requirements for a StdSignDoc before
// it is signed. For use in the CLI.
type StdSignMsg struct {
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Fee StdFee `json:"fee"`
Msgs []sdk.Msg `json:"msgs"`
Memo string `json:"memo"`
}
// get message bytes
func (msg StdSignMsg) Bytes() []byte {
return StdSignBytes(msg.ChainID, msg.AccountNumber, msg.Sequence, msg.Fee, msg.Msgs, msg.Memo)
}
// Standard Signature
type StdSignature struct {
crypto.PubKey `json:"pub_key"` // optional

View File

@ -4,15 +4,17 @@ import (
"fmt"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
)
sdk "github.com/cosmos/cosmos-sdk/types"
var (
priv = ed25519.GenPrivKey()
addr = sdk.AccAddress(priv.PubKey().Address())
)
func TestStdTx(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
fee := newStdFee()
sigs := []StdSignature{}
@ -26,17 +28,26 @@ func TestStdTx(t *testing.T) {
}
func TestStdSignBytes(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
msgs := []sdk.Msg{sdk.NewTestMsg(addr)}
fee := newStdFee()
signMsg := StdSignMsg{
"1234",
3,
6,
fee,
msgs,
"memo",
type args struct {
chainID string
accnum int64
sequence int64
fee StdFee
msgs []sdk.Msg
memo string
}
defaultFee := newStdFee()
tests := []struct {
args args
want string
}{
{
args{"1234", 3, 6, defaultFee, []sdk.Msg{sdk.NewTestMsg(addr)}, "memo"},
fmt.Sprintf("{\"account_number\":\"3\",\"chain_id\":\"1234\",\"fee\":{\"amount\":[{\"amount\":\"150\",\"denom\":\"atom\"}],\"gas\":\"5000\"},\"memo\":\"memo\",\"msgs\":[[\"%s\"]],\"sequence\":\"6\"}", addr),
},
}
for i, tc := range tests {
got := string(StdSignBytes(tc.args.chainID, tc.args.accnum, tc.args.sequence, tc.args.fee, tc.args.msgs, tc.args.memo))
require.Equal(t, tc.want, got, "Got unexpected result on test case i: %d", i)
}
require.Equal(t, fmt.Sprintf("{\"account_number\":\"3\",\"chain_id\":\"1234\",\"fee\":{\"amount\":[{\"amount\":\"150\",\"denom\":\"atom\"}],\"gas\":\"5000\"},\"memo\":\"memo\",\"msgs\":[[\"%s\"]],\"sequence\":\"6\"}", addr), string(signMsg.Bytes()))
}

View File

@ -29,9 +29,12 @@ in place of an input filename, the command reads from standard input.`,
if err != nil {
return
}
return cliCtx.EnsureBroadcastTx(txBytes)
_, err = cliCtx.BroadcastTx(txBytes)
return err
},
}
return cmd
}

View File

@ -67,12 +67,12 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command {
}
// build and sign the transaction, then broadcast to Tendermint
msg := client.BuildMsg(from, to, coins)
msg := client.CreateMsg(from, to, coins)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}

View File

@ -1,16 +1,13 @@
package rest
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/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/bank/client"
@ -23,17 +20,9 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec,
r.HandleFunc("/tx/broadcast", BroadcastTxRequestHandlerFn(cdc, cliCtx)).Methods("POST")
}
type sendBody struct {
// fees is not used currently
// Fees sdk.Coin `json="fees"`
Amount sdk.Coins `json:"amount"`
LocalAccountName string `json:"name"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
type sendReq struct {
BaseReq utils.BaseReq `json:"base_req"`
Amount sdk.Coins `json:"amount"`
}
var msgCdc = codec.New()
@ -42,100 +31,36 @@ func init() {
bank.RegisterCodec(msgCdc)
}
// SendRequestHandlerFn - http request handler to send coins to a address
// SendRequestHandlerFn - http request handler to send coins to a address.
func SendRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// collect data
vars := mux.Vars(r)
bech32addr := vars["address"]
bech32Addr := vars["address"]
to, err := sdk.AccAddressFromBech32(bech32addr)
to, err := sdk.AccAddressFromBech32(bech32Addr)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
var m sendBody
body, err := ioutil.ReadAll(r.Body)
var req sendReq
err = utils.ReadRESTReq(w, r, cdc, &req)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = msgCdc.UnmarshalJSON(body, &m)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
info, err := kb.Get(m.LocalAccountName)
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
info, err := kb.Get(baseReq.Name)
if err != nil {
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())
return
}
simulateGas, gas, err := cliclient.ReadGasFlag(m.Gas)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, cliclient.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.TxBuilder{
Codec: cdc,
Gas: gas,
GasAdjustment: adjustment,
SimulateGas: simulateGas,
ChainID: m.ChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
}
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, newBldr.Gas)
return
}
txBldr = newBldr
}
if utils.HasGenerateOnlyArg(r) {
utils.WriteGenerateStdTxResponse(w, txBldr, []sdk.Msg{msg})
return
}
txBytes, err := txBldr.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := codec.MarshalJSONIndent(cdc, res)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
msg := client.CreateMsg(sdk.AccAddress(info.GetPubKey().Address()), to, req.Amount)
utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc)
}
}

View File

@ -5,8 +5,8 @@ import (
bank "github.com/cosmos/cosmos-sdk/x/bank"
)
// build the sendTx msg
func BuildMsg(from sdk.AccAddress, to sdk.AccAddress, coins sdk.Coins) sdk.Msg {
// create the sendTx msg
func CreateMsg(from sdk.AccAddress, to sdk.AccAddress, coins sdk.Coins) sdk.Msg {
input := bank.NewInput(from, coins)
output := bank.NewOutput(to, coins)
msg := bank.NewMsgSend([]bank.Input{input}, []bank.Output{output})

View File

@ -111,7 +111,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
// Build and sign the transaction, then broadcast to Tendermint
// proposalID must be returned, and it is a part of response.
cliCtx.PrintResponse = true
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -159,7 +159,7 @@ func parseSubmitProposalFlags() (*proposal, error) {
func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "deposit",
Short: "deposit tokens for activing proposal",
Short: "Deposit tokens for activing proposal",
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
@ -191,7 +191,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -205,7 +205,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
func GetCmdVote(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "vote",
Short: "vote for an active proposal, options: Yes/No/NoWithVeto/Abstain",
Short: "Vote for an active proposal, options: Yes/No/NoWithVeto/Abstain",
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
@ -242,7 +242,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command {
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -255,8 +255,8 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command {
// GetCmdQueryProposal implements the query proposal command.
func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-proposal",
Short: "query proposal details",
Use: "proposal",
Short: "Query details of a single proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
@ -288,8 +288,8 @@ func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command {
// GetCmdQueryProposals implements a query proposals command.
func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-proposals",
Short: "query proposals with optional filters",
Use: "proposals",
Short: "Query proposals with optional filters",
RunE: func(cmd *cobra.Command, args []string) error {
bechDepositerAddr := viper.GetString(flagDepositer)
bechVoterAddr := viper.GetString(flagVoter)
@ -367,8 +367,8 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
// GetCmdQueryVote implements the query proposal vote command.
func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-vote",
Short: "query vote",
Use: "vote",
Short: "Query details of a single vote",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
@ -406,8 +406,8 @@ func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
// GetCmdQueryVotes implements the command to query for proposal votes.
func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-votes",
Short: "query votes on a proposal",
Use: "votes",
Short: "Query votes on a proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
@ -439,8 +439,8 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
// GetCmdQueryDeposit implements the query proposal deposit command.
func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-deposit",
Short: "query deposit",
Use: "deposit",
Short: "Query details of a deposit",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
@ -478,8 +478,8 @@ func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
// GetCmdQueryDeposits implements the command to query for proposal deposits.
func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-deposits",
Short: "query deposits on a proposal",
Use: "deposits",
Short: "Query deposits on a proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
@ -510,8 +510,8 @@ func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command {
// GetCmdQueryDeposits implements the command to query for proposal deposits.
func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-tally",
Short: "get the tally of a proposal vote",
Use: "tally",
Short: "Get the tally of a proposal vote",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)

View File

@ -41,7 +41,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec)
}
type postProposalReq struct {
BaseReq baseReq `json:"base_req"`
BaseReq utils.BaseReq `json:"base_req"`
Title string `json:"title"` // Title of the proposal
Description string `json:"description"` // Description of the proposal
ProposalType gov.ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
@ -50,13 +50,13 @@ type postProposalReq struct {
}
type depositReq struct {
BaseReq baseReq `json:"base_req"`
BaseReq utils.BaseReq `json:"base_req"`
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit
}
type voteReq struct {
BaseReq baseReq `json:"base_req"`
BaseReq utils.BaseReq `json:"base_req"`
Voter sdk.AccAddress `json:"voter"` // address of the voter
Option gov.VoteOption `json:"option"` // option from OptionSet chosen by the voter
}
@ -64,12 +64,13 @@ type voteReq struct {
func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req postProposalReq
err := buildReq(w, r, cdc, &req)
err := utils.ReadRESTReq(w, r, cdc, &req)
if err != nil {
return
}
if !req.BaseReq.baseReqValidate(w) {
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
@ -81,7 +82,7 @@ func postProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han
return
}
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc)
}
}
@ -96,17 +97,19 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
var req depositReq
err := buildReq(w, r, cdc, &req)
err := utils.ReadRESTReq(w, r, cdc, &req)
if err != nil {
return
}
if !req.BaseReq.baseReqValidate(w) {
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
@ -118,7 +121,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
return
}
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc)
}
}
@ -133,17 +136,19 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
var req voteReq
err := buildReq(w, r, cdc, &req)
err := utils.ReadRESTReq(w, r, cdc, &req)
if err != nil {
return
}
if !req.BaseReq.baseReqValidate(w) {
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
@ -155,7 +160,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
return
}
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc)
}
}
@ -170,7 +175,7 @@ func queryProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -209,7 +214,7 @@ func queryDepositHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -276,7 +281,7 @@ func queryVoteHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -346,7 +351,7 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}
@ -412,7 +417,7 @@ func queryProposalsWithParameterFn(cdc *codec.Codec) http.HandlerFunc {
params.ProposalStatus = proposalStatus
}
if len(strNumLatest) != 0 {
numLatest, ok := parseInt64OrReturnBadRequest(strNumLatest, w)
numLatest, ok := utils.ParseInt64OrReturnBadRequest(w, strNumLatest)
if !ok {
return
}
@ -451,7 +456,7 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec) http.HandlerFunc {
return
}
proposalID, ok := parseInt64OrReturnBadRequest(strProposalID, w)
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID)
if !ok {
return
}

View File

@ -1,141 +0,0 @@
package rest
import (
"fmt"
"io/ioutil"
"net/http"
"strconv"
"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/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
type baseReq struct {
Name string `json:"name"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
}
func buildReq(w http.ResponseWriter, r *http.Request, cdc *codec.Codec, req interface{}) error {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
}
err = cdc.UnmarshalJSON(body, req)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
}
return nil
}
func (req baseReq) baseReqValidate(w http.ResponseWriter) bool {
if len(req.Name) == 0 {
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")
return false
}
if len(req.ChainID) == 0 {
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")
return false
}
if req.Sequence < 0 {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Sequence required but not specified")
return false
}
return true
}
// TODO: Build this function out into a more generic base-request
// (probably should live in client/lcd).
func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *codec.Codec) {
simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.TxBuilder{
Codec: cdc,
Gas: gas,
GasAdjustment: adjustment,
SimulateGas: simulateGas,
ChainID: baseReq.ChainID,
AccountNumber: baseReq.AccountNumber,
Sequence: baseReq.Sequence,
}
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, newBldr.Gas)
return
}
txBldr = newBldr
}
if utils.HasGenerateOnlyArg(r) {
utils.WriteGenerateStdTxResponse(w, txBldr, []sdk.Msg{msg})
return
}
txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := codec.MarshalJSONIndent(cdc, res)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
}
func parseInt64OrReturnBadRequest(s string, w http.ResponseWriter) (n int64, ok bool) {
var err error
n, err = strconv.ParseInt(s, 10, 64)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
err := fmt.Errorf("'%s' is not a valid int64", s)
w.Write([]byte(err.Error()))
return 0, false
}
return n, true
}

View File

@ -47,7 +47,7 @@ func IBCTransferCmd(cdc *codec.Codec) *cobra.Command {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}

View File

@ -1,16 +1,13 @@
package rest
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/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/gorilla/mux"
@ -21,110 +18,48 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec,
r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST")
}
type transferBody struct {
// Fees sdk.Coin `json="fees"`
Amount sdk.Coins `json:"amount"`
LocalAccountName string `json:"name"`
Password string `json:"password"`
SrcChainID string `json:"src_chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
type transferReq struct {
BaseReq utils.BaseReq `json:"base_req"`
Amount sdk.Coins `json:"amount"`
}
// TransferRequestHandler - http request handler to transfer coins to a address
// on a different chain via IBC
// on a different chain via IBC.
func TransferRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
destChainID := vars["destchain"]
bech32addr := vars["address"]
bech32Addr := vars["address"]
to, err := sdk.AccAddressFromBech32(bech32addr)
to, err := sdk.AccAddressFromBech32(bech32Addr)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
var m transferBody
body, err := ioutil.ReadAll(r.Body)
var req transferReq
err = utils.ReadRESTReq(w, r, cdc, &req)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = cdc.UnmarshalJSON(body, &m)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
info, err := kb.Get(m.LocalAccountName)
info, err := kb.Get(baseReq.Name)
if err != nil {
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
// build message
packet := ibc.NewIBCPacket(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount, m.SrcChainID, destChainID)
msg := ibc.IBCTransferMsg{packet}
packet := ibc.NewIBCPacket(
sdk.AccAddress(info.GetPubKey().Address()), to,
req.Amount, baseReq.ChainID, destChainID,
)
msg := ibc.IBCTransferMsg{IBCPacket: packet}
simulateGas, gas, err := client.ReadGasFlag(m.Gas)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.TxBuilder{
Codec: cdc,
Gas: gas,
GasAdjustment: adjustment,
SimulateGas: simulateGas,
ChainID: m.SrcChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
}
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txBldr.Gas)
return
}
txBldr = newCtx
}
if utils.HasGenerateOnlyArg(r) {
utils.WriteGenerateStdTxResponse(w, txBldr, []sdk.Msg{msg})
return
}
txBytes, err := txBldr.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := cdc.MarshalJSON(res)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc)
}
}

View File

@ -36,7 +36,7 @@ func GetCmdUnjail(cdc *codec.Codec) *cobra.Command {
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}

View File

@ -2,18 +2,14 @@ package rest
import (
"bytes"
"encoding/json"
"fmt"
"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/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/gorilla/mux"
@ -27,98 +23,45 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec
}
// Unjail TX body
type UnjailBody struct {
LocalAccountName string `json:"name"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
ValidatorAddr string `json:"validator_addr"`
type UnjailReq struct {
BaseReq utils.BaseReq `json:"base_req"`
ValidatorAddr string `json:"validator_addr"`
}
func unjailRequestHandlerFn(cdc *codec.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)
var req UnjailReq
err := utils.ReadRESTReq(w, r, cdc, &req)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = json.Unmarshal(body, &m)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
info, err := kb.Get(m.LocalAccountName)
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
info, err := kb.Get(baseReq.Name)
if err != nil {
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
valAddr, err := sdk.ValAddressFromBech32(m.ValidatorAddr)
valAddr, err := sdk.ValAddressFromBech32(req.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("failed to 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
}
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.TxBuilder{
Codec: cdc,
ChainID: m.ChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
Gas: m.Gas,
GasAdjustment: adjustment,
}
msg := slashing.NewMsgUnjail(valAddr)
if utils.HasDryRunArg(r) || m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txBldr.Gas)
return
}
txBldr = newCtx
}
if utils.HasGenerateOnlyArg(r) {
utils.WriteGenerateStdTxResponse(w, txBldr, []sdk.Msg{msg})
return
}
txBytes, err := txBldr.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
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())
return
}
output, err := json.MarshalIndent(res, "", " ")
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
w.Write(output)
utils.CompleteAndBroadcastTxREST(w, r, cliCtx, baseReq, []sdk.Msg{msg}, cdc)
}
}

View File

@ -94,7 +94,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -150,7 +150,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -193,7 +193,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -265,7 +265,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -308,7 +308,7 @@ func GetCmdCompleteRedelegate(cdc *codec.Codec) *cobra.Command {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -372,7 +372,7 @@ func GetCmdBeginUnbonding(storeName string, cdc *codec.Codec) *cobra.Command {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}
@ -410,7 +410,7 @@ func GetCmdCompleteUnbonding(cdc *codec.Codec) *cobra.Command {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
}
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txBldr, cliCtx, []sdk.Msg{msg})
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},
}

View File

@ -27,53 +27,55 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *codec.Codec
).Methods("POST")
}
type msgDelegationsInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
Delegation sdk.Coin `json:"delegation"`
}
type msgBeginRedelegateInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorSrcAddr string `json:"validator_src_addr"` // in bech32
ValidatorDstAddr string `json:"validator_dst_addr"` // in bech32
SharesAmount string `json:"shares"`
}
type msgCompleteRedelegateInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorSrcAddr string `json:"validator_src_addr"` // in bech32
ValidatorDstAddr string `json:"validator_dst_addr"` // in bech32
}
type msgBeginUnbondingInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
SharesAmount string `json:"shares"`
}
type msgCompleteUnbondingInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
}
type (
msgDelegationsInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
Delegation sdk.Coin `json:"delegation"`
}
// the request body for edit delegations
type EditDelegationsBody struct {
LocalAccountName string `json:"name"`
Password string `json:"password"`
ChainID string `json:"chain_id"`
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas string `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
Delegations []msgDelegationsInput `json:"delegations"`
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
CompleteUnbondings []msgCompleteUnbondingInput `json:"complete_unbondings"`
BeginRedelegates []msgBeginRedelegateInput `json:"begin_redelegates"`
CompleteRedelegates []msgCompleteRedelegateInput `json:"complete_redelegates"`
}
msgBeginRedelegateInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorSrcAddr string `json:"validator_src_addr"` // in bech32
ValidatorDstAddr string `json:"validator_dst_addr"` // in bech32
SharesAmount string `json:"shares"`
}
msgCompleteRedelegateInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorSrcAddr string `json:"validator_src_addr"` // in bech32
ValidatorDstAddr string `json:"validator_dst_addr"` // in bech32
}
msgBeginUnbondingInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
SharesAmount string `json:"shares"`
}
msgCompleteUnbondingInput struct {
DelegatorAddr string `json:"delegator_addr"` // in bech32
ValidatorAddr string `json:"validator_addr"` // in bech32
}
// the request body for edit delegations
EditDelegationsReq struct {
BaseReq utils.BaseReq `json:"base_req"`
Delegations []msgDelegationsInput `json:"delegations"`
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
CompleteUnbondings []msgCompleteUnbondingInput `json:"complete_unbondings"`
BeginRedelegates []msgBeginRedelegateInput `json:"begin_redelegates"`
CompleteRedelegates []msgCompleteRedelegateInput `json:"complete_redelegates"`
}
)
// TODO: Split this up into several smaller functions, and remove the above nolint
// TODO: use sdk.ValAddress instead of sdk.AccAddress for validators in messages
// TODO: Seriously consider how to refactor...do we need to make it multiple txs?
// If not, we can just use CompleteAndBroadcastTxREST.
func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m EditDelegationsBody
var req EditDelegationsReq
body, err := ioutil.ReadAll(r.Body)
if err != nil {
@ -82,14 +84,19 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
return
}
err = cdc.UnmarshalJSON(body, &m)
err = cdc.UnmarshalJSON(body, &req)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
info, err := kb.Get(m.LocalAccountName)
baseReq := req.BaseReq.Sanitize()
if !baseReq.ValidateBasic(w) {
return
}
info, err := kb.Get(baseReq.Name)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
@ -97,14 +104,14 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
}
// build messages
messages := make([]sdk.Msg, len(m.Delegations)+
len(m.BeginRedelegates)+
len(m.CompleteRedelegates)+
len(m.BeginUnbondings)+
len(m.CompleteUnbondings))
messages := make([]sdk.Msg, len(req.Delegations)+
len(req.BeginRedelegates)+
len(req.CompleteRedelegates)+
len(req.BeginUnbondings)+
len(req.CompleteUnbondings))
i := 0
for _, msg := range m.Delegations {
for _, msg := range req.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()))
@ -131,7 +138,7 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
i++
}
for _, msg := range m.BeginRedelegates {
for _, msg := range req.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()))
@ -170,7 +177,7 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
i++
}
for _, msg := range m.CompleteRedelegates {
for _, msg := range req.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()))
@ -203,7 +210,7 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
i++
}
for _, msg := range m.BeginUnbondings {
for _, msg := range req.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()))
@ -236,7 +243,7 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
i++
}
for _, msg := range m.CompleteUnbondings {
for _, msg := range req.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()))
@ -262,41 +269,46 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
i++
}
simulateGas, gas, err := client.ReadGasFlag(m.Gas)
simulateGas, gas, err := client.ReadGasFlag(baseReq.Gas)
if err != nil {
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
txBldr := authtxb.TxBuilder{
Codec: cdc,
Gas: gas,
GasAdjustment: adjustment,
SimulateGas: simulateGas,
ChainID: m.ChainID,
ChainID: baseReq.ChainID,
}
// sign messages
signedTxs := make([][]byte, len(messages[:]))
for i, msg := range messages {
// increment sequence for each message
txBldr = txBldr.WithAccountNumber(m.AccountNumber)
txBldr = txBldr.WithSequence(m.Sequence)
m.Sequence++
txBldr = txBldr.WithAccountNumber(baseReq.AccountNumber)
txBldr = txBldr.WithSequence(baseReq.Sequence)
baseReq.Sequence++
if utils.HasDryRunArg(r) || txBldr.SimulateGas {
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
newBldr, err := utils.EnrichCtxWithGas(txBldr, cliCtx, baseReq.Name, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, newBldr.Gas)
return
}
txBldr = newBldr
}
@ -305,7 +317,7 @@ func delegationsRequestHandlerFn(cdc *codec.Codec, kb keys.Keybase, cliCtx conte
return
}
txBytes, err := txBldr.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
txBytes, err := txBldr.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return

View File

@ -172,7 +172,7 @@ func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation ty
}
// Calculate slash amount proportional to stake contributing to infraction
slashAmount = sdk.NewDecFromInt(unbondingDelegation.InitialBalance.Amount).Mul(slashFactor)
slashAmount = slashFactor.MulInt(unbondingDelegation.InitialBalance.Amount)
// Don't slash more tokens than held
// Possible since the unbonding delegation may already
@ -218,7 +218,7 @@ func (k Keeper) slashRedelegation(ctx sdk.Context, validator types.Validator, re
}
// Calculate slash amount proportional to stake contributing to infraction
slashAmount = sdk.NewDecFromInt(redelegation.InitialBalance.Amount).Mul(slashFactor)
slashAmount = slashFactor.MulInt(redelegation.InitialBalance.Amount)
// Don't slash more tokens than held
// Possible since the redelegation may already