From 1f345358e63f4c52859cb4ddc0f9cfc75ba0663d Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 2 Jun 2017 19:06:48 +0300 Subject: [PATCH 01/73] fix broken build script (it relies on make tools) also removed `sudo` from `bash scripts/dish.sh` - I was able to build dist on MacOS without it. Do we need it? --- .gitignore | 1 + Makefile | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 100b0cae2fbb..f906ef0e45c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.swp vendor merkleeyes.db +build diff --git a/Makefile b/Makefile index 7fe0004aa88d..96897b2505a3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,9 @@ -all: test install +GOTOOLS = \ + github.com/mitchellh/gox \ + github.com/Masterminds/glide +PACKAGES=$(shell go list ./... | grep -v '/vendor/') -NOVENDOR = go list ./... | grep -v /vendor/ +all: test install build: go build ./cmd/... @@ -9,11 +12,11 @@ install: go install ./cmd/... dist: - @ sudo bash scripts/dist.sh - @ bash scripts/publish.sh + @bash scripts/dist.sh + @bash scripts/publish.sh test: - go test `${NOVENDOR}` + go test $(PACKAGES) #go run tests/tendermint/*.go get_deps: @@ -22,14 +25,16 @@ get_deps: update_deps: go get -d -u ./... -get_vendor_deps: - go get github.com/Masterminds/glide +get_vendor_deps: tools glide install build-docker: docker run -it --rm -v "$(PWD):/go/src/github.com/tendermint/basecoin" -w "/go/src/github.com/tendermint/basecoin" -e "CGO_ENABLED=0" golang:alpine go build ./cmd/basecoin docker build -t "tendermint/basecoin" . +tools: + go get -u -v $(GOTOOLS) + clean: @rm -f ./basecoin From 2655bf875555182278fba07181bf3dd10d95cbff Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 2 Jun 2017 12:37:51 -0400 Subject: [PATCH 02/73] dist: dont mkdir in container --- scripts/dist.sh | 5 +++++ scripts/dist_build.sh | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/dist.sh b/scripts/dist.sh index 977b36ae2f38..f96d6454f982 100755 --- a/scripts/dist.sh +++ b/scripts/dist.sh @@ -21,6 +21,11 @@ DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )" # Change into that dir because we expect that. cd "$DIR" +# Delete the old dir +echo "==> Removing old directory..." +rm -rf build/pkg +mkdir -p build/pkg + # Do a hermetic build inside a Docker container. docker build -t tendermint/${REPO_NAME}-builder scripts/${REPO_NAME}-builder/ docker run --rm -e "BUILD_TAGS=$BUILD_TAGS" -v "$(pwd)":/go/src/github.com/tendermint/${REPO_NAME} tendermint/${REPO_NAME}-builder ./scripts/dist_build.sh diff --git a/scripts/dist_build.sh b/scripts/dist_build.sh index 2812bef8aefd..f1566c8997f3 100755 --- a/scripts/dist_build.sh +++ b/scripts/dist_build.sh @@ -18,11 +18,6 @@ GIT_IMPORT="github.com/tendermint/basecoin/version" XC_ARCH=${XC_ARCH:-"386 amd64 arm"} XC_OS=${XC_OS:-"solaris darwin freebsd linux windows"} -# Delete the old dir -echo "==> Removing old directory..." -rm -rf build/pkg -mkdir -p build/pkg - # Make sure build tools are available. make tools From e242345d03cceecf5ea6f3c0952863f3c0b96f00 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 5 Jun 2017 15:11:46 +0300 Subject: [PATCH 03/73] fix panic when genesis file does not include app_options (Fixes #101) --- app/genesis.go | 5 +++++ app/genesis_test.go | 9 ++++++++- app/testdata/genesis3.json | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 app/testdata/genesis3.json diff --git a/app/genesis.go b/app/genesis.go index fa6a5ac3053b..3901fa68985e 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -37,6 +37,7 @@ func (app *Basecoin) LoadGenesis(path string) error { r := app.SetOption(kv.Key, kv.Value) app.logger.Info("Done setting Plugin key-value pair via SetOption", "result", r, "k", kv.Key, "v", kv.Value) } + return nil } @@ -71,6 +72,10 @@ func loadGenesis(filePath string) (*FullGenesisDoc, error) { return nil, errors.Wrap(err, "unmarshaling genesis file") } + if genDoc.AppOptions == nil { + genDoc.AppOptions = new(GenesisDoc) + } + pluginOpts, err := parseGenesisList(genDoc.AppOptions.PluginOptions) if err != nil { return nil, err diff --git a/app/genesis_test.go b/app/genesis_test.go index b2a590bcf3d9..dc398afd971f 100644 --- a/app/genesis_test.go +++ b/app/genesis_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/basecoin/types" - "github.com/tendermint/go-crypto" + crypto "github.com/tendermint/go-crypto" eyescli "github.com/tendermint/merkleeyes/client" cmn "github.com/tendermint/tmlibs/common" ) @@ -16,6 +16,13 @@ import ( const genesisFilepath = "./testdata/genesis.json" const genesisAcctFilepath = "./testdata/genesis2.json" +func TestLoadGenesisDoNotFailIfAppOptionsAreMissing(t *testing.T) { + eyesCli := eyescli.NewLocalClient("", 0) + app := NewBasecoin(eyesCli) + err := app.LoadGenesis("./testdata/genesis3.json") + require.Nil(t, err, "%+v", err) +} + func TestLoadGenesis(t *testing.T) { assert, require := assert.New(t), require.New(t) diff --git a/app/testdata/genesis3.json b/app/testdata/genesis3.json new file mode 100644 index 000000000000..b58b1d740256 --- /dev/null +++ b/app/testdata/genesis3.json @@ -0,0 +1,3 @@ +{ + "chain_id": "foo_bar_chain" +} From 25e7a79174f5f078ab93b2cc85a9b07b545790c2 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Wed, 14 Jun 2017 05:02:42 -0400 Subject: [PATCH 04/73] replace basecli state presenters with cmds --- cmd/basecli/commands/adapters.go | 18 +---------- cmd/basecli/commands/query.go | 55 ++++++++++++++++++++++++++++++++ cmd/basecli/counter/query.go | 44 +++++++++++++++++++++++++ cmd/basecli/main.go | 4 +-- cmd/counter/cmd.go | 16 +++++----- glide.lock | 2 +- 6 files changed, 111 insertions(+), 28 deletions(-) create mode 100644 cmd/basecli/commands/query.go create mode 100644 cmd/basecli/counter/query.go diff --git a/cmd/basecli/commands/adapters.go b/cmd/basecli/commands/adapters.go index 516cb2f0df33..7df8ca3384eb 100644 --- a/cmd/basecli/commands/adapters.go +++ b/cmd/basecli/commands/adapters.go @@ -17,22 +17,6 @@ import ( 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 } @@ -65,7 +49,7 @@ func (m SendTxMaker) Flags() (*flag.FlagSet, interface{}) { 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.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{} diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go new file mode 100644 index 000000000000..1162d2b09ed4 --- /dev/null +++ b/cmd/basecli/commands/query.go @@ -0,0 +1,55 @@ +package commands + +import ( + "encoding/hex" + "fmt" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + + wire "github.com/tendermint/go-wire" + "github.com/tendermint/light-client/commands" + proofcmd "github.com/tendermint/light-client/commands/proofs" + "github.com/tendermint/light-client/proofs" + + bccmd "github.com/tendermint/basecoin/cmd/commands" + btypes "github.com/tendermint/basecoin/types" +) + +func init() { + //first modify the full node account query command for the light client + bccmd.AccountCmd.RunE = accountCmd + proofcmd.RootCmd.AddCommand(bccmd.AccountCmd) +} + +func accountCmd(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return fmt.Errorf("account command requires an argument ([address])") //never stack trace + } + + addrHex := StripHex(args[0]) + + // convert destination address to bytes + addr, err := hex.DecodeString(addrHex) + if err != nil { + return errors.Errorf("Account address (%v) is invalid hex: %v\n", addrHex, err) + } + + // get the proof -> this will be used by all prover commands + height := proofcmd.GetHeight() + node := commands.GetNode() + prover := proofs.NewAppProver(node) + key := btypes.AccountKey(addr) + proof, err := proofcmd.GetProof(node, prover, key, height) + if err != nil { + return err + } + + var acc *btypes.Account + err = wire.ReadBinaryBytes(proof.Data(), &acc) + if err != nil { + return err + } + + return proofcmd.OutputProof(&acc, proof.BlockHeight()) +} diff --git a/cmd/basecli/counter/query.go b/cmd/basecli/counter/query.go new file mode 100644 index 000000000000..46973791d6ca --- /dev/null +++ b/cmd/basecli/counter/query.go @@ -0,0 +1,44 @@ +package counter + +import ( + "github.com/spf13/cobra" + + wire "github.com/tendermint/go-wire" + "github.com/tendermint/light-client/commands" + proofcmd "github.com/tendermint/light-client/commands/proofs" + "github.com/tendermint/light-client/proofs" + + "github.com/tendermint/basecoin/plugins/counter" +) + +var CounterTxCmd = &cobra.Command{ + Use: "counter", + Short: "query counter state", + RunE: counterTxCmd, +} + +func init() { + //first modify the full node account query command for the light client + proofcmd.RootCmd.AddCommand(CounterTxCmd) +} + +func counterTxCmd(cmd *cobra.Command, args []string) error { + + // get the proof -> this will be used by all prover commands + height := proofcmd.GetHeight() + node := commands.GetNode() + prover := proofs.NewAppProver(node) + key := counter.New().StateKey() + proof, err := proofcmd.GetProof(node, prover, key, height) + if err != nil { + return err + } + + var cp counter.CounterPluginState + err = wire.ReadBinaryBytes(proof.Data(), &cp) + if err != nil { + return err + } + + return proofcmd.OutputProof(cp, proof.BlockHeight()) +} diff --git a/cmd/basecli/main.go b/cmd/basecli/main.go index 01dc6468329b..7af9ce4de0ea 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -33,9 +33,9 @@ func main() { commands.AddBasicFlags(BaseCli) //initialize proofs and txs - proofs.StatePresenters.Register("account", bcmd.AccountPresenter{}) + //proofs.StatePresenters.Register("account", bcmd.AccountPresenter{}) proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) - proofs.StatePresenters.Register("counter", bcount.CounterPresenter{}) + //proofs.StatePresenters.Register("counter", bcount.CounterPresenter{}) txs.Register("send", bcmd.SendTxMaker{}) txs.Register("counter", bcount.CounterTxMaker{}) diff --git a/cmd/counter/cmd.go b/cmd/counter/cmd.go index e83430498a18..a8c543e13609 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 8379e9e6d918..e034a7afc9e5 100644 --- a/glide.lock +++ b/glide.lock @@ -127,7 +127,7 @@ imports: - data - data/base58 - name: github.com/tendermint/light-client - version: 424905d3813586ce7e64e18690676250a0595ad4 + version: d993d8a9ba6cb51f05faf6e527016288e38c2853 subpackages: - certifiers - certifiers/client From 863e3725fe5699717fee531e54ef7ee8d06758b0 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 12:11:27 +0200 Subject: [PATCH 05/73] Update deps to latest light-client pr, breaking changes --- glide.lock | 22 +++++++++++----------- glide.yaml | 14 +++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/glide.lock b/glide.lock index e034a7afc9e5..fa0ca450d0b4 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-15T12:09:30.832243232+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 @@ -113,7 +113,7 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: 7dff40942a64cdeefefa9446b2d104750b349f8a + version: 438b16f1f84ef002d7408ecd6fc3a3974cbc9559 subpackages: - cmd - keys @@ -122,12 +122,12 @@ imports: - keys/server/types - keys/storage/filestorage - name: github.com/tendermint/go-wire - version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb + version: 97beaedf0f4dbc035309157c92be3b30cc6e5d74 subpackages: - data - data/base58 - name: github.com/tendermint/light-client - version: d993d8a9ba6cb51f05faf6e527016288e38c2853 + version: c90f1a90b28977431c6291a0162228e9e4250401 subpackages: - certifiers - certifiers/client @@ -139,13 +139,13 @@ imports: - commands/txs - proofs - name: github.com/tendermint/merkleeyes - version: 6b06ad654956c951b3d27e38bb566ae45aae1ff7 + version: c722818b460381bc5b82e38c73ff6e22a9df624d subpackages: - app - client - iavl - name: github.com/tendermint/tendermint - version: 2b5b0172531319ebc255a0ba638f6be666e5e46c + version: 11b5d11e9eec170e1d3dce165f0270d5c0759d69 subpackages: - blockchain - cmd/tendermint/commands @@ -172,7 +172,7 @@ imports: - types - version - name: github.com/tendermint/tmlibs - version: 6b619742ac69388dd591c30f55aaee46197b086e + version: 0ecb38c6da95a1e8f60117b2bd4a6f76c7a0f944 subpackages: - autofile - cli diff --git a/glide.yaml b/glide.yaml index 132e8db24423..7e7727aac488 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 From 65837cf9525ce630941b1c037f2dafe4c996dd3c Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 12:27:55 +0200 Subject: [PATCH 06/73] Clean up queries, part 1 --- cmd/basecli/commands/query.go | 34 +++++++++++----------------------- cmd/basecli/counter/query.go | 18 ++++++------------ cmd/basecli/main.go | 25 ++++++++++++++++++------- 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go index 1162d2b09ed4..84098a4246f7 100644 --- a/cmd/basecli/commands/query.go +++ b/cmd/basecli/commands/query.go @@ -1,10 +1,6 @@ package commands import ( - "encoding/hex" - "fmt" - - "github.com/pkg/errors" "github.com/spf13/cobra" wire "github.com/tendermint/go-wire" @@ -12,44 +8,36 @@ import ( proofcmd "github.com/tendermint/light-client/commands/proofs" "github.com/tendermint/light-client/proofs" - bccmd "github.com/tendermint/basecoin/cmd/commands" btypes "github.com/tendermint/basecoin/types" ) -func init() { - //first modify the full node account query command for the light client - bccmd.AccountCmd.RunE = accountCmd - proofcmd.RootCmd.AddCommand(bccmd.AccountCmd) +var AccountQueryCmd = &cobra.Command{ + Use: "account [address]", + Short: "Get details of an account, with proof", + RunE: doAccountQuery, } -func accountCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return fmt.Errorf("account command requires an argument ([address])") //never stack trace - } - - addrHex := StripHex(args[0]) - - // convert destination address to bytes - addr, err := hex.DecodeString(addrHex) +func doAccountQuery(cmd *cobra.Command, args []string) error { + height := proofcmd.GetHeight() + addr, err := proofcmd.ParseHexKey(args, "address") if err != nil { - return errors.Errorf("Account address (%v) is invalid hex: %v\n", addrHex, err) + return err } + key := btypes.AccountKey(addr) // get the proof -> this will be used by all prover commands - height := proofcmd.GetHeight() node := commands.GetNode() prover := proofs.NewAppProver(node) - key := btypes.AccountKey(addr) proof, err := proofcmd.GetProof(node, prover, key, height) if err != nil { return err } - var acc *btypes.Account + acc := new(btypes.Account) err = wire.ReadBinaryBytes(proof.Data(), &acc) if err != nil { return err } - return proofcmd.OutputProof(&acc, proof.BlockHeight()) + return proofcmd.OutputProof(acc, proof.BlockHeight()) } diff --git a/cmd/basecli/counter/query.go b/cmd/basecli/counter/query.go index 46973791d6ca..bb18eee69043 100644 --- a/cmd/basecli/counter/query.go +++ b/cmd/basecli/counter/query.go @@ -11,24 +11,18 @@ import ( "github.com/tendermint/basecoin/plugins/counter" ) -var CounterTxCmd = &cobra.Command{ +var CounterQueryCmd = &cobra.Command{ Use: "counter", - Short: "query counter state", - RunE: counterTxCmd, + Short: "Query counter state, with proof", + RunE: doCounterQuery, } -func init() { - //first modify the full node account query command for the light client - proofcmd.RootCmd.AddCommand(CounterTxCmd) -} - -func counterTxCmd(cmd *cobra.Command, args []string) error { - - // get the proof -> this will be used by all prover commands +func doCounterQuery(cmd *cobra.Command, args []string) error { height := proofcmd.GetHeight() + key := counter.New().StateKey() + node := commands.GetNode() prover := proofs.NewAppProver(node) - key := counter.New().StateKey() proof, err := proofcmd.GetProof(node, prover, key, height) if err != nil { return err diff --git a/cmd/basecli/main.go b/cmd/basecli/main.go index 7af9ce4de0ea..964e0d944546 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -32,8 +32,19 @@ tmcli to work for any custom abci app. func main() { commands.AddBasicFlags(BaseCli) - //initialize proofs and txs - //proofs.StatePresenters.Register("account", bcmd.AccountPresenter{}) + // 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) + + // here is how you would add the custom txs... but don't really add demo in your app + tr := txs.RootCmd + // tr.AddCommand(txs.DemoCmd) + + // TODO proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) //proofs.StatePresenters.Register("counter", bcount.CounterPresenter{}) @@ -42,13 +53,13 @@ func main() { // 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() From 66ec2f266cf89f4cf336aa7baad58f6b330eb59e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 13:11:09 +0200 Subject: [PATCH 07/73] Port sendtx to new format --- cmd/basecli/commands/adapters.go | 144 +++++++++++++------------------ cmd/basecli/commands/query.go | 12 +++ cmd/basecli/commands/sendtx.go | 52 +++++++++++ cmd/basecli/counter/counter.go | 13 --- cmd/basecli/counter/query.go | 15 ++++ cmd/basecli/main.go | 13 ++- glide.lock | 2 +- 7 files changed, 147 insertions(+), 104 deletions(-) diff --git a/cmd/basecli/commands/adapters.go b/cmd/basecli/commands/adapters.go index 7df8ca3384eb..f9bfe0f44b33 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 ***/ -func (_ BaseTxPresenter) ParseData(raw []byte) (interface{}, error) { - var tx btypes.TxS - err := wire.ReadBinaryBytes(raw, &tx) - return tx, err +var SendTxCmd = &cobra.Command{ + Use: "send", + Short: "send tokens from one account to another", + RunE: doSendTx, } -/******** SendTx *********/ - -type SendTxMaker struct{} +const ( + ToFlag = "to" + AmountFlag = "amount" + FeeFlag = "fee" + GasFlag = "gas" + SequenceFlag = "sequence" +) -func (m SendTxMaker) MakeReader() (lightclient.TxReader, error) { - chainID := viper.GetString(commands.ChainFlag) - return SendTxReader{ChainID: chainID}, nil +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") } -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) +// runDemo is an example of how to make a tx +func doSendTx(cmd *cobra.Command, args []string) error { + tx := new(btypes.SendTx) - 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{} -} + // load data from json or flags + found, err := txcmd.LoadJSON(tx) + if !found { + err = readSendTxFlags(tx) + } + if err != nil { + return err + } -// SendTXReader allows us to create SendTx -type SendTxReader struct { - ChainID string -} + send := &SendTx{ + chainID: viper.GetString(commands.ChainFlag), + Tx: tx, + } + send.AddSigner(txcmd.GetSigner()) -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, + // Sign if needed and post. This it the work-horse + bres, err := txcmd.SignAndPostTx(send) + if err != nil { + return err } - return &send, errors.Wrap(err, "parse sendtx") -} -func (t SendTxReader) ReadTxFlags(flags interface{}, pk crypto.PubKey) (interface{}, error) { - data := flags.(*SendFlags) + // output result + return txcmd.OutputTx(bres) +} - // 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 84098a4246f7..aea350d0638e 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 0660ed22c3d5..ccf00c6ed1dc 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 3576e1629a10..9ec931091e1f 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 bb18eee69043..9396c956a717 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 964e0d944546..9b58d1204671 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 fa0ca450d0b4..8964951f09b4 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 From 8f67b6be84e7a5309c66ffbfe1bda737ff69b0fe Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 13:36:18 +0200 Subject: [PATCH 08/73] Got counter tx working, needs testing --- cmd/basecli/commands/apptx.go | 39 ++++++++ cmd/basecli/commands/{adapters.go => cmds.go} | 85 +++++++----------- cmd/basecli/counter/counter.go | 89 ++++++++++--------- cmd/basecli/main.go | 5 +- 4 files changed, 120 insertions(+), 98 deletions(-) rename cmd/basecli/commands/{adapters.go => cmds.go} (64%) diff --git a/cmd/basecli/commands/apptx.go b/cmd/basecli/commands/apptx.go index 7cf9e3c6a2ef..1e68600e1708 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/adapters.go b/cmd/basecli/commands/cmds.go similarity index 64% rename from cmd/basecli/commands/adapters.go rename to cmd/basecli/commands/cmds.go index f9bfe0f44b33..268f4d61d0e6 100644 --- a/cmd/basecli/commands/adapters.go +++ b/cmd/basecli/commands/cmds.go @@ -8,7 +8,6 @@ import ( flag "github.com/spf13/pflag" "github.com/spf13/viper" - crypto "github.com/tendermint/go-crypto" "github.com/tendermint/light-client/commands" txcmd "github.com/tendermint/light-client/commands/txs" @@ -71,7 +70,7 @@ func doSendTx(cmd *cobra.Command, args []string) error { func readSendTxFlags(tx *btypes.SendTx) error { // parse to address - to, err := hex.DecodeString(StripHex(viper.GetString(ToFlag))) + to, err := ParseHexFlag(ToFlag) if err != nil { return errors.Errorf("To address is invalid hex: %v\n", err) } @@ -104,76 +103,52 @@ func readSendTxFlags(tx *btypes.SendTx) error { /******** AppTx *********/ -type AppFlags struct { - Fee string - Gas int64 - Amount string - Sequence int +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") } -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) { +// 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 - feeCoin, err := btypes.ParseCoin(data.Fee) + var err error + 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.Input = btypes.TxInput{ 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, + Sequence: viper.GetInt(SequenceFlag), } - // wrap it in the proper signer thing... - send := AppTx{ - chainID: t.ChainID, - Tx: &tx, + return nil +} + +func WrapAppTx(tx *btypes.AppTx) *AppTx { + return &AppTx{ + chainID: viper.GetString(commands.ChainFlag), + Tx: tx, } - return &send, nil } /** 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" { diff --git a/cmd/basecli/counter/counter.go b/cmd/basecli/counter/counter.go index 9ec931091e1f..b39792e2ceec 100644 --- a/cmd/basecli/counter/counter.go +++ b/cmd/basecli/counter/counter.go @@ -1,72 +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" ) -/**** build out the tx ****/ +var CounterTxCmd = &cobra.Command{ + Use: "counter", + Short: "add a vote to the counter", + Long: `Add a vote to the counter. -var ( - _ txs.ReaderMaker = CounterTxMaker{} - _ lightclient.TxReader = CounterTxReader{} -) +You must pass --valid for it to count and the countfee will be added to the counter.`, + RunE: doCounterTx, +} -type CounterTxMaker struct{} +const ( + CountFeeFlag = "countfee" + ValidFlag = "valid" +) -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 -} + // read the standard flags + err := bcmd.ReadAppTxFlags(tx) + if err != nil { + return err + } -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} -} + // now read the app-specific flags + err = readCounterFlags(tx) + if err != nil { + return err + } -// parse flags + app := bcmd.WrapAppTx(tx) + app.AddSigner(txcmd.GetSigner()) -type CounterTxReader struct { - App bcmd.AppTxReader -} + // Sign if needed and post. This it the work-horse + bres, err := txcmd.SignAndPostTx(app) + if err != nil { + return err + } -func (t CounterTxReader) ReadTxJSON(data []byte, pk crypto.PubKey) (interface{}, error) { - // TODO: something. maybe? - return t.App.ReadTxJSON(data, pk) + // output result + return txcmd.OutputTx(bres) } -func (t CounterTxReader) ReadTxFlags(flags interface{}, pk crypto.PubKey) (interface{}, error) { - data := flags.(*CounterFlags) - countFee, err := btypes.ParseCoins(data.CountFee) +// 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 nil, err + 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/main.go b/cmd/basecli/main.go index 9b58d1204671..d5116d1600cc 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -14,6 +14,7 @@ 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 @@ -37,13 +38,13 @@ 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(bcmd.SendTxCmd) - // tr.AddCommand(bcmd.AppTxCmd) + tr.AddCommand(bcount.CounterTxCmd) // TODO From 282a1579976718a63ba6424f657136d7f861836f Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 15:59:45 +0200 Subject: [PATCH 09/73] Update to use new helper methods, less code dups --- cmd/basecli/commands/cmds.go | 4 ++-- cmd/basecli/commands/query.go | 14 ++------------ cmd/basecli/counter/query.go | 13 +------------ glide.lock | 2 +- 4 files changed, 6 insertions(+), 27 deletions(-) diff --git a/cmd/basecli/commands/cmds.go b/cmd/basecli/commands/cmds.go index 268f4d61d0e6..50a39024b4f1 100644 --- a/cmd/basecli/commands/cmds.go +++ b/cmd/basecli/commands/cmds.go @@ -53,7 +53,7 @@ func doSendTx(cmd *cobra.Command, args []string) error { } send := &SendTx{ - chainID: viper.GetString(commands.ChainFlag), + chainID: commands.GetChainID(), Tx: tx, } send.AddSigner(txcmd.GetSigner()) @@ -138,7 +138,7 @@ func ReadAppTxFlags(tx *btypes.AppTx) error { func WrapAppTx(tx *btypes.AppTx) *AppTx { return &AppTx{ - chainID: viper.GetString(commands.ChainFlag), + chainID: commands.GetChainID(), Tx: tx, } } diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go index aea350d0638e..82ec5649132a 100644 --- a/cmd/basecli/commands/query.go +++ b/cmd/basecli/commands/query.go @@ -4,7 +4,6 @@ import ( "github.com/spf13/cobra" wire "github.com/tendermint/go-wire" - "github.com/tendermint/light-client/commands" proofcmd "github.com/tendermint/light-client/commands/proofs" "github.com/tendermint/light-client/proofs" @@ -18,23 +17,14 @@ var AccountQueryCmd = &cobra.Command{ } func doAccountQuery(cmd *cobra.Command, args []string) error { - height := proofcmd.GetHeight() addr, err := proofcmd.ParseHexKey(args, "address") if err != nil { return err } key := btypes.AccountKey(addr) - // get the proof -> this will be used by all prover commands - node := commands.GetNode() - prover := proofs.NewAppProver(node) - proof, err := proofcmd.GetProof(node, prover, key, height) - if err != nil { - return err - } - acc := new(btypes.Account) - err = wire.ReadBinaryBytes(proof.Data(), &acc) + proof, err := proofcmd.GetAndParseAppProof(key, &acc) if err != nil { return err } @@ -42,7 +32,7 @@ func doAccountQuery(cmd *cobra.Command, args []string) error { return proofcmd.OutputProof(acc, proof.BlockHeight()) } -/*** this decodes the basecoin tx ***/ +/*** this decodes all basecoin tx ***/ type BaseTxPresenter struct { proofs.RawPresenter // this handles MakeKey as hex bytes diff --git a/cmd/basecli/counter/query.go b/cmd/basecli/counter/query.go index 9396c956a717..a1c6aeb9b59e 100644 --- a/cmd/basecli/counter/query.go +++ b/cmd/basecli/counter/query.go @@ -3,10 +3,7 @@ package counter import ( "github.com/spf13/cobra" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/light-client/commands" proofcmd "github.com/tendermint/light-client/commands/proofs" - "github.com/tendermint/light-client/proofs" "github.com/tendermint/basecoin/plugins/counter" ) @@ -18,18 +15,10 @@ var CounterQueryCmd = &cobra.Command{ } func doCounterQuery(cmd *cobra.Command, args []string) error { - height := proofcmd.GetHeight() key := counter.New().StateKey() - node := commands.GetNode() - prover := proofs.NewAppProver(node) - proof, err := proofcmd.GetProof(node, prover, key, height) - if err != nil { - return err - } - var cp counter.CounterPluginState - err = wire.ReadBinaryBytes(proof.Data(), &cp) + proof, err := proofcmd.GetAndParseAppProof(key, &cp) if err != nil { return err } diff --git a/glide.lock b/glide.lock index 8964951f09b4..bd388820949d 100644 --- a/glide.lock +++ b/glide.lock @@ -127,7 +127,7 @@ imports: - data - data/base58 - name: github.com/tendermint/light-client - version: c90f1a90b28977431c6291a0162228e9e4250401 + version: 88fb726e779d97acac5f0bd387892bfc541f3701 subpackages: - certifiers - certifiers/client From 66c9010bcbc46ca5420481edf424062350446bc6 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 17:16:00 +0200 Subject: [PATCH 10/73] Starting bash cli tests --- .gitignore | 1 + Makefile | 18 +++++--- clitest/basictx.sh | 107 +++++++++++++++++++++++++++++++++++++++++++++ clitest/ibc.sh | 3 ++ 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100755 clitest/basictx.sh create mode 100755 clitest/ibc.sh diff --git a/.gitignore b/.gitignore index f906ef0e45c9..cc8fd5d8d9d1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ vendor merkleeyes.db build +shunit2 diff --git a/Makefile b/Makefile index 96897b2505a3..3cb3937e7d43 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,23 @@ 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 + @./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 000000000000..0cface81f4ba --- /dev/null +++ b/clitest/basictx.sh @@ -0,0 +1,107 @@ +#!/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 + sleep 5 + PID_SERVER=$! + echo pid $PID_SERVER + + initClient + + echo "...Testing may begin!" + echo + echo + echo +} + +oneTimeTearDown() { + echo "stopping basecoin test server" + kill -9 $PID_SERVER + 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 & +} + +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 +} + +testGetAccount() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + echo sender $RICH + echo $SENDER + + echo recipient $POOR + echo $RECV + + assertFalse "requires arg" "basecli query account" + ACCT=$(basecli query account $SENDER) + assertTrue "must have proper genesis account" $? + echo $ACCT +} + +# 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 000000000000..2b0c889a74cf --- /dev/null +++ b/clitest/ibc.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "ibc test not implemented" From cfe13e9c130ea5e29f291cf4b8e15b3cfeaca539 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 17:45:44 +0200 Subject: [PATCH 11/73] Cleanup proof format, complete basic cli tests --- Makefile | 1 + clitest/basictx.sh | 60 ++++++++++++++++++++++++++++++++++++---------- glide.lock | 2 +- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 3cb3937e7d43..c336e05e2c0f 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ clitest/shunit2: -q -O clitest/shunit2 test_cli: clitest/shunit2 + # sudo apt-get install jq @./clitest/basictx.sh # @./clitest/ibc.sh diff --git a/clitest/basictx.sh b/clitest/basictx.sh index 0cface81f4ba..e5e159a334a6 100755 --- a/clitest/basictx.sh +++ b/clitest/basictx.sh @@ -17,8 +17,6 @@ oneTimeSetUp() { # start basecoin server (with counter) initServer - sleep 5 - PID_SERVER=$! echo pid $PID_SERVER initClient @@ -30,8 +28,10 @@ oneTimeSetUp() { } oneTimeTearDown() { - echo "stopping basecoin test server" - kill -9 $PID_SERVER + echo + echo + echo "stopping basecoin test server..." + kill -9 $PID_SERVER >/dev/null 2>&1 sleep 1 } @@ -59,6 +59,8 @@ initServer() { echo "Starting server..." basecoin start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & + sleep 5 + PID_SERVER=$! } initClient() { @@ -86,22 +88,56 @@ getAddr() { echo $RAW | cut -d' ' -f2 } -testGetAccount() { +test00GetAccount() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) - echo sender $RICH - echo $SENDER - - echo recipient $POOR - echo $RECV - assertFalse "requires arg" "basecli query account" ACCT=$(basecli query account $SENDER) assertTrue "must have proper genesis account" $? - echo $ACCT + 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/glide.lock b/glide.lock index bd388820949d..3a7d423fa966 100644 --- a/glide.lock +++ b/glide.lock @@ -127,7 +127,7 @@ imports: - data - data/base58 - name: github.com/tendermint/light-client - version: 88fb726e779d97acac5f0bd387892bfc541f3701 + version: a4dbbcacfd2d0a53da1393cbe176c0a81cab42e7 subpackages: - certifiers - certifiers/client From 6e390a6dfb1bc3d27d84ea1a4dda9585158d52b8 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 17:56:08 +0200 Subject: [PATCH 12/73] Updated to newest of develop --- glide.lock | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/glide.lock b/glide.lock index 3a7d423fa966..a83da11261b5 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 6eb1119dccf2ab4d0adb870a14cb4408047119be53c8ec4afeaa281bd1d2b457 -updated: 2017-06-15T12:09:30.832243232+02:00 +updated: 2017-06-15T17:51:21.867322849+02:00 imports: - name: github.com/bgentry/speakeasy version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd @@ -113,7 +113,7 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: 438b16f1f84ef002d7408ecd6fc3a3974cbc9559 + version: 7dff40942a64cdeefefa9446b2d104750b349f8a subpackages: - cmd - keys @@ -122,12 +122,12 @@ imports: - keys/server/types - keys/storage/filestorage - name: github.com/tendermint/go-wire - version: 97beaedf0f4dbc035309157c92be3b30cc6e5d74 + version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb subpackages: - data - data/base58 - name: github.com/tendermint/light-client - version: a4dbbcacfd2d0a53da1393cbe176c0a81cab42e7 + version: 83bede2a7f150fc7f8aedde1aecd30d2bdf043e8 subpackages: - certifiers - certifiers/client @@ -139,17 +139,16 @@ imports: - commands/txs - proofs - name: github.com/tendermint/merkleeyes - version: c722818b460381bc5b82e38c73ff6e22a9df624d + version: feb2c3fadac8221f96fbfce65a63af034327f972 subpackages: - app - client - iavl - name: github.com/tendermint/tendermint - version: 11b5d11e9eec170e1d3dce165f0270d5c0759d69 + version: 4f0f50c62d41d39ad64e07ad642f705cc13c8229 subpackages: - blockchain - cmd/tendermint/commands - - cmd/tendermint/commands/flags - config - consensus - mempool From 3c18c33e9287b4d48d6beeed734771ce768c08b9 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 20:29:26 +0200 Subject: [PATCH 13/73] Fix basecli --chainid to --chain-id --- clitest/basictx.sh | 2 +- cmd/basecli/LIGHT_NODE.md | 2 +- cmd/basecli/README.md | 2 +- glide.lock | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clitest/basictx.sh b/clitest/basictx.sh index e5e159a334a6..cbb15b4341e7 100755 --- a/clitest/basictx.sh +++ b/clitest/basictx.sh @@ -66,7 +66,7 @@ initServer() { initClient() { echo "Attaching client..." # hard-code the expected validator hash - basecli init --chainid=test_chain_id --node=tcp://localhost:46657 --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 + basecli init --chain-id=test_chain_id --node=tcp://localhost:46657 --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 assertTrue "initialized light-client" $? } diff --git a/cmd/basecli/LIGHT_NODE.md b/cmd/basecli/LIGHT_NODE.md index bb58ebb19d6c..002c96cdf736 100644 --- a/cmd/basecli/LIGHT_NODE.md +++ b/cmd/basecli/LIGHT_NODE.md @@ -21,7 +21,7 @@ Just initialize your client with the proper validator set as in the [README](REA ``` $ export BCHOME=~/.lightnode -$ basecli init --node tcp://: --chainid +$ basecli init --node tcp://: --chain-id ``` ## Running diff --git a/cmd/basecli/README.md b/cmd/basecli/README.md index efa737512b95..6e00f3d85134 100644 --- a/cmd/basecli/README.md +++ b/cmd/basecli/README.md @@ -40,7 +40,7 @@ $ basecoin start ## Connect your basecli the first time ``` -% basecli init --chainid test_chain_id --node tcp://localhost:46657 +% basecli init --chain-id test_chain_id --node tcp://localhost:46657 ``` ## Check your balances... diff --git a/glide.lock b/glide.lock index a83da11261b5..38df58154dd1 100644 --- a/glide.lock +++ b/glide.lock @@ -127,7 +127,7 @@ imports: - data - data/base58 - name: github.com/tendermint/light-client - version: 83bede2a7f150fc7f8aedde1aecd30d2bdf043e8 + version: 4ad913f2728307ec13a3b602b040c29b6a2117b8 subpackages: - certifiers - certifiers/client From e356fc1edb4077fc6f09aa45e41a51f32714764b Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Thu, 15 Jun 2017 15:11:47 -0400 Subject: [PATCH 14/73] makefile cleanup --- Makefile | 34 +++++++++++++------------------ {clitest => tests/cli}/basictx.sh | 0 {clitest => tests/cli}/ibc.sh | 0 3 files changed, 14 insertions(+), 20 deletions(-) rename {clitest => tests/cli}/basictx.sh (100%) rename {clitest => tests/cli}/ibc.sh (100%) diff --git a/Makefile b/Makefile index c336e05e2c0f..18fcbbb25092 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ -GOTOOLS = \ - github.com/mitchellh/gox \ - github.com/Masterminds/glide +GOTOOLS = github.com/mitchellh/gox \ + github.com/Masterminds/glide PACKAGES=$(shell go list ./... | grep -v '/vendor/') -all: get_vendor_deps test install +all: get_vendor_deps install test build: go build ./cmd/... @@ -15,30 +14,25 @@ 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: test_unit test_cli -test: +test_unit: go test $(PACKAGES) #go run tests/tendermint/*.go -# get_deps: -# go get -d ./... - -# update_deps: -# go get -d -u ./... +test_cli: + wget "https://raw.githubusercontent.com/kward/shunit2/master/source/2.1/src/shunit2" \ + -q -O tests/cli/shunit2 + # sudo apt-get install jq + @./tests/cli/basictx.sh + # @./clitest/ibc.sh get_vendor_deps: tools glide install build-docker: - docker run -it --rm -v "$(PWD):/go/src/github.com/tendermint/basecoin" -w "/go/src/github.com/tendermint/basecoin" -e "CGO_ENABLED=0" golang:alpine go build ./cmd/basecoin + docker run -it --rm -v "$(PWD):/go/src/github.com/tendermint/basecoin" -w \ + "/go/src/github.com/tendermint/basecoin" -e "CGO_ENABLED=0" golang:alpine go build ./cmd/basecoin docker build -t "tendermint/basecoin" . tools: @@ -47,4 +41,4 @@ tools: clean: @rm -f ./basecoin -.PHONY: all build install test get_deps update_deps get_vendor_deps build-docker clean +.PHONY: all build install test test_cli test_unit get_vendor_deps build-docker clean diff --git a/clitest/basictx.sh b/tests/cli/basictx.sh similarity index 100% rename from clitest/basictx.sh rename to tests/cli/basictx.sh diff --git a/clitest/ibc.sh b/tests/cli/ibc.sh similarity index 100% rename from clitest/ibc.sh rename to tests/cli/ibc.sh From 226546e5582092e963864da7b5c640c8bb1d9454 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Thu, 15 Jun 2017 15:25:08 -0400 Subject: [PATCH 15/73] circle bash integration --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 3e8710ca9e12..09093e34aeb3 100644 --- a/circle.yml +++ b/circle.yml @@ -19,7 +19,7 @@ dependencies: test: override: - - "cd $REPO && glide install && go install ./cmd/basecoin" + - "cd $REPO && glide install && go install ./cmd/..." - ls $GOPATH/bin - "cd $REPO && make test" - "cd $REPO/demo && bash start.sh" From 789ebada42f44edf6504a7e4a3052967d473a217 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 20:47:59 +0200 Subject: [PATCH 16/73] pulled out common helpers, prepare to support ibc --- clitest/common.sh | 67 +++++++++++++++++++++++++++++++++++++++++++ tests/cli/basictx.sh | 68 +++++++------------------------------------- 2 files changed, 77 insertions(+), 58 deletions(-) create mode 100644 clitest/common.sh diff --git a/clitest/common.sh b/clitest/common.sh new file mode 100644 index 000000000000..3294548a0d0e --- /dev/null +++ b/clitest/common.sh @@ -0,0 +1,67 @@ +# this is not executable, but helper functions for the other scripts + +prepareClient() { + echo "Preparing client keys..." + basecli reset_all + assertTrue $? + + for i in "${!ACCOUNTS[@]}"; do + newKey ${ACCOUNTS[$i]} + done +} + +# initServer takes two args - (root dir, chain_id) +# and optionally port prefix as a third arg (default is 4665{6,7,8}) +# it grabs the first account to give it the money +initServer() { + echo "Setting up genesis..." + SERVE_DIR=$1/server + assertNotNull "no chain" $2 + CHAIN=$2 + SERVER_LOG=$1/basecoin.log + basecoin init --home=$SERVE_DIR >>$SERVER_LOG + + #change the genesis to the first account + GENKEY=$(basecli keys get ${ACCOUNTS[0]} -o json | jq .pubkey.data) + GENJSON=$(cat $SERVE_DIR/genesis.json) + echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY \ + | jq ".chain_id=\"$2\"" > $SERVE_DIR/genesis.json + + # optionally set the port + if [ -n "$3" ]; then + echo "setting port $3" + sed -ie "s/4665/$3/" $SERVE_DIR/config.toml + fi + + echo "Starting server..." + basecoin start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & + sleep 5 + PID_SERVER=$! +} + +# initClient requires chain_id arg, port is optional (default 4665{5,6,7}) +initClient() { + echo "Attaching client..." + PORT=${2:-4665} + # hard-code the expected validator hash + basecli init --chain-id=$1 --node=tcp://localhost:${PORT}7 --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 >/dev/null 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 +} diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index cbb15b4341e7..8584535e56e1 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -1,11 +1,11 @@ #!/bin/bash + oneTimeSetUp() { BASE_DIR=$HOME/.basecoin_test_basictx - LOG=$BASE_DIR/test.log - SERVER_LOG=$BASE_DIR/basecoin.log + CHAIN_ID=my-test-chain - rm -rf $BASE_DIR + rm -rf $BASE_DIR 2>/dev/null mkdir -p $BASE_DIR ACCOUNTS=(jae ethan bucky rigel igor) @@ -13,13 +13,14 @@ oneTimeSetUp() { POOR=${ACCOUNTS[1]} # set up client + export BC_HOME=${BASE_DIR}/client prepareClient # start basecoin server (with counter) - initServer + initServer $BASE_DIR $CHAIN_ID 3456 echo pid $PID_SERVER - initClient + initClient $CHAIN_ID 3456 echo "...Testing may begin!" echo @@ -35,59 +36,6 @@ oneTimeTearDown() { 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 --chain-id=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) @@ -140,4 +88,8 @@ test01SendTx() { # load and run these tests with shunit2! DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory + +# load common helpers +. $DIR/common.sh + . $DIR/shunit2 From 9341b8be5d61d18c3a71c34efc93e4a56b868dcd Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 20:56:59 +0200 Subject: [PATCH 17/73] Support other binaries --- clitest/common.sh | 27 ++++++++++++++++----------- tests/cli/basictx.sh | 30 ++++++++++++++++-------------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/clitest/common.sh b/clitest/common.sh index 3294548a0d0e..07fe1a54b128 100644 --- a/clitest/common.sh +++ b/clitest/common.sh @@ -1,8 +1,13 @@ # this is not executable, but helper functions for the other scripts +# these are general accounts to be prepared +ACCOUNTS=(jae ethan bucky rigel igor) +RICH=${ACCOUNTS[0]} +POOR=${ACCOUNTS[4]} + prepareClient() { echo "Preparing client keys..." - basecli reset_all + ${CLIENT_EXE} reset_all assertTrue $? for i in "${!ACCOUNTS[@]}"; do @@ -18,11 +23,11 @@ initServer() { SERVE_DIR=$1/server assertNotNull "no chain" $2 CHAIN=$2 - SERVER_LOG=$1/basecoin.log - basecoin init --home=$SERVE_DIR >>$SERVER_LOG + SERVER_LOG=$1/${SERVER_EXE}.log + ${SERVER_EXE} init --home=$SERVE_DIR >>$SERVER_LOG #change the genesis to the first account - GENKEY=$(basecli keys get ${ACCOUNTS[0]} -o json | jq .pubkey.data) + GENKEY=$(${CLIENT_EXE} 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 \ | jq ".chain_id=\"$2\"" > $SERVE_DIR/genesis.json @@ -33,18 +38,18 @@ initServer() { sed -ie "s/4665/$3/" $SERVE_DIR/config.toml fi - echo "Starting server..." - basecoin start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & + echo "Starting ${SERVER_EXE} server..." + ${SERVER_EXE} start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & sleep 5 PID_SERVER=$! } # initClient requires chain_id arg, port is optional (default 4665{5,6,7}) initClient() { - echo "Attaching client..." + echo "Attaching ${CLIENT_EXE} client..." PORT=${2:-4665} # hard-code the expected validator hash - basecli init --chain-id=$1 --node=tcp://localhost:${PORT}7 --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 + ${CLIENT_EXE} init --chain-id=$1 --node=tcp://localhost:${PORT}7 --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 assertTrue "initialized light-client" $? } @@ -52,15 +57,15 @@ initClient() { newKey(){ assertNotNull "keyname required" "$1" KEYPASS=${2:-qwertyuiop} - (echo $KEYPASS; echo $KEYPASS) | basecli keys new $1 >/dev/null 2>/dev/null + (echo $KEYPASS; echo $KEYPASS) | ${CLIENT_EXE} keys new $1 >/dev/null 2>/dev/null assertTrue "created $1" $? - assertTrue "$1 doesn't exist" "basecli keys get $1" + assertTrue "$1 doesn't exist" "${CLIENT_EXE} keys get $1" } # getAddr gets the address for a key name getAddr() { assertNotNull "keyname required" "$1" - RAW=$(basecli keys get $1) + RAW=$(${CLIENT_EXE} keys get $1) assertTrue "no key for $1" $? # print the addr echo $RAW | cut -d' ' -f2 diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 8584535e56e1..e9a6b0e5fbff 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -1,18 +1,20 @@ #!/bin/bash +# these are two globals to control all scripts (can use eg. counter instead) +SERVER_EXE=basecoin +CLIENT_EXE=basecli oneTimeSetUp() { + # these are passed in as args BASE_DIR=$HOME/.basecoin_test_basictx CHAIN_ID=my-test-chain rm -rf $BASE_DIR 2>/dev/null mkdir -p $BASE_DIR - ACCOUNTS=(jae ethan bucky rigel igor) - RICH=${ACCOUNTS[0]} - POOR=${ACCOUNTS[1]} - # set up client + # set up client - make sure you use the proper prefix if you set + # a custom CLIENT_EXE export BC_HOME=${BASE_DIR}/client prepareClient @@ -31,7 +33,7 @@ oneTimeSetUp() { oneTimeTearDown() { echo echo - echo "stopping basecoin test server..." + echo "stopping $SERVER_EXE test server..." kill -9 $PID_SERVER >/dev/null 2>&1 sleep 1 } @@ -40,13 +42,13 @@ test00GetAccount() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) - assertFalse "requires arg" "basecli query account" - ACCT=$(basecli query account $SENDER) + assertFalse "requires arg" "${CLIENT_EXE} query account" + ACCT=$(${CLIENT_EXE} 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) + ACCT2=$(${CLIENT_EXE} query account $RECV) assertFalse "has no genesis account" $? } @@ -54,10 +56,10 @@ 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" + assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 2>/dev/null" + assertFalse "bad password" "echo foo | ${CLIENT_EXE} 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) + RES=$(echo qwertyuiop | ${CLIENT_EXE} 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) @@ -65,19 +67,19 @@ test01SendTx() { assertEquals "good deliver" "0" $(echo $RES | jq .deliver_tx.code) # make sure sender goes down - ACCT=$(basecli query account $SENDER) + ACCT=$(${CLIENT_EXE} 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) + ACCT2=$(${CLIENT_EXE} 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) + TX=$(${CLIENT_EXE} query tx $HASH) assertTrue "found tx" $? assertEquals "proper height" $TX_HEIGHT $(echo $TX | jq .height) assertEquals "type=send" '"send"' $(echo $TX | jq .data.type) From 81d6d2425f7628559f7b76234751982dbd4137c6 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 15 Jun 2017 21:13:56 +0200 Subject: [PATCH 18/73] Added counter tests as well --- Makefile | 10 +++ {clitest => tests/cli}/common.sh | 0 tests/cli/counter.sh | 137 +++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+) rename {clitest => tests/cli}/common.sh (100%) create mode 100755 tests/cli/counter.sh diff --git a/Makefile b/Makefile index 18fcbbb25092..358a569e5793 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,16 @@ dist: test: test_unit test_cli +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/counter.sh + # @./clitest/ibc.sh + test_unit: go test $(PACKAGES) #go run tests/tendermint/*.go diff --git a/clitest/common.sh b/tests/cli/common.sh similarity index 100% rename from clitest/common.sh rename to tests/cli/common.sh diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh new file mode 100755 index 000000000000..ea3069a2bb34 --- /dev/null +++ b/tests/cli/counter.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +# these are two globals to control all scripts (can use eg. counter instead) +SERVER_EXE=counter +CLIENT_EXE=basecli # TODO: move to countercli + +oneTimeSetUp() { + # these are passed in as args + BASE_DIR=$HOME/.basecoin_test_counter + CHAIN_ID="counter-chain" + + rm -rf $BASE_DIR 2>/dev/null + mkdir -p $BASE_DIR + + # set up client - make sure you use the proper prefix if you set + # a custom CLIENT_EXE + export BC_HOME=${BASE_DIR}/client + prepareClient + + # start basecoin server (with counter) + initServer $BASE_DIR $CHAIN_ID 1234 + echo pid $PID_SERVER + + initClient $CHAIN_ID 1234 + + echo "...Testing may begin!" + echo + echo + echo +} + +oneTimeTearDown() { + echo + echo + echo "stopping $SERVER_EXE test server..." + kill -9 $PID_SERVER >/dev/null 2>&1 + sleep 1 +} + +# blatently copied to make sure it works with counter as well +test00GetAccount() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + assertFalse "requires arg" "${CLIENT_EXE} query account" + ACCT=$(${CLIENT_EXE} 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=$(${CLIENT_EXE} query account $RECV) + assertFalse "has no genesis account" $? +} + +# blatently copied to make sure it works with counter as well +test01SendTx() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 2>/dev/null" + assertFalse "bad password" "echo foo | ${CLIENT_EXE} 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 | ${CLIENT_EXE} 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=$(${CLIENT_EXE} 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=$(${CLIENT_EXE} 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=$(${CLIENT_EXE} 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) +} + +test02GetCounter() { + COUNT=$(${CLIENT_EXE} query counter) + assertFalse "no default count" $? +} + +test02AddCount() { + SENDER=$(getAddr $RICH) + assertFalse "bad password" "echo hi | ${CLIENT_EXE} tx counter --amount=1000mycoin --sequence=2 --name=${RICH} 2>/dev/null" + + # we have to remove the password request from stdout, to just get the json + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --amount=10mycoin --sequence=2 --name=${RICH} --valid --countfee=5mycoin 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) + + # check new state + COUNT=$(${CLIENT_EXE} query counter) + assertTrue "count now set" $? + assertEquals "one tx" "1" $(echo $COUNT | jq .data.Counter) + assertEquals "has money" "5" $(echo $COUNT | jq .data.TotalFees[0].amount) + + # FIXME: cannot load apptx properly. + # Look at the stack trace + # This cannot be fixed with the current ugly apptx structure... + # Leave for refactoring + + # make sure tx is indexed + # echo hash $HASH + # TX=$(${CLIENT_EXE} query tx $HASH --trace) + # echo tx $TX + # if [-z assertTrue "found tx" $?]; then + # assertEquals "proper height" $TX_HEIGHT $(echo $TX | jq .height) + # assertEquals "type=app" '"app"' $(echo $TX | jq .data.type) + # assertEquals "proper sender" "\"$SENDER\"" $(echo $TX | jq .data.data.input.address) + # fi + # echo $TX +} + +# load and run these tests with shunit2! +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory + +# load common helpers +. $DIR/common.sh + +. $DIR/shunit2 From ad17fcf347fd1ab4a9a721c856767dac652ebb3a Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Thu, 15 Jun 2017 15:43:09 -0400 Subject: [PATCH 19/73] makefile cleanup int --- Makefile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 358a569e5793..ef3a3e6849b1 100644 --- a/Makefile +++ b/Makefile @@ -16,16 +16,6 @@ dist: test: test_unit test_cli -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/counter.sh - # @./clitest/ibc.sh - test_unit: go test $(PACKAGES) #go run tests/tendermint/*.go @@ -35,6 +25,7 @@ test_cli: -q -O tests/cli/shunit2 # sudo apt-get install jq @./tests/cli/basictx.sh + @./tests/cli/counter.sh # @./clitest/ibc.sh get_vendor_deps: tools From 9c8ccefd353ae072843ff67fa3a736dee68a07dc Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Fri, 16 Jun 2017 04:57:45 -0400 Subject: [PATCH 20/73] reorganize basecli appTx commands int --- cmd/basecli/commands/cmds.go | 120 +++++++++++++++++---------------- cmd/basecli/counter/counter.go | 56 ++++++++------- cmd/basecli/counter/query.go | 20 +----- cmd/basecli/main.go | 9 ++- 4 files changed, 99 insertions(+), 106 deletions(-) diff --git a/cmd/basecli/commands/cmds.go b/cmd/basecli/commands/cmds.go index 50a39024b4f1..faf54c227997 100644 --- a/cmd/basecli/commands/cmds.go +++ b/cmd/basecli/commands/cmds.go @@ -10,41 +10,48 @@ import ( "github.com/tendermint/light-client/commands" 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" ) -/*** Here is the sendtx command ***/ +/******** SendTx *********/ +// SendTxCmd is CLI command to send tokens between basecoin accounts var SendTxCmd = &cobra.Command{ Use: "send", Short: "send tokens from one account to another", RunE: doSendTx, } +//nolint const ( - ToFlag = "to" - AmountFlag = "amount" - FeeFlag = "fee" - GasFlag = "gas" - SequenceFlag = "sequence" + FlagTo = "to" + FlagAmount = "amount" + FlagFee = "fee" + FlagGas = "gas" + FlagSequence = "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") + flags.String(FlagTo, "", "Destination address for the bits") + flags.String(FlagAmount, "", "Coins to send in the format ,...") + flags.String(FlagFee, "0mycoin", "Coins for the transaction fee of the format ") + flags.Int64(FlagGas, 0, "Amount of gas for this transaction") + flags.Int(FlagSequence, -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 + tx := new(btypes.SendTx) found, err := txcmd.LoadJSON(tx) + if err != nil { + return err + } if !found { err = readSendTxFlags(tx) } @@ -52,6 +59,7 @@ func doSendTx(cmd *cobra.Command, args []string) error { return err } + // Wrap and add signer send := &SendTx{ chainID: commands.GetChainID(), Tx: tx, @@ -64,34 +72,34 @@ func doSendTx(cmd *cobra.Command, args []string) error { return err } - // output result + // Output result return txcmd.OutputTx(bres) } func readSendTxFlags(tx *btypes.SendTx) error { // parse to address - to, err := ParseHexFlag(ToFlag) + to, err := ParseHexFlag(FlagTo) 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)) + tx.Fee, err = btypes.ParseCoin(viper.GetString(FlagFee)) if err != nil { return err } - amountCoins, err := btypes.ParseCoins(viper.GetString(AmountFlag)) + amountCoins, err := btypes.ParseCoins(viper.GetString(FlagAmount)) if err != nil { return err } // set the gas - tx.Gas = viper.GetInt64(GasFlag) + tx.Gas = viper.GetInt64(FlagGas) // craft the inputs and outputs tx.Inputs = []btypes.TxInput{{ Coins: amountCoins, - Sequence: viper.GetInt(SequenceFlag), + Sequence: viper.GetInt(FlagSequence), }} tx.Outputs = []btypes.TxOutput{{ Address: to, @@ -103,39 +111,53 @@ func readSendTxFlags(tx *btypes.SendTx) error { /******** 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) { - 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") + fs.String(FlagAmount, "", "Coins to send in the format ,...") + fs.String(FlagFee, "0mycoin", "Coins for the transaction fee of the format ") + fs.Int64(FlagGas, 0, "Amount of gas for this transaction") + fs.Int(FlagSequence, -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)) +func ReadAppTxFlags() (gas int64, fee btypes.Coin, txInput btypes.TxInput, err error) { + + // Set the gas + gas = viper.GetInt64(FlagGas) + + // Parse the fee and amounts into coin types + fee, err = btypes.ParseCoin(viper.GetString(FlagFee)) 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 { - return err + return } - - // set the gas - tx.Gas = viper.GetInt64(GasFlag) - - // craft the inputs and outputs - tx.Input = btypes.TxInput{ - Coins: amountCoins, - Sequence: viper.GetInt(SequenceFlag), + txInput = btypes.TxInput{ + Coins: amount, + Sequence: viper.GetInt(FlagSequence), } - return nil + return } +// WrapAppTx wraps the transaction with chain id func WrapAppTx(tx *btypes.AppTx) *AppTx { return &AppTx{ chainID: commands.GetChainID(), @@ -145,25 +167,7 @@ func WrapAppTx(tx *btypes.AppTx) *AppTx { /** TODO copied from basecoin cli - put in common somewhere? **/ +// ParseHexFlag parses a flag string to byte array 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 + return hex.DecodeString(cmn.StripHex(viper.GetString(flag))) } diff --git a/cmd/basecli/counter/counter.go b/cmd/basecli/counter/counter.go index b39792e2ceec..60f949fce2ff 100644 --- a/cmd/basecli/counter/counter.go +++ b/cmd/basecli/counter/counter.go @@ -12,68 +12,72 @@ import ( btypes "github.com/tendermint/basecoin/types" ) +//CounterTxCmd is the CLI command to execute the counter +// through the appTx Command var CounterTxCmd = &cobra.Command{ Use: "counter", Short: "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.`, - RunE: doCounterTx, + RunE: counterTxCmd, } const ( - CountFeeFlag = "countfee" - ValidFlag = "valid" + flagCountFee = "countfee" + flagValid = "valid" ) func init() { fs := CounterTxCmd.Flags() bcmd.AddAppTxFlags(fs) - fs.String(CountFeeFlag, "", "Coins to send in the format ,...") - fs.Bool(ValidFlag, false, "Is count valid?") + fs.String(flagCountFee, "", "Coins to send in the format ,...") + fs.Bool(flagValid, false, "Is count valid?") } -func doCounterTx(cmd *cobra.Command, args []string) error { - tx := new(btypes.AppTx) +func counterTxCmd(cmd *cobra.Command, args []string) error { // Note: we don't support loading apptx from json currently, so skip that - // read the standard flags - err := bcmd.ReadAppTxFlags(tx) + // Read the app-specific flags + name, data, err := getAppData() if err != nil { return err } - // now read the app-specific flags - err = readCounterFlags(tx) + // Read the standard app-tx flags + gas, fee, txInput, err := bcmd.ReadAppTxFlags() 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) + // Create AppTx and broadcast + tx := &btypes.AppTx{ + Gas: gas, + Fee: fee, + Name: name, + Input: txInput, + Data: data, + } + res, err := bcmd.BroadcastAppTx(tx) if err != nil { return err } - // output result - return txcmd.OutputTx(bres) + // Output result + return txcmd.OutputTx(res) } -// readCounterFlags sets the app-specific data in the AppTx -func readCounterFlags(tx *btypes.AppTx) error { - countFee, err := btypes.ParseCoins(viper.GetString(CountFeeFlag)) +func getAppData() (name string, data []byte, err error) { + countFee, err := btypes.ParseCoins(viper.GetString(flagCountFee)) if err != nil { - return err + return } ctx := counter.CounterTx{ - Valid: viper.GetBool(ValidFlag), + Valid: viper.GetBool(flagValid), Fee: countFee, } - tx.Name = counter.New().Name() - tx.Data = wire.BinaryBytes(ctx) - return nil + name = counter.New().Name() + data = wire.BinaryBytes(ctx) + return } diff --git a/cmd/basecli/counter/query.go b/cmd/basecli/counter/query.go index a1c6aeb9b59e..9a86df62574b 100644 --- a/cmd/basecli/counter/query.go +++ b/cmd/basecli/counter/query.go @@ -8,13 +8,14 @@ import ( "github.com/tendermint/basecoin/plugins/counter" ) +//CounterQueryCmd CLI command to query the counter state var CounterQueryCmd = &cobra.Command{ Use: "counter", 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() var cp counter.CounterPluginState @@ -25,18 +26,3 @@ 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 d5116d1600cc..753e149fd4a3 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -32,26 +32,25 @@ tmcli to work for any custom abci app. func main() { commands.AddBasicFlags(BaseCli) - // prepare queries + // Prepare queries 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.KeyCmd) pr.AddCommand(bcmd.AccountQueryCmd) 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{}) 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 + // Set up the various commands to use BaseCli.AddCommand( commands.InitCmd, commands.ResetCmd, From 75425b9bc134da0e9dc4290ae035438a02cc767a Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 13:51:48 +0200 Subject: [PATCH 21/73] Update CHANGELOG for some of the 0.6 enhancements --- CHANGELOG.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6205a7e94b6..62e45d6edfb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.6.0 (???) + +BREAKING CHANGES: +- basecli + - `basecli proof state get` -> `basecli query key` + - `basecli proof tx get` -> `basecli query tx` + - `basecli proof state get --app=account` -> `basecli query account` + - use `--chain-id` not `--chainid` for consistency + - update to use `--trace` not `--debug` for stack traces on errors + - complete overhaul on how tx and query subcommands are added. (see counter or trackomatron for examples) + - no longer supports counter app (see new countercli) +- basecoin + - removed all client side functionality from it (use basecli now for proofs) + +ENHANCEMENTS: +- intergrates tendermint 0.10.0 (not the rc-2, but the real thing) +- commands return error code (1) on failure for easier script testing +- add `reset_all` to basecli, and never delete keys on `init` +- new shutil based unit tests, with better coverage of the cli actions + +BUG FIXES: +- no longer panics on missing app_options in genesis (thanks, anton) + + ## 0.5.2 (June 2, 2017) BUG FIXES: From 4d4137855d4af364d8eaa295787e185da82a40b1 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 13:56:12 +0200 Subject: [PATCH 22/73] Cache shunit2 in Makefile, so we don't wget everytime --- CHANGELOG.md | 3 +++ Makefile | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62e45d6edfb6..a917a1c791e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.6.0 (???) +Make the basecli command the only way to use client-side, to enforce best +security practices. Lots of enhancements to get it up to production quality. + BREAKING CHANGES: - basecli - `basecli proof state get` -> `basecli query key` diff --git a/Makefile b/Makefile index ef3a3e6849b1..b61cc2ffd5b8 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,7 @@ test_unit: go test $(PACKAGES) #go run tests/tendermint/*.go -test_cli: - wget "https://raw.githubusercontent.com/kward/shunit2/master/source/2.1/src/shunit2" \ - -q -O tests/cli/shunit2 +test_cli: tests/cli/shunit2 # sudo apt-get install jq @./tests/cli/basictx.sh @./tests/cli/counter.sh @@ -36,6 +34,10 @@ build-docker: "/go/src/github.com/tendermint/basecoin" -e "CGO_ENABLED=0" golang:alpine go build ./cmd/basecoin docker build -t "tendermint/basecoin" . +tests/cli/shunit2: + wget "https://raw.githubusercontent.com/kward/shunit2/master/source/2.1/src/shunit2" \ + -q -O tests/cli/shunit2 + tools: go get -u -v $(GOTOOLS) From 2f3c7002fab7845ebf157d3f47f65dacf4914561 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 14:00:43 +0200 Subject: [PATCH 23/73] Create new command, countercli, removed counter from basecli --- cmd/basecli/main.go | 11 +--- .../commands}/counter.go | 2 +- .../counter => countercli/commands}/query.go | 2 +- cmd/countercli/main.go | 64 +++++++++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) rename cmd/{basecli/counter => countercli/commands}/counter.go (99%) rename cmd/{basecli/counter => countercli/commands}/query.go (97%) create mode 100644 cmd/countercli/main.go diff --git a/cmd/basecli/main.go b/cmd/basecli/main.go index 753e149fd4a3..0506882a279b 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 @@ -34,21 +33,15 @@ func main() { // Prepare queries pr := proofs.RootCmd - // These are default parsers, but you optional in your app + // These are default parsers, but optional in your app (you can remove key) pr.AddCommand(proofs.TxCmd) pr.AddCommand(proofs.KeyCmd) pr.AddCommand(bcmd.AccountQueryCmd) - pr.AddCommand(bcount.CounterQueryCmd) - // Here is how you add custom txs... but don't really add counter in your app + // you will always want this for the base send command 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( diff --git a/cmd/basecli/counter/counter.go b/cmd/countercli/commands/counter.go similarity index 99% rename from cmd/basecli/counter/counter.go rename to cmd/countercli/commands/counter.go index 60f949fce2ff..22064e08cba5 100644 --- a/cmd/basecli/counter/counter.go +++ b/cmd/countercli/commands/counter.go @@ -1,4 +1,4 @@ -package counter +package commands import ( "github.com/spf13/cobra" diff --git a/cmd/basecli/counter/query.go b/cmd/countercli/commands/query.go similarity index 97% rename from cmd/basecli/counter/query.go rename to cmd/countercli/commands/query.go index 9a86df62574b..751f7a11b032 100644 --- a/cmd/basecli/counter/query.go +++ b/cmd/countercli/commands/query.go @@ -1,4 +1,4 @@ -package counter +package commands import ( "github.com/spf13/cobra" diff --git a/cmd/countercli/main.go b/cmd/countercli/main.go new file mode 100644 index 000000000000..57204d3fb6b8 --- /dev/null +++ b/cmd/countercli/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "os" + + "github.com/spf13/cobra" + + keycmd "github.com/tendermint/go-crypto/cmd" + "github.com/tendermint/light-client/commands" + "github.com/tendermint/light-client/commands/proofs" + "github.com/tendermint/light-client/commands/proxy" + "github.com/tendermint/light-client/commands/seeds" + "github.com/tendermint/light-client/commands/txs" + "github.com/tendermint/tmlibs/cli" + + bcmd "github.com/tendermint/basecoin/cmd/basecli/commands" + bcount "github.com/tendermint/basecoin/cmd/countercli/commands" +) + +// BaseCli represents the base command when called without any subcommands +var BaseCli = &cobra.Command{ + Use: "basecli", + Short: "Light client for tendermint", + Long: `Basecli is an version of tmcli including custom logic to +present a nice (not raw hex) interface to the basecoin blockchain structure. + +This is a useful tool, but also serves to demonstrate how one can configure +tmcli to work for any custom abci app. +`, +} + +func main() { + commands.AddBasicFlags(BaseCli) + + // 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) + + // IMPORTANT: here is how you add custom query commands in your app + pr.AddCommand(bcount.CounterQueryCmd) + + proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) + tr := txs.RootCmd + tr.AddCommand(bcmd.SendTxCmd) + + // IMPORTANT: here is how you add custom tx construction for your app + tr.AddCommand(bcount.CounterTxCmd) + + // Set up the various commands to use + BaseCli.AddCommand( + commands.InitCmd, + commands.ResetCmd, + keycmd.RootCmd, + seeds.RootCmd, + pr, + tr, + proxy.RootCmd) + + cmd := cli.PrepareMainCmd(BaseCli, "BC", os.ExpandEnv("$HOME/.basecli")) + cmd.Execute() +} From 526e2136e109d0cc1c2751233b37fabc7df5d3ba Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 14:01:37 +0200 Subject: [PATCH 24/73] Fix cli tests for new countercli app --- tests/cli/counter.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index ea3069a2bb34..3b00adb88140 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -2,7 +2,7 @@ # these are two globals to control all scripts (can use eg. counter instead) SERVER_EXE=counter -CLIENT_EXE=basecli # TODO: move to countercli +CLIENT_EXE=countercli oneTimeSetUp() { # these are passed in as args From fb7fc78b2e636a012c5a963591a2cbdfc04706ea Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 14:26:35 +0200 Subject: [PATCH 25/73] clean up cli tests --- tests/cli/basictx.sh | 31 ++++++-------------------- tests/cli/common.sh | 31 ++++++++++++++++++++++++++ tests/cli/counter.sh | 53 ++++++++++++++++---------------------------- 3 files changed, 57 insertions(+), 58 deletions(-) diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index e9a6b0e5fbff..550bd2c43013 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -43,10 +43,8 @@ test00GetAccount() { RECV=$(getAddr $POOR) assertFalse "requires arg" "${CLIENT_EXE} query account" - ACCT=$(${CLIENT_EXE} 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) + + checkAccount $SENDER "0" "9007199254740992" ACCT2=$(${CLIENT_EXE} query account $RECV) assertFalse "has no genesis account" $? @@ -60,31 +58,16 @@ test01SendTx() { assertFalse "bad password" "echo foo | ${CLIENT_EXE} 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 | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null | tail -n +2) - assertTrue "sent tx" $? + txSucceeded "$RES" + 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=$(${CLIENT_EXE} 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=$(${CLIENT_EXE} 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) + checkAccount $SENDER "1" "9007199254740000" + checkAccount $RECV "0" "992" # make sure tx is indexed - TX=$(${CLIENT_EXE} 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) + checkSendTx $HASH $TX_HEIGHT $SENDER "992" } diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 07fe1a54b128..4a601284449b 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -70,3 +70,34 @@ getAddr() { # print the addr echo $RAW | cut -d' ' -f2 } + +# checkAccount $ADDR $SEQUENCE $BALANCE +# assumes just one coin, checks the balance of first coin in any case +checkAccount() { + # make sure sender goes down + ACCT=$(${CLIENT_EXE} query account $1) + assertTrue "must have genesis account" $? + assertEquals "proper sequence" "$2" $(echo $ACCT | jq .data.sequence) + assertEquals "proper money" "$3" $(echo $ACCT | jq .data.coins[0].amount) +} + +# txSucceeded $RES +# must be called right after the `tx` command, makes sure it got a success response +txSucceeded() { + assertTrue "sent tx" $? + assertEquals "good check" "0" $(echo $1 | jq .check_tx.code) + assertEquals "good deliver" "0" $(echo $1 | jq .deliver_tx.code) +} + +# checkSendTx $HASH $HEIGHT $SENDER $AMOUNT +# this looks up the tx by hash, and makes sure the height and type match +# and that the first input was from this sender for this amount +checkSendTx() { + TX=$(${CLIENT_EXE} query tx $1) + assertTrue "found tx" $? + assertEquals "proper height" $2 $(echo $TX | jq .height) + assertEquals "type=send" '"send"' $(echo $TX | jq .data.type) + assertEquals "proper sender" "\"$3\"" $(echo $TX | jq .data.data.inputs[0].address) + assertEquals "proper out amount" "$4" $(echo $TX | jq .data.data.outputs[0].coins[0].amount) +} + diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index 3b00adb88140..461fb410e52f 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -37,22 +37,19 @@ oneTimeTearDown() { sleep 1 } -# blatently copied to make sure it works with counter as well + test00GetAccount() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) assertFalse "requires arg" "${CLIENT_EXE} query account" - ACCT=$(${CLIENT_EXE} 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) + + checkAccount $SENDER "0" "9007199254740992" ACCT2=$(${CLIENT_EXE} query account $RECV) assertFalse "has no genesis account" $? } -# blatently copied to make sure it works with counter as well test01SendTx() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) @@ -61,31 +58,15 @@ test01SendTx() { assertFalse "bad password" "echo foo | ${CLIENT_EXE} 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 | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null | tail -n +2) - assertTrue "sent tx" $? + txSucceeded "$RES" 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=$(${CLIENT_EXE} 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=$(${CLIENT_EXE} 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) + checkAccount $SENDER "1" "9007199254740000" + checkAccount $RECV "0" "992" # make sure tx is indexed - TX=$(${CLIENT_EXE} 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) + checkSendTx $HASH $TX_HEIGHT $SENDER "992" } test02GetCounter() { @@ -93,23 +74,27 @@ test02GetCounter() { assertFalse "no default count" $? } +# checkAccount $COUNT $BALANCE +# assumes just one coin, checks the balance of first coin in any case +checkCounter() { + # make sure sender goes down + ACCT=$(${CLIENT_EXE} query counter) + assertTrue "count is set" $? + assertEquals "proper count" "$1" $(echo $ACCT | jq .data.Counter) + assertEquals "proper money" "$2" $(echo $ACCT | jq .data.TotalFees[0].amount) +} + test02AddCount() { SENDER=$(getAddr $RICH) assertFalse "bad password" "echo hi | ${CLIENT_EXE} tx counter --amount=1000mycoin --sequence=2 --name=${RICH} 2>/dev/null" # we have to remove the password request from stdout, to just get the json RES=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --amount=10mycoin --sequence=2 --name=${RICH} --valid --countfee=5mycoin 2>/dev/null | tail -n +2) - assertTrue "sent tx" $? + txSucceeded "$RES" 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) - # check new state - COUNT=$(${CLIENT_EXE} query counter) - assertTrue "count now set" $? - assertEquals "one tx" "1" $(echo $COUNT | jq .data.Counter) - assertEquals "has money" "5" $(echo $COUNT | jq .data.TotalFees[0].amount) + checkCounter "1" "5" # FIXME: cannot load apptx properly. # Look at the stack trace From 4606fc84f7687d757009851dc4f20e82c9ad173d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 14:43:54 +0200 Subject: [PATCH 26/73] Add ibc test scaffolding --- Makefile | 2 +- tests/cli/basictx.sh | 2 +- tests/cli/common.sh | 1 - tests/cli/counter.sh | 2 +- tests/cli/ibc.sh | 83 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index b61cc2ffd5b8..dddf4fc2cecb 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ test_cli: tests/cli/shunit2 # sudo apt-get install jq @./tests/cli/basictx.sh @./tests/cli/counter.sh - # @./clitest/ibc.sh + @./clitest/ibc.sh get_vendor_deps: tools glide install diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 550bd2c43013..efb01f185299 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -20,7 +20,7 @@ oneTimeSetUp() { # start basecoin server (with counter) initServer $BASE_DIR $CHAIN_ID 3456 - echo pid $PID_SERVER + PID_SERVER=$! initClient $CHAIN_ID 3456 diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 4a601284449b..08acb71e014d 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -41,7 +41,6 @@ initServer() { echo "Starting ${SERVER_EXE} server..." ${SERVER_EXE} start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & sleep 5 - PID_SERVER=$! } # initClient requires chain_id arg, port is optional (default 4665{5,6,7}) diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index 461fb410e52f..fbc7699d3c77 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -19,7 +19,7 @@ oneTimeSetUp() { # start basecoin server (with counter) initServer $BASE_DIR $CHAIN_ID 1234 - echo pid $PID_SERVER + PID_SERVER=$! initClient $CHAIN_ID 1234 diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 2b0c889a74cf..662f91b1065c 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -1,3 +1,84 @@ #!/bin/bash -echo "ibc test not implemented" +#!/bin/bash + +# these are two globals to control all scripts (can use eg. counter instead) +SERVER_EXE=basecoin +CLIENT_EXE=basecli + +oneTimeSetUp() { + # these are passed in as args + BASE_DIR_1=$HOME/.basecoin_test_ibc/chain1 + CHAIN_ID_1=test-chain-1 + CLIENT_1=${BASE_DIR_1}/client + + BASE_DIR_2=$HOME/.basecoin_test_ibc/chain2 + CHAIN_ID_2=test-chain-2 + CLIENT_2=${BASE_DIR_2}/client + + # clean up and create the test dirs + rm -rf $BASE_DIR_1 $BASE_DIR_2 2>/dev/null + mkdir -p $BASE_DIR_1 $BASE_DIR_2 + + # set up client for chain 1- make sure you use the proper prefix if you set + # a custom CLIENT_EXE + BC_HOME=${CLIENT_1} prepareClient + BC_HOME=${CLIENT_2} prepareClient + + # start basecoin server, giving money to the key in the first client + BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 2345 + PID_SERVER_1=$! + + # start second basecoin server, giving money to the key in the second client + BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 3456 + PID_SERVER_2=$! + + # connect both clients + BC_HOME=${CLIENT_1} initClient $CHAIN_ID_1 2345 + BC_HOME=${CLIENT_2} initClient $CHAIN_ID_2 3456 + + echo "...Testing may begin!" + echo + echo + echo +} + +oneTimeTearDown() { + echo + echo + echo "stopping both $SERVER_EXE test servers... $PID_SERVER_1 $PID_SERVER_2" + kill -9 $PID_SERVER_1 + kill -9 $PID_SERVER_2 + sleep 1 +} + +test00GetAccount() { + export BC_HOME=${CLIENT_1} + SENDER_1=$(getAddr $RICH) + RECV_1=$(getAddr $POOR) + + assertFalse "requires arg" "${CLIENT_EXE} query account" + assertFalse "has no genesis account" "${CLIENT_EXE} query account $RECV_1" + checkAccount $SENDER_1 "0" "9007199254740992" + + export BC_HOME=${CLIENT_2} + SENDER_2=$(getAddr $RICH) + RECV_2=$(getAddr $POOR) + + assertFalse "requires arg" "${CLIENT_EXE} query account" + assertFalse "has no genesis account" "${CLIENT_EXE} query account $RECV_2" + checkAccount $SENDER_2 "0" "9007199254740992" + + # make sure that they have different addresses on both chains (they are random keys) + assertNotEquals "sender keys must be different" "$SENDER_1" "$SENDER_2" + assertNotEquals "recipient keys must be different" "$RECV_1" "$RECV_2" +} + + +# load and run these tests with shunit2! +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory + +# load common helpers +. $DIR/common.sh + +. $DIR/shunit2 From cba5523ca5beece7a6803d0f3c6fdf45e2c9e617 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 15:33:37 +0200 Subject: [PATCH 27/73] Clear output of test failures in ibc --- tests/cli/basictx.sh | 11 +++++------ tests/cli/common.sh | 28 ++++++++++++++++++++++++---- tests/cli/counter.sh | 20 ++++++++++---------- tests/cli/ibc.sh | 44 ++++++++++++++++++++++++++++++++++++++------ 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index efb01f185299..945665b521f2 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -56,12 +56,11 @@ test01SendTx() { assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 2>/dev/null" assertFalse "bad password" "echo foo | ${CLIENT_EXE} 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 | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null | tail -n +2) - txSucceeded "$RES" - - HASH=$(echo $RES | jq .hash | tr -d \") - TX_HEIGHT=$(echo $RES | jq .height) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + TX=`echo $RES | cut -d: -f2-` + HASH=$(echo $TX | jq .hash | tr -d \") + TX_HEIGHT=$(echo $TX | jq .height) checkAccount $SENDER "1" "9007199254740000" checkAccount $RECV "0" "992" diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 08acb71e014d..faa9faa88b94 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -78,14 +78,19 @@ checkAccount() { assertTrue "must have genesis account" $? assertEquals "proper sequence" "$2" $(echo $ACCT | jq .data.sequence) assertEquals "proper money" "$3" $(echo $ACCT | jq .data.coins[0].amount) + return $? } -# txSucceeded $RES +# txSucceeded $? "$RES" # must be called right after the `tx` command, makes sure it got a success response txSucceeded() { - assertTrue "sent tx" $? - assertEquals "good check" "0" $(echo $1 | jq .check_tx.code) - assertEquals "good deliver" "0" $(echo $1 | jq .deliver_tx.code) + if (assertTrue "sent tx: $2" $1); then + TX=`echo $2 | cut -d: -f2-` # strip off first line asking for password + assertEquals "good check: $TX" "0" $(echo $TX | jq .check_tx.code) + assertEquals "good deliver: $TX" "0" $(echo $TX | jq .deliver_tx.code) + else + return 1 + fi } # checkSendTx $HASH $HEIGHT $SENDER $AMOUNT @@ -98,5 +103,20 @@ checkSendTx() { assertEquals "type=send" '"send"' $(echo $TX | jq .data.type) assertEquals "proper sender" "\"$3\"" $(echo $TX | jq .data.data.inputs[0].address) assertEquals "proper out amount" "$4" $(echo $TX | jq .data.data.outputs[0].coins[0].amount) + return $? } +# waitForBlock $port +# waits until the block height on that node increases by one +waitForBlock() { + addr=http://localhost:$1 + b1=`curl -s $addr/status | jq .result.latest_block_height` + b2=$b1 + while [ "$b2" == "$b1" ]; do + echo "Waiting for node $addr to commit a block ..." + sleep 1 + b2=`curl -s $addr/status | jq .result.latest_block_height` + done +} + + diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index fbc7699d3c77..6f83e33da589 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -56,11 +56,11 @@ test01SendTx() { assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 2>/dev/null" assertFalse "bad password" "echo foo | ${CLIENT_EXE} 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 | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null | tail -n +2) - txSucceeded "$RES" - HASH=$(echo $RES | jq .hash | tr -d \") - TX_HEIGHT=$(echo $RES | jq .height) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + TX=`echo $RES | cut -d: -f2-` + HASH=$(echo $TX | jq .hash | tr -d \") + TX_HEIGHT=$(echo $TX | jq .height) checkAccount $SENDER "1" "9007199254740000" checkAccount $RECV "0" "992" @@ -88,11 +88,11 @@ test02AddCount() { SENDER=$(getAddr $RICH) assertFalse "bad password" "echo hi | ${CLIENT_EXE} tx counter --amount=1000mycoin --sequence=2 --name=${RICH} 2>/dev/null" - # we have to remove the password request from stdout, to just get the json - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --amount=10mycoin --sequence=2 --name=${RICH} --valid --countfee=5mycoin 2>/dev/null | tail -n +2) - txSucceeded "$RES" - HASH=$(echo $RES | jq .hash | tr -d \") - TX_HEIGHT=$(echo $RES | jq .height) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --amount=10mycoin --sequence=2 --name=${RICH} --valid --countfee=5mycoin 2>/dev/null) + txSucceeded $? "$RES" + TX=`echo $RES | cut -d: -f2-` + HASH=$(echo $TX | jq .hash | tr -d \") + TX_HEIGHT=$(echo $TX | jq .height) checkCounter "1" "5" diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 662f91b1065c..49c607834573 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -11,10 +11,12 @@ oneTimeSetUp() { BASE_DIR_1=$HOME/.basecoin_test_ibc/chain1 CHAIN_ID_1=test-chain-1 CLIENT_1=${BASE_DIR_1}/client + PORT_1=1234 BASE_DIR_2=$HOME/.basecoin_test_ibc/chain2 CHAIN_ID_2=test-chain-2 CLIENT_2=${BASE_DIR_2}/client + PORT_2=2345 # clean up and create the test dirs rm -rf $BASE_DIR_1 $BASE_DIR_2 2>/dev/null @@ -26,16 +28,16 @@ oneTimeSetUp() { BC_HOME=${CLIENT_2} prepareClient # start basecoin server, giving money to the key in the first client - BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 2345 + BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 $PORT_1 PID_SERVER_1=$! # start second basecoin server, giving money to the key in the second client - BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 3456 + BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 $PORT_2 PID_SERVER_2=$! # connect both clients - BC_HOME=${CLIENT_1} initClient $CHAIN_ID_1 2345 - BC_HOME=${CLIENT_2} initClient $CHAIN_ID_2 3456 + BC_HOME=${CLIENT_1} initClient $CHAIN_ID_1 $PORT_1 + BC_HOME=${CLIENT_2} initClient $CHAIN_ID_2 $PORT_2 echo "...Testing may begin!" echo @@ -53,9 +55,9 @@ oneTimeTearDown() { } test00GetAccount() { + SENDER_1=$(BC_HOME=${CLIENT_1} getAddr $RICH) + RECV_1=$(BC_HOME=${CLIENT_1} getAddr $POOR) export BC_HOME=${CLIENT_1} - SENDER_1=$(getAddr $RICH) - RECV_1=$(getAddr $POOR) assertFalse "requires arg" "${CLIENT_EXE} query account" assertFalse "has no genesis account" "${CLIENT_EXE} query account $RECV_1" @@ -74,6 +76,36 @@ test00GetAccount() { assertNotEquals "recipient keys must be different" "$RECV_1" "$RECV_2" } +test01SendIBCTx() { + # trigger a cross-chain sendTx... from RICH on chain1 to POOR on chain2 + # we make sure the money was reduced, but nothing arrived + SENDER=$(BC_HOME=${CLIENT_1} getAddr $RICH) + RECV=$(BC_HOME=${CLIENT_2} getAddr $POOR) + + # we have to remove the password request from stdout, to just get the json + export BC_HOME=${CLIENT_1} + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20002mycoin --sequence=1 --to=${CHAIN_ID_2}/${RECV} --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + # an example to quit early if there is no point in more tests + if [ $? != 0 ]; then echo "aborting!"; return 1; fi + + TX=`echo $RES | cut -d: -f2-` + HASH=$(echo $TX | jq .hash | tr -d \") + TX_HEIGHT=$(echo $TX | jq .height) + + # make sure balance went down and tx is indexed + checkAccount $SENDER "1" "9007199254720990" + checkSendTx $HASH $TX_HEIGHT $SENDER "20002" + + # # make sure nothing arrived - yet + waitForBlock ${PORT_1}7 + assertFalse "no relay running" "BC_HOME=${CLIENT_2} ${CLIENT_EXE} query account $RECV" + + # start the relay and wait a few blocks... + + # then make sure the money arrived +} + # load and run these tests with shunit2! DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory From 33d4f930da8e582357d0dcb7d1c55125f7bde33b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 15:42:18 +0200 Subject: [PATCH 28/73] basecli sendtx handles chain/addr format --- cmd/basecli/commands/cmds.go | 31 +++++++++++++++++++++++++++++-- cmd/basecli/commands/sendtx.go | 3 ++- tests/cli/ibc.sh | 2 ++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/cmd/basecli/commands/cmds.go b/cmd/basecli/commands/cmds.go index faf54c227997..d6d598590a80 100644 --- a/cmd/basecli/commands/cmds.go +++ b/cmd/basecli/commands/cmds.go @@ -2,6 +2,7 @@ package commands import ( "encoding/hex" + "strings" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -78,9 +79,9 @@ func doSendTx(cmd *cobra.Command, args []string) error { func readSendTxFlags(tx *btypes.SendTx) error { // parse to address - to, err := ParseHexFlag(FlagTo) + to, err := parseChainAddress(viper.GetString(FlagTo)) if err != nil { - return errors.Errorf("To address is invalid hex: %v\n", err) + return err } //parse the fee and amounts into coin types @@ -109,6 +110,32 @@ func readSendTxFlags(tx *btypes.SendTx) error { return nil } +func parseChainAddress(toFlag string) ([]byte, error) { + var toHex string + var chainPrefix string + spl := strings.Split(toFlag, "/") + switch len(spl) { + case 1: + toHex = spl[0] + case 2: + chainPrefix = spl[0] + toHex = spl[1] + default: + return nil, errors.Errorf("To address has too many slashes") + } + + // convert destination address to bytes + to, err := hex.DecodeString(cmn.StripHex(toHex)) + if err != nil { + return nil, errors.Errorf("To address is invalid hex: %v\n", err) + } + + if chainPrefix != "" { + to = []byte(chainPrefix + "/" + string(to)) + } + return to, nil +} + /******** AppTx *********/ // BroadcastAppTx wraps, signs, and executes an app tx basecoin transaction diff --git a/cmd/basecli/commands/sendtx.go b/cmd/basecli/commands/sendtx.go index ccf00c6ed1dc..178e4e37d928 100644 --- a/cmd/basecli/commands/sendtx.go +++ b/cmd/basecli/commands/sendtx.go @@ -97,7 +97,8 @@ func (s *SendTx) ValidateBasic() error { } } for _, out := range s.Tx.Outputs { - if len(out.Address) != 20 { + // we now allow chain/addr, so it can be more than 20 bytes + if len(out.Address) < 20 { return errors.Errorf("Invalid output address length: %d", len(out.Address)) } if !out.Coins.IsValid() { diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 49c607834573..dbe1ff4f9544 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -5,6 +5,8 @@ # these are two globals to control all scripts (can use eg. counter instead) SERVER_EXE=basecoin CLIENT_EXE=basecli +# just uncomment this line for full stack traces in error output +# CLIENT_EXE="basecli --trace" oneTimeSetUp() { # these are passed in as args From 6eac364c4322497f6d2f38f7d675d86cd9b6ee16 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 16:59:23 +0200 Subject: [PATCH 29/73] Complete ibc tests with "basecoin ibc register" and "basecoin relay" --- tests/cli/basictx.sh | 3 +- tests/cli/common.sh | 6 ++-- tests/cli/counter.sh | 2 +- tests/cli/ibc.sh | 78 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 945665b521f2..0f2eb7803a1a 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -12,7 +12,6 @@ oneTimeSetUp() { rm -rf $BASE_DIR 2>/dev/null mkdir -p $BASE_DIR - # set up client - make sure you use the proper prefix if you set # a custom CLIENT_EXE export BC_HOME=${BASE_DIR}/client @@ -22,7 +21,7 @@ oneTimeSetUp() { initServer $BASE_DIR $CHAIN_ID 3456 PID_SERVER=$! - initClient $CHAIN_ID 3456 + initClient $CHAIN_ID 34567 echo "...Testing may begin!" echo diff --git a/tests/cli/common.sh b/tests/cli/common.sh index faa9faa88b94..d39355fe054c 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -43,12 +43,12 @@ initServer() { sleep 5 } -# initClient requires chain_id arg, port is optional (default 4665{5,6,7}) +# initClient requires chain_id arg, port is optional (default 46657) initClient() { echo "Attaching ${CLIENT_EXE} client..." - PORT=${2:-4665} + PORT=${2:-46657} # hard-code the expected validator hash - ${CLIENT_EXE} init --chain-id=$1 --node=tcp://localhost:${PORT}7 --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 + ${CLIENT_EXE} init --chain-id=$1 --node=tcp://localhost:${PORT} --valhash=EB168E17E45BAEB194D4C79067FFECF345C64DE6 assertTrue "initialized light-client" $? } diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index 6f83e33da589..599f511297db 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -21,7 +21,7 @@ oneTimeSetUp() { initServer $BASE_DIR $CHAIN_ID 1234 PID_SERVER=$! - initClient $CHAIN_ID 1234 + initClient $CHAIN_ID 12347 echo "...Testing may begin!" echo diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index dbe1ff4f9544..bc9d76cd9298 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -13,12 +13,14 @@ oneTimeSetUp() { BASE_DIR_1=$HOME/.basecoin_test_ibc/chain1 CHAIN_ID_1=test-chain-1 CLIENT_1=${BASE_DIR_1}/client - PORT_1=1234 + PREFIX_1=1234 + PORT_1=${PREFIX_1}7 BASE_DIR_2=$HOME/.basecoin_test_ibc/chain2 CHAIN_ID_2=test-chain-2 CLIENT_2=${BASE_DIR_2}/client - PORT_2=2345 + PREFIX_2=2345 + PORT_2=${PREFIX_2}7 # clean up and create the test dirs rm -rf $BASE_DIR_1 $BASE_DIR_2 2>/dev/null @@ -30,11 +32,11 @@ oneTimeSetUp() { BC_HOME=${CLIENT_2} prepareClient # start basecoin server, giving money to the key in the first client - BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 $PORT_1 + BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 $PREFIX_1 PID_SERVER_1=$! # start second basecoin server, giving money to the key in the second client - BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 $PORT_2 + BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 $PREFIX_2 PID_SERVER_2=$! # connect both clients @@ -100,14 +102,78 @@ test01SendIBCTx() { checkSendTx $HASH $TX_HEIGHT $SENDER "20002" # # make sure nothing arrived - yet - waitForBlock ${PORT_1}7 + waitForBlock ${PORT_1} assertFalse "no relay running" "BC_HOME=${CLIENT_2} ${CLIENT_EXE} query account $RECV" # start the relay and wait a few blocks... + # (already sent a tx on chain1, so use higher sequence) + startRelay 2 1 + if [ $? != 0 ]; then echo "can't start relay!"; return 1; fi - # then make sure the money arrived + # give it a little time, then make sure the money arrived + echo "waiting for relay..." + sleep 1 + waitForBlock ${PORT_1} + waitForBlock ${PORT_2} + + # check the new account + echo "checking ibc recipient..." + BC_HOME=${CLIENT_2} checkAccount $RECV "0" "20002" + + # stop relay + kill -9 $PID_RELAY } +# startRelay $seq1 $seq2 +# startRelay hooks up a relay between chain1 and chain2 +# it needs the proper sequence number for $RICH on chain1 and chain2 as args +startRelay() { + # send some cash to the default key, so it can send messages + RELAY_KEY=${BASE_DIR_1}/server/key.json + RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") + + # get paid on chain1 + export BC_HOME=${CLIENT_1} + SENDER=$(getAddr $RICH) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin --sequence=$1 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + if [ $? != 0 ]; then echo "can't pay chain1!"; return 1; fi + + # get paid on chain2 + export BC_HOME=${CLIENT_2} + SENDER=$(getAddr $RICH) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin --sequence=$2 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + if [ $? != 0 ]; then echo "can't pay chain2!"; return 1; fi + + # now we need to register the chains + # TODO: do this with basecli!!!! + basecoin tx ibc --amount 10mycoin --from=$RELAY_KEY --chain_id=$CHAIN_ID_2 \ + --node=tcp://localhost:${PORT_2} \ + register --ibc_chain_id=$CHAIN_ID_1 --genesis=$BASE_DIR_1/server/genesis.json \ + >/dev/null + if [ $? != 0 ]; then echo "can't register chain1 on chain 2"; return 1; fi + + basecoin tx ibc --amount 10mycoin --from=$RELAY_KEY --chain_id=$CHAIN_ID_1 \ + --node=tcp://localhost:${PORT_1} \ + register --ibc_chain_id=$CHAIN_ID_2 --genesis=$BASE_DIR_2/server/genesis.json \ + >/dev/null + if [ $? != 0 ]; then echo "can't register chain2 on chain 1"; return 1; fi + + # now start the relay! (this remains a server command) + # TODO: bucky, why does this die if I don't provide home??? + # It doesn't use the --from flag???? + ${SERVER_EXE} relay --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ + --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ + --home=${BASE_DIR_1}/server --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + PID_RELAY=$! + echo starting relay $PID_RELAY ... + + # return an error if it dies in the first two seconds to make sure it is running + sleep 2 + ps $PID_RELAY >/dev/null + return $? +} # load and run these tests with shunit2! DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory From f75ebca3aeef3d38f4a6f5db7a25e20df7687102 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 17:10:45 +0200 Subject: [PATCH 30/73] Fix Makefile, remove no longer needed demo! --- Makefile | 2 +- circle.yml | 1 - demo/clean.sh | 10 -- demo/data/chain1/config.toml | 11 -- demo/data/chain1/genesis.json | 31 ----- demo/data/chain1/key.json | 12 -- demo/data/chain1/priv_validator.json | 1 - demo/data/chain2/config.toml | 11 -- demo/data/chain2/genesis.json | 31 ----- demo/data/chain2/key.json | 11 -- demo/data/chain2/priv_validator.json | 1 - demo/start.sh | 198 --------------------------- 12 files changed, 1 insertion(+), 319 deletions(-) delete mode 100644 demo/clean.sh delete mode 100644 demo/data/chain1/config.toml delete mode 100644 demo/data/chain1/genesis.json delete mode 100644 demo/data/chain1/key.json delete mode 100644 demo/data/chain1/priv_validator.json delete mode 100644 demo/data/chain2/config.toml delete mode 100644 demo/data/chain2/genesis.json delete mode 100644 demo/data/chain2/key.json delete mode 100644 demo/data/chain2/priv_validator.json delete mode 100644 demo/start.sh diff --git a/Makefile b/Makefile index dddf4fc2cecb..159618cc9eb2 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ test_cli: tests/cli/shunit2 # sudo apt-get install jq @./tests/cli/basictx.sh @./tests/cli/counter.sh - @./clitest/ibc.sh + @./tests/cli/ibc.sh get_vendor_deps: tools glide install diff --git a/circle.yml b/circle.yml index 09093e34aeb3..ea4110e9da56 100644 --- a/circle.yml +++ b/circle.yml @@ -22,6 +22,5 @@ test: - "cd $REPO && glide install && go install ./cmd/..." - ls $GOPATH/bin - "cd $REPO && make test" - - "cd $REPO/demo && bash start.sh" diff --git a/demo/clean.sh b/demo/clean.sh deleted file mode 100644 index bffdefdb84f2..000000000000 --- a/demo/clean.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -killall -9 basecoin tendermint -TMHOME=./data/chain1 tendermint unsafe_reset_all -TMHOME=./data/chain2 tendermint unsafe_reset_all - -rm ./*.log - -rm ./data/chain1/*.bak -rm ./data/chain2/*.bak diff --git a/demo/data/chain1/config.toml b/demo/data/chain1/config.toml deleted file mode 100644 index e2bcb49fff87..000000000000 --- a/demo/data/chain1/config.toml +++ /dev/null @@ -1,11 +0,0 @@ -# This is a TOML config file. -# For more information, see https://github.com/toml-lang/toml - -proxy_app = "tcp://127.0.0.1:46658" -moniker = "anonymous" -node_laddr = "tcp://0.0.0.0:46656" -seeds = "" -fast_sync = true -db_backend = "leveldb" -log_level = "info" -rpc_laddr = "tcp://0.0.0.0:46657" diff --git a/demo/data/chain1/genesis.json b/demo/data/chain1/genesis.json deleted file mode 100644 index 284572eb374e..000000000000 --- a/demo/data/chain1/genesis.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "app_hash": "", - "chain_id": "test_chain_1", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "amount": 10, - "name": "", - "pub_key": { - "type": "ed25519", - "data":"D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A" - } - } - ], - "app_options": { - "accounts": [ - { - "pub_key": { - "type": "ed25519", - "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - } - ] - } -} diff --git a/demo/data/chain1/key.json b/demo/data/chain1/key.json deleted file mode 100644 index 751dc858f0dc..000000000000 --- a/demo/data/chain1/key.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "address": "D397BC62B435F3CF50570FBAB4340FE52C60858F", - "priv_key": { - "type": "ed25519", - "data": "39E75AA1CF7BC710585977EFC375CD1730519186BD231478C339F2819C3C26E7B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - }, - "pub_key": { - "type": "ed25519", - "data": "B3588BDC92015ED3CDB6F57A86379E8C79A7111063610B7E625487C76496F4DF" - } -} - diff --git a/demo/data/chain1/priv_validator.json b/demo/data/chain1/priv_validator.json deleted file mode 100644 index 55db06f4bca6..000000000000 --- a/demo/data/chain1/priv_validator.json +++ /dev/null @@ -1 +0,0 @@ -{"address":"EBB0B4A899973C524A6BB18A161056A55F590F41","pub_key":{"type":"ed25519","data":"D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A"},"last_height":0,"last_round":0,"last_step":0,"last_signature":null,"priv_key":{"type":"ed25519","data":"5FFDC1EA5FA2CA4A0A5503C86D2D348C5B401AD80FAA1899508F1ED00D8982E8D6EBB92440CF375054AA59BCF0C99D596DEEDFFB2543CAE1BA1908B72CF9676A"}} \ No newline at end of file diff --git a/demo/data/chain2/config.toml b/demo/data/chain2/config.toml deleted file mode 100644 index e2bcb49fff87..000000000000 --- a/demo/data/chain2/config.toml +++ /dev/null @@ -1,11 +0,0 @@ -# This is a TOML config file. -# For more information, see https://github.com/toml-lang/toml - -proxy_app = "tcp://127.0.0.1:46658" -moniker = "anonymous" -node_laddr = "tcp://0.0.0.0:46656" -seeds = "" -fast_sync = true -db_backend = "leveldb" -log_level = "info" -rpc_laddr = "tcp://0.0.0.0:46657" diff --git a/demo/data/chain2/genesis.json b/demo/data/chain2/genesis.json deleted file mode 100644 index 3ff94b99332b..000000000000 --- a/demo/data/chain2/genesis.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "app_hash": "", - "chain_id": "test_chain_2", - "genesis_time": "0001-01-01T00:00:00.000Z", - "validators": [ - { - "amount": 10, - "name": "", - "pub_key": { - "type": "ed25519", - "data": "9A76DDE4CA4EE660C073D288DBE4F8A128F23857881A95F18167682D47E7058F" - } - } - ], - "app_options": { - "accounts": [ - { - "pub_key": { - "type": "ed25519", - "data": "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" - }, - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - } - ] - } -} diff --git a/demo/data/chain2/key.json b/demo/data/chain2/key.json deleted file mode 100644 index 6aa8b7965f9c..000000000000 --- a/demo/data/chain2/key.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "address": "053BA0F19616AFF975C8756A2CBFF04F408B4D47", - "priv_key": { - "type": "ed25519", - "data": "22920C428043D869987F253D7C9B2305E7010642C40CE88A52C9F6CE5ACC42080628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" - }, - "pub_key": { - "type": "ed25519", - "data": "0628C8E6C2D50B15764B443394E06C6A64F3082CE966A2A8C1A55A4D63D0FC5D" - } -} diff --git a/demo/data/chain2/priv_validator.json b/demo/data/chain2/priv_validator.json deleted file mode 100644 index 12eb625259f9..000000000000 --- a/demo/data/chain2/priv_validator.json +++ /dev/null @@ -1 +0,0 @@ -{"address":"D42CFCB9C42DF9A73143EEA89255D1DF027B6240","pub_key":{"type":"ed25519","data":"9A76DDE4CA4EE660C073D288DBE4F8A128F23857881A95F18167682D47E7058F"},"last_height":0,"last_round":0,"last_step":0,"last_signature":null,"priv_key":{"type":"ed25519","data":"6353FAF4ADEB03EA496A9EAE5BE56C4C6A851CB705401788184FDC9198413C2C9A76DDE4CA4EE660C073D288DBE4F8A128F23857881A95F18167682D47E7058F"}} \ No newline at end of file diff --git a/demo/start.sh b/demo/start.sh deleted file mode 100644 index abb1576be540..000000000000 --- a/demo/start.sh +++ /dev/null @@ -1,198 +0,0 @@ -#! /bin/bash -set -e - -cd $GOPATH/src/github.com/tendermint/basecoin/demo - -LOG_DIR="." -TM_VERSION="master" -#TM_VERSION="v0.10.0" - -if [[ "$CIRCLECI" == "true" ]]; then - # set log dir - LOG_DIR="${CIRCLE_ARTIFACTS}" - - # install tendermint - set +e - go get github.com/tendermint/tendermint - pushd $GOPATH/src/github.com/tendermint/tendermint - git checkout $TM_VERSION - glide install - go install ./cmd/tendermint - popd - set -e -fi - -set -u - -function ifExit() { - if [[ "$?" != 0 ]]; then - echo "FAIL" - exit 1 - fi -} - -function removeQuotes() { - temp="${1%\"}" - temp="${temp#\"}" - echo "$temp" -} - -function waitForNode() { - addr=$1 - set +e - curl -s $addr/status > /dev/null - ERR=$? - i=0 - while [ "$ERR" != 0 ]; do - if [[ "$i" == 10 ]]; then - echo "waited too long for chain to start" - exit 1 - fi - echo "...... still waiting on $addr" - sleep 1 - curl -s $addr/status > /dev/null - ERR=$? - i=$((i+1)) - done - set -e - echo "... node $addr is up" -} - -function waitForBlock() { - addr=$1 - b1=`curl -s $addr/status | jq .result.latest_block_height` - b2=$b1 - while [ "$b2" == "$b1" ]; do - echo "Waiting for node $addr to commit a block ..." - sleep 1 - b2=`curl -s $addr/status | jq .result.latest_block_height` - done -} - -# make basecoin root vars -export BCHOME="." -BCHOME1="./data/chain1" -BCHOME2="./data/chain2" - -# grab the chain ids -CHAIN_ID1=$(cat $BCHOME1/genesis.json | jq .chain_id) -CHAIN_ID1=$(removeQuotes $CHAIN_ID1) -CHAIN_ID2=$(cat $BCHOME2/genesis.json | jq .chain_id) -CHAIN_ID2=$(removeQuotes $CHAIN_ID2) -echo "CHAIN_ID1: $CHAIN_ID1" -echo "CHAIN_ID2: $CHAIN_ID2" - -# make reusable chain flags -CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from $BCHOME1/key.json" -CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from $BCHOME2/key.json --node tcp://localhost:36657" - - -echo "" -echo "... starting chains" -echo "" -# start the first node -TMHOME=$BCHOME1 tendermint node --p2p.skip_upnp --log_level=info &> $LOG_DIR/chain1_tendermint.log & -ifExit -BCHOME=$BCHOME1 basecoin start --without-tendermint &> $LOG_DIR/chain1_basecoin.log & -ifExit - -# start the second node -TMHOME=$BCHOME2 tendermint node --p2p.skip_upnp --log_level=info --p2p.laddr tcp://localhost:36656 --rpc.laddr tcp://localhost:36657 --proxy_app tcp://localhost:36658 &> $LOG_DIR/chain2_tendermint.log & -ifExit -BCHOME=$BCHOME2 basecoin start --address tcp://localhost:36658 --without-tendermint &> $LOG_DIR/chain2_basecoin.log & -ifExit - -echo "" -echo "... waiting for chains to start" -echo "" - -waitForNode localhost:46657 -waitForNode localhost:36657 - -# TODO: remove the sleep -# Without it we sometimes get "Account bytes are empty for address: 053BA0F19616AFF975C8756A2CBFF04F408B4D47" -sleep 3 - -echo "... registering chain1 on chain2" -echo "" -# register chain1 on chain2 -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --ibc_chain_id $CHAIN_ID1 --genesis $BCHOME1/genesis.json -ifExit - -echo "" -echo "... creating egress packet on chain1" -echo "" -# send coins from chain1 to an address on chain2 -# TODO: dont hardcode the address -basecoin tx send --amount 10mycoin $CHAIN_FLAGS1 --to $CHAIN_ID2/053BA0F19616AFF975C8756A2CBFF04F408B4D47 -ifExit - -# alternative way to create packets (for testing) -# basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --ibc_from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload $PAYLOAD --ibc_sequence 0 - -echo "" -echo "... querying for packet data" -echo "" -# query for the packet data and proof -# since we only sent one packet, the sequence number is 0 -QUERY_RESULT=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,0) -ifExit -HEIGHT=$(echo $QUERY_RESULT | jq .height) -PACKET=$(echo $QUERY_RESULT | jq .value) -PROOF=$(echo $QUERY_RESULT | jq .proof) -PACKET=$(removeQuotes $PACKET) -PROOF=$(removeQuotes $PROOF) -echo "" -echo "QUERY_RESULT: $QUERY_RESULT" -echo "HEIGHT: $HEIGHT" -echo "PACKET: $PACKET" -echo "PROOF: $PROOF" - - -# the query returns the height of the next block, which contains the app hash -# but which may not be committed yet, so we have to wait for it to query the commit -echo "" -echo "... waiting for a block to be committed" -echo "" - -waitForBlock localhost:46657 -waitForBlock localhost:36657 - -echo "" -echo "... querying for block data" -echo "" -# get the header and commit for the height -HEADER_AND_COMMIT=$(basecoin block $HEIGHT) -ifExit -HEADER=$(echo $HEADER_AND_COMMIT | jq .hex.header) -HEADER=$(removeQuotes $HEADER) -COMMIT=$(echo $HEADER_AND_COMMIT | jq .hex.commit) -COMMIT=$(removeQuotes $COMMIT) -echo "" -echo "HEADER_AND_COMMIT: $HEADER_AND_COMMIT" -echo "HEADER: $HEADER" -echo "COMMIT: $COMMIT" - -echo "" -echo "... updating state of chain1 on chain2" -echo "" -# update the state of chain1 on chain2 -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x$HEADER --commit 0x$COMMIT -ifExit - -echo "" -echo "... posting packet from chain1 on chain2" -echo "" -# post the packet from chain1 to chain2 -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 packet post --ibc_from $CHAIN_ID1 --height $HEIGHT --packet 0x$PACKET --proof 0x$PROOF -ifExit - -echo "" -echo "... checking if the packet is present on chain2" -echo "" -# query for the packet on chain2 -basecoin query --node tcp://localhost:36657 ibc,ingress,test_chain_2,test_chain_1,0 -ifExit - -echo "" -echo "DONE!" From b15f882ff4f5358ec32926aec1ab2af1c1507c26 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 17:20:45 +0200 Subject: [PATCH 31/73] Ripped out query, tx send, account, keys, and more --- cmd/basecoin/main.go | 5 - cmd/commands/plugin_util.go | 5 - cmd/commands/query.go | 234 ------------------------------------ cmd/commands/tx.go | 118 ------------------ cmd/counter/main.go | 5 - 5 files changed, 367 deletions(-) delete mode 100644 cmd/commands/query.go diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index 5bc03e0fa66b..f95eb93438f0 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -20,11 +20,6 @@ func main() { commands.StartCmd, commands.RelayCmd, commands.TxCmd, - commands.QueryCmd, - commands.KeyCmd, - commands.VerifyCmd, - commands.BlockCmd, - commands.AccountCmd, commands.UnsafeResetAllCmd, commands.VersionCmd, ) diff --git a/cmd/commands/plugin_util.go b/cmd/commands/plugin_util.go index 082ff2669fc7..43afd93c2846 100644 --- a/cmd/commands/plugin_util.go +++ b/cmd/commands/plugin_util.go @@ -19,11 +19,6 @@ func RegisterStartPlugin(name string, newPlugin func() types.Plugin) { plugins = append(plugins, plugin{name: name, newPlugin: newPlugin}) } -// Register a subcommand of QueryCmd for plugin specific query functionality -func RegisterQuerySubcommand(cmd *cobra.Command) { - QueryCmd.AddCommand(cmd) -} - // Register a subcommand of TxCmd to craft transactions for plugins func RegisterTxSubcommand(cmd *cobra.Command) { TxCmd.AddCommand(cmd) diff --git a/cmd/commands/query.go b/cmd/commands/query.go deleted file mode 100644 index e31d62549199..000000000000 --- a/cmd/commands/query.go +++ /dev/null @@ -1,234 +0,0 @@ -package commands - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "strconv" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - - "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - "github.com/tendermint/merkleeyes/iavl" - "github.com/tendermint/tendermint/rpc/client" - tmtypes "github.com/tendermint/tendermint/types" -) - -//commands -var ( - QueryCmd = &cobra.Command{ - Use: "query [key]", - Short: "Query the merkle tree", - RunE: queryCmd, - } - - AccountCmd = &cobra.Command{ - Use: "account [address]", - Short: "Get details of an account", - RunE: accountCmd, - } - - BlockCmd = &cobra.Command{ - Use: "block [height]", - Short: "Get the header and commit of a block", - RunE: blockCmd, - } - - VerifyCmd = &cobra.Command{ - Use: "verify", - Short: "Verify the IAVL proof", - RunE: verifyCmd, - } -) - -//flags -var ( - nodeFlag string - proofFlag string - keyFlag string - valueFlag string - rootFlag string -) - -func init() { - - commonFlags := []Flag2Register{ - {&nodeFlag, "node", "tcp://localhost:46657", "Tendermint RPC address"}, - } - - verifyFlags := []Flag2Register{ - {&proofFlag, "proof", "", "hex-encoded IAVL proof"}, - {&keyFlag, "key", "", "key to the IAVL tree"}, - {&valueFlag, "value", "", "value in the IAVL tree"}, - {&rootFlag, "root", "", "root hash of the IAVL tree"}, - } - - RegisterFlags(QueryCmd, commonFlags) - RegisterFlags(AccountCmd, commonFlags) - RegisterFlags(BlockCmd, commonFlags) - RegisterFlags(VerifyCmd, verifyFlags) -} - -func queryCmd(cmd *cobra.Command, args []string) error { - - if len(args) != 1 { - return fmt.Errorf("query command requires an argument ([key])") //never stack trace - } - - keyString := args[0] - key := []byte(keyString) - if isHex(keyString) { - // convert key to bytes - var err error - key, err = hex.DecodeString(StripHex(keyString)) - if err != nil { - return errors.Errorf("Query key (%v) is invalid hex: %v\n", keyString, err) - } - } - - resp, err := Query(nodeFlag, key) - if err != nil { - return errors.Errorf("Query returns error: %v\n", err) - } - - if !resp.Code.IsOK() { - return errors.Errorf("Query for key (%v) returned non-zero code (%v): %v", keyString, resp.Code, resp.Log) - } - - val := resp.Value - proof := resp.Proof - height := resp.Height - - out, err := json.Marshal(struct { - Value data.Bytes `json:"value"` - Proof data.Bytes `json:"proof"` - Height uint64 `json:"height"` - }{val, proof, height}) - if err != nil { - return err - } - - fmt.Println(string(out)) - return nil -} - -func accountCmd(cmd *cobra.Command, args []string) error { - - if len(args) != 1 { - return fmt.Errorf("account command requires an argument ([address])") //never stack trace - } - - addrHex := StripHex(args[0]) - - // convert destination address to bytes - addr, err := hex.DecodeString(addrHex) - if err != nil { - return errors.Errorf("Account address (%v) is invalid hex: %v\n", addrHex, err) - } - - httpClient := client.NewHTTP(nodeFlag, "/websocket") - acc, err := getAccWithClient(httpClient, addr) - if err != nil { - return err - } - out, err := json.Marshal(acc) - if err != nil { - return err - } - fmt.Println(string(out)) - return nil -} - -func blockCmd(cmd *cobra.Command, args []string) error { - - if len(args) != 1 { - return fmt.Errorf("block command requires an argument ([height])") //never stack trace - } - - heightString := args[0] - height, err := strconv.Atoi(heightString) - if err != nil { - return errors.Errorf("Height must be an int, got %v: %v\n", heightString, err) - } - - header, commit, err := getHeaderAndCommit(nodeFlag, height) - if err != nil { - return err - } - - out, err := json.Marshal(struct { - Hex BlockHex `json:"hex"` - JSON BlockJSON `json:"json"` - }{ - BlockHex{ - Header: wire.BinaryBytes(header), - Commit: wire.BinaryBytes(commit), - }, - BlockJSON{ - Header: header, - Commit: commit, - }, - }) - if err != nil { - return err - } - - fmt.Println(string(out)) - return nil -} - -type BlockHex struct { - Header data.Bytes `json:"header"` - Commit data.Bytes `json:"commit"` -} - -type BlockJSON struct { - Header *tmtypes.Header `json:"header"` - Commit *tmtypes.Commit `json:"commit"` -} - -func verifyCmd(cmd *cobra.Command, args []string) error { - - keyString, valueString := keyFlag, valueFlag - - var err error - key := []byte(keyString) - if isHex(keyString) { - key, err = hex.DecodeString(StripHex(keyString)) - if err != nil { - return errors.Errorf("Key (%v) is invalid hex: %v\n", keyString, err) - } - } - - value := []byte(valueString) - if isHex(valueString) { - value, err = hex.DecodeString(StripHex(valueString)) - if err != nil { - return errors.Errorf("Value (%v) is invalid hex: %v\n", valueString, err) - } - } - - root, err := hex.DecodeString(StripHex(rootFlag)) - if err != nil { - return errors.Errorf("Root (%v) is invalid hex: %v\n", rootFlag, err) - } - - proofBytes, err := hex.DecodeString(StripHex(proofFlag)) - if err != nil { - return errors.Errorf("Proof (%v) is invalid hex: %v\n", proofFlag, err) - } - - proof, err := iavl.ReadProof(proofBytes) - if err != nil { - return errors.Errorf("Error unmarshalling proof: %v\n", err) - } - - if proof.Verify(key, value, root) { - fmt.Println("OK") - } else { - return errors.New("Proof does not verify") - } - return nil -} diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go index 70bc8e626b2c..8c661568c5d8 100644 --- a/cmd/commands/tx.go +++ b/cmd/commands/tx.go @@ -1,9 +1,7 @@ package commands import ( - "encoding/hex" "fmt" - "strings" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -20,18 +18,6 @@ var ( Use: "tx", Short: "Create, sign, and broadcast a transaction", } - - SendTxCmd = &cobra.Command{ - Use: "send", - Short: "A SendTx transaction, for sending tokens around", - RunE: sendTxCmd, - } - - AppTxCmd = &cobra.Command{ - Use: "app", - Short: "An AppTx transaction, for sending raw data to plugins", - RunE: appTxCmd, - } ) var ( @@ -43,11 +29,6 @@ var ( gasFlag int feeFlag string chainIDFlag string - - //non-persistent flags - toFlag string - dataFlag string - nameFlag string ) func init() { @@ -62,106 +43,7 @@ func init() { {&feeFlag, "fee", "0coin", "Coins for the transaction fee of the format "}, {&seqFlag, "sequence", -1, "Sequence number for the account (-1 to autocalculate)"}, } - - sendTxFlags := []Flag2Register{ - {&toFlag, "to", "", "Destination address for the transaction"}, - } - - appTxFlags := []Flag2Register{ - {&nameFlag, "name", "", "Plugin to send the transaction to"}, - {&dataFlag, "data", "", "Data to send with the transaction"}, - } - RegisterPersistentFlags(TxCmd, cmdTxFlags) - RegisterFlags(SendTxCmd, sendTxFlags) - RegisterFlags(AppTxCmd, appTxFlags) - - //register commands - TxCmd.AddCommand(SendTxCmd, AppTxCmd) -} - -func sendTxCmd(cmd *cobra.Command, args []string) error { - - var toHex string - var chainPrefix string - spl := strings.Split(toFlag, "/") - switch len(spl) { - case 1: - toHex = spl[0] - case 2: - chainPrefix = spl[0] - toHex = spl[1] - default: - return errors.Errorf("To address has too many slashes") - } - - // convert destination address to bytes - to, err := hex.DecodeString(StripHex(toHex)) - if err != nil { - return errors.Errorf("To address is invalid hex: %v\n", err) - } - - if chainPrefix != "" { - to = []byte(chainPrefix + "/" + string(to)) - } - - // load the priv key - privKey, err := LoadKey(fromFlag) - if err != nil { - return err - } - - // get the sequence number for the tx - sequence, err := getSeq(privKey.Address[:]) - if err != nil { - return err - } - - //parse the fee and amounts into coin types - feeCoin, err := types.ParseCoin(feeFlag) - if err != nil { - return err - } - amountCoins, err := types.ParseCoins(amountFlag) - if err != nil { - return err - } - - // craft the tx - input := types.NewTxInput(privKey.PubKey, amountCoins, sequence) - output := newOutput(to, amountCoins) - tx := &types.SendTx{ - Gas: int64(gasFlag), - Fee: feeCoin, - Inputs: []types.TxInput{input}, - Outputs: []types.TxOutput{output}, - } - - // sign that puppy - signBytes := tx.SignBytes(chainIDFlag) - tx.Inputs[0].Signature = privKey.Sign(signBytes) - - out := wire.BinaryBytes(tx) - fmt.Println("Signed SendTx:") - fmt.Printf("%X\n", out) - - // broadcast the transaction to tendermint - data, log, err := broadcastTx(tx) - if err != nil { - return err - } - fmt.Printf("Response: %X ; %s\n", data, log) - return nil -} - -func appTxCmd(cmd *cobra.Command, args []string) error { - // convert data to bytes - data := []byte(dataFlag) - if isHex(dataFlag) { - data, _ = hex.DecodeString(dataFlag) - } - name := nameFlag - return AppTx(name, data) } func AppTx(name string, data []byte) error { diff --git a/cmd/counter/main.go b/cmd/counter/main.go index 083535733f36..e96940029448 100644 --- a/cmd/counter/main.go +++ b/cmd/counter/main.go @@ -19,11 +19,6 @@ func main() { commands.InitCmd, commands.StartCmd, commands.TxCmd, - commands.QueryCmd, - commands.KeyCmd, - commands.VerifyCmd, - commands.BlockCmd, - commands.AccountCmd, commands.UnsafeResetAllCmd, commands.VersionCmd, ) From 9bf34cbac274ab25fbb4ce2f1e564c10df81502e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 17:28:26 +0200 Subject: [PATCH 32/73] Removed many more unneeded commands --- cmd/commands/ibc.go | 209 +------------------------------------------- cmd/commands/key.go | 45 +--------- 2 files changed, 4 insertions(+), 250 deletions(-) diff --git a/cmd/commands/ibc.go b/cmd/commands/ibc.go index 8f1bdb4f56b1..ddde46825e78 100644 --- a/cmd/commands/ibc.go +++ b/cmd/commands/ibc.go @@ -1,7 +1,6 @@ package commands import ( - "encoding/hex" "encoding/json" "fmt" "io/ioutil" @@ -12,8 +11,6 @@ import ( "github.com/tendermint/basecoin/plugins/ibc" "github.com/tendermint/go-wire" - "github.com/tendermint/merkleeyes/iavl" - tmtypes "github.com/tendermint/tendermint/types" ) // returns a new IBC plugin to be registered with Basecoin @@ -33,85 +30,25 @@ var ( Short: "Register a blockchain via IBC", RunE: ibcRegisterTxCmd, } - - IBCUpdateTxCmd = &cobra.Command{ - Use: "update", - Short: "Update the latest state of a blockchain via IBC", - RunE: ibcUpdateTxCmd, - } - - IBCPacketTxCmd = &cobra.Command{ - Use: "packet", - Short: "Send a new packet via IBC", - } - - IBCPacketCreateTxCmd = &cobra.Command{ - Use: "create", - Short: "Create an egress IBC packet", - RunE: ibcPacketCreateTxCmd, - } - - IBCPacketPostTxCmd = &cobra.Command{ - Use: "post", - Short: "Deliver an IBC packet to another chain", - RunE: ibcPacketPostTxCmd, - } ) //flags var ( - ibcChainIDFlag string - ibcGenesisFlag string - ibcHeaderFlag string - ibcCommitFlag string - ibcFromFlag string - ibcToFlag string - ibcTypeFlag string - ibcPayloadFlag string - ibcPacketFlag string - ibcProofFlag string - ibcSequenceFlag int - ibcHeightFlag int + ibcChainIDFlag string + ibcGenesisFlag string ) func init() { - // register flags registerFlags := []Flag2Register{ {&ibcChainIDFlag, "ibc_chain_id", "", "ChainID for the new blockchain"}, {&ibcGenesisFlag, "genesis", "", "Genesis file for the new blockchain"}, } - updateFlags := []Flag2Register{ - {&ibcHeaderFlag, "header", "", "Block header for an ibc update"}, - {&ibcCommitFlag, "commit", "", "Block commit for an ibc update"}, - } - - fromFlagReg := Flag2Register{&ibcFromFlag, "ibc_from", "", "Source ChainID"} - - packetCreateFlags := []Flag2Register{ - fromFlagReg, - {&ibcToFlag, "to", "", "Destination ChainID"}, - {&ibcTypeFlag, "type", "", "IBC packet type (eg. coin)"}, - {&ibcPayloadFlag, "payload", "", "IBC packet payload"}, - {&ibcSequenceFlag, "ibc_sequence", -1, "sequence number for IBC packet"}, - } - - packetPostFlags := []Flag2Register{ - fromFlagReg, - {&ibcHeightFlag, "height", 0, "Height the packet became egress in source chain"}, - {&ibcPacketFlag, "packet", "", "hex-encoded IBC packet"}, - {&ibcProofFlag, "proof", "", "hex-encoded proof of IBC packet from source chain"}, - } - RegisterFlags(IBCRegisterTxCmd, registerFlags) - RegisterFlags(IBCUpdateTxCmd, updateFlags) - RegisterFlags(IBCPacketCreateTxCmd, packetCreateFlags) - RegisterFlags(IBCPacketPostTxCmd, packetPostFlags) //register commands - IBCTxCmd.AddCommand(IBCRegisterTxCmd, IBCUpdateTxCmd, IBCPacketTxCmd) - IBCPacketTxCmd.AddCommand(IBCPacketCreateTxCmd, IBCPacketPostTxCmd) + IBCTxCmd.AddCommand(IBCRegisterTxCmd) RegisterTxSubcommand(IBCTxCmd) } @@ -148,143 +85,3 @@ func ibcRegisterTxCmd(cmd *cobra.Command, args []string) error { return AppTx(name, data) } - -func ibcUpdateTxCmd(cmd *cobra.Command, args []string) error { - headerBytes, err := hex.DecodeString(StripHex(ibcHeaderFlag)) - if err != nil { - return errors.Errorf("Header (%v) is invalid hex: %v\n", ibcHeaderFlag, err) - } - - commitBytes, err := hex.DecodeString(StripHex(ibcCommitFlag)) - if err != nil { - return errors.Errorf("Commit (%v) is invalid hex: %v\n", ibcCommitFlag, err) - } - - header := new(tmtypes.Header) - commit := new(tmtypes.Commit) - - err = wire.ReadBinaryBytes(headerBytes, &header) - if err != nil { - return errors.Errorf("Error unmarshalling header: %v\n", err) - } - - err = wire.ReadBinaryBytes(commitBytes, &commit) - if err != nil { - return errors.Errorf("Error unmarshalling commit: %v\n", err) - } - - ibcTx := ibc.IBCUpdateChainTx{ - Header: *header, - Commit: *commit, - } - - out, err := json.Marshal(ibcTx) - if err != nil { - return err - } - fmt.Printf("IBCTx: %s\n", string(out)) - - data := []byte(wire.BinaryBytes(struct { - ibc.IBCTx `json:"unwrap"` - }{ibcTx})) - name := "IBC" - - return AppTx(name, data) -} - -func ibcPacketCreateTxCmd(cmd *cobra.Command, args []string) error { - fromChain, toChain := ibcFromFlag, ibcToFlag - packetType := ibcTypeFlag - - payloadBytes, err := hex.DecodeString(StripHex(ibcPayloadFlag)) - if err != nil { - return errors.Errorf("Payload (%v) is invalid hex: %v\n", ibcPayloadFlag, err) - } - - sequence, err := ibcSequenceCmd() - if err != nil { - return err - } - - var payload ibc.Payload - if err := wire.ReadBinaryBytes(payloadBytes, &payload); err != nil { - return err - } - - ibcTx := ibc.IBCPacketCreateTx{ - Packet: ibc.Packet{ - SrcChainID: fromChain, - DstChainID: toChain, - Sequence: sequence, - Type: packetType, - Payload: payload, - }, - } - - out, err := json.Marshal(ibcTx) - if err != nil { - return err - } - fmt.Printf("IBCTx: %s\n", string(out)) - - data := []byte(wire.BinaryBytes(struct { - ibc.IBCTx `json:"unwrap"` - }{ibcTx})) - - return AppTx("IBC", data) -} - -func ibcPacketPostTxCmd(cmd *cobra.Command, args []string) error { - fromChain, fromHeight := ibcFromFlag, ibcHeightFlag - - packetBytes, err := hex.DecodeString(StripHex(ibcPacketFlag)) - if err != nil { - return errors.Errorf("Packet (%v) is invalid hex: %v\n", ibcPacketFlag, err) - } - - proofBytes, err := hex.DecodeString(StripHex(ibcProofFlag)) - if err != nil { - return errors.Errorf("Proof (%v) is invalid hex: %v\n", ibcProofFlag, err) - } - - var packet ibc.Packet - proof := new(iavl.IAVLProof) - - err = wire.ReadBinaryBytes(packetBytes, &packet) - if err != nil { - return errors.Errorf("Error unmarshalling packet: %v\n", err) - } - - err = wire.ReadBinaryBytes(proofBytes, &proof) - if err != nil { - return errors.Errorf("Error unmarshalling proof: %v\n", err) - } - - ibcTx := ibc.IBCPacketPostTx{ - FromChainID: fromChain, - FromChainHeight: uint64(fromHeight), - Packet: packet, - Proof: proof, - } - - out, err := json.Marshal(ibcTx) - if err != nil { - return err - } - fmt.Printf("IBCTx: %s\n", string(out)) - - data := []byte(wire.BinaryBytes(struct { - ibc.IBCTx `json:"unwrap"` - }{ibcTx})) - - return AppTx("IBC", data) -} - -func ibcSequenceCmd() (uint64, error) { - if ibcSequenceFlag >= 0 { - return uint64(ibcSequenceFlag), nil - } - - // TODO: get sequence - return 0, nil -} diff --git a/cmd/commands/key.go b/cmd/commands/key.go index 4f0b25381880..08f54e0a4211 100644 --- a/cmd/commands/key.go +++ b/cmd/commands/key.go @@ -9,42 +9,13 @@ import ( "strings" //"github.com/pkg/errors" - "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/tendermint/go-crypto" "github.com/tendermint/tmlibs/cli" ) -//commands -var ( - KeyCmd = &cobra.Command{ - Use: "key", - Short: "Manage keys", - } - - NewKeyCmd = &cobra.Command{ - Use: "new", - Short: "Create a new private key", - RunE: newKeyCmd, - } -) - -func newKeyCmd(cmd *cobra.Command, args []string) error { - key := genKey() - keyJSON, err := json.MarshalIndent(key, "", "\t") - if err != nil { - return err - } - fmt.Println(string(keyJSON)) - return nil -} - -func init() { - //register commands - KeyCmd.AddCommand(NewKeyCmd) -} - //--------------------------------------------- // simple implementation of a key @@ -74,20 +45,6 @@ func (k *Key) Sign(msg []byte) crypto.Signature { return k.PrivKey.Sign(msg) } -// Generates a new validator with private key. -func genKey() *Key { - privKey := crypto.GenPrivKeyEd25519() - pubKey := privKey.PubKey() - addrBytes := pubKey.Address() - var addr Address - copy(addr[:], addrBytes) - return &Key{ - Address: addr, - PubKey: pubKey, - PrivKey: privKey.Wrap(), - } -} - func LoadKey(keyFile string) (*Key, error) { filePath := keyFile From 22918ba3d28a1220861ec2049dc95b079bce1665 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 17:35:37 +0200 Subject: [PATCH 33/73] Remove example-plugin code, need to fix docs --- docs/guide/src/example-plugin/cmd.go | 62 ----------- docs/guide/src/example-plugin/main.go | 35 ------- docs/guide/src/example-plugin/plugin.go | 134 ------------------------ 3 files changed, 231 deletions(-) delete mode 100644 docs/guide/src/example-plugin/cmd.go delete mode 100644 docs/guide/src/example-plugin/main.go delete mode 100644 docs/guide/src/example-plugin/plugin.go diff --git a/docs/guide/src/example-plugin/cmd.go b/docs/guide/src/example-plugin/cmd.go deleted file mode 100644 index b439176266d7..000000000000 --- a/docs/guide/src/example-plugin/cmd.go +++ /dev/null @@ -1,62 +0,0 @@ -package main - -import ( - "github.com/spf13/cobra" - - wire "github.com/tendermint/go-wire" - - "github.com/tendermint/basecoin/cmd/commands" - "github.com/tendermint/basecoin/types" -) - -var ( - //CLI Flags - validFlag bool - - //CLI Plugin Commands - ExamplePluginTxCmd = &cobra.Command{ - Use: "example", - Short: "Create, sign, and broadcast a transaction to the example plugin", - RunE: examplePluginTxCmd, - } -) - -//Called during CLI initialization -func init() { - - //Set the Plugin Flags - ExamplePluginTxCmd.Flags().BoolVar(&validFlag, "valid", false, "Set this to make transaction valid") - - //Register a plugin specific CLI command as a subcommand of the tx command - commands.RegisterTxSubcommand(ExamplePluginTxCmd) - - //Register the example with basecoin at start - commands.RegisterStartPlugin("example-plugin", func() types.Plugin { return NewExamplePlugin() }) -} - -//Send a transaction -func examplePluginTxCmd(cmd *cobra.Command, args []string) error { - - // Create a transaction using the flag. - // The tx passes on custom information to the plugin - exampleTx := ExamplePluginTx{validFlag} - - // The tx is passed to the plugin in the form of - // a byte array. This is achieved by serializing the object using go-wire. - // Once received in the plugin, these exampleTxBytes are decoded back - // into the original ExamplePluginTx struct - exampleTxBytes := wire.BinaryBytes(exampleTx) - - // Send the transaction and return any errors. - // Here exampleTxBytes is packaged in the `tx.Data` field of an AppTx, - // and passed on to the plugin through the following sequence: - // - passed as `data` to `commands.AppTx` (cmd/commands/tx.go) - // - set as the `tx.Data` field of an AppTx, which is then passed to commands.broadcastTx (cmd/commands/tx.go) - // - the tx is broadcast to Tendermint, which runs it through app.CheckTx (app/app.go) - // - after passing CheckTx, it will eventually be included in a block and run through app.DeliverTx (app/app.go) - // - DeliverTx receives txBytes, which is the serialization of the full AppTx (app/app.go) - // - Once deserialized, the tx is passed to `state.ExecTx` (state/execution.go) - // - If the tx passes various checks, the `tx.Data` is forwarded as `txBytes` to `plugin.RunTx` (docs/guide/src/example-plugin/plugin.go) - // - Finally, it deserialized back to the ExamplePluginTx - return commands.AppTx("example-plugin", exampleTxBytes) -} diff --git a/docs/guide/src/example-plugin/main.go b/docs/guide/src/example-plugin/main.go deleted file mode 100644 index 328e22025bd8..000000000000 --- a/docs/guide/src/example-plugin/main.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/tendermint/basecoin/cmd/commands" - "github.com/tendermint/tmlibs/cli" -) - -func main() { - - //Initialize example-plugin root command - var RootCmd = &cobra.Command{ - Use: "example-plugin", - Short: "example-plugin usage description", - } - - //Add the default basecoin commands to the root command - RootCmd.AddCommand( - commands.InitCmd, - commands.StartCmd, - commands.TxCmd, - commands.QueryCmd, - commands.KeyCmd, - commands.VerifyCmd, - commands.BlockCmd, - commands.AccountCmd, - commands.UnsafeResetAllCmd, - ) - - cmd := cli.PrepareMainCmd(RootCmd, "BC", os.ExpandEnv("$HOME/.basecoin-example-plugin")) - cmd.Execute() -} diff --git a/docs/guide/src/example-plugin/plugin.go b/docs/guide/src/example-plugin/plugin.go deleted file mode 100644 index 97e80520a4ce..000000000000 --- a/docs/guide/src/example-plugin/plugin.go +++ /dev/null @@ -1,134 +0,0 @@ -package main - -import ( - abci "github.com/tendermint/abci/types" - "github.com/tendermint/basecoin/types" - "github.com/tendermint/go-wire" -) - -//----------------------------------------- -// Structs -// * Note the fields in each struct may be expanded/modified - -// Plugin State Struct -// * Intended to store the current state of the plugin -// * This example contains a field which holds the execution count -// * Serialized (by go-wire) and stored within the KVStore using the key retrieved -// from the ExamplePlugin.StateKey() function/ -// * All fields must be exposed for serialization by external libs (here go-wire) -type ExamplePluginState struct { - Counter int -} - -// Transaction Struct -// * Stores transaction-specific plugin-customized information -// * This example contains a dummy field 'Valid' intended to specify -// if the transaction is a valid and should proceed -// * Deserialized (by go-wire) from txBytes in ExamplePlugin.RunTx -// * All fields must be exposed for serialization by external libs (here go-wire) -type ExamplePluginTx struct { - Valid bool -} - -// Plugin Struct -// * Struct which satisfies the basecoin Plugin interface -// * Stores global plugin settings, in this example just the plugin name -type ExamplePlugin struct { - name string -} - -//----------------------------------------- -// Non-Mandatory Functions - -// Return a new ExamplePlugin pointer with a hard-coded name -func NewExamplePlugin() *ExamplePlugin { - return &ExamplePlugin{ - name: "example-plugin", - } -} - -// Return a byte array unique to this plugin which is used as the key -// to store the plugin state (ExamplePluginState) -func (ep *ExamplePlugin) StateKey() []byte { - return []byte("ExamplePlugin.State") -} - -//----------------------------------------- -// Basecoin Plugin Interface Functions - -//Return the name of the plugin -func (ep *ExamplePlugin) Name() string { - return ep.name -} - -// SetOption may be called during genesis of basecoin and can be used to set -// initial plugin parameters. Within genesis.json file entries are made in -// the format: "/", "" Where is the plugin name, -// in this file ExamplePlugin.name, and and are the strings passed -// into the plugin SetOption function. This function is intended to be used to -// set plugin specific information such as the plugin state. Within this example -// SetOption is left unimplemented. -func (ep *ExamplePlugin) SetOption(store types.KVStore, key string, value string) (log string) { - return "" -} - -// The core tx logic of the app is containted within the RunTx function -// Input fields: -// - store types.KVStore -// - This term provides read/write capabilities to the merkelized data store -// which holds the basecoin state and is accessible to all plugins -// - ctx types.CallContext -// - The ctx contains the callers address, a pointer to the callers account, -// and an amount of coins sent with the transaction -// - txBytes []byte -// - Used to send customized information to your plugin -// -// Other more complex plugins may have a variant on the process order within this -// example including loading and saving multiple or variable states, or not -// including a state stored in the KVStore whatsoever. -func (ep *ExamplePlugin) RunTx(store types.KVStore, ctx types.CallContext, txBytes []byte) (res abci.Result) { - - // Decode txBytes using go-wire. Attempt to write the txBytes to the variable - // tx, if the txBytes have not been properly encoded from a ExamplePluginTx - // struct wire will produce an error. - var tx ExamplePluginTx - err := wire.ReadBinaryBytes(txBytes, &tx) - if err != nil { - return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()) - } - - // Perform Transaction Validation - if !tx.Valid { - return abci.ErrInternalError.AppendLog("Valid must be true") - } - - // Load PluginState - var pluginState ExamplePluginState - stateBytes := store.Get(ep.StateKey()) - // If the state does not exist, stateBytes will be initialized - // as an empty byte array with length of zero - if len(stateBytes) > 0 { - err = wire.ReadBinaryBytes(stateBytes, &pluginState) //decode using go-wire - if err != nil { - return abci.ErrInternalError.AppendLog("Error decoding state: " + err.Error()) - } - } - - //App Logic - pluginState.Counter += 1 - - // Save PluginState - store.Set(ep.StateKey(), wire.BinaryBytes(pluginState)) - - return abci.OK -} - -func (ep *ExamplePlugin) InitChain(store types.KVStore, vals []*abci.Validator) { -} - -func (ep *ExamplePlugin) BeginBlock(store types.KVStore, hash []byte, header *abci.Header) { -} - -func (ep *ExamplePlugin) EndBlock(store types.KVStore, height uint64) abci.ResponseEndBlock { - return abci.ResponseEndBlock{} -} From d7cddb252aea86e63efaa8063eebb87df866f866 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 19:31:09 +0200 Subject: [PATCH 34/73] Cleaned up comments --- cmd/basecli/commands/cmds.go | 6 ++++-- cmd/basecli/commands/query.go | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/basecli/commands/cmds.go b/cmd/basecli/commands/cmds.go index d6d598590a80..8ac60bced522 100644 --- a/cmd/basecli/commands/cmds.go +++ b/cmd/basecli/commands/cmds.go @@ -17,7 +17,8 @@ import ( btypes "github.com/tendermint/basecoin/types" ) -/******** SendTx *********/ +//------------------------- +// SendTx // SendTxCmd is CLI command to send tokens between basecoin accounts var SendTxCmd = &cobra.Command{ @@ -136,7 +137,8 @@ func parseChainAddress(toFlag string) ([]byte, error) { return to, nil } -/******** AppTx *********/ +//------------------------- +// AppTx // BroadcastAppTx wraps, signs, and executes an app tx basecoin transaction func BroadcastAppTx(tx *btypes.AppTx) (*ctypes.ResultBroadcastTxCommit, error) { diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go index 82ec5649132a..5b616dc75fd3 100644 --- a/cmd/basecli/commands/query.go +++ b/cmd/basecli/commands/query.go @@ -32,8 +32,7 @@ func doAccountQuery(cmd *cobra.Command, args []string) error { return proofcmd.OutputProof(acc, proof.BlockHeight()) } -/*** this decodes all basecoin tx ***/ - +// BaseTxPresenter this decodes all basecoin tx type BaseTxPresenter struct { proofs.RawPresenter // this handles MakeKey as hex bytes } From b63f8bd15a2cdf090c30ecbb6e02d2ddc5352b10 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 20:20:23 +0200 Subject: [PATCH 35/73] Move relay to basecoin relay start --- cmd/commands/relay.go | 57 +++++++++++++++++++++++++++++++------------ tests/cli/ibc.sh | 4 ++- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/cmd/commands/relay.go b/cmd/commands/relay.go index 5a2cacfc9632..137e2c9a8ebc 100644 --- a/cmd/commands/relay.go +++ b/cmd/commands/relay.go @@ -24,8 +24,19 @@ import ( var RelayCmd = &cobra.Command{ Use: "relay", + Short: "Relay ibc packets between two chains", +} + +var RelayStartCmd = &cobra.Command{ + Use: "start", Short: "Start basecoin relayer to relay IBC packets between chains", - RunE: relayCmd, + RunE: relayStartCmd, +} + +var RelayInitCmd = &cobra.Command{ + Use: "init", + Short: "Register both chains with each other, to prepare the relayer to run", + RunE: relayInitCmd, } //flags @@ -37,10 +48,12 @@ var ( chain2IDFlag string fromFileFlag string + + genesisFile1Flag string + genesisFile2Flag string ) func init() { - flags := []Flag2Register{ {&chain1AddrFlag, "chain1-addr", "tcp://localhost:46657", "Node address for chain1"}, {&chain2AddrFlag, "chain2-addr", "tcp://localhost:36657", "Node address for chain2"}, @@ -48,7 +61,33 @@ func init() { {&chain2IDFlag, "chain2-id", "test_chain_2", "ChainID for chain2"}, {&fromFileFlag, "from", "key.json", "Path to a private key to sign the transaction"}, } - RegisterFlags(RelayCmd, flags) + RegisterPersistentFlags(RelayCmd, flags) + + initFlags := []Flag2Register{ + {&genesisFile1Flag, "genesis1", "", "Path to genesis file for chain1"}, + {&genesisFile2Flag, "genesis2", "", "Path to genesis file for chain2"}, + } + RegisterFlags(RelayInitCmd, initFlags) + + RelayCmd.AddCommand(RelayStartCmd) + RelayCmd.AddCommand(RelayInitCmd) +} + +func relayInitCmd(cmd *cobra.Command, args []string) error { + fmt.Println("not implemented") + return nil +} + +func relayStartCmd(cmd *cobra.Command, args []string) error { + + go loop(chain1AddrFlag, chain2AddrFlag, chain1IDFlag, chain2IDFlag) + go loop(chain2AddrFlag, chain1AddrFlag, chain2IDFlag, chain1IDFlag) + + cmn.TrapSignal(func() { + // TODO: Cleanup + }) + return nil + } func loop(addr1, addr2, id1, id2 string) { @@ -233,15 +272,3 @@ func broadcastTxWithClient(httpClient *client.HTTP, tx tmtypes.Tx) ([]byte, stri return res.DeliverTx.Data, res.DeliverTx.Log, nil } - -func relayCmd(cmd *cobra.Command, args []string) error { - - go loop(chain1AddrFlag, chain2AddrFlag, chain1IDFlag, chain2IDFlag) - go loop(chain2AddrFlag, chain1AddrFlag, chain2IDFlag, chain1IDFlag) - - cmn.TrapSignal(func() { - // TODO: Cleanup - }) - return nil - -} diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index bc9d76cd9298..69ccb2856de9 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -121,6 +121,8 @@ test01SendIBCTx() { BC_HOME=${CLIENT_2} checkAccount $RECV "0" "20002" # stop relay + echo "stoping relay" + echo kill -9 $PID_RELAY } @@ -163,7 +165,7 @@ startRelay() { # now start the relay! (this remains a server command) # TODO: bucky, why does this die if I don't provide home??? # It doesn't use the --from flag???? - ${SERVER_EXE} relay --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ + ${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ --home=${BASE_DIR_1}/server --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & PID_RELAY=$! From cb075bbb7e07fdba4806c143309d9b4b1de3a142 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 20:36:38 +0200 Subject: [PATCH 36/73] Working with relay init --- cmd/commands/relay.go | 36 ++++++++++++++++++++++++++++++------ tests/cli/ibc.sh | 25 +++++++++---------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/cmd/commands/relay.go b/cmd/commands/relay.go index 137e2c9a8ebc..573a53bbfc60 100644 --- a/cmd/commands/relay.go +++ b/cmd/commands/relay.go @@ -2,6 +2,7 @@ package commands import ( "fmt" + "io/ioutil" "strconv" "time" @@ -73,13 +74,7 @@ func init() { RelayCmd.AddCommand(RelayInitCmd) } -func relayInitCmd(cmd *cobra.Command, args []string) error { - fmt.Println("not implemented") - return nil -} - func relayStartCmd(cmd *cobra.Command, args []string) error { - go loop(chain1AddrFlag, chain2AddrFlag, chain1IDFlag, chain2IDFlag) go loop(chain2AddrFlag, chain1AddrFlag, chain2IDFlag, chain1IDFlag) @@ -87,7 +82,36 @@ func relayStartCmd(cmd *cobra.Command, args []string) error { // TODO: Cleanup }) return nil +} + +func relayInitCmd(cmd *cobra.Command, args []string) error { + err := registerChain(chain1IDFlag, chain1AddrFlag, chain2IDFlag, genesisFile2Flag, fromFileFlag) + if err != nil { + return err + } + err = registerChain(chain2IDFlag, chain2AddrFlag, chain1IDFlag, genesisFile1Flag, fromFileFlag) + return err +} + +func registerChain(chainID, node, registerChainID, registerGenesis, keyFile string) error { + genesisBytes, err := ioutil.ReadFile(registerGenesis) + if err != nil { + return errors.Errorf("Error reading genesis file %v: %v\n", registerGenesis, err) + } + ibcTx := ibc.IBCRegisterChainTx{ + ibc.BlockchainGenesis{ + ChainID: registerChainID, + Genesis: string(genesisBytes), + }, + } + + privKey, err := LoadKey(keyFile) + if err != nil { + return err + } + relay := newRelayer(privKey, chainID, node) + return relay.appTx(ibcTx) } func loop(addr1, addr2, id1, id2 string) { diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 69ccb2856de9..dcb70e64fa7c 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -108,7 +108,7 @@ test01SendIBCTx() { # start the relay and wait a few blocks... # (already sent a tx on chain1, so use higher sequence) startRelay 2 1 - if [ $? != 0 ]; then echo "can't start relay!"; return 1; fi + if [ $? != 0 ]; then echo "can't start relay"; cat ${BASE_DIR_1}/../relay.log; return 1; fi # give it a little time, then make sure the money arrived echo "waiting for relay..." @@ -148,21 +148,14 @@ startRelay() { txSucceeded $? "$RES" if [ $? != 0 ]; then echo "can't pay chain2!"; return 1; fi - # now we need to register the chains - # TODO: do this with basecli!!!! - basecoin tx ibc --amount 10mycoin --from=$RELAY_KEY --chain_id=$CHAIN_ID_2 \ - --node=tcp://localhost:${PORT_2} \ - register --ibc_chain_id=$CHAIN_ID_1 --genesis=$BASE_DIR_1/server/genesis.json \ - >/dev/null - if [ $? != 0 ]; then echo "can't register chain1 on chain 2"; return 1; fi - - basecoin tx ibc --amount 10mycoin --from=$RELAY_KEY --chain_id=$CHAIN_ID_1 \ - --node=tcp://localhost:${PORT_1} \ - register --ibc_chain_id=$CHAIN_ID_2 --genesis=$BASE_DIR_2/server/genesis.json \ - >/dev/null - if [ $? != 0 ]; then echo "can't register chain2 on chain 1"; return 1; fi - - # now start the relay! (this remains a server command) + # initialize the relay (register both chains) + ${SERVER_EXE} relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ + --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ + --genesis1=${BASE_DIR_1}/server/genesis.json --genesis2=${BASE_DIR_2}/server/genesis.json \ + --home=${BASE_DIR_1}/server --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + if [ $? != 0 ]; then echo "can't initialize relays"; cat ${BASE_DIR_1}/../relay.log; return 1; fi + + # now start the relay (constantly send packets) # TODO: bucky, why does this die if I don't provide home??? # It doesn't use the --from flag???? ${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ From a57e2d34b1b0e4d1558615ecfb88f019464571bf Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 20:42:41 +0200 Subject: [PATCH 37/73] Remove remnants of basecoin tx as ibc functions are now under relay --- cmd/basecoin/main.go | 1 - cmd/commands/ibc.go | 81 +------------------- cmd/commands/plugin_util.go | 5 -- cmd/commands/relay.go | 2 +- cmd/commands/tx.go | 142 ------------------------------------ cmd/counter/cmd.go | 48 ------------ cmd/counter/main.go | 1 - 7 files changed, 2 insertions(+), 278 deletions(-) delete mode 100644 cmd/commands/tx.go diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index f95eb93438f0..5d74ae5585ac 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -19,7 +19,6 @@ func main() { commands.InitCmd, commands.StartCmd, commands.RelayCmd, - commands.TxCmd, commands.UnsafeResetAllCmd, commands.VersionCmd, ) diff --git a/cmd/commands/ibc.go b/cmd/commands/ibc.go index ddde46825e78..b76eae90236c 100644 --- a/cmd/commands/ibc.go +++ b/cmd/commands/ibc.go @@ -1,87 +1,8 @@ package commands -import ( - "encoding/json" - "fmt" - "io/ioutil" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - - "github.com/tendermint/basecoin/plugins/ibc" - - "github.com/tendermint/go-wire" -) +import "github.com/tendermint/basecoin/plugins/ibc" // returns a new IBC plugin to be registered with Basecoin func NewIBCPlugin() *ibc.IBCPlugin { return ibc.New() } - -//commands -var ( - IBCTxCmd = &cobra.Command{ - Use: "ibc", - Short: "An IBC transaction, for InterBlockchain Communication", - } - - IBCRegisterTxCmd = &cobra.Command{ - Use: "register", - Short: "Register a blockchain via IBC", - RunE: ibcRegisterTxCmd, - } -) - -//flags -var ( - ibcChainIDFlag string - ibcGenesisFlag string -) - -func init() { - // register flags - registerFlags := []Flag2Register{ - {&ibcChainIDFlag, "ibc_chain_id", "", "ChainID for the new blockchain"}, - {&ibcGenesisFlag, "genesis", "", "Genesis file for the new blockchain"}, - } - - RegisterFlags(IBCRegisterTxCmd, registerFlags) - - //register commands - IBCTxCmd.AddCommand(IBCRegisterTxCmd) - RegisterTxSubcommand(IBCTxCmd) -} - -//--------------------------------------------------------------------- -// ibc command implementations - -func ibcRegisterTxCmd(cmd *cobra.Command, args []string) error { - chainID := ibcChainIDFlag - genesisFile := ibcGenesisFlag - - genesisBytes, err := ioutil.ReadFile(genesisFile) - if err != nil { - return errors.Errorf("Error reading genesis file %v: %v\n", genesisFile, err) - } - - ibcTx := ibc.IBCRegisterChainTx{ - ibc.BlockchainGenesis{ - ChainID: chainID, - Genesis: string(genesisBytes), - }, - } - - out, err := json.Marshal(ibcTx) - if err != nil { - return err - } - - fmt.Printf("IBCTx: %s\n", string(out)) - - data := []byte(wire.BinaryBytes(struct { - ibc.IBCTx `json:"unwrap"` - }{ibcTx})) - name := "IBC" - - return AppTx(name, data) -} diff --git a/cmd/commands/plugin_util.go b/cmd/commands/plugin_util.go index 43afd93c2846..d4f47b323a29 100644 --- a/cmd/commands/plugin_util.go +++ b/cmd/commands/plugin_util.go @@ -19,11 +19,6 @@ func RegisterStartPlugin(name string, newPlugin func() types.Plugin) { plugins = append(plugins, plugin{name: name, newPlugin: newPlugin}) } -// Register a subcommand of TxCmd to craft transactions for plugins -func RegisterTxSubcommand(cmd *cobra.Command) { - TxCmd.AddCommand(cmd) -} - //Returns a version command based on version input func QuickVersionCmd(version string) *cobra.Command { return &cobra.Command{ diff --git a/cmd/commands/relay.go b/cmd/commands/relay.go index 573a53bbfc60..b9ae47afa4ad 100644 --- a/cmd/commands/relay.go +++ b/cmd/commands/relay.go @@ -118,7 +118,7 @@ func loop(addr1, addr2, id1, id2 string) { nextSeq := 0 // load the priv key - privKey, err := LoadKey(fromFlag) + privKey, err := LoadKey(fromFileFlag) if err != nil { logger.Error(err.Error()) cmn.PanicCrisis(err.Error()) diff --git a/cmd/commands/tx.go b/cmd/commands/tx.go deleted file mode 100644 index 8c661568c5d8..000000000000 --- a/cmd/commands/tx.go +++ /dev/null @@ -1,142 +0,0 @@ -package commands - -import ( - "fmt" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - - "github.com/tendermint/basecoin/types" - - wire "github.com/tendermint/go-wire" - "github.com/tendermint/tendermint/rpc/client" -) - -//commands -var ( - TxCmd = &cobra.Command{ - Use: "tx", - Short: "Create, sign, and broadcast a transaction", - } -) - -var ( - //persistent flags - txNodeFlag string - amountFlag string - fromFlag string - seqFlag int - gasFlag int - feeFlag string - chainIDFlag string -) - -func init() { - - // register flags - cmdTxFlags := []Flag2Register{ - {&txNodeFlag, "node", "tcp://localhost:46657", "Tendermint RPC address"}, - {&chainIDFlag, "chain_id", "test_chain_id", "ID of the chain for replay protection"}, - {&fromFlag, "from", "key.json", "Path to a private key to sign the transaction"}, - {&amountFlag, "amount", "", "Coins to send in transaction of the format ,,... (eg: 1btc,2gold,5silver)"}, - {&gasFlag, "gas", 0, "The amount of gas for the transaction"}, - {&feeFlag, "fee", "0coin", "Coins for the transaction fee of the format "}, - {&seqFlag, "sequence", -1, "Sequence number for the account (-1 to autocalculate)"}, - } - RegisterPersistentFlags(TxCmd, cmdTxFlags) -} - -func AppTx(name string, data []byte) error { - - privKey, err := LoadKey(fromFlag) - if err != nil { - return err - } - - sequence, err := getSeq(privKey.Address[:]) - if err != nil { - return err - } - - //parse the fee and amounts into coin types - feeCoin, err := types.ParseCoin(feeFlag) - if err != nil { - return err - } - - amountCoins, err := types.ParseCoins(amountFlag) - if err != nil { - return err - } - - input := types.NewTxInput(privKey.PubKey, amountCoins, sequence) - tx := &types.AppTx{ - Gas: int64(gasFlag), - Fee: feeCoin, - Name: name, - Input: input, - Data: data, - } - - tx.Input.Signature = privKey.Sign(tx.SignBytes(chainIDFlag)) - - out := wire.BinaryBytes(tx) - fmt.Println("Signed AppTx:") - fmt.Printf("%X\n", out) - - data, log, err := broadcastTx(tx) - if err != nil { - return err - } - fmt.Printf("Response: %X ; %s\n", data, log) - return nil -} - -// broadcast the transaction to tendermint -func broadcastTx(tx types.Tx) ([]byte, string, error) { - httpClient := client.NewHTTP(txNodeFlag, "/websocket") - // Don't you hate having to do this? - // How many times have I lost an hour over this trick?! - txBytes := []byte(wire.BinaryBytes(struct { - types.Tx `json:"unwrap"` - }{tx})) - res, err := httpClient.BroadcastTxCommit(txBytes) - if err != nil { - return nil, "", errors.Errorf("Error on broadcast tx: %v", err) - } - - // if it fails check, we don't even get a delivertx back! - if !res.CheckTx.Code.IsOK() { - r := res.CheckTx - return nil, "", errors.Errorf("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log) - } - - if !res.DeliverTx.Code.IsOK() { - r := res.DeliverTx - return nil, "", errors.Errorf("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log) - } - - return res.DeliverTx.Data, res.DeliverTx.Log, nil -} - -// if the sequence flag is set, return it; -// else, fetch the account by querying the app and return the sequence number -func getSeq(address []byte) (int, error) { - if seqFlag >= 0 { - return seqFlag, nil - } - - httpClient := client.NewHTTP(txNodeFlag, "/websocket") - acc, err := getAccWithClient(httpClient, address) - if err != nil { - return 0, err - } - return acc.Sequence + 1, nil -} - -func newOutput(to []byte, amount types.Coins) types.TxOutput { - return types.TxOutput{ - Address: to, - Coins: amount, - } -} diff --git a/cmd/counter/cmd.go b/cmd/counter/cmd.go index a8c543e13609..63431591bbde 100644 --- a/cmd/counter/cmd.go +++ b/cmd/counter/cmd.go @@ -1,59 +1,11 @@ package main import ( - "encoding/json" - "fmt" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/basecoin/cmd/commands" "github.com/tendermint/basecoin/plugins/counter" "github.com/tendermint/basecoin/types" ) -//commands -var CounterTxCmd = &cobra.Command{ - Use: "counter", - Short: "Create, sign, and broadcast a transaction to the counter plugin", - RunE: counterTxCmd, -} - -const ( - flagValid = "valid" - flagCountFee = "countfee" -) - func init() { - - 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() }) } - -func counterTxCmd(cmd *cobra.Command, args []string) error { - - countFee, err := types.ParseCoins(viper.GetString(flagCountFee)) - if err != nil { - return err - } - - counterTx := counter.CounterTx{ - Valid: viper.GetBool(flagValid), - Fee: countFee, - } - - out, err := json.Marshal(counterTx) - if err != nil { - return err - } - fmt.Println("CounterTx:", string(out)) - - data := wire.BinaryBytes(counterTx) - name := "counter" - - return commands.AppTx(name, data) -} diff --git a/cmd/counter/main.go b/cmd/counter/main.go index e96940029448..11c16f8ebf70 100644 --- a/cmd/counter/main.go +++ b/cmd/counter/main.go @@ -18,7 +18,6 @@ func main() { RootCmd.AddCommand( commands.InitCmd, commands.StartCmd, - commands.TxCmd, commands.UnsafeResetAllCmd, commands.VersionCmd, ) From 66584219190fb9e037bcebc974f4d6799b575d62 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 20:47:44 +0200 Subject: [PATCH 38/73] Cleanup tests a bit --- tests/cli/ibc.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index dcb70e64fa7c..f7c870333a72 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -152,15 +152,13 @@ startRelay() { ${SERVER_EXE} relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ --genesis1=${BASE_DIR_1}/server/genesis.json --genesis2=${BASE_DIR_2}/server/genesis.json \ - --home=${BASE_DIR_1}/server --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & if [ $? != 0 ]; then echo "can't initialize relays"; cat ${BASE_DIR_1}/../relay.log; return 1; fi # now start the relay (constantly send packets) - # TODO: bucky, why does this die if I don't provide home??? - # It doesn't use the --from flag???? ${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ - --home=${BASE_DIR_1}/server --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & PID_RELAY=$! echo starting relay $PID_RELAY ... From 4b65d8bac314ccf2fed5dff8f8d50b448ec06419 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 20:51:23 +0200 Subject: [PATCH 39/73] Update changelog notes for relay update --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a917a1c791e3..701e96a3a73b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ BREAKING CHANGES: - no longer supports counter app (see new countercli) - basecoin - removed all client side functionality from it (use basecli now for proofs) + - no tx subcommand + - no query subcommand + - no account (query) subcommand + - a few other random ones... + - enhanced relay subcommand + - relay start did what relay used to do + - relay init registers both chains on one another (to set it up so relay start just works) ENHANCEMENTS: - intergrates tendermint 0.10.0 (not the rc-2, but the real thing) From a20b640f05e9197bde4d310a660bd349e2cc8df1 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 16 Jun 2017 21:06:43 +0200 Subject: [PATCH 40/73] Better error output when setup fails --- tests/cli/basictx.sh | 2 +- tests/cli/common.sh | 6 ++++++ tests/cli/counter.sh | 3 ++- tests/cli/ibc.sh | 8 ++++++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 0f2eb7803a1a..55e518819d3e 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -19,7 +19,7 @@ oneTimeSetUp() { # start basecoin server (with counter) initServer $BASE_DIR $CHAIN_ID 3456 - PID_SERVER=$! + if [ $? != 0 ]; then return 1; fi initClient $CHAIN_ID 34567 diff --git a/tests/cli/common.sh b/tests/cli/common.sh index d39355fe054c..5338a29ce6ad 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -41,6 +41,12 @@ initServer() { echo "Starting ${SERVER_EXE} server..." ${SERVER_EXE} start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & sleep 5 + PID_SERVER=$! + if ! ps $PID_SERVER >/dev/null; then + echo "**FAILED**" + # cat $SERVER_LOG + # return 1 + fi } # initClient requires chain_id arg, port is optional (default 46657) diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index 599f511297db..f09a260b76be 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -19,9 +19,10 @@ oneTimeSetUp() { # start basecoin server (with counter) initServer $BASE_DIR $CHAIN_ID 1234 - PID_SERVER=$! + if [ $? != 0 ]; then return 1; fi initClient $CHAIN_ID 12347 + if [ $? != 0 ]; then return 1; fi echo "...Testing may begin!" echo diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index f7c870333a72..5d8758fc361b 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -33,15 +33,19 @@ oneTimeSetUp() { # start basecoin server, giving money to the key in the first client BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 $PREFIX_1 - PID_SERVER_1=$! + if [ $? != 0 ]; then return 1; fi + PID_SERVER_1=$PID_SERVER # start second basecoin server, giving money to the key in the second client BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 $PREFIX_2 - PID_SERVER_2=$! + if [ $? != 0 ]; then return 1; fi + PID_SERVER_2=$PID_SERVER # connect both clients BC_HOME=${CLIENT_1} initClient $CHAIN_ID_1 $PORT_1 + if [ $? != 0 ]; then return 1; fi BC_HOME=${CLIENT_2} initClient $CHAIN_ID_2 $PORT_2 + if [ $? != 0 ]; then return 1; fi echo "...Testing may begin!" echo From 7dad89b1528936ebd4d1623000faff5995faaad4 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Sat, 17 Jun 2017 21:15:54 -0400 Subject: [PATCH 41/73] doc revisit basecoin-basics.md --- docs/go_basics.md | 2 +- docs/guide/basecoin-basics.md | 173 +++++++++++++++++++++------------- docs/guide/basecoin-tool.md | 4 +- 3 files changed, 113 insertions(+), 66 deletions(-) diff --git a/docs/go_basics.md b/docs/go_basics.md index 4744b1bff381..0ffa7a44ab1a 100644 --- a/docs/go_basics.md +++ b/docs/go_basics.md @@ -115,7 +115,7 @@ git log | head -1 In the main repo (tendermint, basecoin, ...) where the binary will be built: ``` -cd $GOPATH/src/github.com/tendermint/tendermin +cd $GOPATH/src/github.com/tendermint/tendermint git checkout master git pull # -> edit glide.lock, set the version of go-p2p (for example) diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index c2b974df93f0..dceecd84c587 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -6,7 +6,7 @@ and what is happening under the hood. ## Install -Installing basecoin is simple: +Installing Basecoin is simple: ``` go get -u github.com/tendermint/basecoin/cmd/basecoin @@ -14,7 +14,7 @@ go get -u github.com/tendermint/basecoin/cmd/basecoin If you have trouble, see the [installation guide](install.md). -## Initialization +## Initialize Basecoin To initialize a new Basecoin blockchain, run: @@ -22,12 +22,42 @@ To initialize a new Basecoin blockchain, run: basecoin init ``` -This will create the necessary files for a Basecoin blockchain with one validator and one account in `~/.basecoin`. -For more options on setup, see the [guide to using the Basecoin tool](/docs/guide/basecoin-tool.md). +This will create the necessary files for a Basecoin blockchain with one +validator and one account in `~/.basecoin`. For more options on setup, see the +[guide to using the Basecoin tool](/docs/guide/basecoin-tool.md). + +For this example, we will change the genesis account to a new account named +`cool`. First create a new account: + +``` +basecli keys new cool +``` + +While we're at it let's setup a second account which we will use later in the tutorial + +``` +basecli keys new friend +``` + +Next we need to copy in the public address from our new key into the genesis block: + +``` +basecli keys get cool -o=json +vi ~/.basecoin/genesis.json +-> cut/paste your pubkey from the results above +``` +or alternatively, without manual copy pasting: +``` +GENKEY=`basecli keys get cool -o json | jq .pubkey.data` +GENJSON=`cat ~/.basecoin/genesis.json` +echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.basecoin/genesis.json +``` + +Hurray! you are very rich and cool on this blockchain now. ## Start -Now we can start basecoin: +Now we can start Basecoin: ``` basecoin start @@ -35,64 +65,71 @@ basecoin start You should see blocks start streaming in! -## Send transactions +## Initialize Light-Client + +Now that Basecoin is running we can initialize the light-client utility named +`basecli`. Basecli is used for sending transactions and querying the state. +Leave Basecoin running and open a new terminal window. Here run: + +``` +basecli init --chain-id=test_chain_id --node=tcp://localhost:46657 +``` -Now we are ready to send some transactions. First, open another window. -If you take a look at the `~/.basecoin/genesis.json` file, you will see one account listed under the `app_options`. -This account corresponds to the private key in `~/.basecoin/key.json`. -We also included the private key for another account, in `~/.basecoin/key2.json`. +## Send transactions -Leave basecoin running and open a new terminal window. -Let's check the balance of these two accounts: +Now we are ready to send some transactions. First Let's check the balance of +the two accounts we setup earlier these two accounts: ``` -basecoin account 0x1B1BE55F969F54064628A63B9559E7C21C925165 -basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 +ME=`basecli keys get cool -o=json | jq .address | tr -d '"'` +YOU=`basecli keys get friend -o=json | jq .address | tr -d '"'` +basecli query account $ME +basecli query account $YOU ``` The first account is flush with cash, while the second account doesn't exist. Let's send funds from the first account to the second: ``` -basecoin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 10mycoin +basecli tx send --name=cool --amount=1000mycoin --to=0x$YOU --sequence=1 ``` By default, the CLI looks for a `key.json` to sign the transaction with. To specify a different key, we can use the `--from` flag. -Now if we check the second account, it should have `10` 'mycoin' coins! +Now if we check the second account, it should have `1000` 'mycoin' coins! ``` -basecoin account 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 +basecli query account $YOU ``` We can send some of these coins back like so: ``` -basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 5mycoin +basecli tx send --name=friend --amount=500mycoin --to=0x$ME --sequence=1 ``` -Note how we use the `--from` flag to select a different account to send from. +Note how we use the `--name` flag to select a different account to send from. If we try to send too much, we'll get an error: ``` -basecoin tx send --to 0x1B1BE55F969F54064628A63B9559E7C21C925165 --from key2.json --amount 100mycoin +basecli tx send --name=friend --amount=500000mycoin --to=0x$ME --sequence=1 ``` -See `basecoin tx send --help` for additional details. +See `basecli tx send --help` for additional details. -For a better understanding of the options, it helps to understand the underlying data structures. +For a better understanding of the options, it helps to understand the +underlying data structures. ## Accounts -The Basecoin state consists entirely of a set of accounts. -Each account contains a public key, -a balance in many different coin denominations, -and a strictly increasing sequence number for replay protection. -This type of account was directly inspired by accounts in Ethereum, -and is unlike Bitcoin's use of Unspent Transaction Outputs (UTXOs). -Note Basecoin is a multi-asset cryptocurrency, so each account can have many different kinds of tokens. +The Basecoin state consists entirely of a set of accounts. Each account +contains a public key, a balance in many different coin denominations, and a +strictly increasing sequence number for replay protection. This type of +account was directly inspired by accounts in Ethereum, and is unlike Bitcoin's +use of Unspent Transaction Outputs (UTXOs). Note Basecoin is a multi-asset +cryptocurrency, so each account can have many different kinds of tokens. ```golang type Account struct { @@ -109,17 +146,21 @@ type Coin struct { } ``` -Accounts are serialized and stored in a Merkle tree under the key `base/a/
`, where `
` is the address of the account. -Typically, the address of the account is the 20-byte `RIPEMD160` hash of the public key, but other formats are acceptable as well, -as defined in the [Tendermint crypto library](https://github.com/tendermint/go-crypto). -The Merkle tree used in Basecoin is a balanced, binary search tree, which we call an [IAVL tree](https://github.com/tendermint/go-merkle). +Accounts are serialized and stored in a Merkle tree under the key +`base/a/
`, where `
` is the address of the account. +Typically, the address of the account is the 20-byte `RIPEMD160` hash of the +public key, but other formats are acceptable as well, as defined in the +[Tendermint crypto library](https://github.com/tendermint/go-crypto). The +Merkle tree used in Basecoin is a balanced, binary search tree, which we call +an [IAVL tree](https://github.com/tendermint/go-merkle). ## Transactions -Basecoin defines a simple transaction type, the `SendTx`, which allows tokens to be sent to other accounts. -The `SendTx` takes a list of inputs and a list of outputs, -and transfers all the tokens listed in the inputs from their corresponding accounts to the accounts listed in the output. -The `SendTx` is structured as follows: +Basecoin defines a simple transaction type, the `SendTx`, which allows tokens +to be sent to other accounts. The `SendTx` takes a list of inputs and a list +of outputs, and transfers all the tokens listed in the inputs from their +corresponding accounts to the accounts listed in the output. The `SendTx` is +structured as follows: ```golang type SendTx struct { @@ -143,32 +184,38 @@ type TxOutput struct { } ``` -Note the `SendTx` includes a field for `Gas` and `Fee`. -The `Gas` limits the total amount of computation that can be done by the transaction, -while the `Fee` refers to the total amount paid in fees. -This is slightly different from Ethereum's concept of `Gas` and `GasPrice`, -where `Fee = Gas x GasPrice`. In Basecoin, the `Gas` and `Fee` are independent, -and the `GasPrice` is implicit. - -In Basecoin, the `Fee` is meant to be used by the validators to inform the ordering -of transactions, like in Bitcoin. And the `Gas` is meant to be used by the application -plugin to control its execution. There is currently no means to pass `Fee` information -to the Tendermint validators, but it will come soon... - -Note also that the `PubKey` only needs to be sent for `Sequence == 0`. -After that, it is stored under the account in the Merkle tree and subsequent transactions can exclude it, -using only the `Address` to refer to the sender. Ethereum does not require public keys to be sent in transactions -as it uses a different elliptic curve scheme which enables the public key to be derived from the signature itself. - -Finally, note that the use of multiple inputs and multiple outputs allows us to send many -different types of tokens between many different accounts at once in an atomic transaction. -Thus, the `SendTx` can serve as a basic unit of decentralized exchange. When using multiple -inputs and outputs, you must make sure that the sum of coins of the inputs equals the sum of -coins of the outputs (no creating money), and that all accounts that provide inputs have signed the transaction. +Note the `SendTx` includes a field for `Gas` and `Fee`. The `Gas` limits the +total amount of computation that can be done by the transaction, while the +`Fee` refers to the total amount paid in fees. This is slightly different from +Ethereum's concept of `Gas` and `GasPrice`, where `Fee = Gas x GasPrice`. In +Basecoin, the `Gas` and `Fee` are independent, and the `GasPrice` is implicit. + +In Basecoin, the `Fee` is meant to be used by the validators to inform the +ordering of transactions, like in Bitcoin. And the `Gas` is meant to be used +by the application plugin to control its execution. There is currently no +means to pass `Fee` information to the Tendermint validators, but it will come +soon... + +Note also that the `PubKey` only needs to be sent for `Sequence == 0`. After +that, it is stored under the account in the Merkle tree and subsequent +transactions can exclude it, using only the `Address` to refer to the sender. +Ethereum does not require public keys to be sent in transactions as it uses a +different elliptic curve scheme which enables the public key to be derived from +the signature itself. + +Finally, note that the use of multiple inputs and multiple outputs allows us to +send many different types of tokens between many different accounts at once in +an atomic transaction. Thus, the `SendTx` can serve as a basic unit of +decentralized exchange. When using multiple inputs and outputs, you must make +sure that the sum of coins of the inputs equals the sum of coins of the outputs +(no creating money), and that all accounts that provide inputs have signed the +transaction. ## Conclusion -In this guide, we introduced the `basecoin` tool, demonstrated how to use it to send tokens between accounts, -and discussed the underlying data types for accounts and transactions, specifically the `Account` and the `SendTx`. -In the [next guide](basecoin-plugins.md), we introduce the basecoin plugin system, which uses a new transaction type, the `AppTx`, -to extend the functionality of the Basecoin system with arbitrary logic. +In this guide, we introduced the `basecoin` tool, demonstrated how to use it to +send tokens between accounts, and discussed the underlying data types for +accounts and transactions, specifically the `Account` and the `SendTx`. In the +[next guide](basecoin-plugins.md), we introduce the Basecoin plugin system, +which uses a new transaction type, the `AppTx`, to extend the functionality of +the Basecoin system with arbitrary logic. diff --git a/docs/guide/basecoin-tool.md b/docs/guide/basecoin-tool.md index 53d8df037802..c19b4938c613 100644 --- a/docs/guide/basecoin-tool.md +++ b/docs/guide/basecoin-tool.md @@ -125,8 +125,8 @@ Now we can make a `genesis.json` file and add an account with our public key: ``` Here we've granted ourselves `1000000000` units of the `gold` token. -Note that we've also set the `chain_id` to be `example-chain`. -All transactions must therefore include the `--chain_id example-chain` in order to make sure they are valid for this chain. +Note that we've also set the `chain-id` to be `example-chain`. +All transactions must therefore include the `--chain-id example-chain` in order to make sure they are valid for this chain. Previously, we didn't need this flag because we were using the default chain ID ("test_chain_id"). Now that we're using a custom chain, we need to specify the chain explicitly on the command line. From 24bd0f5ed665bb9f664a5030a12d44fe4b1db718 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Sun, 18 Jun 2017 19:01:54 -0400 Subject: [PATCH 42/73] update docs, move counter int int int --- Makefile | 1 + circle.yml | 5 +- cmd/basecli/commands/apptx.go | 2 +- cmd/basecli/commands/sendtx.go | 2 +- cmd/counter/cmd.go | 11 - docs/guide/basecoin-plugins.md | 182 ++++++---- docs/guide/basecoin-tool.md | 137 ++++--- .../guide/counter/cmd}/counter/main.go | 8 +- .../cmd}/countercli/commands/counter.go | 2 +- .../counter/cmd}/countercli/commands/query.go | 2 +- .../guide/counter/cmd}/countercli/main.go | 39 +- .../guide/counter/plugins}/counter/counter.go | 0 .../counter/plugins}/counter/counter_test.go | 0 docs/guide/ibc.md | 341 ++++++++---------- docs/guide/install.md | 5 +- 15 files changed, 389 insertions(+), 348 deletions(-) delete mode 100644 cmd/counter/cmd.go rename {cmd => docs/guide/counter/cmd}/counter/main.go (58%) rename {cmd => docs/guide/counter/cmd}/countercli/commands/counter.go (96%) rename {cmd => docs/guide/counter/cmd}/countercli/commands/query.go (89%) rename {cmd => docs/guide/counter/cmd}/countercli/main.go (62%) rename {plugins => docs/guide/counter/plugins}/counter/counter.go (100%) rename {plugins => docs/guide/counter/plugins}/counter/counter_test.go (100%) diff --git a/Makefile b/Makefile index 159618cc9eb2..c7574c286578 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ build: install: go install ./cmd/... + go install ./docs/guide/counter/cmd/... dist: @bash scripts/dist.sh diff --git a/circle.yml b/circle.yml index ea4110e9da56..3034760d6224 100644 --- a/circle.yml +++ b/circle.yml @@ -19,8 +19,5 @@ dependencies: test: override: - - "cd $REPO && glide install && go install ./cmd/..." + - "cd $REPO && make all" - ls $GOPATH/bin - - "cd $REPO && make test" - - diff --git a/cmd/basecli/commands/apptx.go b/cmd/basecli/commands/apptx.go index 1e68600e1708..1325427d37f9 100644 --- a/cmd/basecli/commands/apptx.go +++ b/cmd/basecli/commands/apptx.go @@ -79,7 +79,7 @@ func (a *AppTx) AddSigner(pk crypto.PubKey) { // but that code is too ugly now, needs refactor.. func (a *AppTx) ValidateBasic() error { if a.chainID == "" { - return errors.New("No chainId specified") + return errors.New("No chain-id specified") } in := a.Tx.Input if len(in.Address) != 20 { diff --git a/cmd/basecli/commands/sendtx.go b/cmd/basecli/commands/sendtx.go index 178e4e37d928..15c5d5871950 100644 --- a/cmd/basecli/commands/sendtx.go +++ b/cmd/basecli/commands/sendtx.go @@ -80,7 +80,7 @@ func (s *SendTx) AddSigner(pk crypto.PubKey) { // but that code is too ugly now, needs refactor.. func (s *SendTx) ValidateBasic() error { if s.chainID == "" { - return errors.New("No chainId specified") + return errors.New("No chain-id specified") } for _, in := range s.Tx.Inputs { if len(in.Address) != 20 { diff --git a/cmd/counter/cmd.go b/cmd/counter/cmd.go deleted file mode 100644 index 63431591bbde..000000000000 --- a/cmd/counter/cmd.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "github.com/tendermint/basecoin/cmd/commands" - "github.com/tendermint/basecoin/plugins/counter" - "github.com/tendermint/basecoin/types" -) - -func init() { - commands.RegisterStartPlugin("counter", func() types.Plugin { return counter.New() }) -} diff --git a/docs/guide/basecoin-plugins.md b/docs/guide/basecoin-plugins.md index 4e1c2251c149..27d65bb851de 100644 --- a/docs/guide/basecoin-plugins.md +++ b/docs/guide/basecoin-plugins.md @@ -1,79 +1,93 @@ # Basecoin Plugins -In the [previous guide](basecoin-basics.md), -we saw how to use the `basecoin` tool to start a blockchain and send transactions. -We also learned about `Account` and `SendTx`, the basic data types giving us a multi-asset cryptocurrency. -Here, we will demonstrate how to extend the `basecoin` tool to use another transaction type, the `AppTx`, -to send data to a custom plugin. In this case we use a simple plugin that takes a single boolean argument, -and only accept the transaction if the argument is set to `true`. +In the [previous guide](basecoin-basics.md), we saw how to use the `basecoin` +tool to start a blockchain and send transactions. We also learned about +`Account` and `SendTx`, the basic data types giving us a multi-asset +cryptocurrency. Here, we will demonstrate how to extend the `basecoin` tool to +use another transaction type, the `AppTx`, to send data to a custom plugin. In +this example we explore a simple plugin name `counter`. ## Example Plugin -The design of the `basecoin` tool makes it easy to extend for custom functionality. -To see what this looks like, install the `example-plugin` tool: +The design of the `basecoin` tool makes it easy to extend for custom +functionality. The Counter plugin is bundled with basecoin, so if you have +already [installed basecoin](install.md) then you should be able to run a full +node with `counter` and the a light-client `countercli` from terminal. The +Counter plugin is just like the `basecoin` tool. They both use the same +library of commands, including one for signing and broadcasting `SendTx`. + +Counter transactions take two custom inputs, a boolean argument named `valid`, +and a coin amount named `countfee`. The transaction is only accepted if both +`valid` is set to true and the transaction input coins is greater than +`countfee` that the user provides. + +A new blockchain can be initialized and started just like with in the [previous +guide](basecoin-basics.md): ``` -cd $GOPATH/src/github.com/tendermint/basecoin -go install ./docs/guide/src/example-plugin -``` +counter init +countercli keys new cool +countercli keys new friend -The `example-plugin` tool is just like the `basecoin` tool. -They both use the same library of commands, including one for signing and broadcasting `SendTx`. -See `example-plugin --help` for details. +GENKEY=`countercli keys get cool -o json | jq .pubkey.data` +GENJSON=`cat ~/.counter/genesis.json` +echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.counter/genesis.json -A new blockchain can be initialized and started just like with `basecoin`: +counter start -``` -example-plugin init -example-plugin start ``` -The default files are stored in `~/.basecoin-example-plugin`. -In another window, we can send a `SendTx` like we are used to: +The default files are stored in `~/.counter`. In another window we can +initialize the light-client and send a transaction: ``` -example-plugin tx send --to 0x1DA7C74F9C219229FD54CC9F7386D5A3839F0090 --amount 1mycoin +countercli init --chain-id=test_chain_id --node=tcp://localhost:46657 + +YOU=`countercli keys get friend -o=json | jq .address | tr -d '"'` +countercli tx send --name=cool --amount=1000mycoin --to=0x$YOU --sequence=1 ``` -But the `example-plugin` tool has an additional command, `example-plugin tx example`, -which crafts an `AppTx` specifically for our example plugin. -This command lets you send a single boolean argument: +But the Counter has an additional command, `countercli tx counter`, which +crafts an `AppTx` specifically for this plugin: ``` -example-plugin tx example --amount 1mycoin -example-plugin tx example --amount 1mycoin --valid +countercli tx counter --name cool --amount=1mycoin --sequence=2 +countercli tx counter --name cool --amount=1mycoin --sequence=3 --valid ``` -The first transaction is rejected by the plugin because it was not marked as valid, while the second transaction passes. -We can build plugins that take many arguments of different types, and easily extend the tool to accomodate them. -Of course, we can also expose queries on our plugin: +The first transaction is rejected by the plugin because it was not marked as +valid, while the second transaction passes. We can build plugins that take +many arguments of different types, and easily extend the tool to accomodate +them. Of course, we can also expose queries on our plugin: ``` -example-plugin query ExamplePlugin.State +countercli query counter ``` -Note the `"value":"0101"`. This is the serialized form of the state, -which contains only an integer, the number of valid transactions. -If we send another transaction, and then query again, we will see the value increment: +Tada! We can now see that our custom counter plugin tx went through. You +should see a Counter value of 1 representing the number of valid transactions. +If we send another transaction, and then query again, we will see the value +increment: ``` -example-plugin tx example --valid --amount 1mycoin -example-plugin query ExamplePlugin.State +countercli tx counter --name cool --amount=1mycoin --sequence=4 --valid +countercli query counter ``` -The value should now be `0102`, because we sent a second valid transaction. -Notice how the result of the query comes with a proof. -This is a Merkle proof that the state is what we say it is. -In a latter [guide on InterBlockchain Communication](ibc.md), -we'll put this proof to work! +The value Counter value should be 2, because we sent a second valid transaction. +Notice how the result of the query comes with a proof. This is a Merkle proof +that the state is what we say it is. In a latter [guide on InterBlockchain +Communication](ibc.md), we'll put this proof to work! -Now, before we implement our own plugin and tooling, it helps to understand the `AppTx` and the design of the plugin system. +Now, before we implement our own plugin and tooling, it helps to understand the +`AppTx` and the design of the plugin system. ## AppTx -The `AppTx` is similar to the `SendTx`, but instead of sending coins from inputs to outputs, -it sends coins from one input to a plugin, and can also send some data. +The `AppTx` is similar to the `SendTx`, but instead of sending coins from +inputs to outputs, it sends coins from one input to a plugin, and can also send +some data. ```golang type AppTx struct { @@ -85,13 +99,15 @@ type AppTx struct { } ``` -The `AppTx` enables Basecoin to be extended with arbitrary additional functionality through the use of plugins. -The `Name` field in the `AppTx` refers to the particular plugin which should process the transaction, -and the `Data` field of the `AppTx` is the data to be forwarded to the plugin for processing. +The `AppTx` enables Basecoin to be extended with arbitrary additional +functionality through the use of plugins. The `Name` field in the `AppTx` +refers to the particular plugin which should process the transaction, and the +`Data` field of the `AppTx` is the data to be forwarded to the plugin for +processing. -Note the `AppTx` also has a `Gas` and `Fee`, with the same meaning as for the `SendTx`. -It also includes a single `TxInput`, which specifies the sender of the transaction, -and some coins that can be forwarded to the plugin as well. +Note the `AppTx` also has a `Gas` and `Fee`, with the same meaning as for the +`SendTx`. It also includes a single `TxInput`, which specifies the sender of +the transaction, and some coins that can be forwarded to the plugin as well. ## Plugins @@ -120,43 +136,59 @@ type CallContext struct { } ``` -The workhorse of the plugin is `RunTx`, which is called when an `AppTx` is processed. -The `Data` from the `AppTx` is passed in as the `txBytes`, -while the `Input` from the `AppTx` is used to populate the `CallContext`. +The workhorse of the plugin is `RunTx`, which is called when an `AppTx` is +processed. The `Data` from the `AppTx` is passed in as the `txBytes`, while +the `Input` from the `AppTx` is used to populate the `CallContext`. -Note that `RunTx` also takes a `KVStore` - this is an abstraction for the underlying Merkle tree which stores the account data. -By passing this to the plugin, we enable plugins to update accounts in the Basecoin state directly, -and also to store arbitrary other information in the state. -In this way, the functionality and state of a Basecoin-derived cryptocurrency can be greatly extended. -One could imagine going so far as to implement the Ethereum Virtual Machine as a plugin! +Note that `RunTx` also takes a `KVStore` - this is an abstraction for the +underlying Merkle tree which stores the account data. By passing this to the +plugin, we enable plugins to update accounts in the Basecoin state directly, +and also to store arbitrary other information in the state. In this way, the +functionality and state of a Basecoin-derived cryptocurrency can be greatly +extended. One could imagine going so far as to implement the Ethereum Virtual +Machine as a plugin! -For details on how to initialize the state using `SetOption`, see the [guide to using the basecoin tool](basecoin-tool.md#genesis). +For details on how to initialize the state using `SetOption`, see the [guide to +using the basecoin tool](basecoin-tool.md#genesis). ## Implement your own -To implement your own plugin and tooling, make a copy of `docs/guide/src/example-plugin`, -and modify the code accordingly. Here, we will briefly describe the design and the changes to be made, -but see the code for more details. +To implement your own plugin and tooling, make a copy of +`docs/guide/counter`, and modify the code accordingly. Here, we will +briefly describe the design and the changes to be made, but see the code for +more details. + +First is the `cmd/counter/main.go`, which drives the program. It can be left +alone, but you should change any occurrences of `counter` to whatever your +plugin tool is going to be called. -First is the `main.go`, which drives the program. It can be left alone, but you should change any occurences of `example-plugin` -to whatever your plugin tool is going to be called. +The light-client which is located in `cmd/countercli/main.go` allows for is +where transaction and query commands are designated. Similarity this command +can be mostly left alone besides replacing the application name and adding +references to new plugin commands -Next is the `cmd.go`. This is where we extend the tool with any new commands and flags we need to send transactions to our plugin. -Note the `init()` function, where we register a new transaction subcommand with `RegisterTxSubcommand`, -and where we load the plugin into the Basecoin app with `RegisterStartPlugin`. +Next is the custom commands in `cmd/countercli/commands/`. These files is +where we extend the tool with any new commands and flags we need to send +transactions or queries to our plugin. Note the `init()` function, where we +register a new transaction subcommand with `RegisterTxSubcommand`, and where we +load the plugin into the Basecoin app with `RegisterStartPlugin`. -Finally is the `plugin.go`, where we provide an implementation of the `Plugin` interface. -The most important part of the implementation is the `RunTx` method, which determines the meaning of the data -sent along in the `AppTx`. In our example, we define a new transaction type, the `ExamplePluginTx`, which -we expect to be encoded in the `AppTx.Data`, and thus to be decoded in the `RunTx` method, and used to update the plugin state. +Finally is `plugins/counter/counter.go`, where we provide an implementation of +the `Plugin` interface. The most important part of the implementation is the +`RunTx` method, which determines the meaning of the data sent along in the +`AppTx`. In our example, we define a new transaction type, the `CounterTx`, +which we expect to be encoded in the `AppTx.Data`, and thus to be decoded in +the `RunTx` method, and used to update the plugin state. -For more examples and inspiration, see our [repository of example plugins](https://github.com/tendermint/basecoin-examples). +For more examples and inspiration, see our [repository of example +plugins](https://github.com/tendermint/basecoin-examples). ## Conclusion In this guide, we demonstrated how to create a new plugin and how to extend the -`basecoin` tool to start a blockchain with the plugin enabled and send transactions to it. -In the next guide, we introduce a [plugin for Inter Blockchain Communication](ibc.md), -which allows us to publish proofs of the state of one blockchain to another, -and thus to transfer tokens and data between them. +`basecoin` tool to start a blockchain with the plugin enabled and send +transactions to it. In the next guide, we introduce a [plugin for Inter +Blockchain Communication](ibc.md), which allows us to publish proofs of the +state of one blockchain to another, and thus to transfer tokens and data +between them. diff --git a/docs/guide/basecoin-tool.md b/docs/guide/basecoin-tool.md index c19b4938c613..0f89f7bd7337 100644 --- a/docs/guide/basecoin-tool.md +++ b/docs/guide/basecoin-tool.md @@ -1,12 +1,14 @@ # The Basecoin Tool -In previous tutorials we learned the [basics of the `basecoin` CLI](/docs/guide/basecoin-basics.md) -and [how to implement a plugin](/docs/guide/basecoin-plugins.md). -In this tutorial, we provide more details on using the `basecoin` tool. +In previous tutorials we learned the [basics of the Basecoin +CLI](/docs/guide/basecoin-basics.md) and [how to implement a +plugin](/docs/guide/basecoin-plugins.md). In this tutorial, we provide more +details on using the Basecoin tool. # Data Directory -By default, `basecoin` works out of `~/.basecoin`. To change this, set the `BCHOME` environment variable: +By default, `basecoin` works out of `~/.basecoin`. To change this, set the +`BCHOME` environment variable: ``` export BCHOME=~/.my_basecoin_data @@ -23,15 +25,16 @@ BCHOME=~/.my_basecoin_data basecoin start # ABCI Server -So far we have run Basecoin and Tendermint in a single process. -However, since we use ABCI, we can actually run them in different processes. -First, initialize them: +So far we have run Basecoin and Tendermint in a single process. However, since +we use ABCI, we can actually run them in different processes. First, +initialize them: ``` basecoin init ``` -This will create a single `genesis.json` file in `~/.basecoin` with the information for both Basecoin and Tendermint. +This will create a single `genesis.json` file in `~/.basecoin` with the +information for both Basecoin and Tendermint. Now, In one window, run @@ -47,7 +50,8 @@ TMROOT=~/.basecoin tendermint node You should see Tendermint start making blocks! -Alternatively, you could ignore the Tendermint details in `~/.basecoin/genesis.json` and use a separate directory by running: +Alternatively, you could ignore the Tendermint details in +`~/.basecoin/genesis.json` and use a separate directory by running: ``` tendermint init @@ -58,9 +62,11 @@ For more details on using `tendermint`, see [the guide](https://tendermint.com/d # Keys and Genesis -In previous tutorials we used `basecoin init` to initialize `~/.basecoin` with the default configuration. -This command creates files both for Tendermint and for Basecoin, and a single `genesis.json` file for both of them. -For more information on these files, see the [guide to using tendermint](https://tendermint.com/docs/guides/using-tendermint). +In previous tutorials we used `basecoin init` to initialize `~/.basecoin` with +the default configuration. This command creates files both for Tendermint and +for Basecoin, and a single `genesis.json` file for both of them. For more +information on these files, see the [guide to using +Tendermint](https://tendermint.com/docs/guides/using-tendermint). Now let's make our own custom Basecoin data. @@ -70,67 +76,88 @@ First, create a new directory: mkdir example-data ``` -We can tell `basecoin` to use this directory by exporting the `BCHOME` environment variable: +We can tell `basecoin` to use this directory by exporting the `BCHOME` +environment variable: ``` export BCHOME=$(pwd)/example-data ``` -If you're going to be using multiple terminal windows, make sure to add this variable to your shell startup scripts (eg. `~/.bashrc`). +If you're going to be using multiple terminal windows, make sure to add this +variable to your shell startup scripts (eg. `~/.bashrc`). -Now, let's create a new private key: +Now, let's create a new key: ``` -basecoin key new > $BCHOME/key.json +basecli keys new foobar ``` -Here's what my `key.json looks like: +The key's info can be retrieved with + +``` +basecli keys get foobar -o=json +``` + +You should get output which looks similar to the following: ```json { - "address": "4EGEhnqOw/gX326c7KARUkY1kic=", - "pub_key": { - "type": "ed25519", - "data": "a20d48b5caff42892d0ac67ccdeee38c1dcbbe42b15b486057d16244541e8141" - }, - "priv_key": { - "type": "ed25519", - "data": "654c845f4b36d1a881deb0ff09381165d3ccd156b4aabb5b51267e91f1d024a5a20d48b5caff42892d0ac67ccdeee38c1dcbbe42b15b486057d16244541e8141" - } + "name": "foobar", + "address": "404C5003A703C7DA888C96A2E901FCE65A6869D9", + "pubkey": { + "type": "ed25519", + "data": "8786B7812AB3B27892D8E14505EEFDBB609699E936F6A4871B1983F210736EEA" + } } ``` -Yours will look different - each key is randomly derrived. - -Now we can make a `genesis.json` file and add an account with our public key: +Yours will look different - each key is randomly derived. Now we can make a +`genesis.json` file and add an account with our public key: ```json { + "app_hash": "", "chain_id": "example-chain", - "app_options": { - "accounts": [{ + "genesis_time": "0001-01-01T00:00:00.000Z", + "validators": [ + { + "amount": 10, + "name": "", "pub_key": { "type": "ed25519", - "data": "a20d48b5caff42892d0ac67ccdeee38c1dcbbe42b15b486057d16244541e8141" - }, - "coins": [ - { - "denom": "gold", - "amount": 1000000000 - } - ] - }] + "data": "7B90EA87E7DC0C7145C8C48C08992BE271C7234134343E8A8E8008E617DE7B30" + } + } + ], + "app_options": { + "accounts": [ + { + "pub_key": { + "type": "ed25519", + "data": "8786B7812AB3B27892D8E14505EEFDBB609699E936F6A4871B1983F210736EEA" + }, + "coins": [ + { + "denom": "gold", + "amount": 1000000000 + } + ] + } + ] } } ``` -Here we've granted ourselves `1000000000` units of the `gold` token. -Note that we've also set the `chain-id` to be `example-chain`. -All transactions must therefore include the `--chain-id example-chain` in order to make sure they are valid for this chain. -Previously, we didn't need this flag because we were using the default chain ID ("test_chain_id"). -Now that we're using a custom chain, we need to specify the chain explicitly on the command line. +Here we've granted ourselves `1000000000` units of the `gold` token. Note that +we've also set the `chain-id` to be `example-chain`. All transactions must +therefore include the `--chain-id example-chain` in order to make sure they are +valid for this chain. Previously, we didn't need this flag because we were +using the default chain ID ("test_chain_id"). Now that we're using a custom +chain, we need to specify the chain explicitly on the command line. -Note we have also left out the details of the tendermint genesis. These are documented in the [tendermint guide](https://tendermint.com/docs/guides/using-tendermint). +Note we have also left out the details of the Tendermint genesis. These are +documented in the [Tendermint +guide](https://tendermint.com/docs/guides/using-tendermint). # Reset @@ -141,13 +168,19 @@ You can reset all blockchain data by running: basecoin unsafe_reset_all ``` +Similarity you can reset client data by running: + +``` +basecli reset_all +``` # Genesis -Any required plugin initialization should be constructed using `SetOption` on genesis. -When starting a new chain for the first time, `SetOption` will be called for each item the genesis file. -Within genesis.json file entries are made in the format: `"/", ""`, where `` is the plugin name, -and `` and `` are the strings passed into the plugin SetOption function. -This function is intended to be used to set plugin specific information such -as the plugin state. +Any required plugin initialization should be constructed using `SetOption` on +genesis. When starting a new chain for the first time, `SetOption` will be +called for each item the genesis file. Within genesis.json file entries are +made in the format: `"/", ""`, where `` is the +plugin name, and `` and `` are the strings passed into the plugin +SetOption function. This function is intended to be used to set plugin +specific information such as the plugin state. diff --git a/cmd/counter/main.go b/docs/guide/counter/cmd/counter/main.go similarity index 58% rename from cmd/counter/main.go rename to docs/guide/counter/cmd/counter/main.go index 11c16f8ebf70..0da66c12f6e9 100644 --- a/cmd/counter/main.go +++ b/docs/guide/counter/cmd/counter/main.go @@ -5,8 +5,11 @@ import ( "github.com/spf13/cobra" - "github.com/tendermint/basecoin/cmd/commands" "github.com/tendermint/tmlibs/cli" + + "github.com/tendermint/basecoin/cmd/commands" + "github.com/tendermint/basecoin/docs/guide/counter/plugins/counter" + "github.com/tendermint/basecoin/types" ) func main() { @@ -22,6 +25,7 @@ func main() { commands.VersionCmd, ) - cmd := cli.PrepareMainCmd(RootCmd, "BC", os.ExpandEnv("$HOME/.basecoin")) + commands.RegisterStartPlugin("counter", func() types.Plugin { return counter.New() }) + cmd := cli.PrepareMainCmd(RootCmd, "CT", os.ExpandEnv("$HOME/.counter")) cmd.Execute() } diff --git a/cmd/countercli/commands/counter.go b/docs/guide/counter/cmd/countercli/commands/counter.go similarity index 96% rename from cmd/countercli/commands/counter.go rename to docs/guide/counter/cmd/countercli/commands/counter.go index 22064e08cba5..0481e3d0654f 100644 --- a/cmd/countercli/commands/counter.go +++ b/docs/guide/counter/cmd/countercli/commands/counter.go @@ -8,7 +8,7 @@ import ( txcmd "github.com/tendermint/light-client/commands/txs" bcmd "github.com/tendermint/basecoin/cmd/basecli/commands" - "github.com/tendermint/basecoin/plugins/counter" + "github.com/tendermint/basecoin/docs/guide/counter/plugins/counter" btypes "github.com/tendermint/basecoin/types" ) diff --git a/cmd/countercli/commands/query.go b/docs/guide/counter/cmd/countercli/commands/query.go similarity index 89% rename from cmd/countercli/commands/query.go rename to docs/guide/counter/cmd/countercli/commands/query.go index 751f7a11b032..692e04c7b3fa 100644 --- a/cmd/countercli/commands/query.go +++ b/docs/guide/counter/cmd/countercli/commands/query.go @@ -5,7 +5,7 @@ import ( proofcmd "github.com/tendermint/light-client/commands/proofs" - "github.com/tendermint/basecoin/plugins/counter" + "github.com/tendermint/basecoin/docs/guide/counter/plugins/counter" ) //CounterQueryCmd CLI command to query the counter state diff --git a/cmd/countercli/main.go b/docs/guide/counter/cmd/countercli/main.go similarity index 62% rename from cmd/countercli/main.go rename to docs/guide/counter/cmd/countercli/main.go index 57204d3fb6b8..7b543d352664 100644 --- a/cmd/countercli/main.go +++ b/docs/guide/counter/cmd/countercli/main.go @@ -14,12 +14,12 @@ import ( "github.com/tendermint/tmlibs/cli" bcmd "github.com/tendermint/basecoin/cmd/basecli/commands" - bcount "github.com/tendermint/basecoin/cmd/countercli/commands" + bcount "github.com/tendermint/basecoin/docs/guide/counter/cmd/countercli/commands" ) // BaseCli represents the base command when called without any subcommands var BaseCli = &cobra.Command{ - Use: "basecli", + Use: "countercli", Short: "Light client for tendermint", Long: `Basecli is an version of tmcli including custom logic to present a nice (not raw hex) interface to the basecoin blockchain structure. @@ -33,21 +33,25 @@ func main() { commands.AddBasicFlags(BaseCli) // 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) + proofs.RootCmd.AddCommand( + // These are default parsers, optional in your app + proofs.TxCmd, + proofs.KeyCmd, + bcmd.AccountQueryCmd, - // IMPORTANT: here is how you add custom query commands in your app - pr.AddCommand(bcount.CounterQueryCmd) + // XXX IMPORTANT: here is how you add custom query commands in your app + bcount.CounterQueryCmd, + ) + // Prepare transactions proofs.TxPresenters.Register("base", bcmd.BaseTxPresenter{}) - tr := txs.RootCmd - tr.AddCommand(bcmd.SendTxCmd) + txs.RootCmd.AddCommand( + // This is the default transaction, optional in your app + bcmd.SendTxCmd, - // IMPORTANT: here is how you add custom tx construction for your app - tr.AddCommand(bcount.CounterTxCmd) + // XXX IMPORTANT: here is how you add custom tx construction for your app + bcount.CounterTxCmd, + ) // Set up the various commands to use BaseCli.AddCommand( @@ -55,10 +59,11 @@ func main() { commands.ResetCmd, keycmd.RootCmd, seeds.RootCmd, - pr, - tr, - proxy.RootCmd) + proofs.RootCmd, + txs.RootCmd, + proxy.RootCmd, + ) - cmd := cli.PrepareMainCmd(BaseCli, "BC", os.ExpandEnv("$HOME/.basecli")) + cmd := cli.PrepareMainCmd(BaseCli, "CTL", os.ExpandEnv("$HOME/.countercli")) cmd.Execute() } diff --git a/plugins/counter/counter.go b/docs/guide/counter/plugins/counter/counter.go similarity index 100% rename from plugins/counter/counter.go rename to docs/guide/counter/plugins/counter/counter.go diff --git a/plugins/counter/counter_test.go b/docs/guide/counter/plugins/counter/counter_test.go similarity index 100% rename from plugins/counter/counter_test.go rename to docs/guide/counter/plugins/counter/counter_test.go diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 71e196d01bdc..9c30a6d391c9 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -1,29 +1,31 @@ # InterBlockchain Communication with Basecoin -One of the most exciting elements of the Cosmos Network is the InterBlockchain Communication (IBC) protocol, -which enables interoperability across different blockchains. -The simplest example of using the IBC protocol is to send a data packet from one blockchain to another. +One of the most exciting elements of the Cosmos Network is the InterBlockchain +Communication (IBC) protocol, which enables interoperability across different +blockchains. The simplest example of using the IBC protocol is to send a data +packet from one blockchain to another. -We implemented IBC as a basecoin plugin. -and here we'll show you how to use the Basecoin IBC-plugin to send a packet of data across blockchains! +We implemented IBC as a basecoin plugin. and here we'll show you how to use +the Basecoin IBC-plugin to send a packet of data across blockchains! -Please note, this tutorial assumes you are familiar with [Basecoin plugins](/docs/guide/basecoin-plugins.md), -but we'll explain how IBC works. You may also want to see [our repository of example plugins](https://github.com/tendermint/basecoin-examples). +Please note, this tutorial assumes you are familiar with [Basecoin +plugins](/docs/guide/basecoin-plugins.md), but we'll explain how IBC works. You +may also want to see [our repository of example +plugins](https://github.com/tendermint/basecoin-examples). The IBC plugin defines a new set of transactions as subtypes of the `AppTx`. -The plugin's functionality is accessed by setting the `AppTx.Name` field to `"IBC"`, -and setting the `Data` field to the serialized IBC transaction type. +The plugin's functionality is accessed by setting the `AppTx.Name` field to +`"IBC"`, and setting the `Data` field to the serialized IBC transaction type. We'll demonstrate exactly how this works below. ## IBC -Let's review the IBC protocol. -The purpose of IBC is to enable one blockchain to function as a light-client of another. -Since we are using a classical Byzantine Fault Tolerant consensus algorithm, -light-client verification is cheap and easy: -all we have to do is check validator signatures on the latest block, -and verify a Merkle proof of the state. +Let's review the IBC protocol. The purpose of IBC is to enable one blockchain +to function as a light-client of another. Since we are using a classical +Byzantine Fault Tolerant consensus algorithm, light-client verification is +cheap and easy: all we have to do is check validator signatures on the latest +block, and verify a Merkle proof of the state. In Tendermint, validators agree on a block before processing it. This means that the signatures and state root for that block aren't included until the @@ -31,9 +33,9 @@ next block. Thus, each block contains a field called `LastCommit`, which contains the votes responsible for committing the previous block, and a field in the block header called `AppHash`, which refers to the Merkle root hash of the application after processing the transactions from the previous block. So, -if we want to verify the `AppHash` from height H, we need the signatures from `LastCommit` -at height H+1. (And remember that this `AppHash` only contains the results from all -transactions up to and including block H-1) +if we want to verify the `AppHash` from height H, we need the signatures from +`LastCommit` at height H+1. (And remember that this `AppHash` only contains the +results from all transactions up to and including block H-1) Unlike Proof-of-Work, the light-client protocol does not need to download and check all the headers in the blockchain - the client can always jump straight @@ -43,109 +45,94 @@ changes, which requires downloading headers for each block in which there is a significant change. Here, we will assume the validator set is constant, and postpone handling validator set changes for another time. -Now we can describe exactly how IBC works. -Suppose we have two blockchains, `chain1` and `chain2`, and we want to send some data from `chain1` to `chain2`. +Now we can describe exactly how IBC works. Suppose we have two blockchains, +`chain1` and `chain2`, and we want to send some data from `chain1` to `chain2`. We need to do the following: - 1. Register the details (ie. chain ID and genesis configuration) of `chain1` on `chain2` - 2. Within `chain1`, broadcast a transaction that creates an outgoing IBC packet destined for `chain2` - 3. Broadcast a transaction to `chain2` informing it of the latest state (ie. header and commit signatures) of `chain1` - 4. Post the outgoing packet from `chain1` to `chain2`, including the proof that -it was indeed committed on `chain1`. Note `chain2` can only verify this proof -because it has a recent header and commit. - -Each of these steps involves a separate IBC transaction type. Let's take them up in turn. + 1. Register the details (ie. chain ID and genesis configuration) of `chain1` + on `chain2` + 2. Within `chain1`, broadcast a transaction that creates an outgoing IBC + packet destined for `chain2` + 3. Broadcast a transaction to `chain2` informing it of the latest state (ie. + header and commit signatures) of `chain1` + 4. Post the outgoing packet from `chain1` to `chain2`, including the proof + that it was indeed committed on `chain1`. Note `chain2` can only verify +this proof because it has a recent header and commit. + +Each of these steps involves a separate IBC transaction type. Let's take them +up in turn. ### IBCRegisterChainTx -The `IBCRegisterChainTx` is used to register one chain on another. -It contains the chain ID and genesis configuration of the chain to register: +The `IBCRegisterChainTx` is used to register one chain on another. It contains +the chain ID and genesis configuration of the chain to register: -```golang -type IBCRegisterChainTx struct { - BlockchainGenesis -} +```golang type IBCRegisterChainTx struct { BlockchainGenesis } -type BlockchainGenesis struct { - ChainID string - Genesis string -} -``` +type BlockchainGenesis struct { ChainID string Genesis string } ``` -This transaction should only be sent once for a given chain ID, and successive sends will return an error. +This transaction should only be sent once for a given chain ID, and successive +sends will return an error. ### IBCUpdateChainTx -The `IBCUpdateChainTx` is used to update the state of one chain on another. -It contains the header and commit signatures for some block in the chain: +The `IBCUpdateChainTx` is used to update the state of one chain on another. It +contains the header and commit signatures for some block in the chain: -```golang -type IBCUpdateChainTx struct { - Header tm.Header - Commit tm.Commit -} +```golang type IBCUpdateChainTx struct { Header tm.Header Commit tm.Commit } ``` -In the future, it needs to be updated to include changes to the validator set as well. -Anyone can relay an `IBCUpdateChainTx`, and they only need to do so as frequently as packets are being sent or the validator set is changing. +In the future, it needs to be updated to include changes to the validator set +as well. Anyone can relay an `IBCUpdateChainTx`, and they only need to do so +as frequently as packets are being sent or the validator set is changing. ### IBCPacketCreateTx -The `IBCPacketCreateTx` is used to create an outgoing packet on one chain. -The packet itself contains the source and destination chain IDs, -a sequence number (i.e. an integer that increments with every message sent between this pair of chains), -a packet type (e.g. coin, data, etc.), -and a payload. - -```golang -type IBCPacketCreateTx struct { - Packet -} - -type Packet struct { - SrcChainID string - DstChainID string - Sequence uint64 - Type string - Payload []byte -} -``` +The `IBCPacketCreateTx` is used to create an outgoing packet on one chain. The +packet itself contains the source and destination chain IDs, a sequence number +(i.e. an integer that increments with every message sent between this pair of +chains), a packet type (e.g. coin, data, etc.), and a payload. + +```golang type IBCPacketCreateTx struct { Packet } -We have yet to define the format for the payload, so, for now, it's just arbitrary bytes. +type Packet struct { SrcChainID string DstChainID string Sequence uint64 Type +string Payload []byte } ``` -One way to think about this is that `chain2` has an account on `chain1`. -With a `IBCPacketCreateTx` on `chain1`, we send funds to that account. -Then we can prove to `chain2` that there are funds locked up for it in it's -account on `chain1`. -Those funds can only be unlocked with corresponding IBC messages back from -`chain2` to `chain1` sending the locked funds to another account on +We have yet to define the format for the payload, so, for now, it's just +arbitrary bytes. + +One way to think about this is that `chain2` has an account on `chain1`. With +a `IBCPacketCreateTx` on `chain1`, we send funds to that account. Then we can +prove to `chain2` that there are funds locked up for it in it's account on +`chain1`. Those funds can only be unlocked with corresponding IBC messages +back from `chain2` to `chain1` sending the locked funds to another account on `chain1`. ### IBCPacketPostTx -The `IBCPacketPostTx` is used to post an outgoing packet from one chain to another. -It contains the packet and a proof that the packet was committed into the state of the sending chain: +The `IBCPacketPostTx` is used to post an outgoing packet from one chain to +another. It contains the packet and a proof that the packet was committed into +the state of the sending chain: -```golang -type IBCPacketPostTx struct { - FromChainID string // The immediate source of the packet, not always Packet.SrcChainID - FromChainHeight uint64 // The block height in which Packet was committed, to check Proof - Packet - Proof *merkle.IAVLProof -} -``` +```golang type IBCPacketPostTx struct { FromChainID string // The immediate +source of the packet, not always Packet.SrcChainID FromChainHeight uint64 // +The block height in which Packet was committed, to check Proof Packet Proof +*merkle.IAVLProof } ``` + +The proof is a Merkle proof in an IAVL tree, our implementation of a balanced, +Merklized binary search tree. It contains a list of nodes in the tree, which +can be hashed together to get the Merkle root hash. This hash must match the +`AppHash` contained in the header at `FromChainHeight + 1` -The proof is a Merkle proof in an IAVL tree, our implementation of a balanced, Merklized binary search tree. -It contains a list of nodes in the tree, which can be hashed together to get the Merkle root hash. -This hash must match the `AppHash` contained in the header at `FromChainHeight + 1` -- note the `+ 1` is necessary since `FromChainHeight` is the height in which the packet was committed, -and the resulting state root is not included until the next block. +- note the `+ 1` is necessary since `FromChainHeight` is the height in which + the packet was committed, and the resulting state root is not included until +the next block. ### IBC State Now that we've seen all the transaction types, let's talk about the state. -Each chain stores some IBC state in its Merkle tree. -For each chain being tracked by our chain, we store: +Each chain stores some IBC state in its Merkle tree. For each chain being +tracked by our chain, we store: - Genesis configuration - Latest state @@ -154,143 +141,131 @@ For each chain being tracked by our chain, we store: We also store all incoming (ingress) and outgoing (egress) packets. The state of a chain is updated every time an `IBCUpdateChainTx` is committed. -New packets are added to the egress state upon `IBCPacketCreateTx`. -New packets are added to the ingress state upon `IBCPacketPostTx`, -assuming the proof checks out. +New packets are added to the egress state upon `IBCPacketCreateTx`. New +packets are added to the ingress state upon `IBCPacketPostTx`, assuming the +proof checks out. ## Merkle Queries -The Basecoin application uses a single Merkle tree that is shared across all its state, -including the built-in accounts state and all plugin state. For this reason, -it's important to use explicit key names and/or hashes to ensure there are no collisions. +The Basecoin application uses a single Merkle tree that is shared across all +its state, including the built-in accounts state and all plugin state. For this +reason, it's important to use explicit key names and/or hashes to ensure there +are no collisions. -We can query the Merkle tree using the ABCI Query method. -If we pass in the correct key, it will return the corresponding value, -as well as a proof that the key and value are contained in the Merkle tree. +We can query the Merkle tree using the ABCI Query method. If we pass in the +correct key, it will return the corresponding value, as well as a proof that +the key and value are contained in the Merkle tree. The results of a query can thus be used as proof in an `IBCPacketPostTx`. ## Try it out -Now that we have all the background knowledge, let's actually walk through the tutorial. +Now that we have all the background knowledge, let's actually walk through the +tutorial. Make sure you have installed [Tendermint](https://tendermint.com/intro/getting-started/download) and [basecoin](/docs/guide/install.md). -`basecoin` is a framework for creating new cryptocurrency applications. -It comes with an `IBC` plugin enabled by default. +`basecoin` is a framework for creating new cryptocurrency applications. It +comes with an `IBC` plugin enabled by default. -You will also want to install the [jq](https://stedolan.github.io/jq/) for handling JSON at the command line. +You will also want to install the [jq](https://stedolan.github.io/jq/) for +handling JSON at the command line. -Now let's start the two blockchains. -In this tutorial, each chain will have only a single validator, -where the initial configuration files are already generated. -Let's change directory so these files are easily accessible: +Now let's start the two blockchains. In this tutorial, each chain will have +only a single validator, where the initial configuration files are already +generated. Let's change directory so these files are easily accessible: -``` -cd $GOPATH/src/github.com/tendermint/basecoin/demo -``` +``` cd $GOPATH/src/github.com/tendermint/basecoin/demo ``` -The relevant data is now in the `data` directory. -Before we begin, let's set some environment variables for convenience: +The relevant data is now in the `data` directory. Before we begin, let's set +some environment variables for convenience: -``` -export BCHOME="." -BCHOME1="./data/chain1" -BCHOME2="./data/chain2" +``` export BCHOME="." BCHOME1="./data/chain1" BCHOME2="./data/chain2" -export CHAIN_ID1=test_chain_1 -export CHAIN_ID2=test_chain_2 +export CHAIN_ID1=test_chain_1 export CHAIN_ID2=test_chain_2 CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from $BCHOME1/key.json" -CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from $BCHOME2/key.json --node tcp://localhost:36657" -``` +CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from $BCHOME2/key.json --node +tcp://localhost:36657" ``` -In previous examples, we started basecoin in-process with tendermint. -Here, we will run them in different processes, using the `--without-tendermint` flag, -as described in the [guide to the basecoin tool](basecoin-tool.md). -We can start the two chains as follows: +In previous examples, we started basecoin in-process with tendermint. Here, we +will run them in different processes, using the `--without-tendermint` flag, as +described in the [guide to the basecoin tool](basecoin-tool.md). We can start +the two chains as follows: -``` -TMROOT=$BCHOME1 tendermint node --log_level=info &> chain1_tendermint.log & +``` TMROOT=$BCHOME1 tendermint node --log_level=info &> chain1_tendermint.log & BCHOME=$BCHOME1 basecoin start --without-tendermint &> chain1_basecoin.log & ``` and -``` -TMROOT=$BCHOME2 tendermint node --log_level=info --node_laddr tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app tcp://localhost:36658 &> chain2_tendermint.log & -BCHOME=$BCHOME2 basecoin start --address tcp://localhost:36658 --without-tendermint &> chain2_basecoin.log & +``` TMROOT=$BCHOME2 tendermint node --log_level=info --node_laddr +tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app +tcp://localhost:36658 &> chain2_tendermint.log & BCHOME=$BCHOME2 basecoin start +--address tcp://localhost:36658 --without-tendermint &> chain2_basecoin.log & ``` -Note how we refer to the relevant data directories, and how we set the various addresses for the second node so as not to conflict with the first. +Note how we refer to the relevant data directories, and how we set the various +addresses for the second node so as not to conflict with the first. We can now check on the status of the two chains: -``` -curl localhost:46657/status -curl localhost:36657/status -``` +``` curl localhost:46657/status curl localhost:36657/status ``` -If either command fails, the nodes may not have finished starting up. Wait a couple seconds and try again. -Once you see the status of both chains, it's time to move on. +If either command fails, the nodes may not have finished starting up. Wait a +couple seconds and try again. Once you see the status of both chains, it's +time to move on. -In this tutorial, we're going to send some data from `test_chain_1` to `test_chain_2`. -We begin by registering `test_chain_1` on `test_chain_2`: +In this tutorial, we're going to send some data from `test_chain_1` to +`test_chain_2`. We begin by registering `test_chain_1` on `test_chain_2`: -``` -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --ibc_chain_id $CHAIN_ID1 --genesis $BCHOME1/genesis.json -``` +``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --ibc_chain_id +$CHAIN_ID1 --genesis $BCHOME1/genesis.json ``` Now we can create the outgoing packet on `test_chain_1`: -``` -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --ibc_from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --ibc_sequence 1 +``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --ibc_from +$CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --ibc_sequence 1 ``` -Note our payload is just `DEADBEEF`. -Now that the packet is committed in the chain, let's get some proof by querying: +Note our payload is just `DEADBEEF`. Now that the packet is committed in the +chain, let's get some proof by querying: -``` -QUERY=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1) -echo $QUERY -``` +``` QUERY=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1) echo $QUERY ``` -The result contains the latest height, a value (i.e. the hex-encoded binary serialization of our packet), -and a proof (i.e. hex-encoded binary serialization of a list of nodes from the Merkle tree) that the value is in the Merkle tree. -We keep the result in the `QUERY` variable so we can easily reference subfields using the `jq` tool. +The result contains the latest height, a value (i.e. the hex-encoded binary +serialization of our packet), and a proof (i.e. hex-encoded binary +serialization of a list of nodes from the Merkle tree) that the value is in the +Merkle tree. We keep the result in the `QUERY` variable so we can easily +reference subfields using the `jq` tool. -If we want to send this data to `test_chain_2`, we first have to update what it knows about `test_chain_1`. -We'll need a recent block header and a set of commit signatures. -Fortunately, we can get them with the `block` command: +If we want to send this data to `test_chain_2`, we first have to update what it +knows about `test_chain_1`. We'll need a recent block header and a set of +commit signatures. Fortunately, we can get them with the `block` command: -``` -BLOCK=$(basecoin block $(echo $QUERY | jq .height)) -echo $BLOCK -``` +``` BLOCK=$(basecoin block $(echo $QUERY | jq .height)) echo $BLOCK ``` Here, we are passing `basecoin block` the `height` from our earlier query. -Note the result contains both a hex-encoded and json-encoded version of the header and the commit. -The former is used as input for later commands; the latter is human-readable, so you know what's going on! +Note the result contains both a hex-encoded and json-encoded version of the +header and the commit. The former is used as input for later commands; the +latter is human-readable, so you know what's going on! Let's send this updated information about `test_chain_1` to `test_chain_2`. First, output the header and commit for reference: -``` -echo $BLOCK | jq .hex.header -echo $BLOCK | jq .hex.commit -``` +``` echo $BLOCK | jq .hex.header echo $BLOCK | jq .hex.commit ``` And now forward those values to `test_chain_2`: -``` -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x
--commit 0x -``` +``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x
+--commit 0x ``` -Now that `test_chain_2` knows about some recent state of `test_chain_1`, we can post the packet to `test_chain_2`, -along with proof the packet was committed on `test_chain_1`. Since `test_chain_2` knows about some recent state -of `test_chain_1`, it will be able to verify the proof! +Now that `test_chain_2` knows about some recent state of `test_chain_1`, we can +post the packet to `test_chain_2`, along with proof the packet was committed on +`test_chain_1`. Since `test_chain_2` knows about some recent state of +`test_chain_1`, it will be able to verify the proof! First, output the height, packet, and proof for reference: @@ -303,18 +278,22 @@ echo $QUERY | jq .proof And forward those values to `test_chain_2`: ``` -basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 packet post --ibc_from $CHAIN_ID1 --height --packet 0x --proof 0x +basecoin tx ibc --amount=10mycoin $CHAIN_FLAGS2 packet post --ibc_from $CHAIN_ID1 --height --packet 0x --proof 0x ``` -If the command does not return an error, then we have successfuly transfered data from `test_chain_1` to `test_chain_2`. Tada! +If the command does not return an error, then we have successfuly transfered +data from `test_chain_1` to `test_chain_2`. Tada! ## Conclusion -In this tutorial we explained how IBC works, and demonstrated how to use it to communicate between two chains. -We did the simplest communciation possible: a one way transfer of data from chain1 to chain2. -The most important part was that we updated chain2 with the latest state (i.e. header and commit) of chain1, -and then were able to post a proof to chain2 that a packet was committed to the outgoing state of chain1. +In this tutorial we explained how IBC works, and demonstrated how to use it to +communicate between two chains. We did the simplest communciation possible: a +one way transfer of data from chain1 to chain2. The most important part was +that we updated chain2 with the latest state (i.e. header and commit) of +chain1, and then were able to post a proof to chain2 that a packet was +committed to the outgoing state of chain1. -In a future tutorial, we will demonstrate how to use IBC to actually transfer tokens between two blockchains, -but we'll do it with real testnets deployed across multiple nodes on the network. Stay tuned! +In a future tutorial, we will demonstrate how to use IBC to actually transfer +tokens between two blockchains, but we'll do it with real testnets deployed +across multiple nodes on the network. Stay tuned! diff --git a/docs/guide/install.md b/docs/guide/install.md index 9c5738a77329..59e45bd2ef6e 100644 --- a/docs/guide/install.md +++ b/docs/guide/install.md @@ -3,7 +3,8 @@ On a good day, basecoin can be installed like a normal Go program: ``` -go get -u github.com/tendermint/basecoin/cmd/basecoin +go get github.com/tendermint/basecoin/ +make all ``` In some cases, if that fails, or if another branch is required, @@ -15,7 +16,7 @@ the correct way to install is: cd $GOPATH/src/github.com/tendermint/basecoin git pull origin master make get_vendor_deps -make install +make all ``` This will create the `basecoin` binary in `$GOPATH/bin`. From 06c854f8469a0173e41653b41ec3ac1617b9214b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 19 Jun 2017 14:16:38 +0200 Subject: [PATCH 43/73] "make fresh" when things are getting stale --- CHANGELOG.md | 1 + Makefile | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 701e96a3a73b..e73ba026ffca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ ENHANCEMENTS: - commands return error code (1) on failure for easier script testing - add `reset_all` to basecli, and never delete keys on `init` - new shutil based unit tests, with better coverage of the cli actions +- just `make fresh` when things are getting stale ;) BUG FIXES: - no longer panics on missing app_options in genesis (thanks, anton) diff --git a/Makefile b/Makefile index c7574c286578..9013b038067c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ GOTOOLS = github.com/mitchellh/gox \ github.com/Masterminds/glide -PACKAGES=$(shell go list ./... | grep -v '/vendor/') all: get_vendor_deps install test @@ -18,7 +17,7 @@ dist: test: test_unit test_cli test_unit: - go test $(PACKAGES) + go test `glide novendor` #go run tests/tendermint/*.go test_cli: tests/cli/shunit2 @@ -43,6 +42,14 @@ tools: go get -u -v $(GOTOOLS) clean: - @rm -f ./basecoin + # maybe cleaning up cache and vendor is overkill, but sometimes + # you don't get the most recent versions with lots of branches, changes, rebases... + @rm -rf ~/.glide/cache/src/https-github.com-tendermint-* + @rm -rf ./vendor + @rm -f $GOPATH/bin/{basecoin,basecli,counter,countercli} -.PHONY: all build install test test_cli test_unit get_vendor_deps build-docker clean +# when your repo is getting a little stale... just make fresh +fresh: clean get_vendor_deps install + @if [[ `git status -s` ]]; then echo; echo "Warning: uncommited changes"; git status -s; fi + +.PHONY: all build install test test_cli test_unit get_vendor_deps build-docker clean fresh From 1e76d92d85414b575a0161031e1d73aa49e338a8 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 19 Jun 2017 14:36:45 +0200 Subject: [PATCH 44/73] Supress ugly kill message with disown - bash magick --- tests/cli/common.sh | 1 + tests/cli/ibc.sh | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 5338a29ce6ad..017da897a4ab 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -42,6 +42,7 @@ initServer() { ${SERVER_EXE} start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & sleep 5 PID_SERVER=$! + disown if ! ps $PID_SERVER >/dev/null; then echo "**FAILED**" # cat $SERVER_LOG diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 5d8758fc361b..7ce565c67a05 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -137,6 +137,7 @@ startRelay() { # send some cash to the default key, so it can send messages RELAY_KEY=${BASE_DIR_1}/server/key.json RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") + echo starting relay $PID_RELAY ... # get paid on chain1 export BC_HOME=${CLIENT_1} @@ -163,11 +164,11 @@ startRelay() { ${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + sleep 2 PID_RELAY=$! - echo starting relay $PID_RELAY ... + disown # return an error if it dies in the first two seconds to make sure it is running - sleep 2 ps $PID_RELAY >/dev/null return $? } From 9bb3493f78ae32d10c6945cd27395d0cb5388fee Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 19 Jun 2017 15:13:13 +0200 Subject: [PATCH 45/73] Ran through the docs, more cleanup, everything except ibc ready --- docs/go_basics.md | 8 +++--- docs/guide/basecoin-basics.md | 30 +++++++++++++++++------ docs/guide/basecoin-plugins.md | 45 ++++++++++++++++++++++------------ docs/guide/install.md | 4 +-- 4 files changed, 58 insertions(+), 29 deletions(-) diff --git a/docs/go_basics.md b/docs/go_basics.md index 0ffa7a44ab1a..8dd00ed23c91 100644 --- a/docs/go_basics.md +++ b/docs/go_basics.md @@ -100,12 +100,12 @@ make test Great! Now when I run `tendermint` I have the newest of the new, the develop branch! But please note that this branch is not considered production ready and may have issues. This should only be done if you want to develop code for the future and run locally. -But wait, I want to mix and match. There is a bugfix in `go-p2p:persistent_peer` that I want to use with tendermint. How to compile this. I will show with a simple example, please update the repo and commit numbers for your usecase. Also, make sure these branches are compatible, so if `persistent_peer` is close to `master` it should work. But if it is 15 commits ahead, you will probably need the `develop` branch of tendermint to compile with it. But I assume you know your way around git and can figure that out. +But wait, I want to mix and match. There is a bugfix in `go-crypto:unstable` that I want to use with tendermint. How to compile this. I will show with a simple example, please update the repo and commit numbers for your usecase. Also, make sure these branches are compatible, so if `unstable` is close to `master` it should work. But if it is 15 commits ahead, you will probably need the `develop` branch of tendermint to compile with it. But I assume you know your way around git and can figure that out. In the dependent repo: ``` -cd $GOPATH/src/github.com/tendermint/go-p2p -git checkout persistent_peer +cd $GOPATH/src/github.com/tendermint/go-crypto +git checkout unstable git pull # double-check this makes sense or if it is too far off git log --oneline --decorate --graph @@ -118,7 +118,7 @@ In the main repo (tendermint, basecoin, ...) where the binary will be built: cd $GOPATH/src/github.com/tendermint/tendermint git checkout master git pull -# -> edit glide.lock, set the version of go-p2p (for example) +# -> edit glide.lock, set the version of go-crypto (for example) # to the commit number you got above (the 40 char version) make get_vendor_deps make install diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index dceecd84c587..9692f3109957 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -1,6 +1,6 @@ # Basecoin Basics -Here we explain how to get started with a simple Basecoin blockchain, +Here we explain how to get started with a simple Basecoin blockchain, how to send transactions between accounts using the `basecoin` tool, and what is happening under the hood. @@ -9,7 +9,7 @@ and what is happening under the hood. Installing Basecoin is simple: ``` -go get -u github.com/tendermint/basecoin/cmd/basecoin +go get -u github.com/tendermint/basecoin/cmd/... ``` If you have trouble, see the [installation guide](install.md). @@ -19,7 +19,10 @@ If you have trouble, see the [installation guide](install.md). To initialize a new Basecoin blockchain, run: ``` -basecoin init +# WARNING: this will wipe out any existing info in the ~/.basecoin dir +# don't run if you have lots of local state already +rm -rf ~/.basecoin +basecoin init ``` This will create the necessary files for a Basecoin blockchain with one @@ -30,6 +33,9 @@ For this example, we will change the genesis account to a new account named `cool`. First create a new account: ``` +# WARNING: this will wipe out any existing info in the ~/.basecli dir +# including private keys, don't run if you have lots of local state already +basecli reset_all basecli keys new cool ``` @@ -46,17 +52,18 @@ basecli keys get cool -o=json vi ~/.basecoin/genesis.json -> cut/paste your pubkey from the results above ``` -or alternatively, without manual copy pasting: +or alternatively, without manual copy pasting: ``` GENKEY=`basecli keys get cool -o json | jq .pubkey.data` GENJSON=`cat ~/.basecoin/genesis.json` -echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.basecoin/genesis.json +echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.basecoin/genesis.json ``` Hurray! you are very rich and cool on this blockchain now. ## Start + Now we can start Basecoin: ``` @@ -106,7 +113,7 @@ basecli query account $YOU We can send some of these coins back like so: ``` -basecli tx send --name=friend --amount=500mycoin --to=0x$ME --sequence=1 +basecli tx send --name=friend --amount=500mycoin --to=$ME --sequence=1 ``` Note how we use the `--name` flag to select a different account to send from. @@ -114,7 +121,16 @@ Note how we use the `--name` flag to select a different account to send from. If we try to send too much, we'll get an error: ``` -basecli tx send --name=friend --amount=500000mycoin --to=0x$ME --sequence=1 +basecli tx send --name=friend --amount=500000mycoin --to=$ME --sequence=1 +``` + +And if you want to see the original tx, as well as verifying that it +really is in the blockchain, look at the send response: + +``` +basecli tx send --name=cool --amount=2345mycoin --to=$YOU --sequence=2 +# TXHASH from the json output +basecli query tx $TXHASH ``` See `basecli tx send --help` for additional details. diff --git a/docs/guide/basecoin-plugins.md b/docs/guide/basecoin-plugins.md index 27d65bb851de..5c2114d0cc9b 100644 --- a/docs/guide/basecoin-plugins.md +++ b/docs/guide/basecoin-plugins.md @@ -14,24 +14,28 @@ functionality. The Counter plugin is bundled with basecoin, so if you have already [installed basecoin](install.md) then you should be able to run a full node with `counter` and the a light-client `countercli` from terminal. The Counter plugin is just like the `basecoin` tool. They both use the same -library of commands, including one for signing and broadcasting `SendTx`. +library of commands, including one for signing and broadcasting `SendTx`. Counter transactions take two custom inputs, a boolean argument named `valid`, and a coin amount named `countfee`. The transaction is only accepted if both `valid` is set to true and the transaction input coins is greater than -`countfee` that the user provides. +`countfee` that the user provides. A new blockchain can be initialized and started just like with in the [previous guide](basecoin-basics.md): ``` +# WARNING: this wipes out data - but counter is only for demos... +rm -rf ~/.counter +countercli reset_all + counter init countercli keys new cool countercli keys new friend GENKEY=`countercli keys get cool -o json | jq .pubkey.data` GENJSON=`cat ~/.counter/genesis.json` -echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.counter/genesis.json +echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.counter/genesis.json counter start @@ -58,7 +62,7 @@ countercli tx counter --name cool --amount=1mycoin --sequence=3 --valid The first transaction is rejected by the plugin because it was not marked as valid, while the second transaction passes. We can build plugins that take many arguments of different types, and easily extend the tool to accomodate -them. Of course, we can also expose queries on our plugin: +them. Of course, we can also expose queries on our plugin: ``` countercli query counter @@ -70,15 +74,25 @@ If we send another transaction, and then query again, we will see the value increment: ``` -countercli tx counter --name cool --amount=1mycoin --sequence=4 --valid +countercli tx counter --name cool --amount=2mycoin --sequence=4 --valid --countfee=2mycoin countercli query counter ``` The value Counter value should be 2, because we sent a second valid transaction. -Notice how the result of the query comes with a proof. This is a Merkle proof -that the state is what we say it is. In a latter [guide on InterBlockchain -Communication](ibc.md), we'll put this proof to work! +And this time, since we sent a countfee (which must be less than or equal to the +total amount sent with the tx), it stores the `TotalFees` on the counter as well. + +Even if you don't see it in the UI, the result of the query comes with a proof. +This is a Merkle proof that the state is what we say it is, and ties that query +to a particular header. Behind the scenes, `countercli` will not only verify that +this state matches the header, but also that the header is properly signed by +the known validator set. It will even update the validator set as needed, so long +as there have not been major changes and it is secure to do so. So, if you wonder +why the query may take a second... there is a lot of work going on in the +background to make sure even a lying full node can't trick your client. +In a latter [guide on InterBlockchainCommunication](ibc.md), we'll use these +proofs to post transactions to other chains. Now, before we implement our own plugin and tooling, it helps to understand the `AppTx` and the design of the plugin system. @@ -91,8 +105,8 @@ some data. ```golang type AppTx struct { - Gas int64 `json:"gas"` - Fee Coin `json:"fee"` + Gas int64 `json:"gas"` + Fee Coin `json:"fee"` Input TxInput `json:"input"` Name string `json:"type"` // Name of the plugin Data []byte `json:"data"` // Data for the plugin to process @@ -161,18 +175,19 @@ more details. First is the `cmd/counter/main.go`, which drives the program. It can be left alone, but you should change any occurrences of `counter` to whatever your -plugin tool is going to be called. +plugin tool is going to be called. You must also register your plugin(s) with +the basecoin app with `RegisterStartPlugin`. The light-client which is located in `cmd/countercli/main.go` allows for is where transaction and query commands are designated. Similarity this command can be mostly left alone besides replacing the application name and adding -references to new plugin commands +references to new plugin commands Next is the custom commands in `cmd/countercli/commands/`. These files is where we extend the tool with any new commands and flags we need to send -transactions or queries to our plugin. Note the `init()` function, where we -register a new transaction subcommand with `RegisterTxSubcommand`, and where we -load the plugin into the Basecoin app with `RegisterStartPlugin`. +transactions or queries to our plugin. You define custom `tx` and `query` +subcommands, which are registered in `main.go` (avoiding `init()` +auto-registration, for less magic and more control in the main executable). Finally is `plugins/counter/counter.go`, where we provide an implementation of the `Plugin` interface. The most important part of the implementation is the diff --git a/docs/guide/install.md b/docs/guide/install.md index 59e45bd2ef6e..cbf3fc7b8af3 100644 --- a/docs/guide/install.md +++ b/docs/guide/install.md @@ -3,8 +3,7 @@ On a good day, basecoin can be installed like a normal Go program: ``` -go get github.com/tendermint/basecoin/ -make all +go get -u github.com/tendermint/basecoin/cmd/... ``` In some cases, if that fails, or if another branch is required, @@ -15,7 +14,6 @@ the correct way to install is: ``` cd $GOPATH/src/github.com/tendermint/basecoin git pull origin master -make get_vendor_deps make all ``` From 0b7b639c58d96dad783fa8747e14fb5777914d3a Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 19 Jun 2017 16:34:41 +0200 Subject: [PATCH 46/73] Rewrote ibc guide for basecli and relay --- CHANGELOG.md | 3 + docs/guide/ibc.md | 237 ++++++++++++++++++++++++++++++++-------------- tests/cli/ibc.sh | 4 +- 3 files changed, 172 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e73ba026ffca..9fb67e697cdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ BREAKING CHANGES: - enhanced relay subcommand - relay start did what relay used to do - relay init registers both chains on one another (to set it up so relay start just works) +- docs + - removed `example-plugin`, put `counter` inside `docs/guide` ENHANCEMENTS: - intergrates tendermint 0.10.0 (not the rc-2, but the real thing) @@ -33,6 +35,7 @@ ENHANCEMENTS: BUG FIXES: - no longer panics on missing app_options in genesis (thanks, anton) +- updated all docs... again ## 0.5.2 (June 2, 2017) diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 9c30a6d391c9..70eb713d391f 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -158,6 +158,22 @@ the key and value are contained in the Merkle tree. The results of a query can thus be used as proof in an `IBCPacketPostTx`. +## Relay + +While we need all these packet types internally to keep track of all the +proofs on both chains in a secure manner, for the normal work-flow, where +we just use the FIFO queue on each side for pending message to send as soon +as possible. + +In this case, there are only two steps. First `basecoin relay init`, +which must be run once to register each chain with the other one, +and make sure they are ready to send and recieve. And then +`basecoin relay start`, which is a long-running process polling the queue +on each side, and relaying all new message to the other block. + +This requires that the relay has access to accounts with some funds on both +chains to pay for all the ibc packets it will be forwarding. + ## Try it out Now that we have all the background knowledge, let's actually walk through the @@ -173,116 +189,197 @@ comes with an `IBC` plugin enabled by default. You will also want to install the [jq](https://stedolan.github.io/jq/) for handling JSON at the command line. -Now let's start the two blockchains. In this tutorial, each chain will have -only a single validator, where the initial configuration files are already -generated. Let's change directory so these files are easily accessible: +If you have any trouble with this, you can also look at the +[test scripts](/tests/cli/ibc.sh) or just run `make test_cli` in basecoin repo. +Otherwise, open up 5 (yes 5!) terminal tabs.... -``` cd $GOPATH/src/github.com/tendermint/basecoin/demo ``` +### Setup Chain 1 -The relevant data is now in the `data` directory. Before we begin, let's set -some environment variables for convenience: +All commands will be prefixed by the name of the terminal window in which to +run it... -``` export BCHOME="." BCHOME1="./data/chain1" BCHOME2="./data/chain2" +``` +# first, clean up any old garbage for a fresh slate... +rm -rf ~/.ibcdemo/ +``` -export CHAIN_ID1=test_chain_1 export CHAIN_ID2=test_chain_2 +Set up some accounts so we can init everything nicely: -CHAIN_FLAGS1="--chain_id $CHAIN_ID1 --from $BCHOME1/key.json" -CHAIN_FLAGS2="--chain_id $CHAIN_ID2 --from $BCHOME2/key.json --node -tcp://localhost:36657" ``` +**Client1** +``` +export BCHOME=~/.ibcdemo/chain1/client +CHAIN_ID=test-chain-1 +PORT=12347 +basecli keys new money +basecli keys new gotnone +``` + +Prepare the genesis block and start the server: + +**Server1** +``` +# set up the directory, chainid and port of this chain... +export BCHOME=~/.ibcdemo/chain1/server +CHAIN_ID=test-chain-1 +PREFIX=1234 +basecoin init + +GENKEY=`basecli keys get money -o json --home=$HOME/.ibcdemo/chain1/client | jq .pubkey.data` +GENJSON=`cat $BCHOME/genesis.json` +echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY | jq ".chain_id=\"$CHAIN_ID\"" > $BCHOME/genesis.json + +sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml + +basecoin start +``` -In previous examples, we started basecoin in-process with tendermint. Here, we -will run them in different processes, using the `--without-tendermint` flag, as -described in the [guide to the basecoin tool](basecoin-tool.md). We can start -the two chains as follows: +Attach the client to the chain and confirm state. The first account should +have money, the second none: -``` TMROOT=$BCHOME1 tendermint node --log_level=info &> chain1_tendermint.log & -BCHOME=$BCHOME1 basecoin start --without-tendermint &> chain1_basecoin.log & +**Client1** ``` +basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} +ME=`basecli keys get money -o=json | jq .address | tr -d '"'` +YOU=`basecli keys get gotnone -o=json | jq .address | tr -d '"'` +basecli query account $ME +basecli query account $YOU +``` + +### Setup Chain 2 -and +This is the same as above, except in two new terminal windows with +different chain ids, ports, etc. Note that you need to make new accounts +on this chain, as the "cool" key only has money on chain 1. -``` TMROOT=$BCHOME2 tendermint node --log_level=info --node_laddr -tcp://localhost:36656 --rpc_laddr tcp://localhost:36657 --proxy_app -tcp://localhost:36658 &> chain2_tendermint.log & BCHOME=$BCHOME2 basecoin start ---address tcp://localhost:36658 --without-tendermint &> chain2_basecoin.log & + +**Client2** +``` +export BCHOME=~/.ibcdemo/chain2/client +CHAIN_ID=test-chain-2 +PORT=23457 +basecli keys new moremoney +basecli keys new broke ``` -Note how we refer to the relevant data directories, and how we set the various -addresses for the second node so as not to conflict with the first. +Prepare the genesis block and start the server: -We can now check on the status of the two chains: +**Server2** +``` +# set up the directory, chainid and port of this chain... +export BCHOME=~/.ibcdemo/chain2/server +CHAIN_ID=test-chain-2 +PREFIX=2345 +basecoin init -``` curl localhost:46657/status curl localhost:36657/status ``` -If either command fails, the nodes may not have finished starting up. Wait a -couple seconds and try again. Once you see the status of both chains, it's -time to move on. +GENKEY=`basecli keys get moremoney -o json --home=$HOME/.ibcdemo/chain2/client | jq .pubkey.data` +GENJSON=`cat $BCHOME/genesis.json` +echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY | jq ".chain_id=\"$CHAIN_ID\"" > $BCHOME/genesis.json -In this tutorial, we're going to send some data from `test_chain_1` to -`test_chain_2`. We begin by registering `test_chain_1` on `test_chain_2`: +sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml -``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --ibc_chain_id -$CHAIN_ID1 --genesis $BCHOME1/genesis.json ``` +basecoin start +``` -Now we can create the outgoing packet on `test_chain_1`: +Attach the client to the chain and confirm state. The first account should +have money, the second none: -``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --ibc_from -$CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload 0xDEADBEEF --ibc_sequence 1 +**Client2** +``` +basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} +ME=`basecli keys get moremoney -o=json | jq .address | tr -d '"'` +YOU=`basecli keys get broke -o=json | jq .address | tr -d '"'` +basecli query account $ME +basecli query account $YOU ``` -Note our payload is just `DEADBEEF`. Now that the packet is committed in the -chain, let's get some proof by querying: +### Connect these chains -``` QUERY=$(basecoin query ibc,egress,$CHAIN_ID1,$CHAIN_ID2,1) echo $QUERY ``` +Great, so we have two chains running on your local machine, with different +keys on each. Now it is time to hook them up together. Let's start +a relay to forward the messages. -The result contains the latest height, a value (i.e. the hex-encoded binary -serialization of our packet), and a proof (i.e. hex-encoded binary -serialization of a list of nodes from the Merkle tree) that the value is in the -Merkle tree. We keep the result in the `QUERY` variable so we can easily -reference subfields using the `jq` tool. +The relay account needs some money in it to pay for the ibc messages, so +for now, we have to transfer some cash from the rich accounts before we start +the actual relay. -If we want to send this data to `test_chain_2`, we first have to update what it -knows about `test_chain_1`. We'll need a recent block header and a set of -commit signatures. Fortunately, we can get them with the `block` command: +**Client1** +``` +# note that this key.json file is a hardcoded demo for all chains, this will +# be updated in a future release +RELAY_KEY=${BCHOME}/../server/key.json +RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") +basecli tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=money +basecli query account $RELAY_ADDR +``` -``` BLOCK=$(basecoin block $(echo $QUERY | jq .height)) echo $BLOCK ``` +**Client2** +``` +# note that this key.json file is a hardcoded demo for all chains, this will +# be updated in a future release +RELAY_KEY=${BCHOME}/../server/key.json +RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") +basecli tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney +basecli query account $RELAY_ADDR +``` -Here, we are passing `basecoin block` the `height` from our earlier query. -Note the result contains both a hex-encoded and json-encoded version of the -header and the commit. The former is used as input for later commands; the -latter is human-readable, so you know what's going on! +**Relay** +``` +# lots of config... +SERVER_1=~/.ibcdemo/chain1/server +SERVER_2=~/.ibcdemo/chain2/server +CHAIN_ID_1=test-chain-1 +CHAIN_ID_2=test-chain-2 +PORT_1=12347 +PORT_2=23457 +RELAY_KEY=${SERVER_1}/key.json + +basecoin relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ + --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ + --genesis1=${SERVER_1}/genesis.json --genesis2=${SERVER_2}/genesis.json \ + --from=$RELAY_KEY + +basecoin relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ + --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ + --from=$RELAY_KEY +``` -Let's send this updated information about `test_chain_1` to `test_chain_2`. -First, output the header and commit for reference: +This should start up the relay, and assuming no error messages came out, +the two chains are now fully connected over IBC. Let's use this to send +our first tx accross the chains... -``` echo $BLOCK | jq .hex.header echo $BLOCK | jq .hex.commit ``` +### Sending cross-chain payments -And now forward those values to `test_chain_2`: +The hard part is over, we set up two blockchains, a few private keys, and +a secure relay between them. Now we can enjoy the fruits of our labor... -``` basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 update --header 0x
---commit 0x ``` +**Client2** -Now that `test_chain_2` knows about some recent state of `test_chain_1`, we can -post the packet to `test_chain_2`, along with proof the packet was committed on -`test_chain_1`. Since `test_chain_2` knows about some recent state of -`test_chain_1`, it will be able to verify the proof! +``` +# this should be empty +basecli query account $YOU +# now, we get the key to copy to the other terminal +echo $YOU +``` -First, output the height, packet, and proof for reference: +**Client1** ``` -echo $QUERY | jq .height -echo $QUERY | jq .value -echo $QUERY | jq .proof +# set TARGET to be $YOU from the other chain +basecli tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$TARGET --name=money ``` -And forward those values to `test_chain_2`: +**Client2** ``` -basecoin tx ibc --amount=10mycoin $CHAIN_FLAGS2 packet post --ibc_from $CHAIN_ID1 --height --packet 0x --proof 0x +# give it time to arrive... +sleep 1 +# now you should see 12345 coins! +basecli query account $YOU ``` -If the command does not return an error, then we have successfuly transfered -data from `test_chain_1` to `test_chain_2`. Tada! +Cool, huh? Now have fun exploring and sending coins across the chains. And +making more accounts as you want to. ## Conclusion diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 7ce565c67a05..2cdaa5843add 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -157,13 +157,13 @@ startRelay() { ${SERVER_EXE} relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ --genesis1=${BASE_DIR_1}/server/genesis.json --genesis2=${BASE_DIR_2}/server/genesis.json \ - --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log if [ $? != 0 ]; then echo "can't initialize relays"; cat ${BASE_DIR_1}/../relay.log; return 1; fi # now start the relay (constantly send packets) ${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ - --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log & + --from=$RELAY_KEY >> ${BASE_DIR_1}/../relay.log & sleep 2 PID_RELAY=$! disown From f204144ee37a3e275c207e07594b5cc32c1fe10e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 19 Jun 2017 16:57:44 +0200 Subject: [PATCH 47/73] Fix up ``` ticks --- docs/guide/ibc.md | 66 ++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 70eb713d391f..aaf4e01b7ff4 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -66,9 +66,11 @@ up in turn. The `IBCRegisterChainTx` is used to register one chain on another. It contains the chain ID and genesis configuration of the chain to register: -```golang type IBCRegisterChainTx struct { BlockchainGenesis } +```golang +type IBCRegisterChainTx struct { BlockchainGenesis } -type BlockchainGenesis struct { ChainID string Genesis string } ``` +type BlockchainGenesis struct { ChainID string Genesis string } +``` This transaction should only be sent once for a given chain ID, and successive sends will return an error. @@ -79,7 +81,11 @@ sends will return an error. The `IBCUpdateChainTx` is used to update the state of one chain on another. It contains the header and commit signatures for some block in the chain: -```golang type IBCUpdateChainTx struct { Header tm.Header Commit tm.Commit } +```golang +type IBCUpdateChainTx struct { + Header tm.Header + Commit tm.Commit +} ``` In the future, it needs to be updated to include changes to the validator set @@ -93,10 +99,19 @@ packet itself contains the source and destination chain IDs, a sequence number (i.e. an integer that increments with every message sent between this pair of chains), a packet type (e.g. coin, data, etc.), and a payload. -```golang type IBCPacketCreateTx struct { Packet } - -type Packet struct { SrcChainID string DstChainID string Sequence uint64 Type -string Payload []byte } ``` +```golang +type IBCPacketCreateTx struct { + Packet +} + +type Packet struct { + SrcChainID string + DstChainID string + Sequence uint64 + Type string + Payload []byte +} +``` We have yet to define the format for the payload, so, for now, it's just arbitrary bytes. @@ -114,10 +129,13 @@ The `IBCPacketPostTx` is used to post an outgoing packet from one chain to another. It contains the packet and a proof that the packet was committed into the state of the sending chain: -```golang type IBCPacketPostTx struct { FromChainID string // The immediate -source of the packet, not always Packet.SrcChainID FromChainHeight uint64 // -The block height in which Packet was committed, to check Proof Packet Proof -*merkle.IAVLProof } ``` +```golang +type IBCPacketPostTx struct { + FromChainID string // The immediate source of the packet, not always Packet.SrcChainID + FromChainHeight uint64 // The block height in which Packet was committed, to check Proof Packet + Proof *merkle.IAVLProof +} +``` The proof is a Merkle proof in an IAVL tree, our implementation of a balanced, Merklized binary search tree. It contains a list of nodes in the tree, which @@ -198,7 +216,7 @@ Otherwise, open up 5 (yes 5!) terminal tabs.... All commands will be prefixed by the name of the terminal window in which to run it... -``` +```bash # first, clean up any old garbage for a fresh slate... rm -rf ~/.ibcdemo/ ``` @@ -206,7 +224,7 @@ rm -rf ~/.ibcdemo/ Set up some accounts so we can init everything nicely: **Client1** -``` +```bash export BCHOME=~/.ibcdemo/chain1/client CHAIN_ID=test-chain-1 PORT=12347 @@ -217,7 +235,7 @@ basecli keys new gotnone Prepare the genesis block and start the server: **Server1** -``` +```bash # set up the directory, chainid and port of this chain... export BCHOME=~/.ibcdemo/chain1/server CHAIN_ID=test-chain-1 @@ -237,7 +255,7 @@ Attach the client to the chain and confirm state. The first account should have money, the second none: **Client1** -``` +```bash basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} ME=`basecli keys get money -o=json | jq .address | tr -d '"'` YOU=`basecli keys get gotnone -o=json | jq .address | tr -d '"'` @@ -253,7 +271,7 @@ on this chain, as the "cool" key only has money on chain 1. **Client2** -``` +```bash export BCHOME=~/.ibcdemo/chain2/client CHAIN_ID=test-chain-2 PORT=23457 @@ -264,7 +282,7 @@ basecli keys new broke Prepare the genesis block and start the server: **Server2** -``` +```bash # set up the directory, chainid and port of this chain... export BCHOME=~/.ibcdemo/chain2/server CHAIN_ID=test-chain-2 @@ -285,7 +303,7 @@ Attach the client to the chain and confirm state. The first account should have money, the second none: **Client2** -``` +```bash basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} ME=`basecli keys get moremoney -o=json | jq .address | tr -d '"'` YOU=`basecli keys get broke -o=json | jq .address | tr -d '"'` @@ -304,7 +322,7 @@ for now, we have to transfer some cash from the rich accounts before we start the actual relay. **Client1** -``` +```bash # note that this key.json file is a hardcoded demo for all chains, this will # be updated in a future release RELAY_KEY=${BCHOME}/../server/key.json @@ -314,7 +332,7 @@ basecli query account $RELAY_ADDR ``` **Client2** -``` +```bash # note that this key.json file is a hardcoded demo for all chains, this will # be updated in a future release RELAY_KEY=${BCHOME}/../server/key.json @@ -324,7 +342,7 @@ basecli query account $RELAY_ADDR ``` **Relay** -``` +```bash # lots of config... SERVER_1=~/.ibcdemo/chain1/server SERVER_2=~/.ibcdemo/chain2/server @@ -355,7 +373,7 @@ a secure relay between them. Now we can enjoy the fruits of our labor... **Client2** -``` +```bash # this should be empty basecli query account $YOU # now, we get the key to copy to the other terminal @@ -364,14 +382,14 @@ echo $YOU **Client1** -``` +```bash # set TARGET to be $YOU from the other chain basecli tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$TARGET --name=money ``` **Client2** -``` +```bash # give it time to arrive... sleep 1 # now you should see 12345 coins! From a3bc96c56b2514f9badce38e8e13558da8fae5c9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 20 Jun 2017 21:35:22 -0400 Subject: [PATCH 48/73] basecoin init takes an account address --- cmd/commands/init.go | 61 ++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/cmd/commands/init.go b/cmd/commands/init.go index 2cfbbcd94ab6..616125222fe8 100644 --- a/cmd/commands/init.go +++ b/cmd/commands/init.go @@ -1,9 +1,9 @@ package commands import ( + "fmt" "io/ioutil" "os" - "path" "github.com/spf13/cobra" ) @@ -37,13 +37,16 @@ func initCmd(cmd *cobra.Command, args []string) error { return err } + if len(args) != 1 { + return fmt.Errorf("`init` takes one argument, a basecoin account address. Generate one using `basecli keys new mykey`") + } + userAddr := args[0] + // initalize basecoin genesisFile := cfg.GenesisFile() privValFile := cfg.PrivValidatorFile() - key1File := path.Join(cfg.RootDir, "key.json") - key2File := path.Join(cfg.RootDir, "key2.json") - mod1, err := setupFile(genesisFile, GenesisJSON, 0644) + mod1, err := setupFile(genesisFile, GetGenesisJSON(userAddr), 0644) if err != nil { return err } @@ -51,17 +54,9 @@ func initCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } - mod3, err := setupFile(key1File, Key1JSON, 0400) - if err != nil { - return err - } - mod4, err := setupFile(key2File, Key2JSON, 0400) - if err != nil { - return err - } - if (mod1 + mod2 + mod3 + mod4) > 0 { - logger.Info("Initialized Basecoin", "genesis", genesisFile, "key", key1File) + if (mod1 + mod2) > 0 { + logger.Info("Initialized Basecoin", "genesis", genesisFile, "priv_validator", privValFile) } else { logger.Info("Already initialized", "priv_validator", privValFile) } @@ -86,7 +81,11 @@ var PrivValJSON = `{ } }` -var GenesisJSON = `{ +// GetGenesisJSON returns a new tendermint genesis with Basecoin app_options +// that grant a large amount of "mycoin" to a single address +// TODO: A better UX for generating genesis files +func GetGenesisJSON(addr string) string { + return fmt.Sprintf(`{ "app_hash": "", "chain_id": "test_chain_id", "genesis_time": "0001-01-01T00:00:00.000Z", @@ -102,10 +101,7 @@ var GenesisJSON = `{ ], "app_options": { "accounts": [{ - "pub_key": { - "type": "ed25519", - "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" - }, + "address": "%s", "coins": [ { "denom": "mycoin", @@ -114,28 +110,5 @@ var GenesisJSON = `{ ] }] } -}` - -var Key1JSON = `{ - "address": "1B1BE55F969F54064628A63B9559E7C21C925165", - "priv_key": { - "type": "ed25519", - "data": "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D1619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" - }, - "pub_key": { - "type": "ed25519", - "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" - } -}` - -var Key2JSON = `{ - "address": "1DA7C74F9C219229FD54CC9F7386D5A3839F0090", - "priv_key": { - "type": "ed25519", - "data": "34BAE9E65CE8245FAD035A0E3EED9401BDE8785FFB3199ACCF8F5B5DDF7486A8352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" - }, - "pub_key": { - "type": "ed25519", - "data": "352195DA90CB0B90C24295B90AEBA25A5A71BC61BAB2FE2387241D439698B7B8" - } -}` +}`, addr) +} From 7b595b3f87e28fa4538a0a4bae1c77d4026de2ad Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 20 Jun 2017 21:35:46 -0400 Subject: [PATCH 49/73] user ErrNoData from light-client --- cmd/basecli/commands/query.go | 7 ++++++- glide.lock | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go index 5b616dc75fd3..34af3b8d6041 100644 --- a/cmd/basecli/commands/query.go +++ b/cmd/basecli/commands/query.go @@ -1,9 +1,12 @@ package commands import ( + "fmt" + "github.com/spf13/cobra" wire "github.com/tendermint/go-wire" + lc "github.com/tendermint/light-client" proofcmd "github.com/tendermint/light-client/commands/proofs" "github.com/tendermint/light-client/proofs" @@ -25,7 +28,9 @@ func doAccountQuery(cmd *cobra.Command, args []string) error { acc := new(btypes.Account) proof, err := proofcmd.GetAndParseAppProof(key, &acc) - if err != nil { + if lc.IsNoDataErr(err) { + return fmt.Errorf("Account bytes are empty for address %X ", addr) + } else if err != nil { return err } diff --git a/glide.lock b/glide.lock index 38df58154dd1..8b96e92922f5 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 6eb1119dccf2ab4d0adb870a14cb4408047119be53c8ec4afeaa281bd1d2b457 -updated: 2017-06-15T17:51:21.867322849+02:00 +updated: 2017-06-20T20:55:16.122030554-04:00 imports: - name: github.com/bgentry/speakeasy version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd @@ -127,7 +127,7 @@ imports: - data - data/base58 - name: github.com/tendermint/light-client - version: 4ad913f2728307ec13a3b602b040c29b6a2117b8 + version: 5ba3d0bce406b4b4ce694ca4387b9d086ac0c10f subpackages: - certifiers - certifiers/client @@ -171,7 +171,7 @@ imports: - types - version - name: github.com/tendermint/tmlibs - version: 59a77e7bef092eef0e1f9b44c983dc9e35eed0d6 + version: bd9d0d1637dadf1330e167189d5e5031aadcda6f subpackages: - autofile - cli From 9b0f4fc65031d688b8ddba480e62320393cfac61 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 20 Jun 2017 21:36:04 -0400 Subject: [PATCH 50/73] docs: update basics and plugins --- docs/guide/basecoin-basics.md | 116 +++++++++++++++++++-------------- docs/guide/basecoin-plugins.md | 59 +++++++---------- 2 files changed, 93 insertions(+), 82 deletions(-) diff --git a/docs/guide/basecoin-basics.md b/docs/guide/basecoin-basics.md index 9692f3109957..716fddb9708c 100644 --- a/docs/guide/basecoin-basics.md +++ b/docs/guide/basecoin-basics.md @@ -14,56 +14,51 @@ go get -u github.com/tendermint/basecoin/cmd/... If you have trouble, see the [installation guide](install.md). -## Initialize Basecoin - -To initialize a new Basecoin blockchain, run: +Note the above command installs two binaries: `basecoin` and `basecli`. +The former is the running node. The latter is a command-line light-client. -``` -# WARNING: this will wipe out any existing info in the ~/.basecoin dir -# don't run if you have lots of local state already -rm -rf ~/.basecoin -basecoin init -``` +## Generate some keys -This will create the necessary files for a Basecoin blockchain with one -validator and one account in `~/.basecoin`. For more options on setup, see the -[guide to using the Basecoin tool](/docs/guide/basecoin-tool.md). - -For this example, we will change the genesis account to a new account named -`cool`. First create a new account: +Let's generate two keys, one to receive an initial allocation of coins, +and one to send some coins to later: ``` # WARNING: this will wipe out any existing info in the ~/.basecli dir # including private keys, don't run if you have lots of local state already basecli reset_all basecli keys new cool +basecli keys new friend ``` -While we're at it let's setup a second account which we will use later in the tutorial +You'll need to enter passwords. You can view your key names and addresses with `basecli keys list`, +or see a particular key's address with `basecli keys get `. + +## Initialize Basecoin -``` -basecli keys new friend -``` -Next we need to copy in the public address from our new key into the genesis block: +To initialize a new Basecoin blockchain, run: ``` -basecli keys get cool -o=json -vi ~/.basecoin/genesis.json --> cut/paste your pubkey from the results above +# WARNING: this will wipe out any existing info in the ~/.basecoin dir +# don't run if you have lots of local state already +rm -rf ~/.basecoin +basecoin init
``` -or alternatively, without manual copy pasting: + +If you prefer not to copy-paste, you can provide the address programatically: + ``` -GENKEY=`basecli keys get cool -o json | jq .pubkey.data` -GENJSON=`cat ~/.basecoin/genesis.json` -echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.basecoin/genesis.json +basecoin init $(basecli keys get cool | awk '{print $2}') ``` -Hurray! you are very rich and cool on this blockchain now. +This will create the necessary files for a Basecoin blockchain with one +validator and one account (corresponding to your key) in `~/.basecoin`. For more options on setup, see the +[guide to using the Basecoin tool](/docs/guide/basecoin-tool.md). + +If you like, you can manually add some more accounts to the blockchain by generating keys and editing the `~/.basecoin/genesis.json`. ## Start - Now we can start Basecoin: ``` @@ -74,22 +69,26 @@ You should see blocks start streaming in! ## Initialize Light-Client -Now that Basecoin is running we can initialize the light-client utility named -`basecli`. Basecli is used for sending transactions and querying the state. +Now that Basecoin is running we can initialize `basecli`, the light-client utility. +Basecli is used for sending transactions and querying the state. Leave Basecoin running and open a new terminal window. Here run: ``` basecli init --chain-id=test_chain_id --node=tcp://localhost:46657 ``` +Note it will ask you to verify the validator hash. For a blockchain on your local computer, don't worry about it. +If you're connecting to a blockchain over the internet, you should verify that the validator hash is correct. +This is so that all queries done with `basecli` can be cryptographically proven to be correct according to a known validator set. + ## Send transactions Now we are ready to send some transactions. First Let's check the balance of -the two accounts we setup earlier these two accounts: +the two accounts we setup earlier: ``` -ME=`basecli keys get cool -o=json | jq .address | tr -d '"'` -YOU=`basecli keys get friend -o=json | jq .address | tr -d '"'` +ME=$(basecli keys get cool | awk '{print $2}') +YOU=$(basecli keys get friend | awk '{print $2}') basecli query account $ME basecli query account $YOU ``` @@ -101,9 +100,6 @@ Let's send funds from the first account to the second: basecli tx send --name=cool --amount=1000mycoin --to=0x$YOU --sequence=1 ``` -By default, the CLI looks for a `key.json` to sign the transaction with. -To specify a different key, we can use the `--from` flag. - Now if we check the second account, it should have `1000` 'mycoin' coins! ``` @@ -124,21 +120,42 @@ If we try to send too much, we'll get an error: basecli tx send --name=friend --amount=500000mycoin --to=$ME --sequence=1 ``` -And if you want to see the original tx, as well as verifying that it -really is in the blockchain, look at the send response: +Let's send another transaction: ``` basecli tx send --name=cool --amount=2345mycoin --to=$YOU --sequence=2 -# TXHASH from the json output -basecli query tx $TXHASH +``` + +Note the `hash` value in the response - this is the hash of the transaction. +We can query for the transaction by this hash: + +``` +basecli query tx ``` See `basecli tx send --help` for additional details. -For a better understanding of the options, it helps to understand the +## Proof + +Even if you don't see it in the UI, the result of every query comes with a proof. +This is a Merkle proof that the result of the query is actually contained in the state. +and the state's Merkle root is contained in a recent block header. +Behind the scenes, `countercli` will not only verify that this state matches the header, +but also that the header is properly signed by the known validator set. +It will even update the validator set as needed, so long +as there have not been major changes and it is secure to do so. So, if you wonder +why the query may take a second... there is a lot of work going on in the +background to make sure even a lying full node can't trick your client. + +In a latter [guide on InterBlockchainCommunication](ibc.md), we'll use these +proofs to post transactions to other chains. + +## Accounts and Transactions + +For a better understanding of how to further use the tools, it helps to understand the underlying data structures. -## Accounts +### Accounts The Basecoin state consists entirely of a set of accounts. Each account contains a public key, a balance in many different coin denominations, and a @@ -162,6 +179,9 @@ type Coin struct { } ``` +If you want to add more coins to a blockchain, you can do so manually in the `~/.basecoin/genesis.json` before +you start the blockchain for the first time. + Accounts are serialized and stored in a Merkle tree under the key `base/a/
`, where `
` is the address of the account. Typically, the address of the account is the 20-byte `RIPEMD160` hash of the @@ -170,7 +190,7 @@ public key, but other formats are acceptable as well, as defined in the Merkle tree used in Basecoin is a balanced, binary search tree, which we call an [IAVL tree](https://github.com/tendermint/go-merkle). -## Transactions +### Transactions Basecoin defines a simple transaction type, the `SendTx`, which allows tokens to be sent to other accounts. The `SendTx` takes a list of inputs and a list @@ -229,9 +249,9 @@ transaction. ## Conclusion -In this guide, we introduced the `basecoin` tool, demonstrated how to use it to -send tokens between accounts, and discussed the underlying data types for -accounts and transactions, specifically the `Account` and the `SendTx`. In the -[next guide](basecoin-plugins.md), we introduce the Basecoin plugin system, +In this guide, we introduced the `basecoin` and `basecli` tools, +demonstrated how to start a new basecoin blockchain and how to send tokens between accounts, +and discussed the underlying data types for accounts and transactions, specifically the `Account` and the `SendTx`. +In the [next guide](basecoin-plugins.md), we introduce the Basecoin plugin system, which uses a new transaction type, the `AppTx`, to extend the functionality of the Basecoin system with arbitrary logic. diff --git a/docs/guide/basecoin-plugins.md b/docs/guide/basecoin-plugins.md index 5c2114d0cc9b..8bdee823ed0b 100644 --- a/docs/guide/basecoin-plugins.md +++ b/docs/guide/basecoin-plugins.md @@ -1,27 +1,32 @@ # Basecoin Plugins In the [previous guide](basecoin-basics.md), we saw how to use the `basecoin` -tool to start a blockchain and send transactions. We also learned about +tool to start a blockchain and the `basecli` tools to send transactions. We also learned about `Account` and `SendTx`, the basic data types giving us a multi-asset -cryptocurrency. Here, we will demonstrate how to extend the `basecoin` tool to -use another transaction type, the `AppTx`, to send data to a custom plugin. In -this example we explore a simple plugin name `counter`. +cryptocurrency. Here, we will demonstrate how to extend the tools to +use another transaction type, the `AppTx`, so we can send data to a custom plugin. In +this example we explore a simple plugin named `counter`. ## Example Plugin -The design of the `basecoin` tool makes it easy to extend for custom -functionality. The Counter plugin is bundled with basecoin, so if you have -already [installed basecoin](install.md) then you should be able to run a full -node with `counter` and the a light-client `countercli` from terminal. The -Counter plugin is just like the `basecoin` tool. They both use the same -library of commands, including one for signing and broadcasting `SendTx`. +The design of the `basecoin` and `basecli` tools makes it easy to extend for custom +functionality. We provide examples of such extensions in the basecoin repository under `docs/guide/counter`. +You can install them from the basecoin directory with: + +``` +`go install ./docs/guide/counter/cmd/... +``` + +This will give you both the `counter` and `countercli` binaries. +The former is just like `basecoin`, but with the counter plugin activated. +The latter is just like `basecli`, but with support for sending transactions to the counter plugin. Counter transactions take two custom inputs, a boolean argument named `valid`, and a coin amount named `countfee`. The transaction is only accepted if both `valid` is set to true and the transaction input coins is greater than `countfee` that the user provides. -A new blockchain can be initialized and started just like with in the [previous +A new blockchain can be initialized and started just like in the [previous guide](basecoin-basics.md): ``` @@ -29,16 +34,12 @@ guide](basecoin-basics.md): rm -rf ~/.counter countercli reset_all -counter init countercli keys new cool countercli keys new friend -GENKEY=`countercli keys get cool -o json | jq .pubkey.data` -GENJSON=`cat ~/.counter/genesis.json` -echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY > ~/.counter/genesis.json +counter init $(countercli keys get cool | awk '{print $2}') counter start - ``` The default files are stored in `~/.counter`. In another window we can @@ -47,7 +48,7 @@ initialize the light-client and send a transaction: ``` countercli init --chain-id=test_chain_id --node=tcp://localhost:46657 -YOU=`countercli keys get friend -o=json | jq .address | tr -d '"'` +YOU=$(countercli keys get friend | awk '{print $2}') countercli tx send --name=cool --amount=1000mycoin --to=0x$YOU --sequence=1 ``` @@ -78,21 +79,12 @@ countercli tx counter --name cool --amount=2mycoin --sequence=4 --valid --countf countercli query counter ``` -The value Counter value should be 2, because we sent a second valid transaction. +The Counter value should be 2, because we sent a second valid transaction. And this time, since we sent a countfee (which must be less than or equal to the total amount sent with the tx), it stores the `TotalFees` on the counter as well. -Even if you don't see it in the UI, the result of the query comes with a proof. -This is a Merkle proof that the state is what we say it is, and ties that query -to a particular header. Behind the scenes, `countercli` will not only verify that -this state matches the header, but also that the header is properly signed by -the known validator set. It will even update the validator set as needed, so long -as there have not been major changes and it is secure to do so. So, if you wonder -why the query may take a second... there is a lot of work going on in the -background to make sure even a lying full node can't trick your client. - -In a latter [guide on InterBlockchainCommunication](ibc.md), we'll use these -proofs to post transactions to other chains. +Keep it mind that, just like with `basecli`, the `countercli` verifies a proof +that the query response is correct and up-to-date. Now, before we implement our own plugin and tooling, it helps to understand the `AppTx` and the design of the plugin system. @@ -178,12 +170,11 @@ alone, but you should change any occurrences of `counter` to whatever your plugin tool is going to be called. You must also register your plugin(s) with the basecoin app with `RegisterStartPlugin`. -The light-client which is located in `cmd/countercli/main.go` allows for is -where transaction and query commands are designated. Similarity this command -can be mostly left alone besides replacing the application name and adding -references to new plugin commands +The light-client is located in `cmd/countercli/main.go` and allows for +transaction and query commands. This file can also be left mostly alone besides replacing the application name and adding +references to new plugin commands. -Next is the custom commands in `cmd/countercli/commands/`. These files is +Next is the custom commands in `cmd/countercli/commands/`. These files are where we extend the tool with any new commands and flags we need to send transactions or queries to our plugin. You define custom `tx` and `query` subcommands, which are registered in `main.go` (avoiding `init()` From 105cdbac383469a0be98186cd9f5d4c2237677a1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 00:26:21 -0400 Subject: [PATCH 51/73] cmd/commands -> cmd/basecoin/commands --- cmd/basecli/commands/apptx.go | 2 +- cmd/basecli/commands/sendtx.go | 2 +- cmd/{ => basecoin}/commands/ibc.go | 0 cmd/{ => basecoin}/commands/init.go | 0 cmd/{ => basecoin}/commands/key.go | 0 cmd/{ => basecoin}/commands/plugin_util.go | 0 cmd/{ => basecoin}/commands/relay.go | 0 cmd/{ => basecoin}/commands/reset.go | 0 cmd/{ => basecoin}/commands/root.go | 0 cmd/{ => basecoin}/commands/start.go | 0 cmd/{ => basecoin}/commands/utils.go | 0 cmd/{ => basecoin}/commands/utils_test.go | 0 cmd/{ => basecoin}/commands/version.go | 0 cmd/basecoin/main.go | 2 +- 14 files changed, 3 insertions(+), 3 deletions(-) rename cmd/{ => basecoin}/commands/ibc.go (100%) rename cmd/{ => basecoin}/commands/init.go (100%) rename cmd/{ => basecoin}/commands/key.go (100%) rename cmd/{ => basecoin}/commands/plugin_util.go (100%) rename cmd/{ => basecoin}/commands/relay.go (100%) rename cmd/{ => basecoin}/commands/reset.go (100%) rename cmd/{ => basecoin}/commands/root.go (100%) rename cmd/{ => basecoin}/commands/start.go (100%) rename cmd/{ => basecoin}/commands/utils.go (100%) rename cmd/{ => basecoin}/commands/utils_test.go (100%) rename cmd/{ => basecoin}/commands/version.go (100%) diff --git a/cmd/basecli/commands/apptx.go b/cmd/basecli/commands/apptx.go index 1325427d37f9..acfc5932d199 100644 --- a/cmd/basecli/commands/apptx.go +++ b/cmd/basecli/commands/apptx.go @@ -51,7 +51,7 @@ func (s *AppTx) Signers() ([]crypto.PubKey, error) { func (s *AppTx) TxBytes() ([]byte, error) { // TODO: verify it is signed - // Code and comment from: basecoin/cmd/commands/tx.go + // Code and comment from: basecoin/cmd/basecoin/commands/tx.go // Don't you hate having to do this? // How many times have I lost an hour over this trick?! txBytes := wire.BinaryBytes(bc.TxS{s.Tx}) diff --git a/cmd/basecli/commands/sendtx.go b/cmd/basecli/commands/sendtx.go index 15c5d5871950..1a338ef29eef 100644 --- a/cmd/basecli/commands/sendtx.go +++ b/cmd/basecli/commands/sendtx.go @@ -50,7 +50,7 @@ func (s *SendTx) Signers() ([]crypto.PubKey, error) { func (s *SendTx) TxBytes() ([]byte, error) { // TODO: verify it is signed - // Code and comment from: basecoin/cmd/commands/tx.go + // Code and comment from: basecoin/cmd/basecoin/commands/tx.go // Don't you hate having to do this? // How many times have I lost an hour over this trick?! txBytes := wire.BinaryBytes(struct { diff --git a/cmd/commands/ibc.go b/cmd/basecoin/commands/ibc.go similarity index 100% rename from cmd/commands/ibc.go rename to cmd/basecoin/commands/ibc.go diff --git a/cmd/commands/init.go b/cmd/basecoin/commands/init.go similarity index 100% rename from cmd/commands/init.go rename to cmd/basecoin/commands/init.go diff --git a/cmd/commands/key.go b/cmd/basecoin/commands/key.go similarity index 100% rename from cmd/commands/key.go rename to cmd/basecoin/commands/key.go diff --git a/cmd/commands/plugin_util.go b/cmd/basecoin/commands/plugin_util.go similarity index 100% rename from cmd/commands/plugin_util.go rename to cmd/basecoin/commands/plugin_util.go diff --git a/cmd/commands/relay.go b/cmd/basecoin/commands/relay.go similarity index 100% rename from cmd/commands/relay.go rename to cmd/basecoin/commands/relay.go diff --git a/cmd/commands/reset.go b/cmd/basecoin/commands/reset.go similarity index 100% rename from cmd/commands/reset.go rename to cmd/basecoin/commands/reset.go diff --git a/cmd/commands/root.go b/cmd/basecoin/commands/root.go similarity index 100% rename from cmd/commands/root.go rename to cmd/basecoin/commands/root.go diff --git a/cmd/commands/start.go b/cmd/basecoin/commands/start.go similarity index 100% rename from cmd/commands/start.go rename to cmd/basecoin/commands/start.go diff --git a/cmd/commands/utils.go b/cmd/basecoin/commands/utils.go similarity index 100% rename from cmd/commands/utils.go rename to cmd/basecoin/commands/utils.go diff --git a/cmd/commands/utils_test.go b/cmd/basecoin/commands/utils_test.go similarity index 100% rename from cmd/commands/utils_test.go rename to cmd/basecoin/commands/utils_test.go diff --git a/cmd/commands/version.go b/cmd/basecoin/commands/version.go similarity index 100% rename from cmd/commands/version.go rename to cmd/basecoin/commands/version.go diff --git a/cmd/basecoin/main.go b/cmd/basecoin/main.go index 5d74ae5585ac..23c46c768071 100644 --- a/cmd/basecoin/main.go +++ b/cmd/basecoin/main.go @@ -5,7 +5,7 @@ import ( "github.com/spf13/cobra" - "github.com/tendermint/basecoin/cmd/commands" + "github.com/tendermint/basecoin/cmd/basecoin/commands" "github.com/tendermint/tmlibs/cli" ) From e671ce60309f80f68e07b358e40bf95550fb2f38 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 00:32:59 -0400 Subject: [PATCH 52/73] bring back key.json. ibc guide edits --- cmd/basecoin/commands/init.go | 20 +++++++++++++++++- docs/guide/ibc.md | 39 +++++++++++------------------------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/cmd/basecoin/commands/init.go b/cmd/basecoin/commands/init.go index 616125222fe8..3fb627138e1e 100644 --- a/cmd/basecoin/commands/init.go +++ b/cmd/basecoin/commands/init.go @@ -45,6 +45,7 @@ func initCmd(cmd *cobra.Command, args []string) error { // initalize basecoin genesisFile := cfg.GenesisFile() privValFile := cfg.PrivValidatorFile() + keyFile := path.Join(cfg.RootDir, "key.json") mod1, err := setupFile(genesisFile, GetGenesisJSON(userAddr), 0644) if err != nil { @@ -54,8 +55,12 @@ func initCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } + mod3, err := setupFile(key1File, KeyJSON, 0400) + if err != nil { + return err + } - if (mod1 + mod2) > 0 { + if (mod1 + mod2 + mod3) > 0 { logger.Info("Initialized Basecoin", "genesis", genesisFile, "priv_validator", privValFile) } else { logger.Info("Already initialized", "priv_validator", privValFile) @@ -112,3 +117,16 @@ func GetGenesisJSON(addr string) string { } }`, addr) } + +// TODO: remove this once not needed for relay +var KeyJSON = `{ + "address": "1B1BE55F969F54064628A63B9559E7C21C925165", + "priv_key": { + "type": "ed25519", + "data": "C70D6934B4F55F1B7BC33B56B9CA8A2061384AFC19E91E44B40C4BBA182953D1619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + }, + "pub_key": { + "type": "ed25519", + "data": "619D3678599971ED29C7529DDD4DA537B97129893598A17C82E3AC9A8BA95279" + } +}` diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index aaf4e01b7ff4..5f82c1f5fc9c 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -2,11 +2,8 @@ One of the most exciting elements of the Cosmos Network is the InterBlockchain Communication (IBC) protocol, which enables interoperability across different -blockchains. The simplest example of using the IBC protocol is to send a data -packet from one blockchain to another. - -We implemented IBC as a basecoin plugin. and here we'll show you how to use -the Basecoin IBC-plugin to send a packet of data across blockchains! +blockchains. We implemented IBC as a basecoin plugin, and we'll show you +how to use it to send tokens across blockchains! Please note, this tutorial assumes you are familiar with [Basecoin plugins](/docs/guide/basecoin-plugins.md), but we'll explain how IBC works. You @@ -179,9 +176,8 @@ The results of a query can thus be used as proof in an `IBCPacketPostTx`. ## Relay While we need all these packet types internally to keep track of all the -proofs on both chains in a secure manner, for the normal work-flow, where -we just use the FIFO queue on each side for pending message to send as soon -as possible. +proofs on both chains in a secure manner, for the normal work-flow, +we can run a relay node that handles the cross-chain interaction. In this case, there are only two steps. First `basecoin relay init`, which must be run once to register each chain with the other one, @@ -197,11 +193,9 @@ chains to pay for all the ibc packets it will be forwarding. Now that we have all the background knowledge, let's actually walk through the tutorial. -Make sure you have installed -[Tendermint](https://tendermint.com/intro/getting-started/download) and -[basecoin](/docs/guide/install.md). +Make sure you have installed [basecoin and basecli](/docs/guide/install.md). -`basecoin` is a framework for creating new cryptocurrency applications. It +Basecoin is a framework for creating new cryptocurrency applications. It comes with an `IBC` plugin enabled by default. You will also want to install the [jq](https://stedolan.github.io/jq/) for @@ -240,11 +234,7 @@ Prepare the genesis block and start the server: export BCHOME=~/.ibcdemo/chain1/server CHAIN_ID=test-chain-1 PREFIX=1234 -basecoin init - -GENKEY=`basecli keys get money -o json --home=$HOME/.ibcdemo/chain1/client | jq .pubkey.data` -GENJSON=`cat $BCHOME/genesis.json` -echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY | jq ".chain_id=\"$CHAIN_ID\"" > $BCHOME/genesis.json +basecoin init $(basecli keys get money | awk '{print $2}') sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml @@ -257,8 +247,8 @@ have money, the second none: **Client1** ```bash basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} -ME=`basecli keys get money -o=json | jq .address | tr -d '"'` -YOU=`basecli keys get gotnone -o=json | jq .address | tr -d '"'` +ME=$(basecli keys get money | awk '{print $2}') +YOU=$(basecli keys get gotnone | awk '{print $2}') basecli query account $ME basecli query account $YOU ``` @@ -287,12 +277,7 @@ Prepare the genesis block and start the server: export BCHOME=~/.ibcdemo/chain2/server CHAIN_ID=test-chain-2 PREFIX=2345 -basecoin init - - -GENKEY=`basecli keys get moremoney -o json --home=$HOME/.ibcdemo/chain2/client | jq .pubkey.data` -GENJSON=`cat $BCHOME/genesis.json` -echo $GENJSON | jq '.app_options.accounts[0].pub_key.data='$GENKEY | jq ".chain_id=\"$CHAIN_ID\"" > $BCHOME/genesis.json +basecoin init $(basecli keys get moremoney | awk '{print $2}') sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml @@ -305,8 +290,8 @@ have money, the second none: **Client2** ```bash basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} -ME=`basecli keys get moremoney -o=json | jq .address | tr -d '"'` -YOU=`basecli keys get broke -o=json | jq .address | tr -d '"'` +ME=$(basecli keys get moremoney | awk '{print $2}') +YOU=$(basecli keys get broke | awk '{print $2}') basecli query account $ME basecli query account $YOU ``` From 43378a9b7bd6df6ee5b3b48af829d56c6599129f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 00:38:54 -0400 Subject: [PATCH 53/73] fix up basecli readme and basecoin-tool.md --- cmd/basecli/README.md | 28 +++++++++------------------- docs/guide/basecoin-tool.md | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/cmd/basecli/README.md b/cmd/basecli/README.md index 6e00f3d85134..2443c92ae50f 100644 --- a/cmd/basecli/README.md +++ b/cmd/basecli/README.md @@ -4,13 +4,6 @@ To keep things clear, let's have two shells... `$` is for basecoin (server), `%` is for basecli (client) -## Set up a clean basecoin, but don't start the chain - -``` -$ export BCHOME=~/.demoserve -$ basecoin init -``` - ## Set up your basecli with a new key ``` @@ -24,16 +17,15 @@ And set up a few more keys for fun... ``` % basecli keys new buddy % basecli keys list -% ME=`basecli keys get demo -o json | jq .address | tr -d '"'` -% YOU=`basecli keys get buddy -o json | jq .address | tr -d '"'` +% ME=$(basecli keys get demo | awk '{print $2}') +% YOU=$(basecli keys get buddy | awk '{print $2}') ``` -## Update genesis so you are rich, and start +## Set up a clean basecoin, initialized with your account ``` -$ vi $BCHOME/genesis.json --> cut/paste your pubkey from the results above - +$ export BCHOME=~/.demoserve +$ basecoin init $ME $ basecoin start ``` @@ -46,8 +38,8 @@ $ basecoin start ## Check your balances... ``` -% basecli proof state get --app=account --key=$ME -% basecli proof state get --app=account --key=$YOU +% basecli query account $ME +% basecli query account $YOU ``` ## Send the money @@ -55,9 +47,7 @@ $ basecoin start ``` % basecli tx send --name demo --amount 1000mycoin --sequence 1 --to $YOU -> copy hash to HASH -% basecli proof tx get --key $HASH - -% basecli proof tx get --key $HASH --app base -% basecli proof state get --key $YOU --app account +% basecli query tx $HASH +% basecli query account $YOU ``` diff --git a/docs/guide/basecoin-tool.md b/docs/guide/basecoin-tool.md index 0f89f7bd7337..eb35ec9ea1a5 100644 --- a/docs/guide/basecoin-tool.md +++ b/docs/guide/basecoin-tool.md @@ -5,6 +5,15 @@ CLI](/docs/guide/basecoin-basics.md) and [how to implement a plugin](/docs/guide/basecoin-plugins.md). In this tutorial, we provide more details on using the Basecoin tool. +# Generate a Key + +Generate a key using the `basecli` tool: + +``` +basecli keys new mykey +ME=$(basecli keys get mykey | awk '{print $2}') +``` + # Data Directory By default, `basecoin` works out of `~/.basecoin`. To change this, set the @@ -12,14 +21,14 @@ By default, `basecoin` works out of `~/.basecoin`. To change this, set the ``` export BCHOME=~/.my_basecoin_data -basecoin init +basecoin init $ME basecoin start ``` or ``` -BCHOME=~/.my_basecoin_data basecoin init +BCHOME=~/.my_basecoin_data basecoin init $ME BCHOME=~/.my_basecoin_data basecoin start ``` @@ -30,7 +39,7 @@ we use ABCI, we can actually run them in different processes. First, initialize them: ``` -basecoin init +basecoin init $ME ``` This will create a single `genesis.json` file in `~/.basecoin` with the @@ -168,7 +177,7 @@ You can reset all blockchain data by running: basecoin unsafe_reset_all ``` -Similarity you can reset client data by running: +Similarly, you can reset client data by running: ``` basecli reset_all From 05e23eda06b84228364a1c8eba686d935fe70be1 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 01:59:20 -0400 Subject: [PATCH 54/73] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fb67e697cdb..2012ec84a195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ BREAKING CHANGES: - complete overhaul on how tx and query subcommands are added. (see counter or trackomatron for examples) - no longer supports counter app (see new countercli) - basecoin + - `basecoin init` takes an argument, an address to allocate funds to in the genesis + - removed key2.json - removed all client side functionality from it (use basecli now for proofs) - no tx subcommand - no query subcommand From 824050a0b42f38d00ccf06a4e178fd9563453785 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 02:47:42 -0400 Subject: [PATCH 55/73] basecoin init --chain-id --- CHANGELOG.md | 1 + cmd/basecoin/commands/init.go | 23 ++++++++++++++++++----- docs/guide/counter/cmd/counter/main.go | 2 +- tests/cli/common.sh | 8 +------- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2012ec84a195..d0c77c03bc60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ BREAKING CHANGES: - removed `example-plugin`, put `counter` inside `docs/guide` ENHANCEMENTS: +- `basecoin init` support `--chain-id` - intergrates tendermint 0.10.0 (not the rc-2, but the real thing) - commands return error code (1) on failure for easier script testing - add `reset_all` to basecli, and never delete keys on `init` diff --git a/cmd/basecoin/commands/init.go b/cmd/basecoin/commands/init.go index 3fb627138e1e..e9f20247ac52 100644 --- a/cmd/basecoin/commands/init.go +++ b/cmd/basecoin/commands/init.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "os" + "path" "github.com/spf13/cobra" ) @@ -17,6 +18,18 @@ var ( } ) +//flags +var ( + chainIDFlag string +) + +func init() { + flags := []Flag2Register{ + {&chainIDFlag, "chain-id", "test_chain_id", "Chain ID"}, + } + RegisterFlags(InitCmd, flags) +} + // returns 1 iff it set a file, otherwise 0 (so we can add them) func setupFile(path, data string, perm os.FileMode) (int, error) { _, err := os.Stat(path) @@ -47,7 +60,7 @@ func initCmd(cmd *cobra.Command, args []string) error { privValFile := cfg.PrivValidatorFile() keyFile := path.Join(cfg.RootDir, "key.json") - mod1, err := setupFile(genesisFile, GetGenesisJSON(userAddr), 0644) + mod1, err := setupFile(genesisFile, GetGenesisJSON(chainIDFlag, userAddr), 0644) if err != nil { return err } @@ -55,7 +68,7 @@ func initCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } - mod3, err := setupFile(key1File, KeyJSON, 0400) + mod3, err := setupFile(keyFile, KeyJSON, 0400) if err != nil { return err } @@ -89,10 +102,10 @@ var PrivValJSON = `{ // GetGenesisJSON returns a new tendermint genesis with Basecoin app_options // that grant a large amount of "mycoin" to a single address // TODO: A better UX for generating genesis files -func GetGenesisJSON(addr string) string { +func GetGenesisJSON(chainID, addr string) string { return fmt.Sprintf(`{ "app_hash": "", - "chain_id": "test_chain_id", + "chain_id": "%s", "genesis_time": "0001-01-01T00:00:00.000Z", "validators": [ { @@ -115,7 +128,7 @@ func GetGenesisJSON(addr string) string { ] }] } -}`, addr) +}`, chainID, addr) } // TODO: remove this once not needed for relay diff --git a/docs/guide/counter/cmd/counter/main.go b/docs/guide/counter/cmd/counter/main.go index 0da66c12f6e9..c877a51eda8f 100644 --- a/docs/guide/counter/cmd/counter/main.go +++ b/docs/guide/counter/cmd/counter/main.go @@ -7,7 +7,7 @@ import ( "github.com/tendermint/tmlibs/cli" - "github.com/tendermint/basecoin/cmd/commands" + "github.com/tendermint/basecoin/cmd/basecoin/commands" "github.com/tendermint/basecoin/docs/guide/counter/plugins/counter" "github.com/tendermint/basecoin/types" ) diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 017da897a4ab..0b507e5969b6 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -24,13 +24,7 @@ initServer() { assertNotNull "no chain" $2 CHAIN=$2 SERVER_LOG=$1/${SERVER_EXE}.log - ${SERVER_EXE} init --home=$SERVE_DIR >>$SERVER_LOG - - #change the genesis to the first account - GENKEY=$(${CLIENT_EXE} 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 \ - | jq ".chain_id=\"$2\"" > $SERVE_DIR/genesis.json + ${SERVER_EXE} init --chain-id $CHAIN $(${CLIENT_EXE} keys get ${RICH} | awk '{print $2}') --home=$SERVE_DIR >>$SERVER_LOG # optionally set the port if [ -n "$3" ]; then From 4cabad09801987670d683cf5d7b07324ace65bd0 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 21 Jun 2017 16:24:51 +0200 Subject: [PATCH 56/73] Minor cleanup --- cmd/basecli/commands/query.go | 5 ++--- tests/cli/common.sh | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/basecli/commands/query.go b/cmd/basecli/commands/query.go index 34af3b8d6041..ac17cbdd92c9 100644 --- a/cmd/basecli/commands/query.go +++ b/cmd/basecli/commands/query.go @@ -1,8 +1,7 @@ package commands import ( - "fmt" - + "github.com/pkg/errors" "github.com/spf13/cobra" wire "github.com/tendermint/go-wire" @@ -29,7 +28,7 @@ func doAccountQuery(cmd *cobra.Command, args []string) error { acc := new(btypes.Account) proof, err := proofcmd.GetAndParseAppProof(key, &acc) if lc.IsNoDataErr(err) { - return fmt.Errorf("Account bytes are empty for address %X ", addr) + return errors.Errorf("Account bytes are empty for address %X ", addr) } else if err != nil { return err } diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 0b507e5969b6..95269f8422fc 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -24,7 +24,9 @@ initServer() { assertNotNull "no chain" $2 CHAIN=$2 SERVER_LOG=$1/${SERVER_EXE}.log - ${SERVER_EXE} init --chain-id $CHAIN $(${CLIENT_EXE} keys get ${RICH} | awk '{print $2}') --home=$SERVE_DIR >>$SERVER_LOG + + GENKEY=$(${CLIENT_EXE} keys get ${RICH} | awk '{print $2}') + ${SERVER_EXE} init --chain-id $CHAIN $GENKEY --home=$SERVE_DIR >>$SERVER_LOG # optionally set the port if [ -n "$3" ]; then From a78a24bbe92808504125f11b9ffaad50ec71bb99 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Tue, 20 Jun 2017 07:21:06 -0400 Subject: [PATCH 57/73] bash test cleanup int --- .gitignore | 2 + docs/guide/basecoin-plugins.md | 22 ++++------ docs/guide/ibc.md | 26 +++++------ tests/cli/basictx.sh | 28 +++++------- tests/cli/common.sh | 48 +++++++++++--------- tests/cli/counter.sh | 31 ++++++------- tests/cli/ibc.sh | 80 +++++++++++++++++----------------- 7 files changed, 115 insertions(+), 122 deletions(-) diff --git a/.gitignore b/.gitignore index cc8fd5d8d9d1..dc0a2ef9e557 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ vendor merkleeyes.db build shunit2 +docs/guide/*.sh + diff --git a/docs/guide/basecoin-plugins.md b/docs/guide/basecoin-plugins.md index 8bdee823ed0b..7e4ac309f338 100644 --- a/docs/guide/basecoin-plugins.md +++ b/docs/guide/basecoin-plugins.md @@ -9,17 +9,13 @@ this example we explore a simple plugin named `counter`. ## Example Plugin -The design of the `basecoin` and `basecli` tools makes it easy to extend for custom -functionality. We provide examples of such extensions in the basecoin repository under `docs/guide/counter`. -You can install them from the basecoin directory with: - -``` -`go install ./docs/guide/counter/cmd/... -``` - -This will give you both the `counter` and `countercli` binaries. -The former is just like `basecoin`, but with the counter plugin activated. -The latter is just like `basecli`, but with support for sending transactions to the counter plugin. +The design of the `basecoin` tool makes it easy to extend for custom +functionality. The Counter plugin is bundled with basecoin, so if you have +already [installed basecoin](install.md) and run `make install` then you should +be able to run a full node with `counter` and the a light-client `countercli` +from terminal. The Counter plugin is just like the `basecoin` tool. They +both use the same library of commands, including one for signing and +broadcasting `SendTx`. Counter transactions take two custom inputs, a boolean argument named `valid`, and a coin amount named `countfee`. The transaction is only accepted if both @@ -83,7 +79,7 @@ The Counter value should be 2, because we sent a second valid transaction. And this time, since we sent a countfee (which must be less than or equal to the total amount sent with the tx), it stores the `TotalFees` on the counter as well. -Keep it mind that, just like with `basecli`, the `countercli` verifies a proof +Keep it mind that, just like with `basecli`, the `countercli` verifies a proof that the query response is correct and up-to-date. Now, before we implement our own plugin and tooling, it helps to understand the @@ -170,7 +166,7 @@ alone, but you should change any occurrences of `counter` to whatever your plugin tool is going to be called. You must also register your plugin(s) with the basecoin app with `RegisterStartPlugin`. -The light-client is located in `cmd/countercli/main.go` and allows for +The light-client is located in `cmd/countercli/main.go` and allows for transaction and query commands. This file can also be left mostly alone besides replacing the application name and adding references to new plugin commands. diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 5f82c1f5fc9c..6a467edfacf7 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -210,7 +210,7 @@ Otherwise, open up 5 (yes 5!) terminal tabs.... All commands will be prefixed by the name of the terminal window in which to run it... -```bash +``` # first, clean up any old garbage for a fresh slate... rm -rf ~/.ibcdemo/ ``` @@ -218,7 +218,7 @@ rm -rf ~/.ibcdemo/ Set up some accounts so we can init everything nicely: **Client1** -```bash +``` export BCHOME=~/.ibcdemo/chain1/client CHAIN_ID=test-chain-1 PORT=12347 @@ -229,7 +229,7 @@ basecli keys new gotnone Prepare the genesis block and start the server: **Server1** -```bash +``` # set up the directory, chainid and port of this chain... export BCHOME=~/.ibcdemo/chain1/server CHAIN_ID=test-chain-1 @@ -245,7 +245,7 @@ Attach the client to the chain and confirm state. The first account should have money, the second none: **Client1** -```bash +``` basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} ME=$(basecli keys get money | awk '{print $2}') YOU=$(basecli keys get gotnone | awk '{print $2}') @@ -261,7 +261,7 @@ on this chain, as the "cool" key only has money on chain 1. **Client2** -```bash +``` export BCHOME=~/.ibcdemo/chain2/client CHAIN_ID=test-chain-2 PORT=23457 @@ -272,7 +272,7 @@ basecli keys new broke Prepare the genesis block and start the server: **Server2** -```bash +``` # set up the directory, chainid and port of this chain... export BCHOME=~/.ibcdemo/chain2/server CHAIN_ID=test-chain-2 @@ -288,7 +288,7 @@ Attach the client to the chain and confirm state. The first account should have money, the second none: **Client2** -```bash +``` basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} ME=$(basecli keys get moremoney | awk '{print $2}') YOU=$(basecli keys get broke | awk '{print $2}') @@ -307,7 +307,7 @@ for now, we have to transfer some cash from the rich accounts before we start the actual relay. **Client1** -```bash +``` # note that this key.json file is a hardcoded demo for all chains, this will # be updated in a future release RELAY_KEY=${BCHOME}/../server/key.json @@ -317,7 +317,7 @@ basecli query account $RELAY_ADDR ``` **Client2** -```bash +``` # note that this key.json file is a hardcoded demo for all chains, this will # be updated in a future release RELAY_KEY=${BCHOME}/../server/key.json @@ -327,7 +327,7 @@ basecli query account $RELAY_ADDR ``` **Relay** -```bash +``` # lots of config... SERVER_1=~/.ibcdemo/chain1/server SERVER_2=~/.ibcdemo/chain2/server @@ -358,7 +358,7 @@ a secure relay between them. Now we can enjoy the fruits of our labor... **Client2** -```bash +``` # this should be empty basecli query account $YOU # now, we get the key to copy to the other terminal @@ -367,14 +367,14 @@ echo $YOU **Client1** -```bash +``` # set TARGET to be $YOU from the other chain basecli tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$TARGET --name=money ``` **Client2** -```bash +``` # give it time to arrive... sleep 1 # now you should see 12345 coins! diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 55e518819d3e..314e0e3e108e 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -1,19 +1,22 @@ #!/bin/bash -# these are two globals to control all scripts (can use eg. counter instead) +# These global variables are required for common.sh SERVER_EXE=basecoin CLIENT_EXE=basecli +ACCOUNTS=(jae ethan bucky rigel igor) +RICH=${ACCOUNTS[0]} +POOR=${ACCOUNTS[4]} oneTimeSetUp() { - # these are passed in as args + # These are passed in as args BASE_DIR=$HOME/.basecoin_test_basictx CHAIN_ID=my-test-chain rm -rf $BASE_DIR 2>/dev/null mkdir -p $BASE_DIR - # set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE + # Set up client - make sure you use the proper prefix if you set + # a custom CLIENT_EXE export BC_HOME=${BASE_DIR}/client prepareClient @@ -23,16 +26,11 @@ oneTimeSetUp() { initClient $CHAIN_ID 34567 - echo "...Testing may begin!" - echo - echo - echo + printf "...Testing may begin!\n\n\n" } oneTimeTearDown() { - echo - echo - echo "stopping $SERVER_EXE test server..." + printf "\n\nstopping $SERVER_EXE test server..." kill -9 $PID_SERVER >/dev/null 2>&1 sleep 1 } @@ -64,15 +62,11 @@ test01SendTx() { checkAccount $SENDER "1" "9007199254740000" checkAccount $RECV "0" "992" - # make sure tx is indexed + # Make sure tx is indexed checkSendTx $HASH $TX_HEIGHT $SENDER "992" } - -# load and run these tests with shunit2! +# Load common then run these tests with shunit2! DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory - -# load common helpers . $DIR/common.sh - . $DIR/shunit2 diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 95269f8422fc..a7b632e598e6 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -1,9 +1,11 @@ -# this is not executable, but helper functions for the other scripts +# This is not executable, but helper functions for the other scripts -# these are general accounts to be prepared -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -POOR=${ACCOUNTS[4]} +# XXX XXX XXX XXX XXX +# The following global variables must be defined before calling common functions: +# SERVER_EXE=foobar # Server binary name +# CLIENT_EXE=foobarcli # Client binary name +# ACCOUNTS=(foo bar) # List of accounts for initialization +# RICH=${ACCOUNTS[0]} # Account to assign genesis balance prepareClient() { echo "Preparing client keys..." @@ -15,9 +17,10 @@ prepareClient() { done } -# initServer takes two args - (root dir, chain_id) -# and optionally port prefix as a third arg (default is 4665{6,7,8}) -# it grabs the first account to give it the money +# XXX Ex Usage1: initServer $ROOTDIR $CHAINID +# XXX Ex Usage2: initServer $ROOTDIR $CHAINID $PORTPREFIX +# Desc: Grabs the Rich account and gives it all genesis money +# port-prefix default is 4665{6,7,8} initServer() { echo "Setting up genesis..." SERVE_DIR=$1/server @@ -46,7 +49,10 @@ initServer() { fi } -# initClient requires chain_id arg, port is optional (default 46657) +# XXX Ex Usage1: initClient $CHAINID +# XXX Ex Usage2: initClient $CHAINID $PORTPREFIX +# Desc: Initialize the client program +# port-prefix default is 46657 initClient() { echo "Attaching ${CLIENT_EXE} client..." PORT=${2:-46657} @@ -55,7 +61,9 @@ initClient() { assertTrue "initialized light-client" $? } -# newKeys makes a key for a given username, second arg optional password +# XXX Ex Usage1: newKey $NAME +# XXX Ex Usage2: newKey $NAME $PASSWORD +# Desc: Generates key for given username and password newKey(){ assertNotNull "keyname required" "$1" KEYPASS=${2:-qwertyuiop} @@ -64,7 +72,8 @@ newKey(){ assertTrue "$1 doesn't exist" "${CLIENT_EXE} keys get $1" } -# getAddr gets the address for a key name +# XXX Ex Usage: getAddr $NAME +# Desc: Gets the address for a key name getAddr() { assertNotNull "keyname required" "$1" RAW=$(${CLIENT_EXE} keys get $1) @@ -73,8 +82,7 @@ getAddr() { echo $RAW | cut -d' ' -f2 } -# checkAccount $ADDR $SEQUENCE $BALANCE -# assumes just one coin, checks the balance of first coin in any case +# Desc: Assumes just one coin, checks the balance of first coin in any case checkAccount() { # make sure sender goes down ACCT=$(${CLIENT_EXE} query account $1) @@ -84,8 +92,8 @@ checkAccount() { return $? } -# txSucceeded $? "$RES" -# must be called right after the `tx` command, makes sure it got a success response +# XXX Ex Usage: txSucceeded $? "$RES" +# Desc: Must be called right after the `tx` command, makes sure it got a success response txSucceeded() { if (assertTrue "sent tx: $2" $1); then TX=`echo $2 | cut -d: -f2-` # strip off first line asking for password @@ -96,9 +104,9 @@ txSucceeded() { fi } -# checkSendTx $HASH $HEIGHT $SENDER $AMOUNT -# this looks up the tx by hash, and makes sure the height and type match -# and that the first input was from this sender for this amount +# XXX Ex Usage: checkSendTx $HASH $HEIGHT $SENDER $AMOUNT +# Desc: This looks up the tx by hash, and makes sure the height and type match +# and that the first input was from this sender for this amount checkSendTx() { TX=$(${CLIENT_EXE} query tx $1) assertTrue "found tx" $? @@ -109,8 +117,8 @@ checkSendTx() { return $? } -# waitForBlock $port -# waits until the block height on that node increases by one +# XXX Ex Usage: waitForBlock $port +# Desc: Waits until the block height on that node increases by one waitForBlock() { addr=http://localhost:$1 b1=`curl -s $addr/status | jq .result.latest_block_height` diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index f09a260b76be..99b0d892085d 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -1,19 +1,22 @@ #!/bin/bash -# these are two globals to control all scripts (can use eg. counter instead) +# These global variables are required for common.sh SERVER_EXE=counter CLIENT_EXE=countercli +ACCOUNTS=(jae ethan bucky rigel igor) +RICH=${ACCOUNTS[0]} +POOR=${ACCOUNTS[4]} oneTimeSetUp() { - # these are passed in as args + # These are passed in as args BASE_DIR=$HOME/.basecoin_test_counter CHAIN_ID="counter-chain" rm -rf $BASE_DIR 2>/dev/null mkdir -p $BASE_DIR - # set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE + # Set up client - make sure you use the proper prefix if you set + # a custom CLIENT_EXE export BC_HOME=${BASE_DIR}/client prepareClient @@ -24,16 +27,11 @@ oneTimeSetUp() { initClient $CHAIN_ID 12347 if [ $? != 0 ]; then return 1; fi - echo "...Testing may begin!" - echo - echo - echo + printf "...Testing may begin!\n\n\n" } oneTimeTearDown() { - echo - echo - echo "stopping $SERVER_EXE test server..." + printf "\n\nstopping $SERVER_EXE test server..." kill -9 $PID_SERVER >/dev/null 2>&1 sleep 1 } @@ -75,8 +73,8 @@ test02GetCounter() { assertFalse "no default count" $? } -# checkAccount $COUNT $BALANCE -# assumes just one coin, checks the balance of first coin in any case +# CheckAccount $COUNT $BALANCE +# Assumes just one coin, checks the balance of first coin in any case checkCounter() { # make sure sender goes down ACCT=$(${CLIENT_EXE} query counter) @@ -85,7 +83,7 @@ checkCounter() { assertEquals "proper money" "$2" $(echo $ACCT | jq .data.TotalFees[0].amount) } -test02AddCount() { +test03AddCount() { SENDER=$(getAddr $RICH) assertFalse "bad password" "echo hi | ${CLIENT_EXE} tx counter --amount=1000mycoin --sequence=2 --name=${RICH} 2>/dev/null" @@ -114,10 +112,7 @@ test02AddCount() { # echo $TX } -# load and run these tests with shunit2! +# Load common then run these tests with shunit2! DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory - -# load common helpers . $DIR/common.sh - . $DIR/shunit2 diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 2cdaa5843add..7afda2d8f67f 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -2,14 +2,18 @@ #!/bin/bash -# these are two globals to control all scripts (can use eg. counter instead) +# These global variables are required for common.sh SERVER_EXE=basecoin CLIENT_EXE=basecli -# just uncomment this line for full stack traces in error output +ACCOUNTS=(jae ethan bucky rigel igor) +RICH=${ACCOUNTS[0]} +POOR=${ACCOUNTS[4]} + +# Uncomment the following line for full stack traces in error output # CLIENT_EXE="basecli --trace" oneTimeSetUp() { - # these are passed in as args + # These are passed in as args BASE_DIR_1=$HOME/.basecoin_test_ibc/chain1 CHAIN_ID_1=test-chain-1 CLIENT_1=${BASE_DIR_1}/client @@ -22,41 +26,36 @@ oneTimeSetUp() { PREFIX_2=2345 PORT_2=${PREFIX_2}7 - # clean up and create the test dirs + # Clean up and create the test dirs rm -rf $BASE_DIR_1 $BASE_DIR_2 2>/dev/null mkdir -p $BASE_DIR_1 $BASE_DIR_2 - # set up client for chain 1- make sure you use the proper prefix if you set - # a custom CLIENT_EXE + # Set up client for chain 1- make sure you use the proper prefix if you set + # a custom CLIENT_EXE BC_HOME=${CLIENT_1} prepareClient BC_HOME=${CLIENT_2} prepareClient - # start basecoin server, giving money to the key in the first client + # Start basecoin server, giving money to the key in the first client BC_HOME=${CLIENT_1} initServer $BASE_DIR_1 $CHAIN_ID_1 $PREFIX_1 if [ $? != 0 ]; then return 1; fi PID_SERVER_1=$PID_SERVER - # start second basecoin server, giving money to the key in the second client + # Start second basecoin server, giving money to the key in the second client BC_HOME=${CLIENT_2} initServer $BASE_DIR_2 $CHAIN_ID_2 $PREFIX_2 if [ $? != 0 ]; then return 1; fi PID_SERVER_2=$PID_SERVER - # connect both clients + # Connect both clients BC_HOME=${CLIENT_1} initClient $CHAIN_ID_1 $PORT_1 if [ $? != 0 ]; then return 1; fi BC_HOME=${CLIENT_2} initClient $CHAIN_ID_2 $PORT_2 if [ $? != 0 ]; then return 1; fi - echo "...Testing may begin!" - echo - echo - echo + printf "...Testing may begin!\n\n\n" } oneTimeTearDown() { - echo - echo - echo "stopping both $SERVER_EXE test servers... $PID_SERVER_1 $PID_SERVER_2" + printf "\n\nstopping both $SERVER_EXE test servers... $PID_SERVER_1 $PID_SERVER_2" kill -9 $PID_SERVER_1 kill -9 $PID_SERVER_2 sleep 1 @@ -79,20 +78,21 @@ test00GetAccount() { assertFalse "has no genesis account" "${CLIENT_EXE} query account $RECV_2" checkAccount $SENDER_2 "0" "9007199254740992" - # make sure that they have different addresses on both chains (they are random keys) + # Make sure that they have different addresses on both chains (they are random keys) assertNotEquals "sender keys must be different" "$SENDER_1" "$SENDER_2" assertNotEquals "recipient keys must be different" "$RECV_1" "$RECV_2" } test01SendIBCTx() { - # trigger a cross-chain sendTx... from RICH on chain1 to POOR on chain2 - # we make sure the money was reduced, but nothing arrived + # Trigger a cross-chain sendTx... from RICH on chain1 to POOR on chain2 + # we make sure the money was reduced, but nothing arrived SENDER=$(BC_HOME=${CLIENT_1} getAddr $RICH) RECV=$(BC_HOME=${CLIENT_2} getAddr $POOR) # we have to remove the password request from stdout, to just get the json export BC_HOME=${CLIENT_1} - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20002mycoin --sequence=1 --to=${CHAIN_ID_2}/${RECV} --name=$RICH 2>/dev/null) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20002mycoin \ + --sequence=1 --to=${CHAIN_ID_2}/${RECV} --name=$RICH 2>/dev/null) txSucceeded $? "$RES" # an example to quit early if there is no point in more tests if [ $? != 0 ]; then echo "aborting!"; return 1; fi @@ -101,66 +101,67 @@ test01SendIBCTx() { HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) - # make sure balance went down and tx is indexed + # Make sure balance went down and tx is indexed checkAccount $SENDER "1" "9007199254720990" checkSendTx $HASH $TX_HEIGHT $SENDER "20002" - # # make sure nothing arrived - yet + # Make sure nothing arrived - yet waitForBlock ${PORT_1} assertFalse "no relay running" "BC_HOME=${CLIENT_2} ${CLIENT_EXE} query account $RECV" - # start the relay and wait a few blocks... + # Start the relay and wait a few blocks... # (already sent a tx on chain1, so use higher sequence) startRelay 2 1 if [ $? != 0 ]; then echo "can't start relay"; cat ${BASE_DIR_1}/../relay.log; return 1; fi - # give it a little time, then make sure the money arrived + # Give it a little time, then make sure the money arrived echo "waiting for relay..." sleep 1 waitForBlock ${PORT_1} waitForBlock ${PORT_2} - # check the new account + # Check the new account echo "checking ibc recipient..." BC_HOME=${CLIENT_2} checkAccount $RECV "0" "20002" - # stop relay - echo "stoping relay" - echo + # Stop relay + printf "stoping relay\n" kill -9 $PID_RELAY } -# startRelay $seq1 $seq2 +# StartRelay $seq1 $seq2 # startRelay hooks up a relay between chain1 and chain2 # it needs the proper sequence number for $RICH on chain1 and chain2 as args startRelay() { - # send some cash to the default key, so it can send messages + # Send some cash to the default key, so it can send messages RELAY_KEY=${BASE_DIR_1}/server/key.json RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") echo starting relay $PID_RELAY ... - # get paid on chain1 + # Get paid on chain1 export BC_HOME=${CLIENT_1} SENDER=$(getAddr $RICH) - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin --sequence=$1 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin \ + --sequence=$1 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) txSucceeded $? "$RES" if [ $? != 0 ]; then echo "can't pay chain1!"; return 1; fi - # get paid on chain2 + # Get paid on chain2 export BC_HOME=${CLIENT_2} SENDER=$(getAddr $RICH) - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin --sequence=$2 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin \ + --sequence=$2 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) txSucceeded $? "$RES" if [ $? != 0 ]; then echo "can't pay chain2!"; return 1; fi - # initialize the relay (register both chains) + # Initialize the relay (register both chains) ${SERVER_EXE} relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ --genesis1=${BASE_DIR_1}/server/genesis.json --genesis2=${BASE_DIR_2}/server/genesis.json \ --from=$RELAY_KEY > ${BASE_DIR_1}/../relay.log if [ $? != 0 ]; then echo "can't initialize relays"; cat ${BASE_DIR_1}/../relay.log; return 1; fi - # now start the relay (constantly send packets) + # Now start the relay (constantly send packets) ${SERVER_EXE} relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ --from=$RELAY_KEY >> ${BASE_DIR_1}/../relay.log & @@ -168,15 +169,12 @@ startRelay() { PID_RELAY=$! disown - # return an error if it dies in the first two seconds to make sure it is running + # Return an error if it dies in the first two seconds to make sure it is running ps $PID_RELAY >/dev/null return $? } -# load and run these tests with shunit2! +# Load common then run these tests with shunit2! DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory - -# load common helpers . $DIR/common.sh - . $DIR/shunit2 From dcb4a40bd2237c8ca090f1a21da49a9a34c37639 Mon Sep 17 00:00:00 2001 From: rigel rozanski Date: Wed, 21 Jun 2017 05:46:37 -0400 Subject: [PATCH 58/73] quick setup/tear-down --- tests/cli/basictx.sh | 24 ++---------------------- tests/cli/common.sh | 35 +++++++++++++++++++++++++++++++++++ tests/cli/counter.sh | 26 ++------------------------ 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 314e0e3e108e..4297bffa0108 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -8,31 +8,11 @@ RICH=${ACCOUNTS[0]} POOR=${ACCOUNTS[4]} oneTimeSetUp() { - # These are passed in as args - BASE_DIR=$HOME/.basecoin_test_basictx - CHAIN_ID=my-test-chain - - rm -rf $BASE_DIR 2>/dev/null - mkdir -p $BASE_DIR - - # Set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE - export BC_HOME=${BASE_DIR}/client - prepareClient - - # start basecoin server (with counter) - initServer $BASE_DIR $CHAIN_ID 3456 - if [ $? != 0 ]; then return 1; fi - - initClient $CHAIN_ID 34567 - - printf "...Testing may begin!\n\n\n" + quickSetup .basecoin_test_basictx basictx-chain } oneTimeTearDown() { - printf "\n\nstopping $SERVER_EXE test server..." - kill -9 $PID_SERVER >/dev/null 2>&1 - sleep 1 + quickTearDown } test00GetAccount() { diff --git a/tests/cli/common.sh b/tests/cli/common.sh index a7b632e598e6..edc7c0e125ed 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -7,6 +7,41 @@ # ACCOUNTS=(foo bar) # List of accounts for initialization # RICH=${ACCOUNTS[0]} # Account to assign genesis balance +# XXX Ex Usage: quickSetup $WORK_NAME $CHAIN_ID +# Desc: Start the program, use with shunit2 OneTimeSetUp() +quickSetup() { + # These are passed in as args + BASE_DIR=$HOME/$1 + CHAIN_ID=$2 + + rm -rf $BASE_DIR 2>/dev/null + mkdir -p $BASE_DIR + + # Set up client - make sure you use the proper prefix if you set + # a custom CLIENT_EXE + export BC_HOME=${BASE_DIR}/client + prepareClient + + # start basecoin server (with counter) + initServer $BASE_DIR $CHAIN_ID + if [ $? != 0 ]; then return 1; fi + + initClient $CHAIN_ID + if [ $? != 0 ]; then return 1; fi + + printf "...Testing may begin!\n\n\n" +} + +# XXX Ex Usage: quickTearDown +# Desc: close the test server, use with shunit2 OneTimeTearDown() +quickTearDown() { + printf "\n\nstopping $SERVER_EXE test server..." + kill -9 $PID_SERVER >/dev/null 2>&1 + sleep 1 +} + +############################################################ + prepareClient() { echo "Preparing client keys..." ${CLIENT_EXE} reset_all diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index 99b0d892085d..3aa6ef61f637 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -8,35 +8,13 @@ RICH=${ACCOUNTS[0]} POOR=${ACCOUNTS[4]} oneTimeSetUp() { - # These are passed in as args - BASE_DIR=$HOME/.basecoin_test_counter - CHAIN_ID="counter-chain" - - rm -rf $BASE_DIR 2>/dev/null - mkdir -p $BASE_DIR - - # Set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE - export BC_HOME=${BASE_DIR}/client - prepareClient - - # start basecoin server (with counter) - initServer $BASE_DIR $CHAIN_ID 1234 - if [ $? != 0 ]; then return 1; fi - - initClient $CHAIN_ID 12347 - if [ $? != 0 ]; then return 1; fi - - printf "...Testing may begin!\n\n\n" + quickSetup .basecoin_test_counter counter-chain } oneTimeTearDown() { - printf "\n\nstopping $SERVER_EXE test server..." - kill -9 $PID_SERVER >/dev/null 2>&1 - sleep 1 + quickTearDown } - test00GetAccount() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) From 3b6648323850686e5272a5c1a195dd75d9416666 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 21 Jun 2017 16:55:19 +0200 Subject: [PATCH 59/73] Fix up one comment --- tests/cli/counter.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index 3aa6ef61f637..e819fef81fe0 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -51,7 +51,7 @@ test02GetCounter() { assertFalse "no default count" $? } -# CheckAccount $COUNT $BALANCE +# checkCounter $COUNT $BALANCE # Assumes just one coin, checks the balance of first coin in any case checkCounter() { # make sure sender goes down From fd28e4e884a389662786d98e71d5a22635c5fb22 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 20 Jun 2017 13:46:49 +0200 Subject: [PATCH 60/73] Added tests on handling restarts well, cleaned up common --- tests/cli/common.sh | 33 +++++++++++--- tests/cli/restart.sh | 106 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 7 deletions(-) create mode 100755 tests/cli/restart.sh diff --git a/tests/cli/common.sh b/tests/cli/common.sh index edc7c0e125ed..12ca5d5a6fc7 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -1,13 +1,13 @@ # This is not executable, but helper functions for the other scripts # XXX XXX XXX XXX XXX -# The following global variables must be defined before calling common functions: +# The following global variables must be defined before calling common functions: # SERVER_EXE=foobar # Server binary name # CLIENT_EXE=foobarcli # Client binary name -# ACCOUNTS=(foo bar) # List of accounts for initialization +# ACCOUNTS=(foo bar) # List of accounts for initialization # RICH=${ACCOUNTS[0]} # Account to assign genesis balance -# XXX Ex Usage: quickSetup $WORK_NAME $CHAIN_ID +# XXX Ex Usage: quickSetup $WORK_NAME $CHAIN_ID # Desc: Start the program, use with shunit2 OneTimeSetUp() quickSetup() { # These are passed in as args @@ -73,17 +73,30 @@ initServer() { fi echo "Starting ${SERVER_EXE} server..." - ${SERVER_EXE} start --home=$SERVE_DIR >>$SERVER_LOG 2>&1 & + startServer $SERVE_DIR $SERVER_LOG + return $? +} + +# usage: startServer SERVE_DIR SERVER_LOG +startServer() { + ${SERVER_EXE} start --home=$1 >>$2 2>&1 & sleep 5 PID_SERVER=$! disown if ! ps $PID_SERVER >/dev/null; then echo "**FAILED**" - # cat $SERVER_LOG - # return 1 + cat $SERVER_LOG + return 1 fi } +# XXX Ex Usage: stopServer $PID_SERVER +stopServer() { + echo "stopping $SERVER_EXE test server..." + kill -9 $1 >/dev/null 2>&1 + sleep 1 +} + # XXX Ex Usage1: initClient $CHAINID # XXX Ex Usage2: initClient $CHAINID $PORTPREFIX # Desc: Initialize the client program @@ -121,7 +134,11 @@ getAddr() { checkAccount() { # make sure sender goes down ACCT=$(${CLIENT_EXE} query account $1) - assertTrue "must have genesis account" $? + if ! assertTrue "account must exist: $ACCT" $?; then + return 1 + fi + + if [ -n "$DEBUG" ]; then echo $ACCT; echo; fi assertEquals "proper sequence" "$2" $(echo $ACCT | jq .data.sequence) assertEquals "proper money" "$3" $(echo $ACCT | jq .data.coins[0].amount) return $? @@ -145,6 +162,8 @@ txSucceeded() { checkSendTx() { TX=$(${CLIENT_EXE} query tx $1) assertTrue "found tx" $? + if [ -n "$DEBUG" ]; then echo $TX; echo; fi + assertEquals "proper height" $2 $(echo $TX | jq .height) assertEquals "type=send" '"send"' $(echo $TX | jq .data.type) assertEquals "proper sender" "\"$3\"" $(echo $TX | jq .data.data.inputs[0].address) diff --git a/tests/cli/restart.sh b/tests/cli/restart.sh new file mode 100755 index 000000000000..dfdfe7c547b0 --- /dev/null +++ b/tests/cli/restart.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# these are two globals to control all scripts (can use eg. counter instead) +SERVER_EXE=basecoin +CLIENT_EXE=basecli + +oneTimeSetUp() { + # these are passed in as args + BASE_DIR=$HOME/.basecoin_test_restart + CHAIN_ID=restart-chain + + rm -rf $BASE_DIR 2>/dev/null + mkdir -p $BASE_DIR + + # set up client - make sure you use the proper prefix if you set + # a custom CLIENT_EXE + export BC_HOME=${BASE_DIR}/client + prepareClient + + # start basecoin server (with counter) + initServer $BASE_DIR $CHAIN_ID 3456 + if [ $? != 0 ]; then return 1; fi + + initClient $CHAIN_ID 34567 + + echo "...Testing may begin!" + echo + echo + echo +} + +oneTimeTearDown() { + echo + echo + stopServer $PID_SERVER +} + +test00PreRestart() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + TX=`echo $RES | cut -d: -f2-` + HASH=$(echo $TX | jq .hash | tr -d \") + TX_HEIGHT=$(echo $TX | jq .height) + + checkAccount $SENDER "1" "9007199254740000" + checkAccount $RECV "0" "992" + + # make sure tx is indexed + checkSendTx $HASH $TX_HEIGHT $SENDER "992" + +} + + +test01OnRestart() { + SENDER=$(getAddr $RICH) + RECV=$(getAddr $POOR) + + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=10000mycoin --sequence=2 --to=$RECV --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + if [ $? != 0 ]; then echo "can't make tx!"; return 1; fi + + TX=`echo $RES | cut -d: -f2-` + HASH=$(echo $TX | jq .hash | tr -d \") + TX_HEIGHT=$(echo $TX | jq .height) + + # wait til we have quite a few blocks... like at least 20, + # so the query command won't just wait for the next eg. 7 blocks to verify the result + echo "waiting to generate lots of blocks..." + sleep 20 + echo "done waiting!" + + # last minute tx just at the block cut-off... + RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20000mycoin --sequence=3 --to=$RECV --name=$RICH 2>/dev/null) + txSucceeded $? "$RES" + if [ $? != 0 ]; then echo "can't make second tx!"; return 1; fi + + # now we do a restart... + stopServer $PID_SERVER + startServer $BASE_DIR/server $BASE_DIR/${SERVER_EXE}.log + if [ $? != 0 ]; then echo "can't restart server!"; return 1; fi + + # make sure queries still work properly, with all 3 tx now executed + checkAccount $SENDER "3" "9007199254710000" + checkAccount $RECV "0" "30992" + + # make sure tx is indexed + checkSendTx $HASH $TX_HEIGHT $SENDER "10000" + + # for double-check of logs + if [ -n "$DEBUG" ]; then + cat $BASE_DIR/${SERVER_EXE}.log; + fi +} + + +# load and run these tests with shunit2! +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" #get this files directory + +# load common helpers +. $DIR/common.sh + +. $DIR/shunit2 + From 0fc0a6232342feecec61ce99148648ca0e2a78e5 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 20 Jun 2017 13:52:32 +0200 Subject: [PATCH 61/73] Added restart cli test to Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 9013b038067c..786771d58001 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ test_cli: tests/cli/shunit2 # sudo apt-get install jq @./tests/cli/basictx.sh @./tests/cli/counter.sh + @./tests/cli/restart.sh @./tests/cli/ibc.sh get_vendor_deps: tools From f249748ce12bb9486a7662f82a2c975d40b1d70d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 21 Jun 2017 16:10:59 +0200 Subject: [PATCH 62/73] Update to latest merkleeyes:fix-restart-height branch --- glide.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glide.lock b/glide.lock index 8b96e92922f5..79207b4f95c3 100644 --- a/glide.lock +++ b/glide.lock @@ -139,7 +139,7 @@ imports: - commands/txs - proofs - name: github.com/tendermint/merkleeyes - version: feb2c3fadac8221f96fbfce65a63af034327f972 + version: 5df9e851e1af64b4fbc7ecab89a9735010ed30fa subpackages: - app - client From 0b81676067eea411911a0897d442e28ec98bac46 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 12:15:11 -0400 Subject: [PATCH 63/73] abci handshake --- app/app.go | 14 +++++++++++--- tests/cli/restart.sh | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/app.go b/app/app.go index 27a3b9c98acf..6f54782ff7a8 100644 --- a/app/app.go +++ b/app/app.go @@ -8,7 +8,7 @@ import ( abci "github.com/tendermint/abci/types" wire "github.com/tendermint/go-wire" eyes "github.com/tendermint/merkleeyes/client" - . "github.com/tendermint/tmlibs/common" + cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" sm "github.com/tendermint/basecoin/state" @@ -53,7 +53,15 @@ func (app *Basecoin) GetState() *sm.State { // ABCI::Info func (app *Basecoin) Info() abci.ResponseInfo { - return abci.ResponseInfo{Data: Fmt("Basecoin v%v", version.Version)} + resp, err := app.eyesCli.InfoSync() + if err != nil { + cmn.PanicCrisis(err) + } + return abci.ResponseInfo{ + Data: cmn.Fmt("Basecoin v%v", version.Version), + LastBlockHeight: resp.LastBlockHeight, + LastBlockAppHash: resp.LastBlockAppHash, + } } func (app *Basecoin) RegisterPlugin(plugin types.Plugin) { @@ -172,7 +180,7 @@ func (app *Basecoin) Commit() (res abci.Result) { app.cacheState = app.state.CacheWrap() if res.IsErr() { - PanicSanity("Error getting hash: " + res.Error()) + cmn.PanicSanity("Error getting hash: " + res.Error()) } return res } diff --git a/tests/cli/restart.sh b/tests/cli/restart.sh index dfdfe7c547b0..09187594e39a 100755 --- a/tests/cli/restart.sh +++ b/tests/cli/restart.sh @@ -69,7 +69,7 @@ test01OnRestart() { # wait til we have quite a few blocks... like at least 20, # so the query command won't just wait for the next eg. 7 blocks to verify the result echo "waiting to generate lots of blocks..." - sleep 20 + sleep 5 echo "done waiting!" # last minute tx just at the block cut-off... From 682f9ecc87f76ca2695d36a32a103452788c9cf4 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 21 Jun 2017 18:50:36 +0200 Subject: [PATCH 64/73] Cleanup after rebase --- tests/cli/common.sh | 9 +-------- tests/cli/restart.sh | 34 +++++++--------------------------- 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 12ca5d5a6fc7..4ceacd22269b 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -77,7 +77,7 @@ initServer() { return $? } -# usage: startServer SERVE_DIR SERVER_LOG +# XXX Ex Usage: startServer $SERVE_DIR $SERVER_LOG startServer() { ${SERVER_EXE} start --home=$1 >>$2 2>&1 & sleep 5 @@ -90,13 +90,6 @@ startServer() { fi } -# XXX Ex Usage: stopServer $PID_SERVER -stopServer() { - echo "stopping $SERVER_EXE test server..." - kill -9 $1 >/dev/null 2>&1 - sleep 1 -} - # XXX Ex Usage1: initClient $CHAINID # XXX Ex Usage2: initClient $CHAINID $PORTPREFIX # Desc: Initialize the client program diff --git a/tests/cli/restart.sh b/tests/cli/restart.sh index 09187594e39a..90ce98e94ef0 100755 --- a/tests/cli/restart.sh +++ b/tests/cli/restart.sh @@ -3,36 +3,16 @@ # these are two globals to control all scripts (can use eg. counter instead) SERVER_EXE=basecoin CLIENT_EXE=basecli +ACCOUNTS=(jae ethan bucky rigel igor) +RICH=${ACCOUNTS[0]} +POOR=${ACCOUNTS[4]} oneTimeSetUp() { - # these are passed in as args - BASE_DIR=$HOME/.basecoin_test_restart - CHAIN_ID=restart-chain - - rm -rf $BASE_DIR 2>/dev/null - mkdir -p $BASE_DIR - - # set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE - export BC_HOME=${BASE_DIR}/client - prepareClient - - # start basecoin server (with counter) - initServer $BASE_DIR $CHAIN_ID 3456 - if [ $? != 0 ]; then return 1; fi - - initClient $CHAIN_ID 34567 - - echo "...Testing may begin!" - echo - echo - echo + quickSetup .basecoin_test_restart restart-chain } oneTimeTearDown() { - echo - echo - stopServer $PID_SERVER + quickTearDown } test00PreRestart() { @@ -53,7 +33,6 @@ test00PreRestart() { } - test01OnRestart() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) @@ -78,11 +57,12 @@ test01OnRestart() { if [ $? != 0 ]; then echo "can't make second tx!"; return 1; fi # now we do a restart... - stopServer $PID_SERVER + quickTearDown startServer $BASE_DIR/server $BASE_DIR/${SERVER_EXE}.log if [ $? != 0 ]; then echo "can't restart server!"; return 1; fi # make sure queries still work properly, with all 3 tx now executed + echo "Checking state after restart..." checkAccount $SENDER "3" "9007199254710000" checkAccount $RECV "0" "30992" From aa18ff4c4c99dde242f239f4356a5f48feaa4c0d Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 21 Jun 2017 20:13:54 +0200 Subject: [PATCH 65/73] Update go-crypto with keys seedphrase, better testable password prompts --- Makefile | 2 +- glide.lock | 33 +++++++++++++++++++-------------- tests/cli/basictx.sh | 9 ++++----- tests/cli/common.sh | 4 ++-- tests/cli/counter.sh | 10 ++++------ tests/cli/ibc.sh | 12 +++++------- tests/cli/restart.sh | 14 ++++++-------- 7 files changed, 41 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index 786771d58001..ea93496b7c4c 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ tests/cli/shunit2: -q -O tests/cli/shunit2 tools: - go get -u -v $(GOTOOLS) + @go get $(GOTOOLS) clean: # maybe cleaning up cache and vendor is overkill, but sometimes diff --git a/glide.lock b/glide.lock index 79207b4f95c3..461e15df802e 100644 --- a/glide.lock +++ b/glide.lock @@ -1,12 +1,14 @@ hash: 6eb1119dccf2ab4d0adb870a14cb4408047119be53c8ec4afeaa281bd1d2b457 -updated: 2017-06-20T20:55:16.122030554-04:00 +updated: 2017-06-21T19:51:10.330315159+02:00 imports: - name: github.com/bgentry/speakeasy version: 4aabc24848ce5fd31929f7d1e4ea74d3709c14cd - name: github.com/btcsuite/btcd - version: 1ae306021e323ae11c71ffb8546fbd9019e6cb6f + version: b8df516b4b267acf2de46be593a9d948d1d2c420 subpackages: - btcec +- name: github.com/btcsuite/fastsha256 + version: 637e656429416087660c84436a2a035d69d54e2e - name: github.com/BurntSushi/toml version: b26d9c308763d68093482582cea63d69be07a0f0 - name: github.com/ebuchman/fail-test @@ -28,7 +30,7 @@ imports: - name: github.com/go-playground/universal-translator version: 71201497bace774495daed26a3874fd339e0b538 - name: github.com/go-stack/stack - version: 7a2f19628aabfe68f0766b59e74d6315f8347d22 + version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf version: b50ceb1fa9818fa4d78b016c2d4ae025593a7ce3 subpackages: @@ -45,7 +47,7 @@ imports: - name: github.com/gorilla/websocket version: a91eba7f97777409bc2c443f5534d41dd20c5720 - name: github.com/hashicorp/hcl - version: 392dba7d905ed5d04a5794ba89f558b27e2ba1ca + version: a4b07c25de5ff55ad3b8936cea69a79a3d95a855 subpackages: - hcl/ast - hcl/parser @@ -63,6 +65,8 @@ imports: version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/magiconair/properties version: 51463bfca2576e06c62a8504b5c0f06d61312647 +- name: github.com/mattn/go-isatty + version: 9622e0cc9d8f9be434ca605520ff9a16808fee47 - name: github.com/mitchellh/mapstructure version: cc8532a8e9a55ea36402aa21efdf403a60d34096 - name: github.com/pelletier/go-buffruneio @@ -78,11 +82,11 @@ imports: - name: github.com/spf13/cast version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4 - name: github.com/spf13/cobra - version: 3454e0e28e69c1b8effa6b5123c8e4185e20d696 + version: db6b9a8b3f3f400c8ecb4a4d7d02245b8facad66 - name: github.com/spf13/jwalterweatherman - version: 8f07c835e5cc1450c082fe3a439cf87b0cbb2d99 + version: fa7ca7e836cf3a8bb4ebf799f472c12d7e903d66 - name: github.com/spf13/pflag - version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 + version: 80fe0fb4eba54167e2ccae1c6c950e72abf61b73 - name: github.com/spf13/viper version: 0967fc9aceab2ce9da34061253ac10fb99bba5b2 - name: github.com/syndtr/goleveldb @@ -113,7 +117,7 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: 7dff40942a64cdeefefa9446b2d104750b349f8a + version: ad70b2222698a2018c4bf18bab86f3727621f492 subpackages: - cmd - keys @@ -121,13 +125,14 @@ imports: - keys/server - keys/server/types - keys/storage/filestorage + - keys/wordlist - name: github.com/tendermint/go-wire version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb subpackages: - data - data/base58 - name: github.com/tendermint/light-client - version: 5ba3d0bce406b4b4ce694ca4387b9d086ac0c10f + version: b66b57d193d2fdeda7b999aebfdc9531cbee39b0 subpackages: - certifiers - certifiers/client @@ -139,7 +144,7 @@ imports: - commands/txs - proofs - name: github.com/tendermint/merkleeyes - version: 5df9e851e1af64b4fbc7ecab89a9735010ed30fa + version: ce7de05896f560ddcc9207f65fea9901835dd238 subpackages: - app - client @@ -185,7 +190,7 @@ imports: - logger - merkle - name: golang.org/x/crypto - version: ab89591268e0c8b748cbe4047b00197516011af5 + version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e subpackages: - curve25519 - nacl/box @@ -206,7 +211,7 @@ imports: - lex/httplex - trace - name: golang.org/x/sys - version: 9c9d83fe39ed3fd2d9249fcf6b755891fff54b03 + version: 9ccfe848b9db8435a24c424abbc07a921adf1df5 subpackages: - unix - name: golang.org/x/text @@ -242,7 +247,7 @@ imports: version: cd8b52f8269e0feb286dfeef29f8fe4d5b397e0b testImports: - name: github.com/davecgh/go-spew - version: 04cdfd42973bb9c8589fd6a731800cf222fde1a9 + version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 subpackages: - spew - name: github.com/pmezard/go-difflib @@ -250,7 +255,7 @@ testImports: subpackages: - difflib - name: github.com/stretchr/testify - version: 4d4bfba8f1d1027c4fdbe371823030df51419987 + version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0 subpackages: - assert - require diff --git a/tests/cli/basictx.sh b/tests/cli/basictx.sh index 4297bffa0108..58f27ceba7e4 100755 --- a/tests/cli/basictx.sh +++ b/tests/cli/basictx.sh @@ -31,11 +31,10 @@ test01SendTx() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) - assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 2>/dev/null" - assertFalse "bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null" - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) - txSucceeded $? "$RES" - TX=`echo $RES | cut -d: -f2-` + assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1" + assertFalse "bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH" + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH) + txSucceeded $? "$TX" HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) diff --git a/tests/cli/common.sh b/tests/cli/common.sh index 4ceacd22269b..576bef0a48a9 100644 --- a/tests/cli/common.sh +++ b/tests/cli/common.sh @@ -137,11 +137,11 @@ checkAccount() { return $? } -# XXX Ex Usage: txSucceeded $? "$RES" +# XXX Ex Usage: txSucceeded $? "$TX" # Desc: Must be called right after the `tx` command, makes sure it got a success response txSucceeded() { if (assertTrue "sent tx: $2" $1); then - TX=`echo $2 | cut -d: -f2-` # strip off first line asking for password + TX=$2 assertEquals "good check: $TX" "0" $(echo $TX | jq .check_tx.code) assertEquals "good deliver: $TX" "0" $(echo $TX | jq .deliver_tx.code) else diff --git a/tests/cli/counter.sh b/tests/cli/counter.sh index e819fef81fe0..28ade7466c14 100755 --- a/tests/cli/counter.sh +++ b/tests/cli/counter.sh @@ -33,9 +33,8 @@ test01SendTx() { assertFalse "missing dest" "${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 2>/dev/null" assertFalse "bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null" - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) - txSucceeded $? "$RES" - TX=`echo $RES | cut -d: -f2-` + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) + txSucceeded $? "$TX" HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) @@ -65,9 +64,8 @@ test03AddCount() { SENDER=$(getAddr $RICH) assertFalse "bad password" "echo hi | ${CLIENT_EXE} tx counter --amount=1000mycoin --sequence=2 --name=${RICH} 2>/dev/null" - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --amount=10mycoin --sequence=2 --name=${RICH} --valid --countfee=5mycoin 2>/dev/null) - txSucceeded $? "$RES" - TX=`echo $RES | cut -d: -f2-` + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx counter --amount=10mycoin --sequence=2 --name=${RICH} --valid --countfee=5mycoin) + txSucceeded $? "$TX" HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) diff --git a/tests/cli/ibc.sh b/tests/cli/ibc.sh index 7afda2d8f67f..9819f5d87db5 100755 --- a/tests/cli/ibc.sh +++ b/tests/cli/ibc.sh @@ -89,15 +89,13 @@ test01SendIBCTx() { SENDER=$(BC_HOME=${CLIENT_1} getAddr $RICH) RECV=$(BC_HOME=${CLIENT_2} getAddr $POOR) - # we have to remove the password request from stdout, to just get the json export BC_HOME=${CLIENT_1} - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20002mycoin \ - --sequence=1 --to=${CHAIN_ID_2}/${RECV} --name=$RICH 2>/dev/null) - txSucceeded $? "$RES" + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20002mycoin \ + --sequence=1 --to=${CHAIN_ID_2}/${RECV} --name=$RICH) + txSucceeded $? "$TX" # an example to quit early if there is no point in more tests if [ $? != 0 ]; then echo "aborting!"; return 1; fi - TX=`echo $RES | cut -d: -f2-` HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) @@ -142,7 +140,7 @@ startRelay() { export BC_HOME=${CLIENT_1} SENDER=$(getAddr $RICH) RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin \ - --sequence=$1 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) + --sequence=$1 --to=$RELAY_ADDR --name=$RICH) txSucceeded $? "$RES" if [ $? != 0 ]; then echo "can't pay chain1!"; return 1; fi @@ -150,7 +148,7 @@ startRelay() { export BC_HOME=${CLIENT_2} SENDER=$(getAddr $RICH) RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=100000mycoin \ - --sequence=$2 --to=$RELAY_ADDR --name=$RICH 2>/dev/null) + --sequence=$2 --to=$RELAY_ADDR --name=$RICH) txSucceeded $? "$RES" if [ $? != 0 ]; then echo "can't pay chain2!"; return 1; fi diff --git a/tests/cli/restart.sh b/tests/cli/restart.sh index 90ce98e94ef0..fb387a701417 100755 --- a/tests/cli/restart.sh +++ b/tests/cli/restart.sh @@ -19,9 +19,8 @@ test00PreRestart() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH 2>/dev/null) - txSucceeded $? "$RES" - TX=`echo $RES | cut -d: -f2-` + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992mycoin --sequence=1 --to=$RECV --name=$RICH) + txSucceeded $? "$TX" HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) @@ -37,11 +36,10 @@ test01OnRestart() { SENDER=$(getAddr $RICH) RECV=$(getAddr $POOR) - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=10000mycoin --sequence=2 --to=$RECV --name=$RICH 2>/dev/null) - txSucceeded $? "$RES" + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=10000mycoin --sequence=2 --to=$RECV --name=$RICH) + txSucceeded $? "$TX" if [ $? != 0 ]; then echo "can't make tx!"; return 1; fi - TX=`echo $RES | cut -d: -f2-` HASH=$(echo $TX | jq .hash | tr -d \") TX_HEIGHT=$(echo $TX | jq .height) @@ -52,8 +50,8 @@ test01OnRestart() { echo "done waiting!" # last minute tx just at the block cut-off... - RES=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20000mycoin --sequence=3 --to=$RECV --name=$RICH 2>/dev/null) - txSucceeded $? "$RES" + TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=20000mycoin --sequence=3 --to=$RECV --name=$RICH) + txSucceeded $? "$TX" if [ $? != 0 ]; then echo "can't make second tx!"; return 1; fi # now we do a restart... From e94ea207064c7a10a6135833222a54bc8f886d62 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 21 Jun 2017 20:21:07 +0200 Subject: [PATCH 66/73] Super rough summary of key recovery - please complete --- docs/guide/key-management.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/guide/key-management.md diff --git a/docs/guide/key-management.md b/docs/guide/key-management.md new file mode 100644 index 000000000000..50a99899d0c2 --- /dev/null +++ b/docs/guide/key-management.md @@ -0,0 +1,20 @@ +# Key Management + +Here we explain a bit how to real with your keys, using the `basecli keys` subcommand. + +**TODO** + +## Creating keys + +Create the keys and store a key phrase. No other way to recover it. + +``` +SEED=$(echo 1234567890 | basecli keys new fred -o json | jq .seed | tr -d \") +echo $SEED +(echo qwertyuiop; echo $SEED stamp) | basecli keys recover oops +(echo qwertyuiop; echo $SEED) | basecli keys recover derf +basecli keys get fred -o json +basecli keys get derf -o json +``` + +You can type it in to recover... try to do this by hand. From da384487bb35fc8c23fd637719ce9c60b87913c0 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 21 Jun 2017 16:34:48 -0400 Subject: [PATCH 67/73] docs: ibc guide all in one terminal --- docs/guide/ibc.md | 199 ++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 102 deletions(-) diff --git a/docs/guide/ibc.md b/docs/guide/ibc.md index 6a467edfacf7..8036a84cb688 100644 --- a/docs/guide/ibc.md +++ b/docs/guide/ibc.md @@ -205,146 +205,148 @@ If you have any trouble with this, you can also look at the [test scripts](/tests/cli/ibc.sh) or just run `make test_cli` in basecoin repo. Otherwise, open up 5 (yes 5!) terminal tabs.... -### Setup Chain 1 - -All commands will be prefixed by the name of the terminal window in which to -run it... +### Preliminaries ``` # first, clean up any old garbage for a fresh slate... rm -rf ~/.ibcdemo/ ``` -Set up some accounts so we can init everything nicely: +Let's start by setting up some environment variables and aliases: -**Client1** ``` -export BCHOME=~/.ibcdemo/chain1/client -CHAIN_ID=test-chain-1 -PORT=12347 -basecli keys new money -basecli keys new gotnone +export BCHOME1_CLIENT=~/.ibcdemo/chain1/client +export BCHOME1_SERVER=~/.ibcdemo/chain1/server +export BCHOME2_CLIENT=~/.ibcdemo/chain2/client +export BCHOME2_SERVER=~/.ibcdemo/chain2/server +alias basecli1="basecli --home $BCHOME1_CLIENT" +alias basecli2="basecli --home $BCHOME2_CLIENT" +alias basecoin1="basecoin --home $BCHOME1_SERVER" +alias basecoin2="basecoin --home $BCHOME2_SERVER" ``` -Prepare the genesis block and start the server: +This will give us some new commands to use instead of raw `basecli` and `basecoin` to ensure we're using the right configuration for the chain we want to talk to. + +We also want to set some chain IDs: -**Server1** ``` -# set up the directory, chainid and port of this chain... -export BCHOME=~/.ibcdemo/chain1/server -CHAIN_ID=test-chain-1 -PREFIX=1234 -basecoin init $(basecli keys get money | awk '{print $2}') +export CHAINID1="test-chain-1" +export CHAINID2="test-chain-2" +``` -sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml +And since we will run two different chains on one machine, we need to maintain different sets of ports: -basecoin start +``` +export PORT_PREFIX1=1234 +export PORT_PREFIX2=2345 +export RPC_PORT1=${PORT_PREFIX1}7 +export RPC_PORT2=${PORT_PREFIX2}7 ``` -Attach the client to the chain and confirm state. The first account should -have money, the second none: +### Setup Chain 1 + +Now, let's create some keys that we can use for accounts on test-chain-1: -**Client1** ``` -basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} -ME=$(basecli keys get money | awk '{print $2}') -YOU=$(basecli keys get gotnone | awk '{print $2}') -basecli query account $ME -basecli query account $YOU +basecli1 keys new money +basecli1 keys new gotnone +export MONEY=$(basecli1 keys get money | awk '{print $2}') +export GOTNONE=$(basecli1 keys get gotnone | awk '{print $2}') +``` + +and create an initial configuration giving lots of coins to the $MONEY key: + +``` +basecoin1 init --chain-id $CHAINID1 $MONEY +``` + +Now start basecoin: + +``` +sed -ie "s/4665/$PORT_PREFIX1/" $BCHOME1_SERVER/config.toml + +basecoin1 start &> basecoin1.log & +``` + +Note the `sed` command to replace the ports in the config file. +You can follow the logs with `tail -f basecoin1.log` + +Now we can attach the client to the chain and verify the state. +The first account should have money, the second none: + +``` +basecli1 init --chain-id=$CHAINID1 --node=tcp://localhost:${RPC_PORT1} +basecli1 query account $MONEY +basecli1 query account $GOTNONE ``` ### Setup Chain 2 -This is the same as above, except in two new terminal windows with -different chain ids, ports, etc. Note that you need to make new accounts -on this chain, as the "cool" key only has money on chain 1. +This is the same as above, except with `basecli2`, `basecoin2`, and `$CHAINID2`. +We will also need to change the ports, since we're running another chain on the same local machine. +Let's create new keys for test-chain-2: -**Client2** ``` -export BCHOME=~/.ibcdemo/chain2/client -CHAIN_ID=test-chain-2 -PORT=23457 -basecli keys new moremoney -basecli keys new broke +basecli2 keys new moremoney +basecli2 keys new broke +MOREMONEY=$(basecli2 keys get moremoney | awk '{print $2}') +BROKE=$(basecli2 keys get broke | awk '{print $2}') ``` -Prepare the genesis block and start the server: +And prepare the genesis block, and start the server: -**Server2** ``` -# set up the directory, chainid and port of this chain... -export BCHOME=~/.ibcdemo/chain2/server -CHAIN_ID=test-chain-2 -PREFIX=2345 -basecoin init $(basecli keys get moremoney | awk '{print $2}') +basecoin2 init --chain-id $CHAINID2 $(basecli2 keys get moremoney | awk '{print $2}') -sed -ie "s/4665/$PREFIX/" $BCHOME/config.toml +sed -ie "s/4665/$PORT_PREFIX2/" $BCHOME2_SERVER/config.toml -basecoin start +basecoin2 start &> basecoin2.log & ``` -Attach the client to the chain and confirm state. The first account should -have money, the second none: +Now attach the client to the chain and verify the state. +The first account should have money, the second none: -**Client2** ``` -basecli init --chain-id=${CHAIN_ID} --node=tcp://localhost:${PORT} -ME=$(basecli keys get moremoney | awk '{print $2}') -YOU=$(basecli keys get broke | awk '{print $2}') -basecli query account $ME -basecli query account $YOU +basecli2 init --chain-id=$CHAINID2 --node=tcp://localhost:${RPC_PORT2} +basecli2 query account $MOREMONEY +basecli2 query account $BROKE ``` ### Connect these chains -Great, so we have two chains running on your local machine, with different -keys on each. Now it is time to hook them up together. Let's start -a relay to forward the messages. +OK! So we have two chains running on your local machine, with different +keys on each. Let's hook them up together by starting a relay process to +forward messages from one chain to the other. The relay account needs some money in it to pay for the ibc messages, so for now, we have to transfer some cash from the rich accounts before we start the actual relay. -**Client1** ``` # note that this key.json file is a hardcoded demo for all chains, this will # be updated in a future release -RELAY_KEY=${BCHOME}/../server/key.json +RELAY_KEY=$BCHOME1_SERVER/key.json RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") -basecli tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=money -basecli query account $RELAY_ADDR -``` -**Client2** -``` -# note that this key.json file is a hardcoded demo for all chains, this will -# be updated in a future release -RELAY_KEY=${BCHOME}/../server/key.json -RELAY_ADDR=$(cat $RELAY_KEY | jq .address | tr -d \") -basecli tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney -basecli query account $RELAY_ADDR -``` +basecli1 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR--name=money +basecli1 query account $RELAY_ADDR -**Relay** +basecli2 tx send --amount=100000mycoin --sequence=1 --to=$RELAY_ADDR --name=moremoney +basecli2 query account $RELAY_ADDR ``` -# lots of config... -SERVER_1=~/.ibcdemo/chain1/server -SERVER_2=~/.ibcdemo/chain2/server -CHAIN_ID_1=test-chain-1 -CHAIN_ID_2=test-chain-2 -PORT_1=12347 -PORT_2=23457 -RELAY_KEY=${SERVER_1}/key.json -basecoin relay init --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ - --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ - --genesis1=${SERVER_1}/genesis.json --genesis2=${SERVER_2}/genesis.json \ - --from=$RELAY_KEY +Now we can start the relay process. -basecoin relay start --chain1-id=$CHAIN_ID_1 --chain2-id=$CHAIN_ID_2 \ - --chain1-addr=tcp://localhost:${PORT_1} --chain2-addr=tcp://localhost:${PORT_2} \ +``` +basecoin relay init --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \ + --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \ + --genesis1=${BCHOME1_SERVER}/genesis.json --genesis2=${BCHOME2_SERVER}/genesis.json \ --from=$RELAY_KEY + +basecoin relay start --chain1-id=$CHAINID1 --chain2-id=$CHAINID2 \ + --chain1-addr=tcp://localhost:${RPC_PORT1} --chain2-addr=tcp://localhost:${RPC_PORT2} \ + --from=$RELAY_KEY &> relay.log & ``` This should start up the relay, and assuming no error messages came out, @@ -356,33 +358,26 @@ our first tx accross the chains... The hard part is over, we set up two blockchains, a few private keys, and a secure relay between them. Now we can enjoy the fruits of our labor... -**Client2** - ``` -# this should be empty -basecli query account $YOU -# now, we get the key to copy to the other terminal -echo $YOU +# Here's an emptt account on test-chain-2 +basecli2 query account $BROKE ``` -**Client1** - ``` -# set TARGET to be $YOU from the other chain -basecli tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$TARGET --name=money +# Let's send some funds from test-chain-1 +basecli1 tx send --amount=12345mycoin --sequence=2 --to=test-chain-2/$BROKE --name=money ``` -**Client2** - ``` # give it time to arrive... -sleep 1 +sleep 2 # now you should see 12345 coins! -basecli query account $YOU +basecli2 query account $BROKE ``` -Cool, huh? Now have fun exploring and sending coins across the chains. And -making more accounts as you want to. +You're no longer broke! Cool, huh? +Now have fun exploring and sending coins across the chains. +And making more accounts as you want to. ## Conclusion From c9b02909dce1db5e10538710a41085e71d4b2fca Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 22 Jun 2017 12:54:05 +0200 Subject: [PATCH 68/73] Add roadmap to repo --- ROADMAP.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 000000000000..40741ce3f579 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,66 @@ +# Roadmap for future basecoin development + +Warning: there are current plans, they may change based on other developments, needs. The further in the future, the less clear, like all plans. + +## 0.6.x - Testnet and Light Client (late June 2017) + +The current release cycle is making sure the server is usable for deploying testnets (easy config, safe restarts, moving nodes). Also that we have a useable light client that does full cryptographic prooofs without syncing the entire block headers. See the [changelog](CHANGELOG.md). + +Patch release here involve improving the usability of the cli tools, adding subcommands, more flags, helper functions, shell integrations, etc. Please add issues if you find the client tool difficult to use, or deployment troublesome. + +## 0.7.x - Towards a modular framework (late July 2017) + +**Breaking changes** + +* Renaming likely this release may well lead to a renaming of the repository to emphasize that it is a generalized framework. `basecoin` and `basecli` executables will remain with generally unchanged usage. +* This will also provide a tx structure that is very different than the current one, and a non-trivial upgrade of running chains. + +The next release cycle involves a big upgrade to the core, especially how one can write modules (aka plugins) as well as configure a basecoin-based executable. The main goal is to leave us with basecoin as a single executable with a similar API, but create a new module/middleware system with a number of standard modules provided (and easy addition of third party modules), so developers can quickly mix-and-match pieces and add custom business logic for there chain. + +The main goal here is to migrate from a basecoin with plugins for extra enhancements, to a proper app development framework, of which basecoin is one example app that can quickly be built. + +Some ideas: + +* Flexible fee/gas system (good for both public and private blockchains) +* Flexible authentication systems (with multi-sig support) +* Basic role permission system +* Abstract IBC to support other transactions from various modules (not just sendtx) + +This will be done in conjunction with some sample apps also building on this framework, where other logic is interesting and money transfers is not the central goal, like [trackomatron](https://github.com/tendermint/trackomatron) + +## Next steps + +The following are three planned steps, the order of which may change. At least one or two of these will most likely occur before any other developments. Clearly, any other feature that + +### ?? - Local client API for UI + +Beyond the CLI, we want to add more interfaces for easily building a UI on top of the basecoin client. One clear example is a local REST API, so you can easily integrate with an electron app, or a chrome app, just as if you wrote a normal Single-Page Application, but connecting to a local proxy to do full crypto-graphic proofs. + +Another **possible** development is providing an SDK, which we can compile with [go-mobile](https://github.com/golang/go/wiki/Mobile) for both Android and iOS to support secure mobile applications. Progress on this front is contingent on participation of an experienced mobile developer. + +Further, when the planned enhancements to real-time events happen in tendermint core, we should expose that via a simple subscriber/listener model in these local APIs. + +### ?? - Proof of Stake and Voting Modules + +We should integrate developments on a [proof-of-stake module](https://github.com/tendermint/basecoin-stake) (currently a work-in-progress) and basic voting modules (currently planned) into properly supported for modules. These would provide the basis for dynamic validator set changes with bondign periods, and the basis for making governance decisions (eg. voting to change the block reward). + +At this point we would have to give full support to these plugins, and third-party devs can build on them to add more complex delegation or governance logic. + +### ?? - Database enhancements + +Depending on developments with merkleeyes, we would like to increase the expressiveness of the storage layer while maintaining provability of all queries. We would also add a number of new primatives to the key-value store, to allow some general data-structures. + +Also, full support for historical queries and performance optimizations of the storage later. But this all depends on supporting developments of another repo, so timing here is unclear. Here are some example ideas: + +Merkle proofs: + +* **Proof of key-value**: only current proof +* **Proof of missing key**: prove there is no data for that key +* **Proof of range**: one proof for all key-values in a range of keys +* **Proof of highest/lowest in range**: just get one key, for example, prove validator hash with highest height <= H + +Data structures: + +* **Queues**: provable push-pop operations, split over multiple keys, so it can scale to 1000s of entries without deserializing them all every time. +* **Priority Queues**: as above, but ordered by priority instead of FIFO. +* **Secondary Indexes**: add support for secondary indexes with proofs. So, I can not only prove my balance, but for example, the list of all accouns with a balance of > 1000000 atoms. These indexes would have to be created by the application and stored extra in the database, but if you have a common query that you want proofs/trust, it can be very useful. From 5d147d1673bc138e1e564afcc270fc45b95afca2 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 22 Jun 2017 13:04:47 +0200 Subject: [PATCH 69/73] Add thoughts on a release process --- RELEASE.md | 33 +++++++++++++++++++++++++++++++++ ROADMAP.md | 10 +++++----- 2 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 000000000000..8c765be2d241 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,33 @@ +# Release Process + +Basecoin is the heart of most demo apps and the testnets, but the last few releases have been a little chaotic. In order to guarantee a higher, production-quality release in the future, we will work on a release process to check before the push to master. This is a work-in-progress and should be trialed on the 0.6.x patches, and used for the 0.7.0 release. + +This is a rough-guide. Please add comments here, let's try it out for 0.6.1 and see what is annoying and useless, and what is missing and useful. + +## Preparation + +* Clarify scope of release +* Create issues +* Write code +* Update CHANGELOG +* Create PR for release +* Update version + +## QA + +Once we have a PR for the release and think it is ready, we should test it out internally: + +* Code review (in addition to individual code reviews on the merged issue) +* Manual run-through of tutorials (and feedback on bad UX) +* Deployment of a private testnet, multiple users test out manually (feedback on bugs, or annoying UX) +* Test out upgrading existing testnet from last version, document or add tools for easier upgrade. +* If outstanding issues here, fix the issues, and repeat. + +## Release + +Once QA passes, we need to orchestrate the release. + +* Merge to master +* Set all glide dependencies to proper master versions of repos +* Push code with new version tag +* Upgrade our public-facing testnets with the latest versions diff --git a/ROADMAP.md b/ROADMAP.md index 40741ce3f579..9e344eb62f26 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,7 +12,7 @@ Patch release here involve improving the usability of the cli tools, adding subc **Breaking changes** -* Renaming likely this release may well lead to a renaming of the repository to emphasize that it is a generalized framework. `basecoin` and `basecli` executables will remain with generally unchanged usage. +* Renaming likely: this release may well lead to a [renaming of the repository](https://github.com/tendermint/basecoin/issues/119) to emphasize that it is a generalized framework. `basecoin` and `basecli` executables will remain with generally unchanged usage. * This will also provide a tx structure that is very different than the current one, and a non-trivial upgrade of running chains. The next release cycle involves a big upgrade to the core, especially how one can write modules (aka plugins) as well as configure a basecoin-based executable. The main goal is to leave us with basecoin as a single executable with a similar API, but create a new module/middleware system with a number of standard modules provided (and easy addition of third party modules), so developers can quickly mix-and-match pieces and add custom business logic for there chain. @@ -30,9 +30,9 @@ This will be done in conjunction with some sample apps also building on this fra ## Next steps -The following are three planned steps, the order of which may change. At least one or two of these will most likely occur before any other developments. Clearly, any other feature that +The following are three planned steps, the order of which may change. At least one or two of these will most likely occur before any other developments. Clearly, any other feature that are urgent for cosmos can jump the list in priority, but all these pieces are part of the cosmos roadmap, especially the first two. -### ?? - Local client API for UI +### 0.8.x??? - Local client API for UI Beyond the CLI, we want to add more interfaces for easily building a UI on top of the basecoin client. One clear example is a local REST API, so you can easily integrate with an electron app, or a chrome app, just as if you wrote a normal Single-Page Application, but connecting to a local proxy to do full crypto-graphic proofs. @@ -40,13 +40,13 @@ Another **possible** development is providing an SDK, which we can compile with Further, when the planned enhancements to real-time events happen in tendermint core, we should expose that via a simple subscriber/listener model in these local APIs. -### ?? - Proof of Stake and Voting Modules +### 0.9.x??? - Proof of Stake and Voting Modules We should integrate developments on a [proof-of-stake module](https://github.com/tendermint/basecoin-stake) (currently a work-in-progress) and basic voting modules (currently planned) into properly supported for modules. These would provide the basis for dynamic validator set changes with bondign periods, and the basis for making governance decisions (eg. voting to change the block reward). At this point we would have to give full support to these plugins, and third-party devs can build on them to add more complex delegation or governance logic. -### ?? - Database enhancements +### 0.10.x??? - Database enhancements Depending on developments with merkleeyes, we would like to increase the expressiveness of the storage layer while maintaining provability of all queries. We would also add a number of new primatives to the key-value store, to allow some general data-structures. From f5e96a8d31db61f07328ef7850cddd0d6d991d5c Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 22 Jun 2017 16:21:59 +0200 Subject: [PATCH 70/73] Bump version to 0.6.0, add to basecli command --- cmd/basecli/main.go | 5 ++++- version/version.go | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/basecli/main.go b/cmd/basecli/main.go index 0506882a279b..50e47cb1bafa 100644 --- a/cmd/basecli/main.go +++ b/cmd/basecli/main.go @@ -14,6 +14,7 @@ import ( "github.com/tendermint/tmlibs/cli" bcmd "github.com/tendermint/basecoin/cmd/basecli/commands" + coincmd "github.com/tendermint/basecoin/cmd/basecoin/commands" ) // BaseCli represents the base command when called without any subcommands @@ -51,7 +52,9 @@ func main() { seeds.RootCmd, pr, tr, - proxy.RootCmd) + proxy.RootCmd, + coincmd.VersionCmd, + ) cmd := cli.PrepareMainCmd(BaseCli, "BC", os.ExpandEnv("$HOME/.basecli")) cmd.Execute() diff --git a/version/version.go b/version/version.go index a45ea4e72d83..8e82ffaffeae 100644 --- a/version/version.go +++ b/version/version.go @@ -1,7 +1,7 @@ package version const Maj = "0" -const Min = "5" -const Fix = "2" +const Min = "6" +const Fix = "0" -const Version = "0.5.2" +const Version = "0.6.0" From 19999ea51751f461c2d5c0f9a8405f33dfac0c28 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 22 Jun 2017 20:32:22 -0400 Subject: [PATCH 71/73] ibc: UpdateChain fix blockid --- plugins/ibc/ibc.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/plugins/ibc/ibc.go b/plugins/ibc/ibc.go index eb8a27f1b096..3a9b0f8c6e79 100644 --- a/plugins/ibc/ibc.go +++ b/plugins/ibc/ibc.go @@ -570,7 +570,17 @@ func verifyCommit(chainState BlockchainState, header *tm.Header, commit *tm.Comm chainID := chainState.ChainID vals := chainState.Validators valSet := tm.NewValidatorSet(vals) - blockID := commit.Precommits[0].BlockID // XXX: incorrect + + var blockID tm.BlockID + for _, pc := range commit.Precommits { + // XXX: incorrect. we want the one for +2/3, not just the first one + if pc != nil { + blockID = pc.BlockID + } + } + if blockID.IsZero() { + return errors.New("All precommits are nil!") + } // NOTE: Currently this only works with the exact same validator set. // Not this, but perhaps "ValidatorSet.VerifyCommitAny" should expose From 9627b7cd60fae52a431f61e1fbfcfae693867d08 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Thu, 22 Jun 2017 22:43:47 -0400 Subject: [PATCH 72/73] update changelog --- CHANGELOG.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0c77c03bc60..fdd0e7a5840a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,12 @@ # Changelog -## 0.6.0 (???) +## 0.6.0 (June 22, 2017) Make the basecli command the only way to use client-side, to enforce best security practices. Lots of enhancements to get it up to production quality. BREAKING CHANGES: +- ./cmd/commands -> ./cmd/basecoin/commands - basecli - `basecli proof state get` -> `basecli query key` - `basecli proof tx get` -> `basecli query tx` @@ -27,6 +28,8 @@ BREAKING CHANGES: - relay init registers both chains on one another (to set it up so relay start just works) - docs - removed `example-plugin`, put `counter` inside `docs/guide` +- app + - Implements ABCI handshake by proxying merkleeyes.Info() ENHANCEMENTS: - `basecoin init` support `--chain-id` @@ -37,9 +40,9 @@ ENHANCEMENTS: - just `make fresh` when things are getting stale ;) BUG FIXES: -- no longer panics on missing app_options in genesis (thanks, anton) -- updated all docs... again - +- app: no longer panics on missing app_options in genesis (thanks, anton) +- docs: updated all docs... again +- ibc: fix panic on getting BlockID from commit without 100% precommits (still a TODO) ## 0.5.2 (June 2, 2017) From 3747f23a25ab14e5f46efaf1fcc344acbe7e5641 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 23 Jun 2017 09:24:08 +0200 Subject: [PATCH 73/73] Add basecli to packaging script --- scripts/dist_build.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/dist_build.sh b/scripts/dist_build.sh index f1566c8997f3..4268a7633fee 100755 --- a/scripts/dist_build.sh +++ b/scripts/dist_build.sh @@ -25,7 +25,7 @@ make tools make get_vendor_deps # Build! -echo "==> Building..." +echo "==> Building basecoin..." "$(which gox)" \ -os="${XC_OS}" \ -arch="${XC_ARCH}" \ @@ -35,6 +35,16 @@ echo "==> Building..." -tags="${BUILD_TAGS}" \ github.com/tendermint/basecoin/cmd/basecoin +echo "==> Building basecli..." +"$(which gox)" \ + -os="${XC_OS}" \ + -arch="${XC_ARCH}" \ + -osarch="!darwin/arm !solaris/amd64 !freebsd/amd64" \ + -ldflags "-X ${GIT_IMPORT}.GitCommit='${GIT_COMMIT}' -X ${GIT_IMPORT}.GitDescribe='${GIT_DESCRIBE}'" \ + -output "build/pkg/{{.OS}}_{{.Arch}}/basecli" \ + -tags="${BUILD_TAGS}" \ + github.com/tendermint/basecoin/cmd/basecli + # Zip all the files. echo "==> Packaging..." for PLATFORM in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type d); do