From b6347db664103d6adc4de248ddb5dcac1afe06f0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 3 Mar 2018 19:07:50 +0000 Subject: [PATCH] refactor client --- client/builder/builder.go | 127 ++++++++++++++++++++ client/flags.go | 4 + client/helpers.go | 54 --------- examples/basecoin/x/cool/commands/cooltx.go | 51 ++++++++ x/auth/commands/account.go | 4 +- x/bank/commands/sendtx.go | 3 +- 6 files changed, 186 insertions(+), 57 deletions(-) create mode 100644 client/builder/builder.go create mode 100644 examples/basecoin/x/cool/commands/cooltx.go diff --git a/client/builder/builder.go b/client/builder/builder.go new file mode 100644 index 000000000..65c2ffe43 --- /dev/null +++ b/client/builder/builder.go @@ -0,0 +1,127 @@ +package builder + +import ( + "fmt" + + "github.com/pkg/errors" + "github.com/spf13/viper" + + "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 +func BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) { + + node, err := client.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 +} + +// Query from Tendermint with the provided key and storename +func Query(key cmn.HexBytes, storeName string) (res []byte, err error) { + + path := fmt.Sprintf("/%s/key", storeName) + node, err := client.GetNode() + if err != nil { + return res, err + } + + opts := rpcclient.ABCIQueryOptions{ + Height: viper.GetInt64(client.FlagHeight), + Trusted: viper.GetBool(client.FlagTrustNode), + } + 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 +func GetFromAddress() (from sdk.Address, err error) { + + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + + name := viper.GetString(client.FlagName) + 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 +func SignAndBuild(msg sdk.Msg, cdc *wire.Codec) ([]byte, error) { + + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + name := viper.GetString(client.FlagName) + + // sign and build + bz := msg.GetSignBytes() + buf := client.BufferStdin() + prompt := fmt.Sprintf("Password to sign with '%s':", name) + passphrase, err := client.GetPassword(prompt, buf) + if err != nil { + return nil, err + } + sig, pubkey, err := keybase.Sign(name, passphrase, bz) + if err != nil { + return nil, err + } + sigs := []sdk.StdSignature{{ + PubKey: pubkey, + Signature: sig, + Sequence: viper.GetInt64(client.FlagSequence), + }} + + // marshal bytes + tx := sdk.NewStdTx(msg, sigs) + + return cdc.MarshalBinary(tx) +} + +// sign and build the transaction from the msg +func SignBuildBroadcast(msg sdk.Msg, cdc *wire.Codec) (*ctypes.ResultBroadcastTxCommit, error) { + txBytes, err := SignAndBuild(msg, cdc) + if err != nil { + return nil, err + } + + return BroadcastTx(txBytes) +} diff --git a/client/flags.go b/client/flags.go index 843cb52d1..ceaf5a3a9 100644 --- a/client/flags.go +++ b/client/flags.go @@ -9,6 +9,8 @@ const ( FlagHeight = "height" FlagTrustNode = "trust-node" FlagName = "name" + FlagSequence = "sequence" + FlagFee = "fee" ) // LineBreak can be included in a command list to provide a blank line @@ -31,6 +33,8 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command { func PostCommands(cmds ...*cobra.Command) []*cobra.Command { for _, c := range cmds { c.Flags().String(FlagName, "", "Name of private key with which to sign") + c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx") + c.Flags().String(FlagFee, "", "Fee to pay along with transaction") c.Flags().String(FlagChainID, "", "Chain ID of tendermint node") c.Flags().String(FlagNode, "tcp://localhost:46657", ": to tendermint rpc interface for this chain") } diff --git a/client/helpers.go b/client/helpers.go index 10ffcc88e..f383b95f7 100644 --- a/client/helpers.go +++ b/client/helpers.go @@ -1,14 +1,10 @@ package client import ( - "fmt" - "github.com/pkg/errors" "github.com/spf13/viper" rpcclient "github.com/tendermint/tendermint/rpc/client" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - cmn "github.com/tendermint/tmlibs/common" ) // GetNode prepares a simple rpc.Client from the flags @@ -19,53 +15,3 @@ func GetNode() (rpcclient.Client, error) { } return rpcclient.NewHTTP(uri, "/websocket"), nil } - -// Broadcast the transaction bytes to Tendermint -func BroadcastTx(tx []byte) (*ctypes.ResultBroadcastTxCommit, error) { - - node, err := 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 -} - -// Query from Tendermint with the provided key and storename -func Query(key cmn.HexBytes, storeName string) (res []byte, err error) { - - path := fmt.Sprintf("/%s/key", storeName) - node, err := GetNode() - if err != nil { - return res, err - } - - opts := rpcclient.ABCIQueryOptions{ - Height: viper.GetInt64(FlagHeight), - Trusted: viper.GetBool(FlagTrustNode), - } - 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 -} diff --git a/examples/basecoin/x/cool/commands/cooltx.go b/examples/basecoin/x/cool/commands/cooltx.go new file mode 100644 index 000000000..8a8452a00 --- /dev/null +++ b/examples/basecoin/x/cool/commands/cooltx.go @@ -0,0 +1,51 @@ +package commands + +import ( + "fmt" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client/builder" + "github.com/cosmos/cosmos-sdk/wire" + + "github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool" +) + +// SendTxCommand will create a send tx and sign it with the given key +func WhatCoolTxCmd(cdc *wire.Codec) *cobra.Command { + cmdr := commander{cdc} + return &cobra.Command{ + Use: "whatcool [answer]", + Short: "What's cooler than being cool?", + RunE: cmdr.whatCoolTxCmd, + } +} + +type commander struct { + cdc *wire.Codec +} + +func (c commander) whatCoolTxCmd(cmd *cobra.Command, args []string) error { + if len(args) != 1 || len(args[0]) == 0 { + return errors.New("You must provide an answer") + } + + // get the from address from the name flag + from, err := builder.GetFromAddress() + if err != nil { + return err + } + + // create the message + msg := cool.NewWhatCoolMsg(from, args[0]) + + // build and sign the transaction, then broadcast to Tendermint + res, err := builder.SignBuildBroadcast(msg, c.cdc) + if err != nil { + return err + } + + fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) + return nil +} diff --git a/x/auth/commands/account.go b/x/auth/commands/account.go index 86df60a38..a8bbfa226 100644 --- a/x/auth/commands/account.go +++ b/x/auth/commands/account.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/builder" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" @@ -61,7 +61,7 @@ func (c commander) getAccountCmd(cmd *cobra.Command, args []string) error { } key := sdk.Address(bz) - res, err := client.Query(key, c.storeName) + res, err := builder.Query(key, c.storeName) // parse out the value account, err := c.parser(res) diff --git a/x/bank/commands/sendtx.go b/x/bank/commands/sendtx.go index af171fb72..8d0c0be6e 100644 --- a/x/bank/commands/sendtx.go +++ b/x/bank/commands/sendtx.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/builder" "github.com/cosmos/cosmos-sdk/client/keys" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -48,7 +49,7 @@ func (c commander) sendTxCmd(cmd *cobra.Command, args []string) error { return err } - res, err := client.BroadcastTx(txBytes) + res, err := builder.BroadcastTx(txBytes) if err != nil { return err }