...
This commit is contained in:
commit
0436f50c00
6
Makefile
6
Makefile
|
@ -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
|
||||
|
|
11
PENDING.md
11
PENDING.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
38
types/gas.go
38
types/gas.go
|
@ -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()
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue