Merge PR #1741: CoreContext Refactor

This commit is contained in:
Alexander Bezobchuk 2018-08-06 14:11:30 -04:00 committed by Christopher Goes
parent 3c4985c315
commit 12c2c236c2
48 changed files with 1522 additions and 1196 deletions

31
Gopkg.lock generated
View File

@ -38,7 +38,7 @@
name = "github.com/btcsuite/btcd"
packages = ["btcec"]
pruneopts = "UT"
revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898"
revision = "9a2f9524024889e129a5422aca2cff73cb3eabf6"
[[projects]]
digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2"
@ -165,12 +165,13 @@
[[projects]]
branch = "master"
digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
digest = "1:a361611b8c8c75a1091f00027767f7779b29cb37c456a71b8f2604c88057ab40"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
@ -231,11 +232,11 @@
[[projects]]
branch = "master"
digest = "1:e730597b38a4d56e2361e0b6236cb800e52c73cace2ff91396f4ff35792ddfa7"
digest = "1:5ab79470a1d0fb19b041a624415612f8236b3c06070161a910562f2b2d064355"
name = "github.com/mitchellh/mapstructure"
packages = ["."]
pruneopts = "UT"
revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac"
[[projects]]
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
@ -273,15 +274,15 @@
[[projects]]
branch = "master"
digest = "1:32d10bdfa8f09ecf13598324dba86ab891f11db3c538b6a34d1c3b5b99d7c36b"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c"
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
[[projects]]
branch = "master"
digest = "1:e469cd65badf7694aeb44874518606d93c1d59e7735d3754ad442782437d3cc3"
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
name = "github.com/prometheus/common"
packages = [
"expfmt",
@ -289,11 +290,11 @@
"model",
]
pruneopts = "UT"
revision = "7600349dcfe1abd18d72d3a1770870d9800a7801"
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
[[projects]]
branch = "master"
digest = "1:20d9bb50dbee172242f9bcd6ec24a917dd7a5bb17421bf16a79c33111dea7db1"
digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
name = "github.com/prometheus/procfs"
packages = [
".",
@ -302,7 +303,7 @@
"xfs",
]
pruneopts = "UT"
revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a"
revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
[[projects]]
digest = "1:c4556a44e350b50a490544d9b06e9fba9c286c21d6c0e47f54f3a9214597298c"
@ -514,7 +515,7 @@
"salsa20/salsa",
]
pruneopts = "UT"
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
revision = "c126467f60eb25f8f27e5a981f32a87e3965053f"
[[projects]]
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
@ -534,11 +535,11 @@
[[projects]]
branch = "master"
digest = "1:d773e525476aefa22ea944a5425a9bfb99819b2e67eeb9b1966454fd57522bbf"
digest = "1:8466957fb2af510f68b13aec64ccad13e9e756dc1da3ea28c422f8ac410e56f0"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
revision = "1b2967e3c290b7c545b3db0deeda16e9be4f98a2"
revision = "bd9dbc187b6e1dacfdd2722a87e83093c2d7bd6e"
[[projects]]
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
@ -565,11 +566,11 @@
[[projects]]
branch = "master"
digest = "1:601e63e7d4577f907118bec825902505291918859d223bce015539e79f1160e3"
digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "e92b116572682a5b432ddd840aeaba2a559eeff1"
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
[[projects]]
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"

View File

@ -27,6 +27,7 @@ BREAKING CHANGES
* [x/gov] Governance parameters are now stored in globalparams store
* [lcd] \#1866 Updated lcd /slashing/signing_info endpoint to take cosmosvalpub instead of cosmosvaladdr
* [types] sdk.NewCoin now takes sdk.Int, sdk.NewInt64Coin takes int64
* [cli] #1551: Officially removed `--name` from CLI commands
* [cli] Genesis/key creation (`init`) now supports user-provided key passwords
FEATURES
@ -69,3 +70,14 @@ BUG FIXES
* \#1828 Force user to specify amount on create-validator command by removing default
* \#1839 Fixed bug where intra-tx counter wasn't set correctly for genesis validators
* [tests] \#1675 Fix non-deterministic `test_cover`
* [client] \#1551: Refactored `CoreContext`
* Renamed `CoreContext` to `QueryContext`
* Removed all tx related fields and logic (building & signing) to separate
structure `TxContext` in `x/auth/client/context`
* Cleaned up documentation and API of what used to be `CoreContext`
* Implemented `KeyType` enum for key info
BUG FIXES
* \#1666 Add intra-tx counter to the genesis validators
* [tests] \#1551: Fixed invalid LCD test JSON payload in `doIBCTransfer`
* \#1787 Fixed bug where Tally fails due to revoked/unbonding validator

115
client/context/context.go Normal file
View File

@ -0,0 +1,115 @@
package context
import (
"io"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/spf13/viper"
rpcclient "github.com/tendermint/tendermint/rpc/client"
)
const ctxAccStoreName = "acc"
// CLIContext implements a typical CLI context created in SDK modules for
// transaction handling and queries.
type CLIContext struct {
Codec *wire.Codec
AccDecoder auth.AccountDecoder
Client rpcclient.Client
Logger io.Writer
Height int64
NodeURI string
FromAddressName string
AccountStore string
TrustNode bool
UseLedger bool
Async bool
JSON bool
PrintResponse bool
}
// NewCLIContext returns a new initialized CLIContext with parameters from the
// command line using Viper.
func NewCLIContext() CLIContext {
var rpc rpcclient.Client
nodeURI := viper.GetString(client.FlagNode)
if nodeURI != "" {
rpc = rpcclient.NewHTTP(nodeURI, "/websocket")
}
return CLIContext{
Client: rpc,
NodeURI: nodeURI,
AccountStore: ctxAccStoreName,
FromAddressName: viper.GetString(client.FlagFrom),
Height: viper.GetInt64(client.FlagHeight),
TrustNode: viper.GetBool(client.FlagTrustNode),
UseLedger: viper.GetBool(client.FlagUseLedger),
Async: viper.GetBool(client.FlagAsync),
JSON: viper.GetBool(client.FlagJson),
PrintResponse: viper.GetBool(client.FlagPrintResponse),
}
}
// WithCodec returns a copy of the context with an updated codec.
func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext {
ctx.Codec = cdc
return ctx
}
// WithAccountDecoder returns a copy of the context with an updated account
// decoder.
func (ctx CLIContext) WithAccountDecoder(decoder auth.AccountDecoder) CLIContext {
ctx.AccDecoder = decoder
return ctx
}
// WithLogger returns a copy of the context with an updated logger.
func (ctx CLIContext) WithLogger(w io.Writer) CLIContext {
ctx.Logger = w
return ctx
}
// WithAccountStore returns a copy of the context with an updated AccountStore.
func (ctx CLIContext) WithAccountStore(accountStore string) CLIContext {
ctx.AccountStore = accountStore
return ctx
}
// WithFromAddressName returns a copy of the context with an updated from
// address.
func (ctx CLIContext) WithFromAddressName(addrName string) CLIContext {
ctx.FromAddressName = addrName
return ctx
}
// WithTrustNode returns a copy of the context with an updated TrustNode flag.
func (ctx CLIContext) WithTrustNode(trustNode bool) CLIContext {
ctx.TrustNode = trustNode
return ctx
}
// WithNodeURI returns a copy of the context with an updated node URI.
func (ctx CLIContext) WithNodeURI(nodeURI string) CLIContext {
ctx.NodeURI = nodeURI
ctx.Client = rpcclient.NewHTTP(nodeURI, "/websocket")
return ctx
}
// WithClient returns a copy of the context with an updated RPC client
// instance.
func (ctx CLIContext) WithClient(client rpcclient.Client) CLIContext {
ctx.Client = client
return ctx
}
// WithUseLedger returns a copy of the context with an updated UseLedger flag.
func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext {
ctx.UseLedger = useLedger
return ctx
}

13
client/context/errors.go Normal file
View File

@ -0,0 +1,13 @@
package context
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/pkg/errors"
)
// ErrInvalidAccount returns a standardized error reflecting that a given
// account address does not exist.
func ErrInvalidAccount(addr sdk.AccAddress) error {
return errors.Errorf(`No account with address %s was found in the state.
Are you sure there has been a transaction involving it?`, addr)
}

View File

@ -1,347 +0,0 @@
package context
import (
"fmt"
"github.com/tendermint/tendermint/libs/common"
"github.com/pkg/errors"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
cmn "github.com/tendermint/tendermint/libs/common"
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Broadcast the transaction bytes to Tendermint
func (ctx CoreContext) 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.Code != uint32(0) {
return res, errors.Errorf("checkTx failed: (%d) %s",
res.CheckTx.Code,
res.CheckTx.Log)
}
if res.DeliverTx.Code != uint32(0) {
return res, errors.Errorf("deliverTx failed: (%d) %s",
res.DeliverTx.Code,
res.DeliverTx.Log)
}
return res, err
}
// Broadcast the transaction bytes to Tendermint
func (ctx CoreContext) 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
}
// Query information about the connected node
func (ctx CoreContext) Query(path string) (res []byte, err error) {
return ctx.query(path, nil)
}
// QueryStore from Tendermint with the provided key and storename
func (ctx CoreContext) QueryStore(key cmn.HexBytes, storeName string) (res []byte, err error) {
return ctx.queryStore(key, storeName, "key")
}
// Query from Tendermint with the provided storename and subspace
func (ctx CoreContext) QuerySubspace(cdc *wire.Codec, subspace []byte, storeName string) (res []sdk.KVPair, err error) {
resRaw, err := ctx.queryStore(subspace, storeName, "subspace")
if err != nil {
return res, err
}
cdc.MustUnmarshalBinary(resRaw, &res)
return
}
// Query from Tendermint with the provided storename and path
func (ctx CoreContext) query(path string, key common.HexBytes) (res []byte, err error) {
node, err := ctx.GetNode()
if err != nil {
return res, err
}
opts := rpcclient.ABCIQueryOptions{
Height: ctx.Height,
Trusted: ctx.TrustNode,
}
result, err := node.ABCIQueryWithOptions(path, key, opts)
if err != nil {
return res, err
}
resp := result.Response
if resp.Code != uint32(0) {
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
}
return resp.Value, nil
}
// Query from Tendermint with the provided storename and path
func (ctx CoreContext) queryStore(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) {
path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
return ctx.query(path, key)
}
// Get the from address from the name flag
func (ctx CoreContext) GetFromAddress() (from sdk.AccAddress, err error) {
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
name := ctx.FromAddressName
if name == "" {
return nil, errors.Errorf("must provide a from address name")
}
info, err := keybase.Get(name)
if err != nil {
return nil, errors.Errorf("no key for: %s", name)
}
return sdk.AccAddress(info.GetPubKey().Address()), nil
}
// sign and build the transaction from the msg
func (ctx CoreContext) SignAndBuild(name, passphrase string, msgs []sdk.Msg, cdc *wire.Codec) ([]byte, error) {
// build the Sign Messsage from the Standard Message
chainID := ctx.ChainID
if chainID == "" {
return nil, errors.Errorf("chain ID required but not specified")
}
accnum := ctx.AccountNumber
sequence := ctx.Sequence
memo := ctx.Memo
fee := sdk.Coin{}
if ctx.Fee != "" {
parsedFee, err := sdk.ParseCoin(ctx.Fee)
if err != nil {
return nil, err
}
fee = parsedFee
}
signMsg := auth.StdSignMsg{
ChainID: chainID,
AccountNumber: accnum,
Sequence: sequence,
Msgs: msgs,
Memo: memo,
Fee: auth.NewStdFee(ctx.Gas, fee), // TODO run simulate to estimate gas?
}
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
// sign and build
bz := signMsg.Bytes()
sig, pubkey, err := keybase.Sign(name, passphrase, bz)
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
PubKey: pubkey,
Signature: sig,
AccountNumber: accnum,
Sequence: sequence,
}}
// marshal bytes
tx := auth.NewStdTx(signMsg.Msgs, signMsg.Fee, sigs, memo)
return cdc.MarshalBinary(tx)
}
// sign and build the transaction from the msg
func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Codec) (tyBytes []byte, err error) {
err = EnsureAccountExists(ctx, name)
if err != nil {
return nil, err
}
ctx, err = EnsureAccountNumber(ctx)
if err != nil {
return nil, err
}
// default to next sequence number if none provided
ctx, err = EnsureSequence(ctx)
if err != nil {
return nil, err
}
var txBytes []byte
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
info, err := keybase.Get(name)
if err != nil {
return nil, err
}
var passphrase string
// Only need a passphrase for locally-stored keys
if info.GetType() == "local" {
passphrase, err = ctx.GetPassphraseFromStdin(name)
if err != nil {
return nil, fmt.Errorf("Error fetching passphrase: %v", err)
}
}
txBytes, err = ctx.SignAndBuild(name, passphrase, msgs, cdc)
if err != nil {
return nil, fmt.Errorf("Error signing transaction: %v", err)
}
return txBytes, err
}
// sign and build the transaction from the msg
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (err error) {
txBytes, err := ctx.ensureSignBuild(name, msgs, cdc)
if err != nil {
return err
}
if ctx.Async {
res, err := ctx.BroadcastTxAsync(txBytes)
if err != nil {
return err
}
if ctx.JSON {
type toJSON struct {
TxHash string
}
valueToJSON := toJSON{res.Hash.String()}
JSON, err := cdc.MarshalJSON(valueToJSON)
if err != nil {
return err
}
fmt.Println(string(JSON))
} else {
fmt.Println("Async tx sent. tx hash: ", res.Hash.String())
}
return nil
}
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 string
}
valueToJSON := toJSON{res.Height, res.Hash.String(), fmt.Sprintf("%+v", res.DeliverTx)}
JSON, err := cdc.MarshalJSON(valueToJSON)
if err != nil {
return err
}
fmt.Println(string(JSON))
return nil
}
if ctx.PrintResponse {
fmt.Printf("Committed at block %d. Hash: %s Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx)
} else {
fmt.Printf("Committed at block %d. Hash: %s \n", res.Height, res.Hash.String())
}
return nil
}
// get the next sequence for the account address
func (ctx CoreContext) GetAccountNumber(address []byte) (int64, error) {
if ctx.Decoder == nil {
return 0, errors.New("accountDecoder required but not provided")
}
res, err := ctx.QueryStore(auth.AddressStoreKey(address), ctx.AccountStore)
if err != nil {
return 0, err
}
if len(res) == 0 {
fmt.Printf("No account found. Returning 0.\n")
return 0, err
}
account, err := ctx.Decoder(res)
if err != nil {
panic(err)
}
return account.GetAccountNumber(), nil
}
// get the next sequence for the account address
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
if ctx.Decoder == nil {
return 0, errors.New("accountDecoder required but not provided")
}
res, err := ctx.QueryStore(auth.AddressStoreKey(address), ctx.AccountStore)
if err != nil {
return 0, err
}
if len(res) == 0 {
fmt.Printf("No account found, defaulting to sequence 0\n")
return 0, err
}
account, err := ctx.Decoder(res)
if err != nil {
panic(err)
}
return account.GetSequence(), nil
}
// get passphrase from std input
func (ctx CoreContext) GetPassphraseFromStdin(name string) (pass string, err error) {
buf := client.BufferStdin()
prompt := fmt.Sprintf("Password to sign with '%s':", name)
return client.GetPassword(prompt, buf)
}
// GetNode prepares a simple rpc.Client
func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
if ctx.Client == nil {
return nil, errors.New("must define node URI")
}
return ctx.Client, nil
}

311
client/context/query.go Normal file
View File

@ -0,0 +1,311 @@
package context
import (
"fmt"
"io"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/pkg/errors"
"github.com/tendermint/tendermint/libs/common"
cmn "github.com/tendermint/tendermint/libs/common"
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
// error is returned.
func (ctx CLIContext) GetNode() (rpcclient.Client, error) {
if ctx.Client == nil {
return nil, errors.New("no RPC client defined")
}
return ctx.Client, nil
}
// Query performs a query for information about the connected node.
func (ctx CLIContext) Query(path string) (res []byte, err error) {
return ctx.query(path, nil)
}
// QueryStore performs a query from a Tendermint node with the provided key and
// store name.
func (ctx CLIContext) QueryStore(key cmn.HexBytes, storeName string) (res []byte, err error) {
return ctx.queryStore(key, storeName, "key")
}
// QuerySubspace performs a query from a Tendermint node with the provided
// store name and subspace.
func (ctx CLIContext) QuerySubspace(subspace []byte, storeName string) (res []sdk.KVPair, err error) {
resRaw, err := ctx.queryStore(subspace, storeName, "subspace")
if err != nil {
return res, err
}
ctx.Codec.MustUnmarshalBinary(resRaw, &res)
return
}
// GetAccount queries for an account given an address and a block height. An
// error is returned if the query or decoding fails.
func (ctx CLIContext) GetAccount(address []byte) (auth.Account, error) {
if ctx.AccDecoder == nil {
return nil, errors.New("account decoder required but not provided")
}
res, err := ctx.QueryStore(auth.AddressStoreKey(address), ctx.AccountStore)
if err != nil {
return nil, err
} else if len(res) == 0 {
return nil, err
}
account, err := ctx.AccDecoder(res)
if err != nil {
return nil, err
}
return account, nil
}
// GetFromAddress returns the from address from the context's name.
func (ctx CLIContext) GetFromAddress() (from sdk.AccAddress, err error) {
if ctx.FromAddressName == "" {
return nil, errors.Errorf("must provide a from address name")
}
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
info, err := keybase.Get(ctx.FromAddressName)
if err != nil {
return nil, errors.Errorf("no key for: %s", ctx.FromAddressName)
}
return sdk.AccAddress(info.GetPubKey().Address()), nil
}
// GetAccountNumber returns the next account number for the given account
// address.
func (ctx CLIContext) GetAccountNumber(address []byte) (int64, error) {
account, err := ctx.GetAccount(address)
if err != nil {
return 0, err
}
return account.GetAccountNumber(), nil
}
// GetAccountSequence returns the sequence number for the given account
// address.
func (ctx CLIContext) GetAccountSequence(address []byte) (int64, error) {
account, err := ctx.GetAccount(address)
if err != nil {
return 0, err
}
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 {
addr, err := ctx.GetFromAddress()
if err != nil {
return err
}
accountBytes, err := ctx.QueryStore(auth.AddressStoreKey(addr), ctx.AccountStore)
if err != nil {
return err
}
if len(accountBytes) == 0 {
return ErrInvalidAccount(addr)
}
return nil
}
// EnsureAccountExistsFromAddr ensures that an account exists for a given
// address. Instead of using the context's from name, a direct address is
// given. An error is returned if it does not.
func (ctx CLIContext) EnsureAccountExistsFromAddr(addr sdk.AccAddress) error {
accountBytes, err := ctx.QueryStore(auth.AddressStoreKey(addr), ctx.AccountStore)
if err != nil {
return err
}
if len(accountBytes) == 0 {
return ErrInvalidAccount(addr)
}
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 string
}
if ctx.Logger != nil {
resJSON := toJSON{res.Height, res.Hash.String(), fmt.Sprintf("%+v", 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 common.HexBytes) (res []byte, err error) {
node, err := ctx.GetNode()
if err != nil {
return res, err
}
opts := rpcclient.ABCIQueryOptions{
Height: ctx.Height,
Trusted: ctx.TrustNode,
}
result, err := node.ABCIQueryWithOptions(path, key, opts)
if err != nil {
return res, err
}
resp := result.Response
if !resp.IsOK() {
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
}
return resp.Value, nil
}
// queryStore performs a query from a Tendermint node with the provided a store
// name and path.
func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, error) {
path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
return ctx.query(path, key)
}

View File

@ -1,113 +0,0 @@
package context
import (
rpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// typical context created in sdk modules for transactions/queries
type CoreContext struct {
ChainID string
Height int64
Gas int64
Fee string
TrustNode bool
NodeURI string
FromAddressName string
AccountNumber int64
Sequence int64
Memo string
Client rpcclient.Client
Decoder auth.AccountDecoder
AccountStore string
UseLedger bool
Async bool
JSON bool
PrintResponse bool
}
// WithChainID - return a copy of the context with an updated chainID
func (c CoreContext) WithChainID(chainID string) CoreContext {
c.ChainID = chainID
return c
}
// WithHeight - return a copy of the context with an updated height
func (c CoreContext) WithHeight(height int64) CoreContext {
c.Height = height
return c
}
// WithGas - return a copy of the context with an updated gas
func (c CoreContext) WithGas(gas int64) CoreContext {
c.Gas = gas
return c
}
// WithFee - return a copy of the context with an updated fee
func (c CoreContext) WithFee(fee string) CoreContext {
c.Fee = fee
return c
}
// WithTrustNode - return a copy of the context with an updated TrustNode flag
func (c CoreContext) WithTrustNode(trustNode bool) CoreContext {
c.TrustNode = trustNode
return c
}
// WithNodeURI - return a copy of the context with an updated node URI
func (c CoreContext) WithNodeURI(nodeURI string) CoreContext {
c.NodeURI = nodeURI
c.Client = rpcclient.NewHTTP(nodeURI, "/websocket")
return c
}
// WithFromAddressName - return a copy of the context with an updated from address
func (c CoreContext) WithFromAddressName(fromAddressName string) CoreContext {
c.FromAddressName = fromAddressName
return c
}
// WithSequence - return a copy of the context with an account number
func (c CoreContext) WithAccountNumber(accnum int64) CoreContext {
c.AccountNumber = accnum
return c
}
// WithSequence - return a copy of the context with an updated sequence number
func (c CoreContext) WithSequence(sequence int64) CoreContext {
c.Sequence = sequence
return c
}
// WithMemo - return a copy of the context with an updated memo
func (c CoreContext) WithMemo(memo string) CoreContext {
c.Memo = memo
return c
}
// WithClient - return a copy of the context with an updated RPC client instance
func (c CoreContext) WithClient(client rpcclient.Client) CoreContext {
c.Client = client
return c
}
// WithDecoder - return a copy of the context with an updated Decoder
func (c CoreContext) WithDecoder(decoder auth.AccountDecoder) CoreContext {
c.Decoder = decoder
return c
}
// WithAccountStore - return a copy of the context with an updated AccountStore
func (c CoreContext) WithAccountStore(accountStore string) CoreContext {
c.AccountStore = accountStore
return c
}
// WithUseLedger - return a copy of the context with an updated UseLedger
func (c CoreContext) WithUseLedger(useLedger bool) CoreContext {
c.UseLedger = useLedger
return c
}

View File

@ -1,141 +0,0 @@
package context
import (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/viper"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
rpcclient "github.com/tendermint/tendermint/rpc/client"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// NewCoreContextFromViper - return a new context with parameters from the command line
func NewCoreContextFromViper() CoreContext {
nodeURI := viper.GetString(client.FlagNode)
var rpc rpcclient.Client
if nodeURI != "" {
rpc = rpcclient.NewHTTP(nodeURI, "/websocket")
}
chainID := viper.GetString(client.FlagChainID)
// if chain ID is not specified manually, read default chain ID
if chainID == "" {
def, err := defaultChainID()
if err != nil {
chainID = def
}
}
// TODO: Remove the following deprecation code after Gaia-7000 is launched
keyName := viper.GetString(client.FlagName)
if keyName != "" {
fmt.Println("** Note --name is deprecated and will be removed next release. Please use --from instead **")
} else {
keyName = viper.GetString(client.FlagFrom)
}
return CoreContext{
ChainID: chainID,
Height: viper.GetInt64(client.FlagHeight),
Gas: viper.GetInt64(client.FlagGas),
Fee: viper.GetString(client.FlagFee),
TrustNode: viper.GetBool(client.FlagTrustNode),
FromAddressName: keyName,
NodeURI: nodeURI,
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
Sequence: viper.GetInt64(client.FlagSequence),
Memo: viper.GetString(client.FlagMemo),
Client: rpc,
Decoder: nil,
AccountStore: "acc",
UseLedger: viper.GetBool(client.FlagUseLedger),
Async: viper.GetBool(client.FlagAsync),
JSON: viper.GetBool(client.FlagJson),
PrintResponse: viper.GetBool(client.FlagPrintResponse),
}
}
// read chain ID from genesis file, if present
func defaultChainID() (string, error) {
cfg, err := tcmd.ParseConfig()
if err != nil {
return "", err
}
doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
return "", err
}
return doc.ChainID, nil
}
// EnsureAccountExists - Make sure account exists
func EnsureAccountExists(ctx CoreContext, name string) error {
keybase, err := keys.GetKeyBase()
if err != nil {
return err
}
if name == "" {
return errors.Errorf("must provide a from address name")
}
info, err := keybase.Get(name)
if err != nil {
return errors.Errorf("no key for: %s", name)
}
accAddr := sdk.AccAddress(info.GetPubKey().Address())
Acc, err := ctx.QueryStore(auth.AddressStoreKey(accAddr), ctx.AccountStore)
if err != nil {
return err
}
// Check if account was found
if Acc == nil {
return errors.Errorf("No account with address %s was found in the state.\nAre you sure there has been a transaction involving it?", accAddr)
}
return nil
}
// EnsureAccount - automatically set account number if none provided
func EnsureAccountNumber(ctx CoreContext) (CoreContext, error) {
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331
if viper.GetInt64(client.FlagAccountNumber) != 0 {
return ctx, nil
}
from, err := ctx.GetFromAddress()
if err != nil {
return ctx, err
}
accnum, err := ctx.GetAccountNumber(from)
if err != nil {
return ctx, err
}
fmt.Printf("Defaulting to account number: %d\n", accnum)
ctx = ctx.WithAccountNumber(accnum)
return ctx, nil
}
// EnsureSequence - automatically set sequence number if none provided
func EnsureSequence(ctx CoreContext) (CoreContext, error) {
// Should be viper.IsSet, but this does not work - https://github.com/spf13/viper/pull/331
if viper.GetInt64(client.FlagSequence) != 0 {
return ctx, nil
}
from, err := ctx.GetFromAddress()
if err != nil {
return ctx, err
}
seq, err := ctx.NextSequence(from)
if err != nil {
return ctx, err
}
fmt.Printf("Defaulting to next sequence number: %d\n", seq)
ctx = ctx.WithSequence(seq)
return ctx, nil
}

View File

@ -42,7 +42,6 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
for _, c := range cmds {
c.Flags().String(FlagFrom, "", "Name of private key with which to sign")
c.Flags().String(FlagName, "", "DEPRECATED - Name of private key with which to sign")
c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
c.Flags().String(FlagMemo, "", "Memo to send along with transaction")

View File

@ -29,6 +29,55 @@ func GetKeyBase() (keys.Keybase, error) {
return GetKeyBaseFromDir(rootDir)
}
// GetKeyInfo returns key info for a given name. An error is returned if the
// keybase cannot be retrieved or getting the info fails.
func GetKeyInfo(name string) (keys.Info, error) {
keybase, err := GetKeyBase()
if err != nil {
return nil, err
}
return keybase.Get(name)
}
// GetPassphrase returns a passphrase for a given name. It will first retrieve
// the key info for that name if the type is local, it'll fetch input from
// STDIN. Otherwise, an empty passphrase is returned. An error is returned if
// the key info cannot be fetched or reading from STDIN fails.
func GetPassphrase(name string) (string, error) {
var passphrase string
keyInfo, err := GetKeyInfo(name)
if err != nil {
return passphrase, err
}
// we only need a passphrase for locally stored keys
// TODO: (ref: #864) address security concerns
if keyInfo.GetType() == keys.TypeLocal {
passphrase, err = ReadPassphraseFromStdin(name)
if err != nil {
return passphrase, err
}
}
return passphrase, nil
}
// ReadPassphraseFromStdin attempts to read a passphrase from STDIN return an
// error upon failure.
func ReadPassphraseFromStdin(name string) (string, error) {
buf := client.BufferStdin()
prompt := fmt.Sprintf("Password to sign with '%s':", name)
passphrase, err := client.GetPassword(prompt, buf)
if err != nil {
return passphrase, fmt.Errorf("Error reading passphrase: %v", err)
}
return passphrase, nil
}
// initialize a keybase based on the configuration
func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
if keybase == nil {
@ -77,7 +126,7 @@ func Bech32KeyOutput(info keys.Info) (KeyOutput, error) {
}
return KeyOutput{
Name: info.GetName(),
Type: info.GetType(),
Type: info.GetType().String(),
Address: account,
PubKey: bechPubKey,
}, nil

View File

@ -647,7 +647,6 @@ func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
// send
coinbz, err := cdc.MarshalJSON(sdk.NewInt64Coin("steak", 1))
if err != nil {
@ -693,7 +692,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc
"account_number":"%d",
"sequence": "%d",
"gas": "100000",
"chain_id": "%s",
"src_chain_id": "%s",
"amount":[
{
"denom": "%s",
@ -701,6 +700,7 @@ func doIBCTransfer(t *testing.T, port, seed, name, password string, addr sdk.Acc
}
]
}`, name, password, accnum, sequence, chainID, "steak"))
res, body := Request(t, port, "POST", fmt.Sprintf("/ibc/testchain/%s/send", receiveAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)

View File

@ -78,21 +78,21 @@ func createHandler(cdc *wire.Codec) http.Handler {
panic(err)
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc).WithLogger(os.Stdout)
// TODO: make more functional? aka r = keys.RegisterRoutes(r)
r.HandleFunc("/version", CLIVersionRequestHandler).Methods("GET")
r.HandleFunc("/node_version", NodeVersionRequestHandler(ctx)).Methods("GET")
r.HandleFunc("/node_version", NodeVersionRequestHandler(cliCtx)).Methods("GET")
keys.RegisterRoutes(r)
rpc.RegisterRoutes(ctx, r)
tx.RegisterRoutes(ctx, r, cdc)
auth.RegisterRoutes(ctx, r, cdc, "acc")
bank.RegisterRoutes(ctx, r, cdc, kb)
ibc.RegisterRoutes(ctx, r, cdc, kb)
stake.RegisterRoutes(ctx, r, cdc, kb)
slashing.RegisterRoutes(ctx, r, cdc, kb)
gov.RegisterRoutes(ctx, r, cdc)
rpc.RegisterRoutes(cliCtx, r)
tx.RegisterRoutes(cliCtx, r, cdc)
auth.RegisterRoutes(cliCtx, r, cdc, "acc")
bank.RegisterRoutes(cliCtx, r, cdc, kb)
ibc.RegisterRoutes(cliCtx, r, cdc, kb)
stake.RegisterRoutes(cliCtx, r, cdc, kb)
slashing.RegisterRoutes(cliCtx, r, cdc, kb)
gov.RegisterRoutes(cliCtx, r, cdc)
return r
}

View File

@ -15,14 +15,15 @@ func CLIVersionRequestHandler(w http.ResponseWriter, r *http.Request) {
}
// connected node version REST handler endpoint
func NodeVersionRequestHandler(ctx context.CoreContext) http.HandlerFunc {
func NodeVersionRequestHandler(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
version, err := ctx.Query("/app/version")
version, err := cliCtx.Query("/app/version")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Could't query version. Error: %s", err.Error())))
return
}
w.Write(version)
}
}

View File

@ -5,11 +5,11 @@ import (
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
)
const (
@ -31,9 +31,9 @@ func BlockCommand() *cobra.Command {
return cmd
}
func getBlock(ctx context.CoreContext, height *int64) ([]byte, error) {
func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) {
// get the node
node, err := ctx.GetNode()
node, err := cliCtx.GetNode()
if err != nil {
return nil, err
}
@ -57,8 +57,8 @@ func getBlock(ctx context.CoreContext, height *int64) ([]byte, error) {
}
// get the current blockchain height
func GetChainHeight(ctx context.CoreContext) (int64, error) {
node, err := ctx.GetNode()
func GetChainHeight(cliCtx context.CLIContext) (int64, error) {
node, err := cliCtx.GetNode()
if err != nil {
return -1, err
}
@ -86,7 +86,7 @@ func printBlock(cmd *cobra.Command, args []string) error {
}
}
output, err := getBlock(context.NewCoreContextFromViper(), height)
output, err := getBlock(context.NewCLIContext(), height)
if err != nil {
return err
}
@ -97,7 +97,7 @@ func printBlock(cmd *cobra.Command, args []string) error {
// REST
// REST handler to get a block
func BlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func BlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
height, err := strconv.ParseInt(vars["height"], 10, 64)
@ -106,13 +106,13 @@ func BlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/block/{height}'."))
return
}
chainHeight, err := GetChainHeight(ctx)
chainHeight, err := GetChainHeight(cliCtx)
if height > chainHeight {
w.WriteHeader(404)
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
return
}
output, err := getBlock(ctx, &height)
output, err := getBlock(cliCtx, &height)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
@ -123,15 +123,15 @@ func BlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
}
// REST handler to get the latest block
func LatestBlockRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func LatestBlockRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
height, err := GetChainHeight(ctx)
height, err := GetChainHeight(cliCtx)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := getBlock(ctx, &height)
output, err := getBlock(cliCtx, &height)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

View File

@ -44,11 +44,11 @@ func initClientCommand() *cobra.Command {
}
// Register REST endpoints
func RegisterRoutes(ctx context.CoreContext, r *mux.Router) {
r.HandleFunc("/node_info", NodeInfoRequestHandlerFn(ctx)).Methods("GET")
r.HandleFunc("/syncing", NodeSyncingRequestHandlerFn(ctx)).Methods("GET")
r.HandleFunc("/blocks/latest", LatestBlockRequestHandlerFn(ctx)).Methods("GET")
r.HandleFunc("/blocks/{height}", BlockRequestHandlerFn(ctx)).Methods("GET")
r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandlerFn(ctx)).Methods("GET")
r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandlerFn(ctx)).Methods("GET")
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/node_info", NodeInfoRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/syncing", NodeSyncingRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/blocks/latest", LatestBlockRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/blocks/{height}", BlockRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/validatorsets/latest", LatestValidatorSetRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/validatorsets/{height}", ValidatorSetRequestHandlerFn(cliCtx)).Methods("GET")
}

View File

@ -18,23 +18,25 @@ func statusCommand() *cobra.Command {
Short: "Query remote node for status",
RunE: printNodeStatus,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
return cmd
}
func getNodeStatus(ctx context.CoreContext) (*ctypes.ResultStatus, error) {
func getNodeStatus(cliCtx context.CLIContext) (*ctypes.ResultStatus, error) {
// get the node
node, err := ctx.GetNode()
node, err := cliCtx.GetNode()
if err != nil {
return &ctypes.ResultStatus{}, err
}
return node.Status()
}
// CMD
func printNodeStatus(cmd *cobra.Command, args []string) error {
status, err := getNodeStatus(context.NewCoreContextFromViper())
status, err := getNodeStatus(context.NewCLIContext())
if err != nil {
return err
}
@ -52,9 +54,9 @@ func printNodeStatus(cmd *cobra.Command, args []string) error {
// REST
// REST handler for node info
func NodeInfoRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func NodeInfoRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
status, err := getNodeStatus(ctx)
status, err := getNodeStatus(cliCtx)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
@ -68,14 +70,15 @@ func NodeInfoRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
// REST handler for node syncing
func NodeSyncingRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func NodeSyncingRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
status, err := getNodeStatus(ctx)
status, err := getNodeStatus(cliCtx)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
@ -88,6 +91,7 @@ func NodeSyncingRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
w.Write([]byte(err.Error()))
return
}
w.Write([]byte(strconv.FormatBool(syncing)))
}
}

View File

@ -58,9 +58,9 @@ func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error
}, nil
}
func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
func getValidators(cliCtx context.CLIContext, height *int64) ([]byte, error) {
// get the node
node, err := ctx.GetNode()
node, err := cliCtx.GetNode()
if err != nil {
return nil, err
}
@ -74,6 +74,7 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
}
for i := 0; i < len(validatorsRes.Validators); i++ {
outputValidatorsRes.Validators[i], err = bech32ValidatorOutput(validatorsRes.Validators[i])
if err != nil {
@ -85,6 +86,7 @@ func getValidators(ctx context.CoreContext, height *int64) ([]byte, error) {
if err != nil {
return nil, err
}
return output, nil
}
@ -104,7 +106,7 @@ func printValidators(cmd *cobra.Command, args []string) error {
}
}
output, err := getValidators(context.NewCoreContextFromViper(), height)
output, err := getValidators(context.NewCLIContext(), height)
if err != nil {
return err
}
@ -116,22 +118,25 @@ func printValidators(cmd *cobra.Command, args []string) error {
// REST
// Validator Set at a height REST handler
func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func ValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
height, err := strconv.ParseInt(vars["height"], 10, 64)
if err != nil {
w.WriteHeader(400)
w.Write([]byte("ERROR: Couldn't parse block height. Assumed format is '/validatorsets/{height}'."))
return
}
chainHeight, err := GetChainHeight(ctx)
chainHeight, err := GetChainHeight(cliCtx)
if height > chainHeight {
w.WriteHeader(404)
w.Write([]byte("ERROR: Requested block height is bigger then the chain length."))
return
}
output, err := getValidators(ctx, &height)
output, err := getValidators(cliCtx, &height)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
@ -143,20 +148,22 @@ func ValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
}
// Latest Validator Set REST handler
func LatestValidatorSetRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func LatestValidatorSetRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
height, err := GetChainHeight(ctx)
height, err := GetChainHeight(cliCtx)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := getValidators(ctx, &height)
output, err := getValidators(cliCtx, &height)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}

View File

@ -13,7 +13,7 @@ type BroadcastTxBody struct {
}
// BroadcastTx REST Handler
func BroadcastTxRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
func BroadcastTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m BroadcastTxBody
@ -25,7 +25,7 @@ func BroadcastTxRequestHandlerFn(ctx context.CoreContext) http.HandlerFunc {
return
}
res, err := ctx.BroadcastTx([]byte(m.TxBytes))
res, err := cliCtx.BroadcastTx([]byte(m.TxBytes))
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

View File

@ -21,24 +21,25 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
)
// Get the default command for a tx query
// QueryTxCmd implements the default command for a tx query.
func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "tx [hash]",
Short: "Matches this txhash over all committed blocks",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// find the key to look up the account
hashHexStr := args[0]
trustNode := viper.GetBool(client.FlagTrustNode)
output, err := queryTx(cdc, context.NewCoreContextFromViper(), hashHexStr, trustNode)
cliCtx := context.NewCLIContext().WithCodec(cdc)
output, err := queryTx(cdc, cliCtx, hashHexStr, trustNode)
if err != nil {
return err
}
fmt.Println(string(output))
fmt.Println(string(output))
return nil
},
}
@ -50,14 +51,13 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
return cmd
}
func queryTx(cdc *wire.Codec, ctx context.CoreContext, hashHexStr string, trustNode bool) ([]byte, error) {
func queryTx(cdc *wire.Codec, cliCtx context.CLIContext, hashHexStr string, trustNode bool) ([]byte, error) {
hash, err := hex.DecodeString(hashHexStr)
if err != nil {
return nil, err
}
// get the node
node, err := ctx.GetNode()
node, err := cliCtx.GetNode()
if err != nil {
return nil, err
}
@ -66,6 +66,7 @@ func queryTx(cdc *wire.Codec, ctx context.CoreContext, hashHexStr string, trustN
if err != nil {
return nil, err
}
info, err := formatTxResult(cdc, res)
if err != nil {
return nil, err
@ -81,13 +82,12 @@ func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (txInfo, error) {
return txInfo{}, err
}
info := txInfo{
return txInfo{
Hash: res.Hash,
Height: res.Height,
Tx: tx,
Result: res.TxResult,
}
return info, nil
}, nil
}
// txInfo is used to prepare info to display
@ -100,17 +100,19 @@ type txInfo struct {
func parseTx(cdc *wire.Codec, txBytes []byte) (sdk.Tx, error) {
var tx auth.StdTx
err := cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, err
}
return tx, nil
}
// REST
// transaction query REST handler
func QueryTxRequestHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
func QueryTxRequestHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
hashHexStr := vars["hash"]
@ -120,12 +122,13 @@ func QueryTxRequestHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.Hand
trustNode = true
}
output, err := queryTx(cdc, ctx, hashHexStr, trustNode)
output, err := queryTx(cdc, cliCtx, hashHexStr, trustNode)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}

View File

@ -17,9 +17,9 @@ func AddCommands(cmd *cobra.Command, cdc *wire.Codec) {
}
// register REST routes
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, ctx)).Methods("GET")
r.HandleFunc("/txs", SearchTxRequestHandlerFn(ctx, cdc)).Methods("GET")
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cdc, cliCtx)).Methods("GET")
r.HandleFunc("/txs", SearchTxRequestHandlerFn(cliCtx, cdc)).Methods("GET")
// r.HandleFunc("/txs/sign", SignTxRequstHandler).Methods("POST")
// r.HandleFunc("/txs/broadcast", BroadcastTxRequestHandler).Methods("POST")
}

View File

@ -7,15 +7,15 @@ import (
"net/url"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/spf13/cobra"
"github.com/spf13/viper"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
const (
@ -31,14 +31,18 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
tags := viper.GetStringSlice(flagTags)
txs, err := searchTxs(context.NewCoreContextFromViper(), cdc, tags)
cliCtx := context.NewCLIContext().WithCodec(cdc)
txs, err := searchTxs(cliCtx, cdc, tags)
if err != nil {
return err
}
output, err := cdc.MarshalJSON(txs)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
},
@ -53,19 +57,22 @@ func SearchTxCmd(cdc *wire.Codec) *cobra.Command {
return cmd
}
func searchTxs(ctx context.CoreContext, cdc *wire.Codec, tags []string) ([]txInfo, error) {
func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]txInfo, error) {
if len(tags) == 0 {
return nil, errors.New("must declare at least one tag to search")
}
// XXX: implement ANY
query := strings.Join(tags, " AND ")
// get the node
node, err := ctx.GetNode()
node, err := cliCtx.GetNode()
if err != nil {
return nil, err
}
prove := !viper.GetBool(client.FlagTrustNode)
// TODO: take these as args
page := 0
perPage := 100
@ -98,7 +105,7 @@ func formatTxResults(cdc *wire.Codec, res []*ctypes.ResultTx) ([]txInfo, error)
// REST
// Search Tx REST Handler
func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
func SearchTxRequestHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
tag := r.FormValue("tag")
if tag == "" {
@ -106,14 +113,17 @@ func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.Han
w.Write([]byte("You need to provide at least a tag as a key=value pair to search for. Postfix the key with _bech32 to search bech32-encoded addresses or public keys"))
return
}
keyValue := strings.Split(tag, "=")
key := keyValue[0]
value, err := url.QueryUnescape(keyValue[1])
if err != nil {
w.WriteHeader(400)
w.Write([]byte("Could not decode address: " + err.Error()))
return
}
if strings.HasSuffix(key, "_bech32") {
bech32address := strings.Trim(value, "'")
prefix := strings.Split(bech32address, "1")[0]
@ -127,7 +137,7 @@ func SearchTxRequestHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.Han
tag = strings.TrimRight(key, "_bech32") + "='" + sdk.AccAddress(bz).String() + "'"
}
txs, err := searchTxs(ctx, cdc, []string{tag})
txs, err := searchTxs(cliCtx, cdc, []string{tag})
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))

60
client/utils/utils.go Normal file
View File

@ -0,0 +1,60 @@
package utils
import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
)
// SendTx implements a auxiliary handler that facilitates sending a series of
// messages in a signed transaction given a TxContext and a QueryContext. It
// ensures that the account exists, has a proper number and sequence set. In
// addition, it builds and signs a transaction with the supplied messages.
// Finally, it broadcasts the signed transaction to a node.
func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) error {
if err := cliCtx.EnsureAccountExists(); err != nil {
return err
}
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txCtx.AccountNumber == 0 {
accNum, err := cliCtx.GetAccountNumber(from)
if err != nil {
return err
}
txCtx = txCtx.WithAccountNumber(accNum)
}
// TODO: (ref #1903) Allow for user supplied account sequence without
// automatically doing a manual lookup.
if txCtx.Sequence == 0 {
accSeq, err := cliCtx.GetAccountSequence(from)
if err != nil {
return err
}
txCtx = txCtx.WithSequence(accSeq)
}
passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName)
if err != nil {
return err
}
// build and sign the transaction
txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs)
if err != nil {
return err
}
// broadcast to a Tendermint node
return cliCtx.EnsureBroadcastTx(txBytes)
}

View File

@ -44,10 +44,31 @@ type Keybase interface {
ExportPrivateKeyObject(name string, passphrase string) (crypto.PrivKey, error)
}
// KeyType reflects a human-readable type for key listing.
type KeyType uint
// Info KeyTypes
const (
TypeLocal KeyType = 0
TypeLedger KeyType = 1
TypeOffline KeyType = 2
)
var keyTypes = map[KeyType]string{
TypeLocal: "local",
TypeLedger: "ledger",
TypeOffline: "offline",
}
// String implements the stringer interface for KeyType.
func (kt KeyType) String() string {
return keyTypes[kt]
}
// Info is the publicly exposed information about a keypair
type Info interface {
// Human-readable type for key listing
GetType() string
GetType() KeyType
// Name of the key
GetName() string
// Public key
@ -73,8 +94,8 @@ func newLocalInfo(name string, pub crypto.PubKey, privArmor string) Info {
}
}
func (i localInfo) GetType() string {
return "local"
func (i localInfo) GetType() KeyType {
return TypeLocal
}
func (i localInfo) GetName() string {
@ -100,8 +121,8 @@ func newLedgerInfo(name string, pub crypto.PubKey, path ccrypto.DerivationPath)
}
}
func (i ledgerInfo) GetType() string {
return "ledger"
func (i ledgerInfo) GetType() KeyType {
return TypeLedger
}
func (i ledgerInfo) GetName() string {
@ -125,8 +146,8 @@ func newOfflineInfo(name string, pub crypto.PubKey) Info {
}
}
func (i offlineInfo) GetType() string {
return "offline"
func (i offlineInfo) GetType() KeyType {
return TypeOffline
}
func (i offlineInfo) GetName() string {

View File

@ -1,78 +1,65 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
"github.com/spf13/cobra"
"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/examples/democoin/x/cool"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
)
// take the coolness quiz transaction
// QuizTxCmd invokes the coolness quiz transaction.
func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
return &cobra.Command{
Use: "cool [answer]",
Short: "What's cooler than being cool?",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
// get the from address from the name flag
from, err := ctx.GetFromAddress()
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
// create the message
msg := cool.NewMsgQuiz(from, args[0])
// get account name
name := viper.GetString(client.FlagName)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
}
// set a new cool trend transaction
// SetTrendTxCmd sends a new cool trend transaction.
func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
return &cobra.Command{
Use: "setcool [answer]",
Short: "You're so cool, tell us what is cool!",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
// get the from address from the name flag
from, err := ctx.GetFromAddress()
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
// get account name
name := viper.GetString(client.FlagName)
// create the message
msg := cool.NewMsgSetTrend(from, args[0])
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -1,16 +1,18 @@
package cli
import (
"os"
"strconv"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/spf13/cobra"
)
// command to mine some pow!
@ -20,9 +22,13 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
Short: "Mine some coins with proof-of-work!",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
from, err := ctx.GetFromAddress()
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -31,29 +37,23 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
count, err := strconv.ParseUint(args[1], 0, 64)
if err != nil {
return err
}
nonce, err := strconv.ParseUint(args[2], 0, 64)
if err != nil {
return err
}
solution := []byte(args[3])
msg := pow.NewMsgMine(from, difficulty, count, nonce, solution)
// get account name
name := ctx.FromAddressName
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
}

View File

@ -3,18 +3,20 @@ package cli
import (
"encoding/hex"
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/spf13/viper"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/simplestake"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/simplestake"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/crypto/ed25519"
)
const (
@ -28,9 +30,13 @@ func BondTxCmd(cdc *wire.Codec) *cobra.Command {
Use: "bond",
Short: "Bond to a validator",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper()
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
from, err := ctx.GetFromAddress()
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -60,11 +66,15 @@ func BondTxCmd(cdc *wire.Codec) *cobra.Command {
msg := simplestake.NewMsgBond(from, stake, pubKeyEd)
return sendMsg(cdc, msg)
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().String(flagStake, "", "Amount of coins to stake")
cmd.Flags().String(flagValidator, "", "Validator address to stake")
return cmd
}
@ -74,23 +84,23 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
Use: "unbond",
Short: "Unbond from a validator",
RunE: func(cmd *cobra.Command, args []string) error {
from, err := context.NewCoreContextFromViper().GetFromAddress()
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout)
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
msg := simplestake.NewMsgUnbond(from)
return sendMsg(cdc, msg)
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
return cmd
}
func sendMsg(cdc *wire.Codec, msg sdk.Msg) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
}

View File

@ -1,7 +1,6 @@
package cli
import (
"errors"
"fmt"
"github.com/spf13/cobra"
@ -12,32 +11,31 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
)
// GetAccountCmd for the auth.BaseAccount type
// GetAccountCmdDefault invokes the GetAccountCmd for the auth.BaseAccount type.
func GetAccountCmdDefault(storeName string, cdc *wire.Codec) *cobra.Command {
return GetAccountCmd(storeName, cdc, GetAccountDecoder(cdc))
}
// Get account decoder for auth.DefaultAccount
// GetAccountDecoder gets the account decoder for auth.DefaultAccount.
func GetAccountDecoder(cdc *wire.Codec) auth.AccountDecoder {
return func(accBytes []byte) (acct auth.Account, err error) {
// acct := new(auth.BaseAccount)
err = cdc.UnmarshalBinaryBare(accBytes, &acct)
if err != nil {
panic(err)
}
return acct, err
}
}
// GetAccountCmd returns a query account that will display the
// state of the account at a given address
// GetAccountCmd returns a query account that will display the state of the
// account at a given address.
func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder) *cobra.Command {
return &cobra.Command{
Use: "account [address]",
Short: "Query account balance",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
// find the key to look up the account
addr := args[0]
@ -46,30 +44,24 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode
return err
}
// perform query
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(auth.AddressStoreKey(key), storeName)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(decoder)
if err := cliCtx.EnsureAccountExistsFromAddr(key); err != nil {
return err
}
acc, err := cliCtx.GetAccount(key)
if err != nil {
return err
}
// Check if account was found
if res == nil {
return errors.New("No account with address " + addr +
" was found in the state.\nAre you sure there has been a transaction involving it?")
}
// decode the value
account, err := decoder(res)
output, err := wire.MarshalJSONIndent(cdc, acc)
if err != nil {
return err
}
// print out whole account
output, err := wire.MarshalJSONIndent(cdc, account)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
},

View File

@ -0,0 +1,152 @@
package context
import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
// TxContext implements a transaction context created in SDK modules.
type TxContext struct {
Codec *wire.Codec
AccountNumber int64
Sequence int64
Gas int64
ChainID string
Memo string
Fee string
}
// NewTxContextFromCLI returns a new initialized TxContext with parameters from
// the command line using Viper.
func NewTxContextFromCLI() TxContext {
// if chain ID is not specified manually, read default chain ID
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
defaultChainID, err := defaultChainID()
if err != nil {
chainID = defaultChainID
}
}
return TxContext{
ChainID: chainID,
Gas: viper.GetInt64(client.FlagGas),
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
Sequence: viper.GetInt64(client.FlagSequence),
Fee: viper.GetString(client.FlagFee),
Memo: viper.GetString(client.FlagMemo),
}
}
// WithCodec returns a copy of the context with an updated codec.
func (ctx TxContext) WithCodec(cdc *wire.Codec) TxContext {
ctx.Codec = cdc
return ctx
}
// WithChainID returns a copy of the context with an updated chainID.
func (ctx TxContext) WithChainID(chainID string) TxContext {
ctx.ChainID = chainID
return ctx
}
// WithGas returns a copy of the context with an updated gas.
func (ctx TxContext) WithGas(gas int64) TxContext {
ctx.Gas = gas
return ctx
}
// WithFee returns a copy of the context with an updated fee.
func (ctx TxContext) WithFee(fee string) TxContext {
ctx.Fee = fee
return ctx
}
// WithSequence returns a copy of the context with an updated sequence number.
func (ctx TxContext) WithSequence(sequence int64) TxContext {
ctx.Sequence = sequence
return ctx
}
// WithMemo returns a copy of the context with an updated memo.
func (ctx TxContext) WithMemo(memo string) TxContext {
ctx.Memo = memo
return ctx
}
// WithAccountNumber returns a copy of the context with an account number.
func (ctx TxContext) WithAccountNumber(accnum int64) TxContext {
ctx.AccountNumber = accnum
return ctx
}
// Build builds a single message to be signed from a TxContext given a set of
// messages. It returns an error if a fee is supplied but cannot be parsed.
func (ctx TxContext) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) {
chainID := ctx.ChainID
if chainID == "" {
return auth.StdSignMsg{}, errors.Errorf("chain ID required but not specified")
}
fee := sdk.Coin{}
if ctx.Fee != "" {
parsedFee, err := sdk.ParseCoin(ctx.Fee)
if err != nil {
return auth.StdSignMsg{}, err
}
fee = parsedFee
}
return auth.StdSignMsg{
ChainID: ctx.ChainID,
AccountNumber: ctx.AccountNumber,
Sequence: ctx.Sequence,
Memo: ctx.Memo,
Msgs: msgs,
// TODO: run simulate to estimate gas?
Fee: auth.NewStdFee(ctx.Gas, fee),
}, nil
}
// Sign signs a transaction given a name, passphrase, and a single message to
// signed. An error is returned if signing fails.
func (ctx TxContext) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) {
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
sig, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes())
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
AccountNumber: msg.AccountNumber,
Sequence: msg.Sequence,
PubKey: pubkey,
Signature: sig,
}}
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
}
// BuildAndSign builds a single message to be signed, and signs a transaction
// with the built message given a name, passphrase, and a set of
// messages.
func (ctx TxContext) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
msg, err := ctx.Build(msgs)
if err != nil {
return nil, err
}
return ctx.Sign(name, passphrase, msg)
}

View File

@ -0,0 +1,25 @@
package context
import (
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmtypes "github.com/tendermint/tendermint/types"
)
// defaultChainID returns the chain ID from the genesis file if present. An
// error is returned if the file cannot be read or parsed.
//
// TODO: This should be removed and the chainID should always be provided by
// the end user.
func defaultChainID() (string, error) {
cfg, err := tcmd.ParseConfig()
if err != nil {
return "", err
}
doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
return "", err
}
return doc.ChainID, nil
}

View File

@ -4,25 +4,28 @@ import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/gorilla/mux"
)
// register REST routes
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, storeName string) {
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, storeName string) {
r.HandleFunc(
"/accounts/{address}",
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), ctx),
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
).Methods("GET")
}
// query accountREST Handler
func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder auth.AccountDecoder, ctx context.CoreContext) http.HandlerFunc {
func QueryAccountRequestHandlerFn(
storeName string, cdc *wire.Codec,
decoder auth.AccountDecoder, cliCtx context.CLIContext,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
bech32addr := vars["address"]
@ -34,7 +37,7 @@ func QueryAccountRequestHandlerFn(storeName string, cdc *wire.Codec, decoder aut
return
}
res, err := ctx.QueryStore(auth.AddressStoreKey(addr), storeName)
res, err := cliCtx.QueryStore(auth.AddressStoreKey(addr), storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query account. Error: %s", err.Error())))

View File

@ -1,14 +1,17 @@
package cli
import (
"github.com/pkg/errors"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/bank/client"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -18,36 +21,29 @@ const (
flagAmount = "amount"
)
// SendTxCmd will create a send tx and sign it with the given key
// SendTxCmd will create a send tx and sign it with the given key.
func SendTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "send",
Short: "Create and sign a send tx",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
// get the from/to address
from, err := ctx.GetFromAddress()
if err != nil {
if err := cliCtx.EnsureAccountExists(); err != nil {
return err
}
fromAcc, err := ctx.QueryStore(auth.AddressStoreKey(from), ctx.AccountStore)
if err != nil {
return err
}
// Check if account was found
if fromAcc == nil {
return errors.Errorf("No account with address %s was found in the state.\nAre you sure there has been a transaction involving it?", from)
}
toStr := viper.GetString(flagTo)
to, err := sdk.AccAddressFromBech32(toStr)
if err != nil {
return err
}
// parse coins trying to be sent
amount := viper.GetString(flagAmount)
coins, err := sdk.ParseCoins(amount)
@ -55,11 +51,17 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
return err
}
// ensure account has enough coins
account, err := ctx.Decoder(fromAcc)
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
account, err := cliCtx.GetAccount(from)
if err != nil {
return err
}
// ensure account has enough coins
if !account.GetCoins().IsGTE(coins) {
return errors.Errorf("Address %s doesn't have enough coins to pay for this transaction.", from)
}
@ -67,12 +69,7 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
msg := client.BuildMsg(from, to, coins)
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}

View File

@ -4,19 +4,20 @@ import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/bank/client"
"github.com/gorilla/mux"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
r.HandleFunc("/accounts/{address}/send", SendRequestHandlerFn(cdc, kb, ctx)).Methods("POST")
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
r.HandleFunc("/accounts/{address}/send", SendRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST")
}
type sendBody struct {
@ -38,7 +39,7 @@ func init() {
}
// SendRequestHandlerFn - http request handler to send coins to a address
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// collect data
vars := mux.Vars(r)
@ -80,23 +81,22 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreCont
return
}
// add gas to context
ctx = ctx.WithGas(m.Gas)
// add chain-id to context
ctx = ctx.WithChainID(m.ChainID)
txCtx := authctx.TxContext{
Codec: cdc,
Gas: m.Gas,
ChainID: m.ChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
}
// sign
ctx = ctx.WithAccountNumber(m.AccountNumber)
ctx = ctx.WithSequence(m.Sequence)
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc)
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
return
}
// send
res, err := ctx.BroadcastTx(txBytes)
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))

View File

@ -2,16 +2,19 @@ package cli
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
@ -27,21 +30,24 @@ const (
flagLatestProposalIDs = "latest"
)
// submit a proposal tx
// GetCmdSubmitProposal implements submitting a proposal transaction command.
func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "submit-proposal",
Short: "Submit a proposal along with an initial deposit",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
title := viper.GetString(flagTitle)
description := viper.GetString(flagDescription)
strProposalType := viper.GetString(flagProposalType)
initialDeposit := viper.GetString(flagDeposit)
// get the from address from the name flag
fromAddr, err := ctx.GetFromAddress()
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
fromAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -56,7 +62,6 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
return err
}
// create the message
msg := gov.NewMsgSubmitProposal(title, description, proposalType, fromAddr, amount)
err = msg.ValidateBasic()
@ -64,14 +69,10 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
return err
}
// build and sign the transaction, then broadcast to Tendermint
// proposalID must be returned, and it is a part of response
ctx.PrintResponse = true
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
// 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(txCtx, cliCtx, []sdk.Msg{msg})
},
}
@ -83,16 +84,19 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
return cmd
}
// set a new Deposit transaction
// GetCmdDeposit implements depositing tokens for an active proposal.
func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "deposit",
Short: "deposit tokens for activing proposal",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
// get the from address from the name flag
depositerAddr, err := ctx.GetFromAddress()
depositerAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -104,7 +108,6 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
return err
}
// create the message
msg := gov.NewMsgDeposit(depositerAddr, proposalID, amount)
err = msg.ValidateBasic()
@ -112,12 +115,9 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
return err
}
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
@ -127,21 +127,24 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
return cmd
}
// set a new Vote transaction
// GetCmdVote implements creating a new vote command.
func GetCmdVote(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "vote",
Short: "vote for an active proposal, options: Yes/No/NoWithVeto/Abstain",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
voterAddr, err := ctx.GetFromAddress()
voterAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
proposalID := viper.GetInt64(flagProposalID)
option := viper.GetString(flagOption)
byteVoteOption, err := gov.VoteOptionFromString(option)
@ -149,7 +152,6 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
return err
}
// create the message
msg := gov.NewMsgVote(voterAddr, proposalID, byteVoteOption)
err = msg.ValidateBasic()
@ -158,14 +160,12 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
}
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",
voterAddr.String(), msg.ProposalID, msg.Option.String())
voterAddr.String(), msg.ProposalID, msg.Option.String(),
)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
// Build and sign the transaction, then broadcast to a Tendermint
// node.
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
@ -175,27 +175,28 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
return cmd
}
// Command to Get a Proposal Information
// GetCmdQueryProposal implements the query proposal command.
func GetCmdQueryProposal(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-proposal",
Short: "query proposal details",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if len(res) == 0 || err != nil {
return errors.Errorf("proposalID [%d] is not existed", proposalID)
}
var proposal gov.Proposal
cdc.MustUnmarshalBinary(res, &proposal)
output, err := wire.MarshalJSONIndent(cdc, proposal)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
},
@ -207,7 +208,7 @@ func GetCmdQueryProposal(storeName string, cdc *wire.Codec) *cobra.Command {
}
// nolint: gocyclo
// Command to Query Proposals
// GetCmdQueryProposals implements a query proposals command.
func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-proposals",
@ -244,9 +245,9 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command {
}
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := ctx.QueryStore(gov.KeyNextProposalID, storeName)
res, err := cliCtx.QueryStore(gov.KeyNextProposalID, storeName)
if err != nil {
return err
}
@ -261,20 +262,20 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command {
for proposalID := maxProposalID - latestProposalsIDs; proposalID < maxProposalID; proposalID++ {
if voterAddr != nil {
res, err = ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
res, err = cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
if err != nil || len(res) == 0 {
continue
}
}
if depositerAddr != nil {
res, err = ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
res, err = cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
if err != nil || len(res) == 0 {
continue
}
}
res, err = ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err = cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if err != nil || len(res) == 0 {
continue
}
@ -299,6 +300,7 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command {
for _, proposal := range matchingProposals {
fmt.Printf(" %d - %s\n", proposal.GetProposalID(), proposal.GetTitle())
}
return nil
},
}
@ -312,11 +314,13 @@ func GetCmdQueryProposals(storeName string, cdc *wire.Codec) *cobra.Command {
}
// Command to Get a Proposal Information
// GetCmdQueryVote implements the query proposal vote command.
func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-vote",
Short: "query vote",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
voterAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagVoter))
@ -324,19 +328,19 @@ func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command {
return err
}
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
res, err := cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
if len(res) == 0 || err != nil {
return errors.Errorf("proposalID [%d] does not exist", proposalID)
}
var vote gov.Vote
cdc.MustUnmarshalBinary(res, &vote)
output, err := wire.MarshalJSONIndent(cdc, vote)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
},
@ -348,17 +352,16 @@ func GetCmdQueryVote(storeName string, cdc *wire.Codec) *cobra.Command {
return cmd
}
// Command to Get a Proposal Information
// GetCmdQueryVotes implements the command to query for proposal votes.
func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "query-votes",
Short: "query votes on a proposal",
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if len(res) == 0 || err != nil {
return errors.Errorf("proposalID [%d] does not exist", proposalID)
}
@ -371,7 +374,7 @@ func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command {
return nil
}
res2, err := ctx.QuerySubspace(cdc, gov.KeyVotesSubspace(proposalID), storeName)
res2, err := cliCtx.QuerySubspace(gov.KeyVotesSubspace(proposalID), storeName)
if err != nil {
return err
}
@ -389,7 +392,6 @@ func GetCmdQueryVotes(storeName string, cdc *wire.Codec) *cobra.Command {
}
fmt.Println(string(output))
return nil
},
}

View File

@ -9,6 +9,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/gorilla/mux"
"github.com/pkg/errors"
)
@ -24,10 +25,10 @@ const (
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, ctx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, ctx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, ctx)).Methods("POST")
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc("/gov/proposals", postProposalHandlerFn(cdc, cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), depositHandlerFn(cdc, cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), voteHandlerFn(cdc, cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}", RestProposalID), queryProposalHandlerFn(cdc)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits/{%s}", RestProposalID, RestDepositer), queryDepositHandlerFn(cdc)).Methods("GET")
@ -59,7 +60,7 @@ type voteReq struct {
Option gov.VoteOption `json:"option"` // option from OptionSet chosen by the voter
}
func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
func postProposalHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req postProposalReq
err := buildReq(w, r, cdc, &req)
@ -79,12 +80,11 @@ func postProposalHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.Handle
return
}
// sign
signAndBuild(w, ctx, req.BaseReq, msg, cdc)
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
}
}
func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
strProposalID := vars[RestProposalID]
@ -93,6 +93,7 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc
w.WriteHeader(http.StatusBadRequest)
err := errors.New("proposalId required but not specified")
w.Write([]byte(err.Error()))
return
}
@ -100,6 +101,7 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc
if err != nil {
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
w.Write([]byte(err.Error()))
return
}
@ -120,12 +122,11 @@ func depositHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc
return
}
// sign
signAndBuild(w, ctx, req.BaseReq, msg, cdc)
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
}
}
func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
strProposalID := vars[RestProposalID]
@ -134,6 +135,7 @@ func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.New("proposalId required but not specified")
w.Write([]byte(err.Error()))
return
}
@ -161,8 +163,7 @@ func voteHandlerFn(cdc *wire.Codec, ctx context.CoreContext) http.HandlerFunc {
return
}
// sign
signAndBuild(w, ctx, req.BaseReq, msg, cdc)
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
}
}
@ -175,6 +176,7 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.New("proposalId required but not specified")
w.Write([]byte(err.Error()))
return
}
@ -182,26 +184,31 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if err != nil {
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
w.Write([]byte(err.Error()))
return
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if err != nil || len(res) == 0 {
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
w.Write([]byte(err.Error()))
return
}
var proposal gov.Proposal
cdc.MustUnmarshalBinary(res, &proposal)
output, err := wire.MarshalJSONIndent(cdc, proposal)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
@ -216,6 +223,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.New("proposalId required but not specified")
w.Write([]byte(err.Error()))
return
}
@ -224,6 +232,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("proposalID [%d] is not positive", proposalID)
w.Write([]byte(err.Error()))
return
}
@ -231,6 +240,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.New("depositer address required but not specified")
w.Write([]byte(err.Error()))
return
}
@ -239,34 +249,41 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
w.Write([]byte(err.Error()))
return
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
res, err := cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
if err != nil || len(res) == 0 {
res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if err != nil || len(res) == 0 {
w.WriteHeader(http.StatusNotFound)
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
w.Write([]byte(err.Error()))
return
}
w.WriteHeader(http.StatusNotFound)
err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID)
w.Write([]byte(err.Error()))
return
}
var deposit gov.Deposit
cdc.MustUnmarshalBinary(res, &deposit)
output, err := wire.MarshalJSONIndent(cdc, deposit)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
@ -289,6 +306,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("proposalID [%s] is not positive", proposalID)
w.Write([]byte(err.Error()))
return
}
@ -304,35 +322,41 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter)
w.Write([]byte(err.Error()))
return
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
res, err := cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
if err != nil || len(res) == 0 {
res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if err != nil || len(res) == 0 {
w.WriteHeader(http.StatusNotFound)
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
w.Write([]byte(err.Error()))
return
}
w.WriteHeader(http.StatusNotFound)
err = errors.Errorf("voter [%s] did not vote on proposalID [%d]", bechVoterAddr, proposalID)
w.Write([]byte(err.Error()))
return
}
var vote gov.Vote
cdc.MustUnmarshalBinary(res, &vote)
output, err := wire.MarshalJSONIndent(cdc, vote)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
@ -348,6 +372,7 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.New("proposalId required but not specified")
w.Write([]byte(err.Error()))
return
}
@ -356,15 +381,17 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("proposalID [%s] is not positive", proposalID)
w.Write([]byte(err.Error()))
return
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err := cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if err != nil || len(res) == 0 {
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
w.Write([]byte(err.Error()))
return
}
@ -374,10 +401,11 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if proposal.GetStatus() != gov.StatusVotingPeriod {
err := errors.Errorf("proposal is not in Voting Period", proposalID)
w.Write([]byte(err.Error()))
return
}
res2, err := ctx.QuerySubspace(cdc, gov.KeyVotesSubspace(proposalID), storeName)
res2, err := cliCtx.QuerySubspace(gov.KeyVotesSubspace(proposalID), storeName)
if err != nil {
err = errors.New("ProposalID doesn't exist")
w.Write([]byte(err.Error()))
@ -396,8 +424,10 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}
@ -431,6 +461,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
w.Write([]byte(err.Error()))
return
}
}
@ -441,18 +472,21 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
w.WriteHeader(http.StatusBadRequest)
err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus)
w.Write([]byte(err.Error()))
return
}
}
ctx := context.NewCoreContextFromViper()
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := ctx.QueryStore(gov.KeyNextProposalID, storeName)
res, err := cliCtx.QueryStore(gov.KeyNextProposalID, storeName)
if err != nil {
err = errors.New("no proposals exist yet and proposalID has not been set")
w.Write([]byte(err.Error()))
return
}
var maxProposalID int64
cdc.MustUnmarshalBinary(res, &maxProposalID)
@ -460,20 +494,20 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
for proposalID := int64(0); proposalID < maxProposalID; proposalID++ {
if voterAddr != nil {
res, err = ctx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
res, err = cliCtx.QueryStore(gov.KeyVote(proposalID, voterAddr), storeName)
if err != nil || len(res) == 0 {
continue
}
}
if depositerAddr != nil {
res, err = ctx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
res, err = cliCtx.QueryStore(gov.KeyDeposit(proposalID, depositerAddr), storeName)
if err != nil || len(res) == 0 {
continue
}
}
res, err = ctx.QueryStore(gov.KeyProposal(proposalID), storeName)
res, err = cliCtx.QueryStore(gov.KeyProposal(proposalID), storeName)
if err != nil || len(res) == 0 {
continue
}
@ -494,8 +528,10 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.Write(output)
}
}

View File

@ -7,6 +7,8 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/pkg/errors"
)
@ -67,23 +69,24 @@ func writeErr(w *http.ResponseWriter, status int, msg string) {
(*w).Write([]byte(err.Error()))
}
// TODO: Build this function out into a more generic base-request (probably should live in client/lcd)
func signAndBuild(w http.ResponseWriter, ctx context.CoreContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
ctx = ctx.WithAccountNumber(baseReq.AccountNumber)
ctx = ctx.WithSequence(baseReq.Sequence)
ctx = ctx.WithChainID(baseReq.ChainID)
// TODO: Build this function out into a more generic base-request
// (probably should live in client/lcd).
func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
txCtx := authctx.TxContext{
Codec: cdc,
AccountNumber: baseReq.AccountNumber,
Sequence: baseReq.Sequence,
ChainID: baseReq.ChainID,
Gas: baseReq.Gas,
}
// add gas to context
ctx = ctx.WithGas(baseReq.Gas)
txBytes, err := ctx.SignAndBuild(baseReq.Name, baseReq.Password, []sdk.Msg{msg}, cdc)
txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
if err != nil {
writeErr(&w, http.StatusUnauthorized, err.Error())
return
}
// send
res, err := ctx.BroadcastTx(txBytes)
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
writeErr(&w, http.StatusInternalServerError, err.Error())
return

View File

@ -2,18 +2,19 @@ package cli
import (
"encoding/hex"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
wire "github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
@ -22,37 +23,35 @@ const (
flagChain = "chain"
)
// IBC transfer command
// IBCTransferCmd implements the IBC transfer command.
func IBCTransferCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "transfer",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
// get the from address
from, err := ctx.GetFromAddress()
from, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
// build the message
msg, err := buildMsg(from)
if err != nil {
return err
}
// get password
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().String(flagTo, "", "Address to send coins")
cmd.Flags().String(flagAmount, "", "Amount of coins to send")
cmd.Flags().String(flagChain, "", "Destination chain to send coins")
return cmd
}

View File

@ -4,17 +4,19 @@ import (
"os"
"time"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
wire "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
)
// flags
@ -36,7 +38,7 @@ type relayCommander struct {
logger log.Logger
}
// IBC relay command
// IBCRelayCmd implements the IBC relay command.
func IBCRelayCmd(cdc *wire.Codec) *cobra.Command {
cmdr := relayCommander{
cdc: cdc,
@ -77,10 +79,12 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) {
fromChainNode := viper.GetString(FlagFromChainNode)
toChainID := viper.GetString(FlagToChainID)
toChainNode := viper.GetString(FlagToChainNode)
address, err := context.NewCoreContextFromViper().GetFromAddress()
address, err := context.NewCLIContext().GetFromAddress()
if err != nil {
panic(err)
}
c.address = address
c.loop(fromChainID, fromChainNode, toChainID, toChainNode)
@ -88,12 +92,10 @@ func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) {
// This is nolinted as someone is in the process of refactoring this to remove the goto
// nolint: gocyclo
func (c relayCommander) loop(fromChainID, fromChainNode, toChainID,
toChainNode string) {
func (c relayCommander) loop(fromChainID, fromChainNode, toChainID, toChainNode string) {
cliCtx := context.NewCLIContext()
ctx := context.NewCoreContextFromViper()
// get password
passphrase, err := ctx.GetPassphraseFromStdin(ctx.FromAddressName)
passphrase, err := keys.ReadPassphraseFromStdin(cliCtx.FromAddressName)
if err != nil {
panic(err)
}
@ -122,12 +124,14 @@ OUTER:
c.logger.Error("error querying outgoing packet list length", "err", err)
continue OUTER //TODO replace with continue (I think it should just to the correct place where OUTER is now)
}
var egressLength int64
if egressLengthbz == nil {
egressLength = 0
} else if err = c.cdc.UnmarshalBinary(egressLengthbz, &egressLength); err != nil {
panic(err)
}
if egressLength > processed {
c.logger.Info("Detected IBC packet", "number", egressLength-1)
}
@ -142,7 +146,9 @@ OUTER:
}
err = c.broadcastTx(seq, toChainNode, c.refine(egressbz, i, passphrase))
seq++
if err != nil {
c.logger.Error("error broadcasting ingress packet", "err", err)
continue OUTER // TODO replace to break, will break first loop then send back to the beginning (aka OUTER)
@ -154,11 +160,11 @@ OUTER:
}
func query(node string, key []byte, storeName string) (res []byte, err error) {
return context.NewCoreContextFromViper().WithNodeURI(node).QueryStore(key, storeName)
return context.NewCLIContext().WithNodeURI(node).QueryStore(key, storeName)
}
func (c relayCommander) broadcastTx(seq int64, node string, tx []byte) error {
_, err := context.NewCoreContextFromViper().WithNodeURI(node).WithSequence(seq + 1).BroadcastTx(tx)
_, err := context.NewCLIContext().WithNodeURI(node).BroadcastTx(tx)
return err
}
@ -167,6 +173,7 @@ func (c relayCommander) getSequence(node string) int64 {
if err != nil {
panic(err)
}
if nil != res {
account, err := c.decoder(res)
if err != nil {
@ -191,10 +198,13 @@ func (c relayCommander) refine(bz []byte, sequence int64, passphrase string) []b
Sequence: sequence,
}
ctx := context.NewCoreContextFromViper().WithSequence(sequence)
res, err := ctx.SignAndBuild(ctx.FromAddressName, passphrase, []sdk.Msg{msg}, c.cdc)
txCtx := authctx.NewTxContextFromCLI().WithSequence(sequence).WithCodec(c.cdc)
cliCtx := context.NewCLIContext()
res, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, []sdk.Msg{msg})
if err != nil {
panic(err)
}
return res
}

View File

@ -4,18 +4,19 @@ import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/gorilla/mux"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandlerFn(cdc, kb, ctx)).Methods("POST")
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
r.HandleFunc("/ibc/{destchain}/{address}/send", TransferRequestHandlerFn(cdc, kb, cliCtx)).Methods("POST")
}
type transferBody struct {
@ -31,9 +32,8 @@ type transferBody struct {
// TransferRequestHandler - http request handler to transfer coins to a address
// on a different chain via IBC
func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// collect data
vars := mux.Vars(r)
destChainID := vars["destchain"]
bech32addr := vars["address"]
@ -52,6 +52,7 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
w.Write([]byte(err.Error()))
return
}
err = cdc.UnmarshalJSON(body, &m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
@ -70,21 +71,22 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
packet := ibc.NewIBCPacket(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount, m.SrcChainID, destChainID)
msg := ibc.IBCTransferMsg{packet}
// add gas to context
ctx = ctx.WithGas(m.Gas)
txCtx := authctx.TxContext{
Codec: cdc,
ChainID: m.SrcChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
Gas: m.Gas,
}
// sign
ctx = ctx.WithAccountNumber(m.AccountNumber)
ctx = ctx.WithSequence(m.Sequence)
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc)
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
return
}
// send
res, err := ctx.BroadcastTx(txBytes)
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))

View File

@ -13,24 +13,26 @@ import (
"github.com/cosmos/cosmos-sdk/x/slashing"
)
// get the command to query signing info
// GetCmdQuerySigningInfo implements the command to query signing info.
func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "signing-info [validator-pubkey]",
Short: "Query a validator's signing information",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
pk, err := sdk.GetValPubKeyBech32(args[0])
if err != nil {
return err
}
key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address()))
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return err
}
signingInfo := new(slashing.ValidatorSigningInfo)
cdc.MustUnmarshalBinary(res, signingInfo)

View File

@ -1,38 +1,42 @@
package cli
import (
"github.com/spf13/cobra"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/spf13/cobra"
)
// create unrevoke command
// GetCmdUnrevoke implements the create unrevoke validator command.
func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unrevoke",
Args: cobra.ExactArgs(0),
Short: "unrevoke validator previously revoked for downtime",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
validatorAddr, err := ctx.GetFromAddress()
validatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
msg := slashing.NewMsgUnrevoke(validatorAddr)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
return cmd
}

View File

@ -4,26 +4,23 @@ import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/gorilla/mux"
)
func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc(
"/slashing/signing_info/{validator}",
signingInfoHandlerFn(ctx, "slashing", cdc),
signingInfoHandlerFn(cliCtx, "slashing", cdc),
).Methods("GET")
}
// http request handler to query signing info
func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
pk, err := sdk.GetValPubKeyBech32(vars["validator"])
@ -34,7 +31,8 @@ func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.C
}
key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address()))
res, err := ctx.QueryStore(key, storeName)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query signing info. Error: %s", err.Error())))
@ -42,6 +40,7 @@ func signingInfoHandlerFn(ctx context.CoreContext, storeName string, cdc *wire.C
}
var signingInfo slashing.ValidatorSigningInfo
err = cdc.UnmarshalBinary(res, &signingInfo)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)

View File

@ -1,15 +1,15 @@
package rest
import (
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/gorilla/mux"
)
// RegisterRoutes registers staking-related REST handlers to a router
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
registerQueryRoutes(ctx, r, cdc)
registerTxRoutes(ctx, r, cdc, kb)
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
registerQueryRoutes(cliCtx, r, cdc)
registerTxRoutes(cliCtx, r, cdc, kb)
}

View File

@ -7,19 +7,20 @@ import (
"io/ioutil"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/gorilla/mux"
)
func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
r.HandleFunc(
"/slashing/unrevoke",
unrevokeRequestHandlerFn(cdc, kb, ctx),
unrevokeRequestHandlerFn(cdc, kb, cliCtx),
).Methods("POST")
}
@ -34,7 +35,7 @@ type UnrevokeBody struct {
ValidatorAddr string `json:"validator_addr"`
}
func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m UnrevokeBody
body, err := ioutil.ReadAll(r.Body)
@ -70,21 +71,24 @@ func unrevokeRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.Core
return
}
ctx = ctx.WithGas(m.Gas)
ctx = ctx.WithChainID(m.ChainID)
ctx = ctx.WithAccountNumber(m.AccountNumber)
ctx = ctx.WithSequence(m.Sequence)
txCtx := authctx.TxContext{
Codec: cdc,
ChainID: m.ChainID,
AccountNumber: m.AccountNumber,
Sequence: m.Sequence,
Gas: m.Gas,
}
msg := slashing.NewMsgUnrevoke(validatorAddr)
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc)
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
return
}
res, err := ctx.BroadcastTx(txBytes)
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))

View File

@ -14,26 +14,28 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
// get the command to query a validator
// GetCmdQueryValidator implements the validator query command.
func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "validator [owner-addr]",
Short: "Query a validator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
addr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
key := stake.GetValidatorKey(addr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return err
} else if len(res) == 0 {
return fmt.Errorf("No validator found with address %s", args[0])
}
validator := types.MustUnmarshalValidator(cdc, addr, res)
switch viper.Get(cli.OutputFlag) {
@ -50,9 +52,11 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
fmt.Println(string(output))
}
// TODO output with proofs / machine parseable etc.
// TODO: output with proofs / machine parseable etc.
return nil
},
}
@ -60,16 +64,16 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
return cmd
}
// get the command to query a validator
// GetCmdQueryValidators implements the query all validators command.
func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "validators",
Short: "Query for all validators",
RunE: func(cmd *cobra.Command, args []string) error {
key := stake.ValidatorsKey
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
resKVs, err := cliCtx.QuerySubspace(key, storeName)
if err != nil {
return err
}
@ -89,6 +93,7 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
fmt.Println(resp)
}
case "json":
@ -96,24 +101,25 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
return nil
// TODO output with proofs / machine parseable etc.
// TODO: output with proofs / machine parseable etc.
return nil
},
}
return cmd
}
// get the command to query a single delegation
// GetCmdQueryDelegation the query delegation command.
func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "delegation",
Short: "Query a delegation based on address and validator address",
RunE: func(cmd *cobra.Command, args []string) error {
valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
@ -125,8 +131,9 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
}
key := stake.GetDelegationKey(delAddr, valAddr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return err
}
@ -140,39 +147,45 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
fmt.Println(resp)
case "json":
output, err := wire.MarshalJSONIndent(cdc, delegation)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
return nil
},
}
cmd.Flags().AddFlagSet(fsValidator)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
}
// get the command to query all the delegations made from one delegator
// GetCmdQueryDelegations implements the command to query all the delegations
// made from one delegator.
func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "delegations [delegator-addr]",
Short: "Query all delegations made from one delegator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
delegatorAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
key := stake.GetDelegationsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
resKVs, err := cliCtx.QuerySubspace(key, storeName)
if err != nil {
return err
}
@ -188,22 +201,24 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
fmt.Println(string(output))
return nil
// TODO output with proofs / machine parseable etc.
fmt.Println(string(output))
// TODO: output with proofs / machine parseable etc.
return nil
},
}
return cmd
}
// get the command to query a single unbonding-delegation record
// GetCmdQueryUnbondingDelegation implements the command to query a single
// unbonding-delegation record.
func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unbonding-delegation",
Short: "Query an unbonding-delegation record based on delegator and validator address",
RunE: func(cmd *cobra.Command, args []string) error {
valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
@ -215,8 +230,9 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
}
key := stake.GetUBDKey(delAddr, valAddr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return err
}
@ -230,39 +246,45 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
if err != nil {
return err
}
fmt.Println(resp)
case "json":
output, err := wire.MarshalJSONIndent(cdc, ubd)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
return nil
},
}
cmd.Flags().AddFlagSet(fsValidator)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
}
// get the command to query all the unbonding-delegation records for a delegator
// GetCmdQueryUnbondingDelegations implements the command to query all the
// unbonding-delegation records for a delegator.
func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unbonding-delegations [delegator-addr]",
Short: "Query all unbonding-delegations records for one delegator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
delegatorAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
key := stake.GetUBDsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
resKVs, err := cliCtx.QuerySubspace(key, storeName)
if err != nil {
return err
}
@ -278,38 +300,43 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
if err != nil {
return err
}
fmt.Println(string(output))
return nil
// TODO output with proofs / machine parseable etc.
fmt.Println(string(output))
// TODO: output with proofs / machine parseable etc.
return nil
},
}
return cmd
}
// get the command to query a single unbonding-delegation record
// GetCmdQueryRedelegation implements the command to query a single
// unbonding-delegation record.
func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unbonding-delegation",
Short: "Query an unbonding-delegation record based on delegator and validator address",
RunE: func(cmd *cobra.Command, args []string) error {
valSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
if err != nil {
return err
}
valDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
if err != nil {
return err
}
delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
if err != nil {
return err
}
key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr)
ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return err
}
@ -323,39 +350,45 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
fmt.Println(resp)
case "json":
output, err := wire.MarshalJSONIndent(cdc, red)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
}
return nil
},
}
cmd.Flags().AddFlagSet(fsRedelegation)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
}
// get the command to query all the unbonding-delegation records for a delegator
// GetCmdQueryRedelegations implements the command to query all the
// unbonding-delegation records for a delegator.
func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unbonding-delegations [delegator-addr]",
Short: "Query all unbonding-delegations records for one delegator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
delegatorAddr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
return err
}
key := stake.GetREDsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
cliCtx := context.NewCLIContext().WithCodec(cdc)
resKVs, err := cliCtx.QuerySubspace(key, storeName)
if err != nil {
return err
}
@ -371,11 +404,13 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
if err != nil {
return err
}
fmt.Println(string(output))
return nil
// TODO output with proofs / machine parseable etc.
fmt.Println(string(output))
// TODO: output with proofs / machine parseable etc.
return nil
},
}
return cmd
}

View File

@ -2,27 +2,34 @@ package cli
import (
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
// create create validator command
// GetCmdCreateValidator implements the create validator command handler.
func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "create-validator",
Short: "create new validator initialized with a self-delegation to it",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
amounstStr := viper.GetString(FlagAmount)
if amounstStr == "" {
@ -32,7 +39,8 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
validatorAddr, err := ctx.GetFromAddress()
validatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -41,13 +49,16 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
if len(pkStr) == 0 {
return fmt.Errorf("must use --pubkey flag")
}
pk, err := sdk.GetValPubKeyBech32(pkStr)
if err != nil {
return err
}
if viper.GetString(FlagMoniker) == "" {
return fmt.Errorf("please enter a moniker for the validator using --moniker")
}
description := stake.Description{
Moniker: viper.GetString(FlagMoniker),
Identity: viper.GetString(FlagIdentity),
@ -61,17 +72,14 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
if err != nil {
return err
}
msg = stake.NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, amount, description)
} else {
msg = stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
}
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
@ -79,21 +87,27 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsDescriptionCreate)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
}
// create edit validator command
// GetCmdEditValidator implements the create edit validator command.
func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "edit-validator",
Short: "edit and existing validator account",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
validatorAddr, err := ctx.GetFromAddress()
validatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
description := stake.Description{
Moniker: viper.GetString(FlagMoniker),
Identity: viper.GetString(FlagIdentity),
@ -103,36 +117,37 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgEditValidator(validatorAddr, description)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsDescriptionEdit)
return cmd
}
// delegate command
// GetCmdDelegate implements the delegate command.
func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "delegate",
Short: "delegate liquid tokens to an validator",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
amount, err := sdk.ParseCoin(viper.GetString(FlagAmount))
if err != nil {
return err
}
delegatorAddr, err := ctx.GetFromAddress()
delegatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
@ -141,51 +156,55 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgDelegate(delegatorAddr, validatorAddr, amount)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsValidator)
return cmd
}
// create edit validator command
// GetCmdRedelegate implements the redelegate validator command.
func GetCmdRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "redelegate",
Short: "redelegate illiquid tokens from one validator to another",
}
cmd.AddCommand(
client.PostCommands(
GetCmdBeginRedelegate(storeName, cdc),
GetCmdCompleteRedelegate(cdc),
)...)
return cmd
}
// redelegate command
// GetCmdBeginRedelegate the begin redelegation command.
func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "begin",
Short: "begin redelegation",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
var err error
delegatorAddr, err := ctx.GetFromAddress()
delegatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
if err != nil {
return err
}
validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
if err != nil {
return err
@ -194,8 +213,10 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
// get the shares amount
sharesAmountStr := viper.GetString(FlagSharesAmount)
sharesPercentStr := viper.GetString(FlagSharesPercent)
sharesAmount, err := getShares(storeName, cdc, sharesAmountStr, sharesPercentStr,
delegatorAddr, validatorSrcAddr)
sharesAmount, err := getShares(
storeName, cdc, sharesAmountStr, sharesPercentStr,
delegatorAddr, validatorSrcAddr,
)
if err != nil {
return err
}
@ -203,25 +224,22 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr, sharesAmount)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsShares)
cmd.Flags().AddFlagSet(fsRedelegation)
return cmd
}
// nolint: gocyclo
// TODO: Make this pass gocyclo linting
func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercentStr string,
delegatorAddr, validatorAddr sdk.AccAddress) (sharesAmount sdk.Rat, err error) {
func getShares(
storeName string, cdc *wire.Codec, sharesAmountStr,
sharesPercentStr string, delegatorAddr, validatorAddr sdk.AccAddress,
) (sharesAmount sdk.Rat, err error) {
switch {
case sharesAmountStr != "" && sharesPercentStr != "":
return sharesAmount, errors.Errorf("can either specify the amount OR the percent of the shares, not both")
@ -247,33 +265,44 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent
// make a query to get the existing delegation shares
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
ctx := context.NewCoreContextFromViper()
resQuery, err := ctx.QueryStore(key, storeName)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
resQuery, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return sharesAmount, errors.Errorf("cannot find delegation to determine percent Error: %v", err)
}
delegation := types.MustUnmarshalDelegation(cdc, key, resQuery)
sharesAmount = sharesPercent.Mul(delegation.Shares)
}
return
}
// redelegate command
// GetCmdCompleteRedelegate implements the complete redelegation command.
func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "complete",
Short: "complete redelegation",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
delegatorAddr, err := ctx.GetFromAddress()
delegatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
if err != nil {
return err
}
validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
if err != nil {
return err
@ -282,44 +311,48 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgCompleteRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsRedelegation)
return cmd
}
// create edit validator command
// GetCmdUnbond implements the unbond validator command.
func GetCmdUnbond(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unbond",
Short: "begin or complete unbonding shares from a validator",
}
cmd.AddCommand(
client.PostCommands(
GetCmdBeginUnbonding(storeName, cdc),
GetCmdCompleteUnbonding(cdc),
)...)
return cmd
}
// create edit validator command
// GetCmdBeginUnbonding implements the begin unbonding validator command.
func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "begin",
Short: "begin unbonding",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
delegatorAddr, err := ctx.GetFromAddress()
delegatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
@ -328,8 +361,10 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
// get the shares amount
sharesAmountStr := viper.GetString(FlagSharesAmount)
sharesPercentStr := viper.GetString(FlagSharesPercent)
sharesAmount, err := getShares(storeName, cdc, sharesAmountStr, sharesPercentStr,
delegatorAddr, validatorAddr)
sharesAmount, err := getShares(
storeName, cdc, sharesAmountStr, sharesPercentStr,
delegatorAddr, validatorAddr,
)
if err != nil {
return err
}
@ -337,32 +372,33 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sharesAmount)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsShares)
cmd.Flags().AddFlagSet(fsValidator)
return cmd
}
// create edit validator command
// GetCmdCompleteUnbonding implements the complete unbonding validator command.
func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "complete",
Short: "complete unbonding",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
txCtx := authctx.NewTxContextFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
delegatorAddr, err := ctx.GetFromAddress()
delegatorAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
@ -371,14 +407,11 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgCompleteUnbonding(delegatorAddr, validatorAddr)
// build and sign the transaction, then broadcast to Tendermint
err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
return nil
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().AddFlagSet(fsValidator)
return cmd
}

View File

@ -4,46 +4,42 @@ import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/gorilla/mux"
)
const storeName = "stake"
func registerQueryRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec) {
func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec) {
r.HandleFunc(
"/stake/{delegator}/delegation/{validator}",
delegationHandlerFn(ctx, cdc),
delegationHandlerFn(cliCtx, cdc),
).Methods("GET")
r.HandleFunc(
"/stake/{delegator}/ubd/{validator}",
ubdHandlerFn(ctx, cdc),
ubdHandlerFn(cliCtx, cdc),
).Methods("GET")
r.HandleFunc(
"/stake/{delegator}/red/{validator_src}/{validator_dst}",
redHandlerFn(ctx, cdc),
redHandlerFn(cliCtx, cdc),
).Methods("GET")
r.HandleFunc(
"/stake/validators",
validatorsHandlerFn(ctx, cdc),
validatorsHandlerFn(cliCtx, cdc),
).Methods("GET")
}
// http request handler to query a delegation
func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegator"]
bech32validator := vars["validator"]
@ -64,7 +60,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
res, err := ctx.QueryStore(key, storeName)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query delegation. Error: %s", err.Error())))
@ -96,10 +92,8 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
}
// http request handler to query an unbonding-delegation
func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
func ubdHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegator"]
bech32validator := vars["validator"]
@ -120,7 +114,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
key := stake.GetUBDKey(delegatorAddr, validatorAddr)
res, err := ctx.QueryStore(key, storeName)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
@ -152,9 +146,8 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
}
// http request handler to query an redelegation
func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
func redHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegator"]
@ -184,7 +177,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr)
res, err := ctx.QueryStore(key, storeName)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query redelegation. Error: %s", err.Error())))
@ -217,9 +210,9 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
// TODO bech32
// http request handler to query list of validators
func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
func validatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
kvs, err := ctx.QuerySubspace(cdc, stake.ValidatorsKey, storeName)
kvs, err := cliCtx.QuerySubspace(stake.ValidatorsKey, storeName)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't query validators. Error: %s", err.Error())))

View File

@ -1,15 +1,15 @@
package rest
import (
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/gorilla/mux"
)
// RegisterRoutes registers staking-related REST handlers to a router
func RegisterRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
registerQueryRoutes(ctx, r, cdc)
registerTxRoutes(ctx, r, cdc, kb)
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
registerQueryRoutes(cliCtx, r, cdc)
registerTxRoutes(cliCtx, r, cdc, kb)
}

View File

@ -6,21 +6,23 @@ import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/gorilla/mux"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/gorilla/mux"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
func registerTxRoutes(ctx context.CoreContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, kb keys.Keybase) {
r.HandleFunc(
"/stake/delegations",
editDelegationsRequestHandlerFn(cdc, kb, ctx),
editDelegationsRequestHandlerFn(cdc, kb, cliCtx),
).Methods("POST")
}
@ -67,15 +69,17 @@ type EditDelegationsBody struct {
// nolint: gocyclo
// TODO: Split this up into several smaller functions, and remove the above nolint
func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx context.CoreContext) http.HandlerFunc {
func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m EditDelegationsBody
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
err = cdc.UnmarshalJSON(body, &m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
@ -105,22 +109,26 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address"))
return
}
messages[i] = stake.MsgDelegate{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
Delegation: msg.Delegation,
}
i++
}
@ -131,35 +139,41 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address"))
return
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
validatorDstAddr, err := sdk.AccAddressFromBech32(msg.ValidatorDstAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error())))
return
}
messages[i] = stake.MsgBeginRedelegate{
DelegatorAddr: delegatorAddr,
ValidatorSrcAddr: validatorSrcAddr,
ValidatorDstAddr: validatorDstAddr,
SharesAmount: shares,
}
i++
}
@ -170,28 +184,33 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
validatorDstAddr, err := sdk.AccAddressFromBech32(msg.ValidatorDstAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address"))
return
}
messages[i] = stake.MsgCompleteRedelegate{
DelegatorAddr: delegatorAddr,
ValidatorSrcAddr: validatorSrcAddr,
ValidatorDstAddr: validatorDstAddr,
}
i++
}
@ -202,28 +221,33 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address"))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
shares, err := sdk.NewRatFromDecimal(msg.SharesAmount, types.MaxBondDenominatorPrecision)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error())))
return
}
messages[i] = stake.MsgBeginUnbonding{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
SharesAmount: shares,
}
i++
}
@ -234,36 +258,44 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
w.Write([]byte(fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error())))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error())))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Must use own delegator address"))
return
}
messages[i] = stake.MsgCompleteUnbonding{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
}
i++
}
// add gas to context
ctx = ctx.WithGas(m.Gas)
txCtx := authctx.TxContext{
Codec: cdc,
ChainID: m.ChainID,
Gas: m.Gas,
}
// sign messages
signedTxs := make([][]byte, len(messages[:]))
for i, msg := range messages {
// increment sequence for each message
ctx = ctx.WithAccountNumber(m.AccountNumber)
ctx = ctx.WithSequence(m.Sequence)
txCtx = txCtx.WithAccountNumber(m.AccountNumber)
txCtx = txCtx.WithSequence(m.Sequence)
m.Sequence++
txBytes, err := ctx.SignAndBuild(m.LocalAccountName, m.Password, []sdk.Msg{msg}, cdc)
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(err.Error()))
@ -278,12 +310,13 @@ func editDelegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, ctx conte
// should we have a sdk.MultiMsg type to make sending atomic?
results := make([]*ctypes.ResultBroadcastTxCommit, len(signedTxs[:]))
for i, txBytes := range signedTxs {
res, err := ctx.BroadcastTx(txBytes)
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
results[i] = res
}