reorganize basecli appTx commands

int
This commit is contained in:
rigel rozanski 2017-06-16 04:57:45 -04:00 committed by Ethan Frey
parent ad17fcf347
commit 9c8ccefd35
4 changed files with 100 additions and 107 deletions

View File

@ -10,41 +10,48 @@ import (
"github.com/tendermint/light-client/commands" "github.com/tendermint/light-client/commands"
txcmd "github.com/tendermint/light-client/commands/txs" txcmd "github.com/tendermint/light-client/commands/txs"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
cmn "github.com/tendermint/tmlibs/common"
btypes "github.com/tendermint/basecoin/types" btypes "github.com/tendermint/basecoin/types"
) )
/*** Here is the sendtx command ***/ /******** SendTx *********/
// SendTxCmd is CLI command to send tokens between basecoin accounts
var SendTxCmd = &cobra.Command{ var SendTxCmd = &cobra.Command{
Use: "send", Use: "send",
Short: "send tokens from one account to another", Short: "send tokens from one account to another",
RunE: doSendTx, RunE: doSendTx,
} }
//nolint
const ( const (
ToFlag = "to" FlagTo = "to"
AmountFlag = "amount" FlagAmount = "amount"
FeeFlag = "fee" FlagFee = "fee"
GasFlag = "gas" FlagGas = "gas"
SequenceFlag = "sequence" FlagSequence = "sequence"
) )
func init() { func init() {
flags := SendTxCmd.Flags() flags := SendTxCmd.Flags()
flags.String(ToFlag, "", "Destination address for the bits") flags.String(FlagTo, "", "Destination address for the bits")
flags.String(AmountFlag, "", "Coins to send in the format <amt><coin>,<amt><coin>...") flags.String(FlagAmount, "", "Coins to send in the format <amt><coin>,<amt><coin>...")
flags.String(FeeFlag, "0mycoin", "Coins for the transaction fee of the format <amt><coin>") flags.String(FlagFee, "0mycoin", "Coins for the transaction fee of the format <amt><coin>")
flags.Int64(GasFlag, 0, "Amount of gas for this transaction") flags.Int64(FlagGas, 0, "Amount of gas for this transaction")
flags.Int(SequenceFlag, -1, "Sequence number for this transaction") flags.Int(FlagSequence, -1, "Sequence number for this transaction")
} }
// runDemo is an example of how to make a tx // runDemo is an example of how to make a tx
func doSendTx(cmd *cobra.Command, args []string) error { func doSendTx(cmd *cobra.Command, args []string) error {
tx := new(btypes.SendTx)
// load data from json or flags // load data from json or flags
tx := new(btypes.SendTx)
found, err := txcmd.LoadJSON(tx) found, err := txcmd.LoadJSON(tx)
if err != nil {
return err
}
if !found { if !found {
err = readSendTxFlags(tx) err = readSendTxFlags(tx)
} }
@ -52,6 +59,7 @@ func doSendTx(cmd *cobra.Command, args []string) error {
return err return err
} }
// Wrap and add signer
send := &SendTx{ send := &SendTx{
chainID: commands.GetChainID(), chainID: commands.GetChainID(),
Tx: tx, Tx: tx,
@ -64,34 +72,34 @@ func doSendTx(cmd *cobra.Command, args []string) error {
return err return err
} }
// output result // Output result
return txcmd.OutputTx(bres) return txcmd.OutputTx(bres)
} }
func readSendTxFlags(tx *btypes.SendTx) error { func readSendTxFlags(tx *btypes.SendTx) error {
// parse to address // parse to address
to, err := ParseHexFlag(ToFlag) to, err := ParseHexFlag(FlagTo)
if err != nil { if err != nil {
return errors.Errorf("To address is invalid hex: %v\n", err) return errors.Errorf("To address is invalid hex: %v\n", err)
} }
//parse the fee and amounts into coin types //parse the fee and amounts into coin types
tx.Fee, err = btypes.ParseCoin(viper.GetString(FeeFlag)) tx.Fee, err = btypes.ParseCoin(viper.GetString(FlagFee))
if err != nil { if err != nil {
return err return err
} }
amountCoins, err := btypes.ParseCoins(viper.GetString(AmountFlag)) amountCoins, err := btypes.ParseCoins(viper.GetString(FlagAmount))
if err != nil { if err != nil {
return err return err
} }
// set the gas // set the gas
tx.Gas = viper.GetInt64(GasFlag) tx.Gas = viper.GetInt64(FlagGas)
// craft the inputs and outputs // craft the inputs and outputs
tx.Inputs = []btypes.TxInput{{ tx.Inputs = []btypes.TxInput{{
Coins: amountCoins, Coins: amountCoins,
Sequence: viper.GetInt(SequenceFlag), Sequence: viper.GetInt(FlagSequence),
}} }}
tx.Outputs = []btypes.TxOutput{{ tx.Outputs = []btypes.TxOutput{{
Address: to, Address: to,
@ -103,39 +111,53 @@ func readSendTxFlags(tx *btypes.SendTx) error {
/******** AppTx *********/ /******** AppTx *********/
// BroadcastAppTx wraps, signs, and executes an app tx basecoin transaction
func BroadcastAppTx(tx *btypes.AppTx) (*ctypes.ResultBroadcastTxCommit, error) {
// Generate app transaction to be broadcast
appTx := WrapAppTx(tx)
appTx.AddSigner(txcmd.GetSigner())
// Sign if needed and post to the node. This it the work-horse
return txcmd.SignAndPostTx(appTx)
}
// AddAppTxFlags adds flags required by apptx
func AddAppTxFlags(fs *flag.FlagSet) { func AddAppTxFlags(fs *flag.FlagSet) {
fs.String(AmountFlag, "", "Coins to send in the format <amt><coin>,<amt><coin>...") fs.String(FlagAmount, "", "Coins to send in the format <amt><coin>,<amt><coin>...")
fs.String(FeeFlag, "0mycoin", "Coins for the transaction fee of the format <amt><coin>") fs.String(FlagFee, "0mycoin", "Coins for the transaction fee of the format <amt><coin>")
fs.Int64(GasFlag, 0, "Amount of gas for this transaction") fs.Int64(FlagGas, 0, "Amount of gas for this transaction")
fs.Int(SequenceFlag, -1, "Sequence number for this transaction") fs.Int(FlagSequence, -1, "Sequence number for this transaction")
} }
// ReadAppTxFlags reads in the standard flags // ReadAppTxFlags reads in the standard flags
// your command should parse info to set tx.Name and tx.Data // your command should parse info to set tx.Name and tx.Data
func ReadAppTxFlags(tx *btypes.AppTx) error { func ReadAppTxFlags() (gas int64, fee btypes.Coin, txInput btypes.TxInput, err error) {
//parse the fee and amounts into coin types
var err error // Set the gas
tx.Fee, err = btypes.ParseCoin(viper.GetString(FeeFlag)) gas = viper.GetInt64(FlagGas)
// Parse the fee and amounts into coin types
fee, err = btypes.ParseCoin(viper.GetString(FlagFee))
if err != nil { if err != nil {
return err return
} }
amountCoins, err := btypes.ParseCoins(viper.GetString(AmountFlag))
// craft the inputs
var amount btypes.Coins
amount, err = btypes.ParseCoins(viper.GetString(FlagAmount))
if err != nil { if err != nil {
return err return
}
txInput = btypes.TxInput{
Coins: amount,
Sequence: viper.GetInt(FlagSequence),
} }
// set the gas return
tx.Gas = viper.GetInt64(GasFlag)
// craft the inputs and outputs
tx.Input = btypes.TxInput{
Coins: amountCoins,
Sequence: viper.GetInt(SequenceFlag),
}
return nil
} }
// WrapAppTx wraps the transaction with chain id
func WrapAppTx(tx *btypes.AppTx) *AppTx { func WrapAppTx(tx *btypes.AppTx) *AppTx {
return &AppTx{ return &AppTx{
chainID: commands.GetChainID(), chainID: commands.GetChainID(),
@ -145,25 +167,7 @@ func WrapAppTx(tx *btypes.AppTx) *AppTx {
/** TODO copied from basecoin cli - put in common somewhere? **/ /** TODO copied from basecoin cli - put in common somewhere? **/
// ParseHexFlag parses a flag string to byte array
func ParseHexFlag(flag string) ([]byte, error) { func ParseHexFlag(flag string) ([]byte, error) {
return hex.DecodeString(StripHex(viper.GetString(flag))) return hex.DecodeString(cmn.StripHex(viper.GetString(flag)))
}
// Returns true for non-empty hex-string prefixed with "0x"
func isHex(s string) bool {
if len(s) > 2 && s[:2] == "0x" {
_, err := hex.DecodeString(s[2:])
if err != nil {
return false
}
return true
}
return false
}
func StripHex(s string) string {
if isHex(s) {
return s[2:]
}
return s
} }

View File

@ -12,68 +12,72 @@ import (
btypes "github.com/tendermint/basecoin/types" btypes "github.com/tendermint/basecoin/types"
) )
//CounterTxCmd is the CLI command to execute the counter
// through the appTx Command
var CounterTxCmd = &cobra.Command{ var CounterTxCmd = &cobra.Command{
Use: "counter", Use: "counter",
Short: "add a vote to the counter", Short: "add a vote to the counter",
Long: `Add a vote to the counter. Long: `Add a vote to the counter.
You must pass --valid for it to count and the countfee will be added to the counter.`, You must pass --valid for it to count and the countfee will be added to the counter.`,
RunE: doCounterTx, RunE: counterTxCmd,
} }
const ( const (
CountFeeFlag = "countfee" flagCountFee = "countfee"
ValidFlag = "valid" flagValid = "valid"
) )
func init() { func init() {
fs := CounterTxCmd.Flags() fs := CounterTxCmd.Flags()
bcmd.AddAppTxFlags(fs) bcmd.AddAppTxFlags(fs)
fs.String(CountFeeFlag, "", "Coins to send in the format <amt><coin>,<amt><coin>...") fs.String(flagCountFee, "", "Coins to send in the format <amt><coin>,<amt><coin>...")
fs.Bool(ValidFlag, false, "Is count valid?") fs.Bool(flagValid, false, "Is count valid?")
} }
func doCounterTx(cmd *cobra.Command, args []string) error { func counterTxCmd(cmd *cobra.Command, args []string) error {
tx := new(btypes.AppTx)
// Note: we don't support loading apptx from json currently, so skip that // Note: we don't support loading apptx from json currently, so skip that
// read the standard flags // Read the app-specific flags
err := bcmd.ReadAppTxFlags(tx) name, data, err := getAppData()
if err != nil { if err != nil {
return err return err
} }
// now read the app-specific flags // Read the standard app-tx flags
err = readCounterFlags(tx) gas, fee, txInput, err := bcmd.ReadAppTxFlags()
if err != nil { if err != nil {
return err return err
} }
app := bcmd.WrapAppTx(tx) // Create AppTx and broadcast
app.AddSigner(txcmd.GetSigner()) tx := &btypes.AppTx{
Gas: gas,
// Sign if needed and post. This it the work-horse Fee: fee,
bres, err := txcmd.SignAndPostTx(app) Name: name,
Input: txInput,
Data: data,
}
res, err := bcmd.BroadcastAppTx(tx)
if err != nil { if err != nil {
return err return err
} }
// output result // Output result
return txcmd.OutputTx(bres) return txcmd.OutputTx(res)
} }
// readCounterFlags sets the app-specific data in the AppTx func getAppData() (name string, data []byte, err error) {
func readCounterFlags(tx *btypes.AppTx) error { countFee, err := btypes.ParseCoins(viper.GetString(flagCountFee))
countFee, err := btypes.ParseCoins(viper.GetString(CountFeeFlag))
if err != nil { if err != nil {
return err return
} }
ctx := counter.CounterTx{ ctx := counter.CounterTx{
Valid: viper.GetBool(ValidFlag), Valid: viper.GetBool(flagValid),
Fee: countFee, Fee: countFee,
} }
tx.Name = counter.New().Name() name = counter.New().Name()
tx.Data = wire.BinaryBytes(ctx) data = wire.BinaryBytes(ctx)
return nil return
} }

View File

@ -8,13 +8,14 @@ import (
"github.com/tendermint/basecoin/plugins/counter" "github.com/tendermint/basecoin/plugins/counter"
) )
//CounterQueryCmd CLI command to query the counter state
var CounterQueryCmd = &cobra.Command{ var CounterQueryCmd = &cobra.Command{
Use: "counter", Use: "counter",
Short: "Query counter state, with proof", Short: "Query counter state, with proof",
RunE: doCounterQuery, RunE: counterQueryCmd,
} }
func doCounterQuery(cmd *cobra.Command, args []string) error { func counterQueryCmd(cmd *cobra.Command, args []string) error {
key := counter.New().StateKey() key := counter.New().StateKey()
var cp counter.CounterPluginState var cp counter.CounterPluginState
@ -25,18 +26,3 @@ func doCounterQuery(cmd *cobra.Command, args []string) error {
return proofcmd.OutputProof(cp, proof.BlockHeight()) return proofcmd.OutputProof(cp, proof.BlockHeight())
} }
/*** doesn't seem to be needed anymore??? ***/
// type CounterPresenter struct{}
// func (_ CounterPresenter) MakeKey(str string) ([]byte, error) {
// key := counter.New().StateKey()
// return key, nil
// }
// func (_ CounterPresenter) ParseData(raw []byte) (interface{}, error) {
// var cp counter.CounterPluginState
// err := wire.ReadBinaryBytes(raw, &cp)
// return cp, err
// }

View File

@ -32,26 +32,25 @@ tmcli to work for any custom abci app.
func main() { func main() {
commands.AddBasicFlags(BaseCli) commands.AddBasicFlags(BaseCli)
// prepare queries // Prepare queries
pr := proofs.RootCmd pr := proofs.RootCmd
// these are default parsers, but you optional in your app // These are default parsers, but you optional in your app
pr.AddCommand(proofs.TxCmd) pr.AddCommand(proofs.TxCmd)
pr.AddCommand(proofs.KeyCmd) pr.AddCommand(proofs.KeyCmd)
pr.AddCommand(bcmd.AccountQueryCmd) pr.AddCommand(bcmd.AccountQueryCmd)
pr.AddCommand(bcount.CounterQueryCmd) pr.AddCommand(bcount.CounterQueryCmd)
// here is how you would add the custom txs... but don't really add demo in your app // Here is how you add custom txs... but don't really add counter in your app
proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{})
tr := txs.RootCmd tr := txs.RootCmd
tr.AddCommand(bcmd.SendTxCmd) tr.AddCommand(bcmd.SendTxCmd)
tr.AddCommand(bcount.CounterTxCmd) tr.AddCommand(bcount.CounterTxCmd)
// TODO // TODO
// txs.Register("send", bcmd.SendTxMaker{}) // txs.Register("send", bcmd.SendTxMaker{})
// txs.Register("counter", bcount.CounterTxMaker{}) // txs.Register("counter", bcount.CounterTxMaker{})
// set up the various commands to use // Set up the various commands to use
BaseCli.AddCommand( BaseCli.AddCommand(
commands.InitCmd, commands.InitCmd,
commands.ResetCmd, commands.ResetCmd,