diff --git a/cmd/basecli/commands/adapters.go b/cmd/basecli/commands/adapters.go index 7df8ca3384..f9bfe0f44b 100644 --- a/cmd/basecli/commands/adapters.go +++ b/cmd/basecli/commands/adapters.go @@ -2,126 +2,104 @@ package commands import ( "encoding/hex" - "encoding/json" "github.com/pkg/errors" + "github.com/spf13/cobra" flag "github.com/spf13/pflag" "github.com/spf13/viper" crypto "github.com/tendermint/go-crypto" - wire "github.com/tendermint/go-wire" - lightclient "github.com/tendermint/light-client" "github.com/tendermint/light-client/commands" - "github.com/tendermint/light-client/proofs" + txcmd "github.com/tendermint/light-client/commands/txs" btypes "github.com/tendermint/basecoin/types" ) -type BaseTxPresenter struct { - proofs.RawPresenter // this handles MakeKey as hex bytes +/*** Here is the sendtx command ***/ + +var SendTxCmd = &cobra.Command{ + Use: "send", + Short: "send tokens from one account to another", + RunE: doSendTx, } -func (_ BaseTxPresenter) ParseData(raw []byte) (interface{}, error) { - var tx btypes.TxS - err := wire.ReadBinaryBytes(raw, &tx) - return tx, err +const ( + ToFlag = "to" + AmountFlag = "amount" + FeeFlag = "fee" + GasFlag = "gas" + SequenceFlag = "sequence" +) + +func init() { + flags := SendTxCmd.Flags() + flags.String(ToFlag, "", "Destination address for the bits") + flags.String(AmountFlag, "", "Coins to send in the format ,...") + flags.String(FeeFlag, "0mycoin", "Coins for the transaction fee of the format ") + flags.Int64(GasFlag, 0, "Amount of gas for this transaction") + flags.Int(SequenceFlag, -1, "Sequence number for this transaction") } -/******** SendTx *********/ +// runDemo is an example of how to make a tx +func doSendTx(cmd *cobra.Command, args []string) error { + tx := new(btypes.SendTx) -type SendTxMaker struct{} - -func (m SendTxMaker) MakeReader() (lightclient.TxReader, error) { - chainID := viper.GetString(commands.ChainFlag) - return SendTxReader{ChainID: chainID}, nil -} - -type SendFlags struct { - To string - Amount string - Fee string - Gas int64 - Sequence int -} - -func (m SendTxMaker) Flags() (*flag.FlagSet, interface{}) { - fs := flag.NewFlagSet("", flag.ContinueOnError) - - fs.String("to", "", "Destination address for the bits") - fs.String("amount", "", "Coins to send in the format ,...") - fs.String("fee", "0mycoin", "Coins for the transaction fee of the format ") - fs.Int64("gas", 0, "Amount of gas for this transaction") - fs.Int("sequence", -1, "Sequence number for this transaction") - return fs, &SendFlags{} -} - -// SendTXReader allows us to create SendTx -type SendTxReader struct { - ChainID string -} - -func (t SendTxReader) ReadTxJSON(data []byte, pk crypto.PubKey) (interface{}, error) { - // TODO: use pk info to help construct data - var tx btypes.SendTx - err := json.Unmarshal(data, &tx) - send := SendTx{ - chainID: t.ChainID, - Tx: &tx, + // load data from json or flags + found, err := txcmd.LoadJSON(tx) + if !found { + err = readSendTxFlags(tx) } - return &send, errors.Wrap(err, "parse sendtx") + if err != nil { + return err + } + + send := &SendTx{ + chainID: viper.GetString(commands.ChainFlag), + Tx: tx, + } + send.AddSigner(txcmd.GetSigner()) + + // Sign if needed and post. This it the work-horse + bres, err := txcmd.SignAndPostTx(send) + if err != nil { + return err + } + + // output result + return txcmd.OutputTx(bres) } -func (t SendTxReader) ReadTxFlags(flags interface{}, pk crypto.PubKey) (interface{}, error) { - data := flags.(*SendFlags) - - // parse to and from addresses - to, err := hex.DecodeString(StripHex(data.To)) +func readSendTxFlags(tx *btypes.SendTx) error { + // parse to address + to, err := hex.DecodeString(StripHex(viper.GetString(ToFlag))) if err != nil { - return nil, 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 - feeCoin, err := btypes.ParseCoin(data.Fee) + tx.Fee, err = btypes.ParseCoin(viper.GetString(FeeFlag)) if err != nil { - return nil, err + return err } - amountCoins, err := btypes.ParseCoins(data.Amount) + amountCoins, err := btypes.ParseCoins(viper.GetString(AmountFlag)) if err != nil { - return nil, err + return err } - // get addr if available - var addr []byte - if !pk.Empty() { - addr = pk.Address() - } + // set the gas + tx.Gas = viper.GetInt64(GasFlag) - // craft the tx - input := btypes.TxInput{ - Address: addr, + // craft the inputs and outputs + tx.Inputs = []btypes.TxInput{{ Coins: amountCoins, - Sequence: data.Sequence, - } - if data.Sequence == 1 { - input.PubKey = pk - } - output := btypes.TxOutput{ + Sequence: viper.GetInt(SequenceFlag), + }} + tx.Outputs = []btypes.TxOutput{{ Address: to, Coins: amountCoins, - } - tx := btypes.SendTx{ - Gas: data.Gas, - Fee: feeCoin, - Inputs: []btypes.TxInput{input}, - Outputs: []btypes.TxOutput{output}, - } + }} - // wrap it in the proper signer thing... - send := SendTx{ - chainID: t.ChainID, - Tx: &tx, - } - return &send, nil + return nil } /******** AppTx *********/ diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go index 84098a4246..aea350d063 100644 --- a/cmd/basecli/commands/query.go +++ b/cmd/basecli/commands/query.go @@ -41,3 +41,15 @@ func doAccountQuery(cmd *cobra.Command, args []string) error { return proofcmd.OutputProof(acc, proof.BlockHeight()) } + +/*** this decodes the basecoin tx ***/ + +type BaseTxPresenter struct { + proofs.RawPresenter // this handles MakeKey as hex bytes +} + +func (_ BaseTxPresenter) ParseData(raw []byte) (interface{}, error) { + var tx btypes.TxS + err := wire.ReadBinaryBytes(raw, &tx) + return tx, err +} diff --git a/cmd/basecli/commands/sendtx.go b/cmd/basecli/commands/sendtx.go index 0660ed22c3..ccf00c6ed1 100644 --- a/cmd/basecli/commands/sendtx.go +++ b/cmd/basecli/commands/sendtx.go @@ -58,3 +58,55 @@ func (s *SendTx) TxBytes() ([]byte, error) { }{s.Tx}) return txBytes, nil } + +// AddSigner sets address and pubkey info on the tx based on the key that +// will be used for signing +func (s *SendTx) AddSigner(pk crypto.PubKey) { + // get addr if available + var addr []byte + if !pk.Empty() { + addr = pk.Address() + } + + // set the send address, and pubkey if needed + in := s.Tx.Inputs + in[0].Address = addr + if in[0].Sequence == 1 { + in[0].PubKey = pk + } +} + +// TODO: this should really be in the basecoin.types SendTx, +// but that code is too ugly now, needs refactor.. +func (s *SendTx) ValidateBasic() error { + if s.chainID == "" { + return errors.New("No chainId specified") + } + for _, in := range s.Tx.Inputs { + if len(in.Address) != 20 { + return errors.Errorf("Invalid input address length: %d", len(in.Address)) + } + if !in.Coins.IsValid() { + return errors.Errorf("Invalid input coins %v", in.Coins) + } + if in.Coins.IsZero() { + return errors.New("Input coins cannot be zero") + } + if in.Sequence <= 0 { + return errors.New("Sequence must be greater than 0") + } + } + for _, out := range s.Tx.Outputs { + if len(out.Address) != 20 { + return errors.Errorf("Invalid output address length: %d", len(out.Address)) + } + if !out.Coins.IsValid() { + return errors.Errorf("Invalid output coins %v", out.Coins) + } + if out.Coins.IsZero() { + return errors.New("Output coins cannot be zero") + } + } + + return nil +} diff --git a/cmd/basecli/counter/counter.go b/cmd/basecli/counter/counter.go index 3576e1629a..9ec931091e 100644 --- a/cmd/basecli/counter/counter.go +++ b/cmd/basecli/counter/counter.go @@ -15,19 +15,6 @@ import ( btypes "github.com/tendermint/basecoin/types" ) -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 -} - /**** build out the tx ****/ var ( diff --git a/cmd/basecli/counter/query.go b/cmd/basecli/counter/query.go index bb18eee690..9396c956a7 100644 --- a/cmd/basecli/counter/query.go +++ b/cmd/basecli/counter/query.go @@ -36,3 +36,18 @@ func doCounterQuery(cmd *cobra.Command, args []string) error { 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 +// } diff --git a/cmd/basecli/main.go b/cmd/basecli/main.go index 964e0d9445..9b58d12046 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -14,7 +14,6 @@ import ( "github.com/tendermint/tmlibs/cli" bcmd "github.com/tendermint/basecoin/cmd/basecli/commands" - bcount "github.com/tendermint/basecoin/cmd/basecli/counter" ) // BaseCli represents the base command when called without any subcommands @@ -38,18 +37,18 @@ func main() { pr.AddCommand(proofs.TxCmd) pr.AddCommand(proofs.KeyCmd) 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 + proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) tr := txs.RootCmd - // tr.AddCommand(txs.DemoCmd) + tr.AddCommand(bcmd.SendTxCmd) + // tr.AddCommand(bcmd.AppTxCmd) // TODO - proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) - //proofs.StatePresenters.Register("counter", bcount.CounterPresenter{}) - txs.Register("send", bcmd.SendTxMaker{}) - txs.Register("counter", bcount.CounterTxMaker{}) + // txs.Register("send", bcmd.SendTxMaker{}) + // txs.Register("counter", bcount.CounterTxMaker{}) // set up the various commands to use BaseCli.AddCommand( diff --git a/glide.lock b/glide.lock index fa0ca450d0..8964951f09 100644 --- a/glide.lock +++ b/glide.lock @@ -172,7 +172,7 @@ imports: - types - version - name: github.com/tendermint/tmlibs - version: 0ecb38c6da95a1e8f60117b2bd4a6f76c7a0f944 + version: 59a77e7bef092eef0e1f9b44c983dc9e35eed0d6 subpackages: - autofile - cli