diff --git a/.gitignore b/.gitignore index f906ef0e45..cc8fd5d8d9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ vendor merkleeyes.db build +shunit2 diff --git a/Makefile b/Makefile index 96897b2505..c336e05e2c 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ GOTOOLS = \ github.com/Masterminds/glide PACKAGES=$(shell go list ./... | grep -v '/vendor/') -all: test install +all: get_vendor_deps test install build: go build ./cmd/... @@ -15,15 +15,24 @@ dist: @bash scripts/dist.sh @bash scripts/publish.sh +clitest/shunit2: + wget "https://raw.githubusercontent.com/kward/shunit2/master/source/2.1/src/shunit2" \ + -q -O clitest/shunit2 + +test_cli: clitest/shunit2 + # sudo apt-get install jq + @./clitest/basictx.sh + # @./clitest/ibc.sh + test: go test $(PACKAGES) #go run tests/tendermint/*.go -get_deps: - go get -d ./... +# get_deps: +# go get -d ./... -update_deps: - go get -d -u ./... +# update_deps: +# go get -d -u ./... get_vendor_deps: tools glide install diff --git a/clitest/basictx.sh b/clitest/basictx.sh new file mode 100755 index 0000000000..e5e159a334 --- /dev/null +++ b/clitest/basictx.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +oneTimeSetUp() { + BASE_DIR=$HOME/.basecoin_test_basictx + LOG=$BASE_DIR/test.log + SERVER_LOG=$BASE_DIR/basecoin.log + + rm -rf $BASE_DIR + mkdir -p $BASE_DIR + + ACCOUNTS=(jae ethan bucky rigel igor) + RICH=${ACCOUNTS[0]} + POOR=${ACCOUNTS[1]} + + # set up client + prepareClient + + # start basecoin server (with counter) + initServer + echo pid $PID_SERVER + + initClient + + echo "...Testing may begin!" + echo + echo + echo +} + +oneTimeTearDown() { + echo + echo + echo "stopping basecoin test server..." + kill -9 $PID_SERVER >/dev/null 2>&1 + sleep 1 +} + +prepareClient() { + echo "Preparing client keys..." + export BC_HOME=$BASE_DIR/client + basecli reset_all + assertTrue $? + + for i in "${!ACCOUNTS[@]}"; do + newKey ${ACCOUNTS[$i]} + done +} + +initServer() { + echo "Setting up genesis..." + SERVE_DIR=$BASE_DIR/server + rm -rf $SERVE_DIR 2>/dev/null + basecoin init --home=$SERVE_DIR >>$SERVER_LOG + + #change the genesis to the first account + GENKEY=$(basecli keys get ${RICH} -o json | jq .pubkey.data) + GENJSON=$(cat $SERVE_DIR/genesis.json) + echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > $SERVE_DIR/genesis.json + + echo "Starting server..." + basecoin start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & + sleep 5 + PID_SERVER=$! +} + +initClient() { + echo "Attaching client..." + # hard-code the expected validator hash + basecli init --chainid=test_chain_id --node=tcp://localhost:46657 --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 + assertTrue "initialized light-client" $? +} + +# newKeys makes a key for a given username, second arg optional password +newKey(){ + assertNotNull "keyname required" "$1" + KEYPASS=${2:-qwertyuiop} + (echo $KEYPASS; echo $KEYPASS) | basecli keys new $1 >>$LOG 2>/dev/null + assertTrue "created $1" $? + assertTrue "$1 doesn't exist" "basecli keys get $1" +} + +# getAddr gets the address for a key name +getAddr() { + assertNotNull "keyname required" "$1" + RAW=$(basecli keys get $1) + assertTrue "no key for $1" $? + # print the addr + echo $RAW | cut -d' ' -f2 +} + +test00GetAccount() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + assertFalse "requires arg" "basecli query account" + ACCT=$(basecli query account $SENDER) + assertTrue "must have proper genesis account" $? + assertEquals "no tx" "0" $(echo $ACCT | jq .data.sequence) + assertEquals "has money" "9007199254740992" $(echo $ACCT | jq .data.coins[0].amount) + + ACCT2=$(basecli query account $RECV) + assertFalse "has no genesis account" $? +} + +test01SendTx() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + assertFalse "missing dest" "basecli tx send --amount=992mycoin --sequence=1 2>/dev/null" + assertFalse "bad password" "echo foo | basecli tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null" + # we have to remove the password request from stdout, to just get the json + RES=$(echo qwertyuiop | basecli tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null | tail -n +2) + assertTrue "sent tx" $? + HASH=$(echo $RES | jq .hash | tr -d \") + TX_HEIGHT=$(echo $RES | jq .height) + assertEquals "good check" "0" $(echo $RES | jq .check_tx.code) + assertEquals "good deliver" "0" $(echo $RES | jq .deliver_tx.code) + + # make sure sender goes down + ACCT=$(basecli query account $SENDER) + assertTrue "must have genesis account" $? + assertEquals "one tx" "1" $(echo $ACCT | jq .data.sequence) + assertEquals "has money" "9007199254740000" $(echo $ACCT | jq .data.coins[0].amount) + + # make sure recipient goes up + ACCT2=$(basecli query account $RECV) + assertTrue "must have new account" $? + assertEquals "no tx" "0" $(echo $ACCT2 | jq .data.sequence) + assertEquals "has money" "992" $(echo $ACCT2 | jq .data.coins[0].amount) + + # make sure tx is indexed + TX=$(basecli query tx $HASH) + assertTrue "found tx" $? + assertEquals "proper height" $TX_HEIGHT $(echo $TX | jq .height) + assertEquals "type=send" '"send"' $(echo $TX | jq .data.type) + assertEquals "proper sender" "\"$SENDER\"" $(echo $TX | jq .data.data.inputs[0].address) + assertEquals "proper out amount" "992" $(echo $TX | jq .data.data.outputs[0].coins[0].amount) +} + + +# load and run these tests with shunit2! +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory +. $DIR/shunit2 diff --git a/clitest/ibc.sh b/clitest/ibc.sh new file mode 100755 index 0000000000..2b0c889a74 --- /dev/null +++ b/clitest/ibc.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "ibc test not implemented" diff --git a/cmd/basecli/commands/adapters.go b/cmd/basecli/commands/adapters.go deleted file mode 100644 index 516cb2f0df..0000000000 --- a/cmd/basecli/commands/adapters.go +++ /dev/null @@ -1,232 +0,0 @@ -package commands - -import ( - "encoding/hex" - "encoding/json" - - "github.com/pkg/errors" - 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" - - btypes "github.com/tendermint/basecoin/types" -) - -type AccountPresenter struct{} - -func (_ AccountPresenter) MakeKey(str string) ([]byte, error) { - res, err := hex.DecodeString(str) - if err == nil { - res = btypes.AccountKey(res) - } - return res, err -} - -func (_ AccountPresenter) ParseData(raw []byte) (interface{}, error) { - var acc *btypes.Account - err := wire.ReadBinaryBytes(raw, &acc) - return acc, err -} - -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 -} - -/******** 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", "", "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, - } - return &send, errors.Wrap(err, "parse sendtx") -} - -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)) - if err != nil { - return nil, errors.Errorf("To address is invalid hex: %v\n", err) - } - - //parse the fee and amounts into coin types - feeCoin, err := btypes.ParseCoin(data.Fee) - if err != nil { - return nil, err - } - amountCoins, err := btypes.ParseCoins(data.Amount) - if err != nil { - return nil, err - } - - // get addr if available - var addr []byte - if !pk.Empty() { - addr = pk.Address() - } - - // craft the tx - input := btypes.TxInput{ - Address: addr, - Coins: amountCoins, - Sequence: data.Sequence, - } - if data.Sequence == 1 { - input.PubKey = pk - } - output := 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 -} - -/******** AppTx *********/ - -type AppFlags struct { - Fee string - Gas int64 - Amount string - Sequence int -} - -func AppFlagSet() (*flag.FlagSet, AppFlags) { - fs := flag.NewFlagSet("", flag.ContinueOnError) - - fs.String("amount", "", "Coins to send in the format ,...") - fs.String("fee", "", "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, AppFlags{} -} - -// AppTxReader allows us to create AppTx -type AppTxReader struct { - ChainID string -} - -func (t AppTxReader) ReadTxJSON(data []byte, pk crypto.PubKey) (interface{}, error) { - return nil, errors.New("Not implemented...") -} - -func (t AppTxReader) ReadTxFlags(data *AppFlags, app string, appData []byte, pk crypto.PubKey) (interface{}, error) { - //parse the fee and amounts into coin types - feeCoin, err := btypes.ParseCoin(data.Fee) - if err != nil { - return nil, err - } - amountCoins, err := btypes.ParseCoins(data.Amount) - if err != nil { - return nil, err - } - - // get addr if available - var addr []byte - if !pk.Empty() { - addr = pk.Address() - } - - // craft the tx - input := btypes.TxInput{ - Address: addr, - Coins: amountCoins, - Sequence: data.Sequence, - } - if data.Sequence == 1 { - input.PubKey = pk - } - tx := btypes.AppTx{ - Gas: data.Gas, - Fee: feeCoin, - Input: input, - Name: app, - Data: appData, - } - - // wrap it in the proper signer thing... - send := AppTx{ - chainID: t.ChainID, - Tx: &tx, - } - return &send, nil -} - -/** TODO copied from basecoin cli - put in common somewhere? **/ - -// 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 -} diff --git a/cmd/basecli/commands/apptx.go b/cmd/basecli/commands/apptx.go index 7cf9e3c6a2..1e68600e17 100644 --- a/cmd/basecli/commands/apptx.go +++ b/cmd/basecli/commands/apptx.go @@ -57,3 +57,42 @@ func (s *AppTx) TxBytes() ([]byte, error) { txBytes := wire.BinaryBytes(bc.TxS{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 (a *AppTx) 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 := &a.Tx.Input + in.Address = addr + if in.Sequence == 1 { + in.PubKey = pk + } +} + +// TODO: this should really be in the basecoin.types SendTx, +// but that code is too ugly now, needs refactor.. +func (a *AppTx) ValidateBasic() error { + if a.chainID == "" { + return errors.New("No chainId specified") + } + in := a.Tx.Input + 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") + } + return nil +} diff --git a/cmd/basecli/commands/cmds.go b/cmd/basecli/commands/cmds.go new file mode 100644 index 0000000000..50a39024b4 --- /dev/null +++ b/cmd/basecli/commands/cmds.go @@ -0,0 +1,169 @@ +package commands + +import ( + "encoding/hex" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/tendermint/light-client/commands" + txcmd "github.com/tendermint/light-client/commands/txs" + + btypes "github.com/tendermint/basecoin/types" +) + +/*** Here is the sendtx command ***/ + +var SendTxCmd = &cobra.Command{ + Use: "send", + Short: "send tokens from one account to another", + RunE: doSendTx, +} + +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") +} + +// runDemo is an example of how to make a tx +func doSendTx(cmd *cobra.Command, args []string) error { + tx := new(btypes.SendTx) + + // load data from json or flags + found, err := txcmd.LoadJSON(tx) + if !found { + err = readSendTxFlags(tx) + } + if err != nil { + return err + } + + send := &SendTx{ + chainID: commands.GetChainID(), + 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 readSendTxFlags(tx *btypes.SendTx) error { + // parse to address + to, err := ParseHexFlag(ToFlag) + if err != nil { + return errors.Errorf("To address is invalid hex: %v\n", err) + } + + //parse the fee and amounts into coin types + tx.Fee, err = btypes.ParseCoin(viper.GetString(FeeFlag)) + if err != nil { + return err + } + amountCoins, err := btypes.ParseCoins(viper.GetString(AmountFlag)) + if err != nil { + return err + } + + // set the gas + tx.Gas = viper.GetInt64(GasFlag) + + // craft the inputs and outputs + tx.Inputs = []btypes.TxInput{{ + Coins: amountCoins, + Sequence: viper.GetInt(SequenceFlag), + }} + tx.Outputs = []btypes.TxOutput{{ + Address: to, + Coins: amountCoins, + }} + + return nil +} + +/******** AppTx *********/ + +func AddAppTxFlags(fs *flag.FlagSet) { + fs.String(AmountFlag, "", "Coins to send in the format ,...") + fs.String(FeeFlag, "0mycoin", "Coins for the transaction fee of the format ") + fs.Int64(GasFlag, 0, "Amount of gas for this transaction") + fs.Int(SequenceFlag, -1, "Sequence number for this transaction") +} + +// ReadAppTxFlags reads in the standard flags +// your command should parse info to set tx.Name and tx.Data +func ReadAppTxFlags(tx *btypes.AppTx) error { + //parse the fee and amounts into coin types + var err error + tx.Fee, err = btypes.ParseCoin(viper.GetString(FeeFlag)) + if err != nil { + return err + } + amountCoins, err := btypes.ParseCoins(viper.GetString(AmountFlag)) + if err != nil { + return err + } + + // set the gas + tx.Gas = viper.GetInt64(GasFlag) + + // craft the inputs and outputs + tx.Input = btypes.TxInput{ + Coins: amountCoins, + Sequence: viper.GetInt(SequenceFlag), + } + + return nil +} + +func WrapAppTx(tx *btypes.AppTx) *AppTx { + return &AppTx{ + chainID: commands.GetChainID(), + Tx: tx, + } +} + +/** TODO copied from basecoin cli - put in common somewhere? **/ + +func ParseHexFlag(flag string) ([]byte, error) { + return hex.DecodeString(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 +} diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go new file mode 100644 index 0000000000..82ec564913 --- /dev/null +++ b/cmd/basecli/commands/query.go @@ -0,0 +1,45 @@ +package commands + +import ( + "github.com/spf13/cobra" + + wire "github.com/tendermint/go-wire" + proofcmd "github.com/tendermint/light-client/commands/proofs" + "github.com/tendermint/light-client/proofs" + + btypes "github.com/tendermint/basecoin/types" +) + +var AccountQueryCmd = &cobra.Command{ + Use: "account [address]", + Short: "Get details of an account, with proof", + RunE: doAccountQuery, +} + +func doAccountQuery(cmd *cobra.Command, args []string) error { + addr, err := proofcmd.ParseHexKey(args, "address") + if err != nil { + return err + } + key := btypes.AccountKey(addr) + + acc := new(btypes.Account) + proof, err := proofcmd.GetAndParseAppProof(key, &acc) + if err != nil { + return err + } + + return proofcmd.OutputProof(acc, proof.BlockHeight()) +} + +/*** this decodes all 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..b39792e2ce 100644 --- a/cmd/basecli/counter/counter.go +++ b/cmd/basecli/counter/counter.go @@ -1,85 +1,79 @@ package counter import ( - flag "github.com/spf13/pflag" + "github.com/spf13/cobra" "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/commands/txs" + txcmd "github.com/tendermint/light-client/commands/txs" bcmd "github.com/tendermint/basecoin/cmd/basecli/commands" "github.com/tendermint/basecoin/plugins/counter" btypes "github.com/tendermint/basecoin/types" ) -type CounterPresenter struct{} +var CounterTxCmd = &cobra.Command{ + Use: "counter", + Short: "add a vote to the counter", + Long: `Add a vote to the counter. -func (_ CounterPresenter) MakeKey(str string) ([]byte, error) { - key := counter.New().StateKey() - return key, nil +You must pass --valid for it to count and the countfee will be added to the counter.`, + RunE: doCounterTx, } -func (_ CounterPresenter) ParseData(raw []byte) (interface{}, error) { - var cp counter.CounterPluginState - err := wire.ReadBinaryBytes(raw, &cp) - return cp, err -} - -/**** build out the tx ****/ - -var ( - _ txs.ReaderMaker = CounterTxMaker{} - _ lightclient.TxReader = CounterTxReader{} +const ( + CountFeeFlag = "countfee" + ValidFlag = "valid" ) -type CounterTxMaker struct{} - -func (m CounterTxMaker) MakeReader() (lightclient.TxReader, error) { - chainID := viper.GetString(commands.ChainFlag) - return CounterTxReader{bcmd.AppTxReader{ChainID: chainID}}, nil +func init() { + fs := CounterTxCmd.Flags() + bcmd.AddAppTxFlags(fs) + fs.String(CountFeeFlag, "", "Coins to send in the format ,...") + fs.Bool(ValidFlag, false, "Is count valid?") } -// define flags +func doCounterTx(cmd *cobra.Command, args []string) error { + tx := new(btypes.AppTx) + // Note: we don't support loading apptx from json currently, so skip that -type CounterFlags struct { - bcmd.AppFlags `mapstructure:",squash"` - Valid bool - CountFee string -} - -func (m CounterTxMaker) Flags() (*flag.FlagSet, interface{}) { - fs, app := bcmd.AppFlagSet() - fs.String("countfee", "", "Coins to send in the format ,...") - fs.Bool("valid", false, "Is count valid?") - return fs, &CounterFlags{AppFlags: app} -} - -// parse flags - -type CounterTxReader struct { - App bcmd.AppTxReader -} - -func (t CounterTxReader) ReadTxJSON(data []byte, pk crypto.PubKey) (interface{}, error) { - // TODO: something. maybe? - return t.App.ReadTxJSON(data, pk) -} - -func (t CounterTxReader) ReadTxFlags(flags interface{}, pk crypto.PubKey) (interface{}, error) { - data := flags.(*CounterFlags) - countFee, err := btypes.ParseCoins(data.CountFee) + // read the standard flags + err := bcmd.ReadAppTxFlags(tx) if err != nil { - return nil, err + return err } + // now read the app-specific flags + err = readCounterFlags(tx) + if err != nil { + return err + } + + app := bcmd.WrapAppTx(tx) + app.AddSigner(txcmd.GetSigner()) + + // Sign if needed and post. This it the work-horse + bres, err := txcmd.SignAndPostTx(app) + if err != nil { + return err + } + + // output result + return txcmd.OutputTx(bres) +} + +// readCounterFlags sets the app-specific data in the AppTx +func readCounterFlags(tx *btypes.AppTx) error { + countFee, err := btypes.ParseCoins(viper.GetString(CountFeeFlag)) + if err != nil { + return err + } ctx := counter.CounterTx{ - Valid: viper.GetBool("valid"), + Valid: viper.GetBool(ValidFlag), Fee: countFee, } - txBytes := wire.BinaryBytes(ctx) - return t.App.ReadTxFlags(&data.AppFlags, counter.New().Name(), txBytes, pk) + tx.Name = counter.New().Name() + tx.Data = wire.BinaryBytes(ctx) + return nil } diff --git a/cmd/basecli/counter/query.go b/cmd/basecli/counter/query.go new file mode 100644 index 0000000000..a1c6aeb9b5 --- /dev/null +++ b/cmd/basecli/counter/query.go @@ -0,0 +1,42 @@ +package counter + +import ( + "github.com/spf13/cobra" + + proofcmd "github.com/tendermint/light-client/commands/proofs" + + "github.com/tendermint/basecoin/plugins/counter" +) + +var CounterQueryCmd = &cobra.Command{ + Use: "counter", + Short: "Query counter state, with proof", + RunE: doCounterQuery, +} + +func doCounterQuery(cmd *cobra.Command, args []string) error { + key := counter.New().StateKey() + + var cp counter.CounterPluginState + proof, err := proofcmd.GetAndParseAppProof(key, &cp) + if err != nil { + return err + } + + 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 01dc646832..d5116d1600 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -32,23 +32,34 @@ tmcli to work for any custom abci app. func main() { commands.AddBasicFlags(BaseCli) - //initialize proofs and txs - proofs.StatePresenters.Register("account", bcmd.AccountPresenter{}) - proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) - proofs.StatePresenters.Register("counter", bcount.CounterPresenter{}) + // prepare queries + pr := proofs.RootCmd + // these are default parsers, but you optional in your app + pr.AddCommand(proofs.TxCmd) + pr.AddCommand(proofs.KeyCmd) + pr.AddCommand(bcmd.AccountQueryCmd) + pr.AddCommand(bcount.CounterQueryCmd) - txs.Register("send", bcmd.SendTxMaker{}) - txs.Register("counter", bcount.CounterTxMaker{}) + // 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(bcmd.SendTxCmd) + tr.AddCommand(bcount.CounterTxCmd) + + // TODO + + // txs.Register("send", bcmd.SendTxMaker{}) + // txs.Register("counter", bcount.CounterTxMaker{}) // set up the various commands to use BaseCli.AddCommand( - keycmd.RootCmd, commands.InitCmd, + commands.ResetCmd, + keycmd.RootCmd, seeds.RootCmd, - proofs.RootCmd, - txs.RootCmd, - proxy.RootCmd, - ) + pr, + tr, + proxy.RootCmd) cmd := cli.PrepareMainCmd(BaseCli, "BC", os.ExpandEnv("$HOME/.basecli")) cmd.Execute() diff --git a/cmd/counter/cmd.go b/cmd/counter/cmd.go index e83430498a..a8c543e136 100644 --- a/cmd/counter/cmd.go +++ b/cmd/counter/cmd.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/spf13/cobra" + "github.com/spf13/viper" wire "github.com/tendermint/go-wire" "github.com/tendermint/basecoin/cmd/commands" @@ -19,16 +20,15 @@ var CounterTxCmd = &cobra.Command{ RunE: counterTxCmd, } -//flags -var ( - validFlag bool - countFeeFlag string +const ( + flagValid = "valid" + flagCountFee = "countfee" ) func init() { - CounterTxCmd.Flags().BoolVar(&validFlag, "valid", false, "Set valid field in CounterTx") - CounterTxCmd.Flags().StringVar(&countFeeFlag, "countfee", "", "Coins for the counter fee of the format ") + CounterTxCmd.Flags().Bool(flagValid, false, "Set valid field in CounterTx") + CounterTxCmd.Flags().String(flagCountFee, "", "Coins for the counter fee of the format ") commands.RegisterTxSubcommand(CounterTxCmd) commands.RegisterStartPlugin("counter", func() types.Plugin { return counter.New() }) @@ -36,13 +36,13 @@ func init() { func counterTxCmd(cmd *cobra.Command, args []string) error { - countFee, err := types.ParseCoins(countFeeFlag) + countFee, err := types.ParseCoins(viper.GetString(flagCountFee)) if err != nil { return err } counterTx := counter.CounterTx{ - Valid: validFlag, + Valid: viper.GetBool(flagValid), Fee: countFee, } diff --git a/glide.lock b/glide.lock index 8379e9e6d9..a83da11261 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: b31c6e45072e1015b04b5a201fb5ffcbadb837f21fe4a499f3b7e93229ee1c45 -updated: 2017-06-02T09:22:48.505187474Z +hash: 6eb1119dccf2ab4d0adb870a14cb4408047119be53c8ec4afeaa281bd1d2b457 +updated: 2017-06-15T17:51:21.867322849+02:00 imports: - name: github.com/bgentry/speakeasy version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd @@ -39,9 +39,9 @@ imports: - name: github.com/gorilla/context version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42 - name: github.com/gorilla/handlers - version: 13d73096a474cac93275c679c7b8a2dc17ddba82 + version: a4043c62cc2329bacda331d33fc908ab11ef0ec3 - name: github.com/gorilla/mux - version: 392c28fe23e1c45ddba891b0320b3b5df220beea + version: bcd8bc72b08df0f70df986b97f95590779502d31 - name: github.com/gorilla/websocket version: a91eba7f97777409bc2c443f5534d41dd20c5720 - name: github.com/hashicorp/hcl @@ -101,7 +101,7 @@ imports: - leveldb/table - leveldb/util - name: github.com/tendermint/abci - version: b86da575718079396af1f7fe3609ea34be6f855d + version: 7f5f48b6b9ec3964de4b07b6c3cd05d7c91aeee5 subpackages: - client - example/dummy @@ -127,7 +127,7 @@ imports: - data - data/base58 - name: github.com/tendermint/light-client - version: 424905d3813586ce7e64e18690676250a0595ad4 + version: 83bede2a7f150fc7f8aedde1aecd30d2bdf043e8 subpackages: - certifiers - certifiers/client @@ -139,17 +139,16 @@ imports: - commands/txs - proofs - name: github.com/tendermint/merkleeyes - version: 6b06ad654956c951b3d27e38bb566ae45aae1ff7 + version: feb2c3fadac8221f96fbfce65a63af034327f972 subpackages: - app - client - iavl - name: github.com/tendermint/tendermint - version: 2b5b0172531319ebc255a0ba638f6be666e5e46c + version: 4f0f50c62d41d39ad64e07ad642f705cc13c8229 subpackages: - blockchain - cmd/tendermint/commands - - cmd/tendermint/commands/flags - config - consensus - mempool @@ -172,7 +171,7 @@ imports: - types - version - name: github.com/tendermint/tmlibs - version: 6b619742ac69388dd591c30f55aaee46197b086e + version: 59a77e7bef092eef0e1f9b44c983dc9e35eed0d6 subpackages: - autofile - cli diff --git a/glide.yaml b/glide.yaml index 132e8db244..7e7727aac4 100644 --- a/glide.yaml +++ b/glide.yaml @@ -7,22 +7,22 @@ import: - package: github.com/spf13/pflag - package: github.com/spf13/viper - package: github.com/tendermint/abci - version: ~0.5.0 + version: develop version: subpackages: - server - types - package: github.com/tendermint/go-crypto - version: ~0.2.0 + version: develop subpackages: - cmd - keys - package: github.com/tendermint/go-wire - version: ~0.6.2 + version: develop subpackages: - data - package: github.com/tendermint/light-client - version: ~0.10.0 + version: develop subpackages: - commands - commands/proofs @@ -30,12 +30,12 @@ import: - commands/txs - proofs - package: github.com/tendermint/merkleeyes - version: ~0.2.0 + version: develop subpackages: - client - iavl - package: github.com/tendermint/tendermint - version: ~0.10.0 + version: develop subpackages: - config - node @@ -46,7 +46,7 @@ import: - rpc/lib/types - types - package: github.com/tendermint/tmlibs - version: ~0.2.0 + version: develop subpackages: - cli - cli/flags