Merge PR #1741: CoreContext Refactor
This commit is contained in:
parent
3c4985c315
commit
12c2c236c2
|
@ -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"
|
||||
|
|
12
PENDING.md
12
PENDING.md
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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())))
|
||||
|
|
|
@ -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})
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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())))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue