cosmos-sdk/client/context/helpers.go

183 lines
4.2 KiB
Go
Raw Normal View History

2018-04-18 12:39:32 -07:00
package context
2018-03-03 11:07:50 -08:00
import (
"fmt"
"github.com/pkg/errors"
"github.com/cosmos/cosmos-sdk/wire"
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
cmn "github.com/tendermint/tmlibs/common"
"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
2018-03-30 05:57:53 -07:00
func (ctx CoreContext) BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) {
2018-03-03 11:07:50 -08:00
2018-03-30 05:57:53 -07:00
node, err := ctx.GetNode()
2018-03-03 11:07:50 -08:00
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
}
// Query from Tendermint with the provided key and storename
2018-03-30 05:57:53 -07:00
func (ctx CoreContext) Query(key cmn.HexBytes, storeName string) (res []byte, err error) {
2018-03-03 11:07:50 -08:00
path := fmt.Sprintf("/%s/key", storeName)
2018-03-30 05:57:53 -07:00
node, err := ctx.GetNode()
2018-03-03 11:07:50 -08:00
if err != nil {
return res, err
}
opts := rpcclient.ABCIQueryOptions{
2018-03-30 05:57:53 -07:00
Height: ctx.Height,
Trusted: ctx.TrustNode,
2018-03-03 11:07:50 -08:00
}
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
}
// Get the from address from the name flag
2018-03-30 05:57:53 -07:00
func (ctx CoreContext) GetFromAddress() (from sdk.Address, err error) {
2018-03-03 11:07:50 -08:00
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
2018-03-30 05:57:53 -07:00
name := ctx.FromAddressName
2018-03-03 11:41:43 -08:00
if name == "" {
2018-03-30 05:57:53 -07:00
return nil, errors.Errorf("must provide a from address name")
2018-03-03 11:41:43 -08:00
}
2018-03-03 11:07:50 -08:00
info, err := keybase.Get(name)
if err != nil {
return nil, errors.Errorf("No key for: %s", name)
}
return info.PubKey.Address(), nil
}
// sign and build the transaction from the msg
2018-03-30 05:57:53 -07:00
func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *wire.Codec) ([]byte, error) {
// build the Sign Messsage from the Standard Message
2018-03-30 05:57:53 -07:00
chainID := ctx.ChainID
if chainID == "" {
return nil, errors.Errorf("Chain ID required but not specified")
}
2018-03-30 05:57:53 -07:00
sequence := ctx.Sequence
signMsg := sdk.StdSignMsg{
ChainID: chainID,
Sequences: []int64{sequence},
Msg: msg,
}
2018-03-03 11:07:50 -08:00
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
// sign and build
2018-03-14 05:11:19 -07:00
bz := signMsg.Bytes()
2018-03-17 17:42:18 -07:00
2018-03-03 11:07:50 -08:00
sig, pubkey, err := keybase.Sign(name, passphrase, bz)
if err != nil {
return nil, err
}
sigs := []sdk.StdSignature{{
PubKey: pubkey,
Signature: sig,
2018-03-30 05:57:53 -07:00
Sequence: sequence,
2018-03-03 11:07:50 -08:00
}}
// marshal bytes
2018-03-17 11:54:18 -07:00
tx := sdk.NewStdTx(signMsg.Msg, signMsg.Fee, sigs)
2018-03-03 11:07:50 -08:00
return cdc.MarshalBinary(tx)
}
// sign and build the transaction from the msg
2018-04-18 21:49:24 -07:00
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) {
// default to next sequence number if none provided
ctx, err = EnsureSequence(ctx)
if err != nil {
return nil, err
}
2018-03-30 05:57:53 -07:00
passphrase, err := ctx.GetPassphraseFromStdin(name)
if err != nil {
return nil, err
}
2018-03-30 05:57:53 -07:00
txBytes, err := ctx.SignAndBuild(name, passphrase, msg, cdc)
2018-03-03 11:07:50 -08:00
if err != nil {
return nil, err
}
2018-03-30 05:57:53 -07:00
return ctx.BroadcastTx(txBytes)
2018-03-03 11:07:50 -08:00
}
// get the next sequence for the account address
2018-04-18 12:39:32 -07:00
func (ctx CoreContext) NextSequence(address []byte) (int64, error) {
if ctx.Decoder == nil {
return 0, errors.New("AccountDecoder required but not provided")
}
2018-04-18 12:39:32 -07:00
res, err := ctx.Query(address, ctx.AccountStore)
if err != nil {
return 0, err
}
2018-04-18 12:39:32 -07:00
account, err := ctx.Decoder(res)
if err != nil {
panic(err)
}
return account.GetSequence(), nil
}
// get passphrase from std input
2018-03-30 05:57:53 -07:00
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)
}
2018-03-30 05:57:53 -07:00
// GetNode prepares a simple rpc.Client
func (ctx CoreContext) GetNode() (rpcclient.Client, error) {
if ctx.Client == nil {
2018-03-30 05:57:53 -07:00
return nil, errors.New("Must define node URI")
}
return ctx.Client, nil
2018-03-30 05:57:53 -07:00
}