2018-03-30 04:27:58 -07:00
|
|
|
package core
|
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) {
|
2018-03-17 08:49:47 -07:00
|
|
|
|
|
|
|
// build the Sign Messsage from the Standard Message
|
2018-03-30 05:57:53 -07:00
|
|
|
chainID := ctx.ChainID
|
|
|
|
sequence := ctx.Sequence
|
2018-03-17 08:49:47 -07:00
|
|
|
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-03-30 05:57:53 -07:00
|
|
|
func (ctx CoreContext) SignBuildBroadcast(name string, msg sdk.Msg, cdc *wire.Codec) (*ctypes.ResultBroadcastTxCommit, error) {
|
|
|
|
passphrase, err := ctx.GetPassphraseFromStdin(name)
|
2018-03-24 23:08:27 -07:00
|
|
|
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
|
|
|
}
|
2018-03-24 23:08:27 -07:00
|
|
|
|
|
|
|
// get passphrase from std input
|
2018-03-30 05:57:53 -07:00
|
|
|
func (ctx CoreContext) GetPassphraseFromStdin(name string) (pass string, err error) {
|
2018-03-24 23:08:27 -07:00
|
|
|
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.NodeURI == "" {
|
|
|
|
return nil, errors.New("Must define node URI")
|
|
|
|
}
|
|
|
|
return rpcclient.NewHTTP(ctx.NodeURI, "/websocket"), nil
|
|
|
|
}
|