From 15cd7fb1e3b75c436b6dee89a44db35f3d265bd0 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 4 Oct 2017 00:06:46 +0400 Subject: [PATCH 01/28] fix comment [ci skip] --- example/dummy/persistent_dummy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index d392be53c..a8bfbcf02 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -67,7 +67,7 @@ func (app *PersistentDummyApplication) SetOption(key string, value string) (log return app.app.SetOption(key, value) } -// tx is either "key=value" or just arbitrary bytes +// tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result { // if it starts with "val:", update the validator set // format is "val:pubkey/power" From 46d94f83259b5a3985a1c001a96276c1a901902d Mon Sep 17 00:00:00 2001 From: Emmanuel Odeke Date: Tue, 17 Oct 2017 22:08:17 -0600 Subject: [PATCH 02/28] socketClient: fix and test for StopForError deadlock Fixes https://github.com/tendermint/abci/issues/114. Fix and test for StopForError deadlock due to accidental Mutex misuse. The test should return instantenously if StopForError works without erraneous contention, lest it regressed. --- client/socket_client.go | 2 +- client/socket_client_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 client/socket_client_test.go diff --git a/client/socket_client.go b/client/socket_client.go index fd9d0ae9a..1045dea78 100644 --- a/client/socket_client.go +++ b/client/socket_client.go @@ -97,11 +97,11 @@ func (cli *socketClient) OnStop() { // Stop the client and set the error func (cli *socketClient) StopForError(err error) { - cli.mtx.Lock() if !cli.IsRunning() { return } + cli.mtx.Lock() if cli.err == nil { cli.err = err } diff --git a/client/socket_client_test.go b/client/socket_client_test.go new file mode 100644 index 000000000..814d5a68c --- /dev/null +++ b/client/socket_client_test.go @@ -0,0 +1,28 @@ +package abcicli_test + +import ( + "errors" + "testing" + "time" + + "github.com/tendermint/abci/client" +) + +func TestSocketClientStopForErrorDeadlock(t *testing.T) { + c := abcicli.NewSocketClient(":80", false) + err := errors.New("foo-tendermint") + + // See Issue https://github.com/tendermint/abci/issues/114 + doneChan := make(chan bool) + go func() { + defer close(doneChan) + c.StopForError(err) + c.StopForError(err) + }() + + select { + case <-doneChan: + case <-time.After(time.Second * 4): + t.Fatalf("Test took too long, potential deadlock still exists") + } +} From 9aff9f94dde85528686856815405d92f47b8fbb3 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 18 Oct 2017 12:46:51 +0200 Subject: [PATCH 03/28] dummy app now uses iavl --- example/dummy/dummy.go | 23 ++++++---- example/dummy/dummy_test.go | 12 ++--- example/dummy/persistent_dummy.go | 74 +++++++++++++------------------ glide.lock | 16 +++---- glide.yaml | 4 +- 5 files changed, 59 insertions(+), 70 deletions(-) diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 5db71f96c..82927ca6e 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -4,19 +4,20 @@ import ( "strings" "github.com/tendermint/abci/types" - "github.com/tendermint/merkleeyes/iavl" + wire "github.com/tendermint/go-wire" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/merkle" + dbm "github.com/tendermint/tmlibs/db" ) type DummyApplication struct { types.BaseApplication - state merkle.Tree + state *iavl.VersionedTree } func NewDummyApplication() *DummyApplication { - state := iavl.NewIAVLTree(0, nil) + state := iavl.NewVersionedTree(0, dbm.NewMemDB()) return &DummyApplication{state: state} } @@ -46,22 +47,26 @@ func (app *DummyApplication) Commit() types.Result { func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { if reqQuery.Prove { - value, proof, exists := app.state.Proof(reqQuery.Data) + value, proof, err := app.state.GetWithProof(reqQuery.Data) + // be stupid here + if err != nil { + panic(err) + } resQuery.Index = -1 // TODO make Proof return index resQuery.Key = reqQuery.Data resQuery.Value = value - resQuery.Proof = proof - if exists { + resQuery.Proof = wire.BinaryBytes(proof) + if value == nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" } return } else { - index, value, exists := app.state.Get(reqQuery.Data) + index, value := app.state.Get(reqQuery.Data) resQuery.Index = int64(index) resQuery.Value = value - if exists { + if value != nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index fa9d531b7..41e033bc0 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -11,7 +11,7 @@ import ( "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/merkleeyes/iavl" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" ) @@ -39,9 +39,10 @@ func testDummy(t *testing.T, app types.Application, tx []byte, key, value string }) require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, value, string(resQuery.Value)) - proof, err := iavl.ReadProof(resQuery.Proof) + proof, err := iavl.ReadKeyExistsProof(resQuery.Proof) require.Nil(t, err) - require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash + err = proof.Verify([]byte(key), resQuery.Value, proof.RootHash) + require.Nil(t, err, "%+v", err) // NOTE: we have no way to verify the RootHash } func TestDummyKV(t *testing.T) { @@ -309,7 +310,8 @@ func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) require.Nil(t, err) require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, value, string(resQuery.Value)) - proof, err := iavl.ReadProof(resQuery.Proof) + proof, err := iavl.ReadKeyExistsProof(resQuery.Proof) require.Nil(t, err) - require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash + err = proof.Verify([]byte(key), resQuery.Value, proof.RootHash) + require.Nil(t, err, "%+v", err) // NOTE: we have no way to verify the RootHash } diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index a8bfbcf02..89bc6e721 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -3,13 +3,12 @@ package dummy import ( "bytes" "encoding/hex" + "path" "strconv" "strings" - "github.com/pkg/errors" "github.com/tendermint/abci/types" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/merkleeyes/iavl" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -23,11 +22,11 @@ const ( type PersistentDummyApplication struct { app *DummyApplication - db dbm.DB // latest received // TODO: move to merkle tree? blockHeader *types.Header + height uint64 // validator set changes []*types.Validator @@ -36,17 +35,22 @@ type PersistentDummyApplication struct { } func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication { - db := dbm.NewDB("dummy", "leveldb", dbDir) - lastBlock := LoadLastBlock(db) + name := "dummy" + dbPath := path.Join(dbDir, name+".db") + empty, _ := cmn.IsDirEmpty(dbPath) - stateTree := iavl.NewIAVLTree(0, db) - stateTree.Load(lastBlock.AppHash) + db, err := dbm.NewGoLevelDB(name, dbDir) + if err != nil { + panic(err) + } - // log.Notice("Loaded state", "block", lastBlock.Height, "root", stateTree.Hash()) + stateTree := iavl.NewVersionedTree(500, db) + if !empty { + stateTree.Load() + } return &PersistentDummyApplication{ app: &DummyApplication{state: stateTree}, - db: db, logger: log.NewNopLogger(), } } @@ -57,9 +61,8 @@ func (app *PersistentDummyApplication) SetLogger(l log.Logger) { func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { resInfo = app.app.Info(req) - lastBlock := LoadLastBlock(app.db) - resInfo.LastBlockHeight = lastBlock.Height - resInfo.LastBlockAppHash = lastBlock.AppHash + resInfo.LastBlockHeight = app.height + resInfo.LastBlockAppHash = app.app.state.Hash() return resInfo } @@ -86,18 +89,26 @@ func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { } func (app *PersistentDummyApplication) Commit() types.Result { - // Save - appHash := app.app.state.Save() - app.logger.Info("Saved state", "root", appHash) + app.height = app.blockHeader.Height + + // Save a new version + var appHash []byte + var err error + if app.app.state.Size() > 0 { + appHash, err = app.app.state.SaveVersion(app.height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) + } + app.logger.Info("Saved state", "root", appHash) + } lastBlock := LastBlockInfo{ - Height: app.blockHeader.Height, + Height: app.height, AppHash: appHash, // this hash will be in the next block header } app.logger.Info("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash) - SaveLastBlock(app.db, lastBlock) - return types.NewResultOK(appHash, "") } @@ -139,31 +150,6 @@ type LastBlockInfo struct { AppHash []byte } -// Get the last block from the db -func LoadLastBlock(db dbm.DB) (lastBlock LastBlockInfo) { - buf := db.Get(lastBlockKey) - if len(buf) != 0 { - r, n, err := bytes.NewReader(buf), new(int), new(error) - wire.ReadBinaryPtr(&lastBlock, r, 0, n, err) - if *err != nil { - cmn.PanicCrisis(errors.Wrap(*err, "cannot load last block (data has been corrupted or its spec has changed)")) - } - // TODO: ensure that buf is completely read. - } - - return lastBlock -} - -func SaveLastBlock(db dbm.DB, lastBlock LastBlockInfo) { - buf, n, err := new(bytes.Buffer), new(int), new(error) - wire.WriteBinary(lastBlock, buf, n, err) - if *err != nil { - // TODO - cmn.PanicCrisis(errors.Wrap(*err, "cannot save last block")) - } - db.Set(lastBlockKey, buf.Bytes()) -} - //--------------------------------------------- // update validators diff --git a/glide.lock b/glide.lock index 7b79f0e55..d2dfc9a68 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: f9c2ddad16bf8652076a93bd9f398bb498eefb2f5bd2c89a77d966ebd12feec8 -updated: 2017-09-22T10:34:17.228026799-04:00 +hash: 876bc65024f66612325ebafcedeb3e4d5014d46b339cf7583f1c00c6bac6e32c +updated: 2017-10-18T11:59:44.724549502+02:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -57,17 +57,15 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: e6ea9499ff958479e4a921850d2382eb599f204c + version: 8e7f0e7701f92206679ad093d013b9b162427631 - name: github.com/tendermint/go-wire - version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb + version: 26ee079df7fca1958da8995c727b59759b197534 subpackages: - data -- name: github.com/tendermint/merkleeyes - version: 2f6e5d31e7a35045d8d0a5895cb1fec33dd4d32b - subpackages: - - iavl +- name: github.com/tendermint/iavl + version: ff4ffa531df48509d51f0c16c2432f986eed9fcc - name: github.com/tendermint/tmlibs - version: bffe6744ec277d60f707ab442e25513617842f8e + version: 8e5266a9ef2527e68a1571f932db8228a331b556 subpackages: - common - db diff --git a/glide.yaml b/glide.yaml index 11379aad4..e8cf8302c 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,10 +8,8 @@ import: version: develop - package: github.com/tendermint/go-wire version: develop -- package: github.com/tendermint/merkleeyes +- package: github.com/tendermint/iavl version: develop - subpackages: - - iavl - package: github.com/tendermint/tmlibs version: develop subpackages: From bae4e4acce1c364c76c95663788f9fa8c2abc312 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 18 Oct 2017 13:13:18 +0200 Subject: [PATCH 04/28] Fix up commits, debug cli tests --- example/dummy/dummy.go | 17 ++++++++++++++++- example/dummy/persistent_dummy.go | 8 ++------ tests/test_cli/ex1.abci.out | 18 +++++++++--------- tests/test_cli/test.sh | 1 + 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 82927ca6e..89f997a48 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -1,6 +1,7 @@ package dummy import ( + "fmt" "strings" "github.com/tendermint/abci/types" @@ -33,6 +34,7 @@ func (app *DummyApplication) DeliverTx(tx []byte) types.Result { } else { app.state.Set(tx, tx) } + fmt.Println("set data") return types.OK } @@ -41,7 +43,20 @@ func (app *DummyApplication) CheckTx(tx []byte) types.Result { } func (app *DummyApplication) Commit() types.Result { - hash := app.state.Hash() + // Save a new version + var hash []byte + var err error + + if app.state.Size() > 0 { + // just add one more to height (kind of arbitrarily stupid) + height := app.state.LatestVersion() + 1 + hash, err = app.state.SaveVersion(height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) + } + } + return types.NewResultOK(hash, "") } diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index 89bc6e721..cc2d2d400 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -94,6 +94,7 @@ func (app *PersistentDummyApplication) Commit() types.Result { // Save a new version var appHash []byte var err error + if app.app.state.Size() > 0 { appHash, err = app.app.state.SaveVersion(app.height) if err != nil { @@ -103,12 +104,7 @@ func (app *PersistentDummyApplication) Commit() types.Result { app.logger.Info("Saved state", "root", appHash) } - lastBlock := LastBlockInfo{ - Height: app.height, - AppHash: appHash, // this hash will be in the next block header - } - - app.logger.Info("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash) + app.logger.Info("Commit block", "height", app.height, "root", appHash) return types.NewResultOK(appHash, "") } diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index e434944a4..c3a62d550 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -2,21 +2,21 @@ -> data: hello -> data.hex: 68656C6C6F -> info +> info -> data: {"size":0} -> data.hex: 7B2273697A65223A307D -> commit +> commit > deliver_tx "abc" -> info +> info -> data: {"size":1} -> data.hex: 7B2273697A65223A317D -> commit --> data: uü~„»×ˆíX–$ðlú‡EÑ --> data.hex: 750502FC7E84BBD788ED589624F06CFA871845D1 +> commit +-> data: IßÑ\ͬޮ—(ËûµèhŒ¥‹‘ +-> data.hex: 49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 > query "abc" -> log: exists @@ -26,9 +26,9 @@ > deliver_tx "def=xyz" -> commit --> data: v9;Š.E†°iLbžËQ²†ïÕ --> data.hex: 76393B8A182E450286B0694C629ECB51B286EFD5 +> commit +-> data: p-³"€7?¿?Ÿ‰Ú* Î,Ö+ +-> data.hex: 70102DB32280373FBF3F9F89DA2A20CE2CD62B0B > query "def" -> log: exists diff --git a/tests/test_cli/test.sh b/tests/test_cli/test.sh index 4266dd16f..8ea8d545b 100644 --- a/tests/test_cli/test.sh +++ b/tests/test_cli/test.sh @@ -15,6 +15,7 @@ function testExample() { echo "Example $N" $APP &> /dev/null & + # $APP &> ./app.out & sleep 2 abci-cli --verbose batch < "$INPUT" > "${INPUT}.out.new" killall "$APP" From d236e0eef9a6ecc12a736fdae85f635238053e24 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 18 Oct 2017 13:28:24 +0200 Subject: [PATCH 05/28] Fix trailing whitespace in tutorial test --- tests/test_cli/ex1.abci.out | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index c3a62d550..21c778c71 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -2,19 +2,19 @@ -> data: hello -> data.hex: 68656C6C6F -> info +> info -> data: {"size":0} -> data.hex: 7B2273697A65223A307D -> commit +> commit > deliver_tx "abc" -> info +> info -> data: {"size":1} -> data.hex: 7B2273697A65223A317D -> commit +> commit -> data: IßÑ\ͬޮ—(ËûµèhŒ¥‹‘ -> data.hex: 49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 @@ -26,7 +26,7 @@ > deliver_tx "def=xyz" -> commit +> commit -> data: p-³"€7?¿?Ÿ‰Ú* Î,Ö+ -> data.hex: 70102DB32280373FBF3F9F89DA2A20CE2CD62B0B From 46e1f1ae653a49f18ae813fc3a441edf219f0ce5 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 19 Oct 2017 14:43:34 +0200 Subject: [PATCH 06/28] Cleaup based on Antons PR comments --- example/dummy/dummy.go | 6 ++---- example/dummy/persistent_dummy.go | 7 ++++--- tests/test_cli/test.sh | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 89f997a48..7e95c859b 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -1,7 +1,6 @@ package dummy import ( - "fmt" "strings" "github.com/tendermint/abci/types" @@ -34,7 +33,6 @@ func (app *DummyApplication) DeliverTx(tx []byte) types.Result { } else { app.state.Set(tx, tx) } - fmt.Println("set data") return types.OK } @@ -63,7 +61,7 @@ func (app *DummyApplication) Commit() types.Result { func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { if reqQuery.Prove { value, proof, err := app.state.GetWithProof(reqQuery.Data) - // be stupid here + // if this wasn't a dummy app, we'd do something smarter if err != nil { panic(err) } @@ -71,7 +69,7 @@ func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types. resQuery.Key = reqQuery.Data resQuery.Value = value resQuery.Proof = wire.BinaryBytes(proof) - if value == nil { + if value != nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index cc2d2d400..94ce85adf 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -89,14 +89,14 @@ func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { } func (app *PersistentDummyApplication) Commit() types.Result { - app.height = app.blockHeader.Height + h := app.blockHeader.Height // Save a new version var appHash []byte var err error if app.app.state.Size() > 0 { - appHash, err = app.app.state.SaveVersion(app.height) + appHash, err = app.app.state.SaveVersion(h) if err != nil { // if this wasn't a dummy app, we'd do something smarter panic(err) @@ -104,7 +104,8 @@ func (app *PersistentDummyApplication) Commit() types.Result { app.logger.Info("Saved state", "root", appHash) } - app.logger.Info("Commit block", "height", app.height, "root", appHash) + app.height = h + app.logger.Info("Commit block", "height", h, "root", appHash) return types.NewResultOK(appHash, "") } diff --git a/tests/test_cli/test.sh b/tests/test_cli/test.sh index 8ea8d545b..4266dd16f 100644 --- a/tests/test_cli/test.sh +++ b/tests/test_cli/test.sh @@ -15,7 +15,6 @@ function testExample() { echo "Example $N" $APP &> /dev/null & - # $APP &> ./app.out & sleep 2 abci-cli --verbose batch < "$INPUT" > "${INPUT}.out.new" killall "$APP" From 7aa00e9ddd0ecb7e5dc3f003d61a834795c532d8 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 19 Oct 2017 14:48:07 +0200 Subject: [PATCH 07/28] Fix metalinter errors --- Makefile | 2 +- example/dummy/persistent_dummy.go | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Makefile b/Makefile index d097ae72b..8b621a9a4 100644 --- a/Makefile +++ b/Makefile @@ -52,7 +52,6 @@ metalinter: tools metalinter_test: tools @gometalinter --install gometalinter --vendor --deadline=600s --disable-all \ - --enable=aligncheck \ --enable=deadcode \ --enable=gas \ --enable=goconst \ @@ -71,6 +70,7 @@ metalinter_test: tools --enable=vetshadow \ ./... + # --enable=aligncheck \ <== disabled as not installed #--enable=dupl \ #--enable=errcheck \ #--enable=gocyclo \ diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index 94ce85adf..20b68b9aa 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -137,16 +137,6 @@ func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock type return types.ResponseEndBlock{Diffs: app.changes} } -//----------------------------------------- -// persist the last block info - -var lastBlockKey = []byte("lastblock") - -type LastBlockInfo struct { - Height uint64 - AppHash []byte -} - //--------------------------------------------- // update validators From 5162ed1b2b4e7c0cea98be442210b43a0b6b94b9 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 19 Oct 2017 15:12:27 +0200 Subject: [PATCH 08/28] Remove gotype from metalinter so it passes (need newer go on circleci) --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 8b621a9a4..6c72d0632 100644 --- a/Makefile +++ b/Makefile @@ -52,12 +52,12 @@ metalinter: tools metalinter_test: tools @gometalinter --install gometalinter --vendor --deadline=600s --disable-all \ + --enable=maligned \ --enable=deadcode \ --enable=gas \ --enable=goconst \ --enable=goimports \ --enable=gosimple \ - --enable=gotype \ --enable=ineffassign \ --enable=megacheck \ --enable=misspell \ @@ -70,13 +70,13 @@ metalinter_test: tools --enable=vetshadow \ ./... - # --enable=aligncheck \ <== disabled as not installed - #--enable=dupl \ - #--enable=errcheck \ - #--enable=gocyclo \ - #--enable=golint \ <== comments on anything exported - #--enable=interfacer \ - #--enable=unparam \ - #--enable=vet \ + #--enable=dupl \ + #--enable=errcheck \ + #--enable=gocyclo \ + #--enable=golint \ <== comments on anything exported + #--enable=gotype \ + #--enable=interfacer \ + #--enable=unparam \ + #--enable=vet \ .PHONY: all build test fmt get_deps tools From a4443ddb0c29227c619c03c660acc4b4bdf2ec38 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Mon, 23 Oct 2017 00:06:50 -0400 Subject: [PATCH 09/28] update persistent dummy for versioned iavl --- example/dummy/dummy_test.go | 12 +++++++++--- example/dummy/persistent_dummy.go | 28 +++++++++------------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index 41e033bc0..fbc095e6d 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -81,6 +81,8 @@ func TestPersistentDummyInfo(t *testing.T) { dummy := NewPersistentDummyApplication(dir) height := uint64(0) + dummy.InitChain(types.RequestInitChain{[]*types.Validator{randVal(0)}}) + resInfo := dummy.Info(types.RequestInfo{}) if resInfo.LastBlockHeight != height { t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) @@ -103,6 +105,12 @@ func TestPersistentDummyInfo(t *testing.T) { } +func randVal(i int) *types.Validator { + pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() + power := cmn.RandInt() + return &types.Validator{pubkey, uint64(power)} +} + // add a validator, remove a validator, update a validator func TestValSetChanges(t *testing.T) { dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO @@ -116,9 +124,7 @@ func TestValSetChanges(t *testing.T) { nInit := 5 vals := make([]*types.Validator, total) for i := 0; i < total; i++ { - pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() - power := cmn.RandInt() - vals[i] = &types.Validator{pubkey, uint64(power)} + vals[i] = randVal(i) } // iniitalize with the first nInit dummy.InitChain(types.RequestInitChain{vals[:nInit]}) diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index 20b68b9aa..de4aaa569 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -23,11 +23,6 @@ const ( type PersistentDummyApplication struct { app *DummyApplication - // latest received - // TODO: move to merkle tree? - blockHeader *types.Header - height uint64 - // validator set changes []*types.Validator @@ -61,7 +56,7 @@ func (app *PersistentDummyApplication) SetLogger(l log.Logger) { func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { resInfo = app.app.Info(req) - resInfo.LastBlockHeight = app.height + resInfo.LastBlockHeight = app.app.state.LatestVersion() resInfo.LastBlockAppHash = app.app.state.Hash() return resInfo } @@ -88,24 +83,21 @@ func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { return app.app.CheckTx(tx) } +// Commit will panic if InitChain was not called func (app *PersistentDummyApplication) Commit() types.Result { - h := app.blockHeader.Height - // Save a new version + // Save a new version for next height + height := app.app.state.LatestVersion() + 1 var appHash []byte var err error - if app.app.state.Size() > 0 { - appHash, err = app.app.state.SaveVersion(h) - if err != nil { - // if this wasn't a dummy app, we'd do something smarter - panic(err) - } - app.logger.Info("Saved state", "root", appHash) + appHash, err = app.app.state.SaveVersion(height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) } - app.height = h - app.logger.Info("Commit block", "height", h, "root", appHash) + app.logger.Info("Commit block", "height", height, "root", appHash) return types.NewResultOK(appHash, "") } @@ -125,8 +117,6 @@ func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) // Track the block hash and header information func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) { - // update latest block info - app.blockHeader = params.Header // reset valset changes app.changes = make([]*types.Validator, 0) From e7ebf62092705e144a05882f7622622153333848 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 23 Oct 2017 14:08:36 +0200 Subject: [PATCH 10/28] Remove empty check after iavl fixup --- example/dummy/persistent_dummy.go | 9 +-------- glide.lock | 8 ++++---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index de4aaa569..15fe150d5 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -3,7 +3,6 @@ package dummy import ( "bytes" "encoding/hex" - "path" "strconv" "strings" @@ -31,18 +30,13 @@ type PersistentDummyApplication struct { func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication { name := "dummy" - dbPath := path.Join(dbDir, name+".db") - empty, _ := cmn.IsDirEmpty(dbPath) - db, err := dbm.NewGoLevelDB(name, dbDir) if err != nil { panic(err) } stateTree := iavl.NewVersionedTree(500, db) - if !empty { - stateTree.Load() - } + stateTree.Load() return &PersistentDummyApplication{ app: &DummyApplication{state: stateTree}, @@ -117,7 +111,6 @@ func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) // Track the block hash and header information func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) { - // reset valset changes app.changes = make([]*types.Validator, 0) } diff --git a/glide.lock b/glide.lock index d2dfc9a68..cc94dbd55 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 876bc65024f66612325ebafcedeb3e4d5014d46b339cf7583f1c00c6bac6e32c -updated: 2017-10-18T11:59:44.724549502+02:00 +updated: 2017-10-23T14:04:02.596189966+02:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -63,7 +63,7 @@ imports: subpackages: - data - name: github.com/tendermint/iavl - version: ff4ffa531df48509d51f0c16c2432f986eed9fcc + version: 721710e7aa59f61dbfbf558943a207ba3fe6b926 - name: github.com/tendermint/tmlibs version: 8e5266a9ef2527e68a1571f932db8228a331b556 subpackages: @@ -73,7 +73,7 @@ imports: - merkle - process - name: github.com/urfave/cli - version: d70f47eeca3afd795160003bc6e28b001d60c67c + version: 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c - name: golang.org/x/crypto version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e subpackages: @@ -121,7 +121,7 @@ imports: - tap - transport - name: gopkg.in/go-playground/validator.v9 - version: d529ee1b0f30352444f507cc6cdac96bfd12decc + version: 6d8c18553ea1ac493d049edd6f102f52e618f085 testImports: - name: github.com/davecgh/go-spew version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 From 446e50ca9ee8ed3fbea9e5418282acf8b5842dbf Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Mon, 23 Oct 2017 14:20:15 +0200 Subject: [PATCH 11/28] Moved RandVal into test helper functions, as needed in other repos for testing --- example/dummy/dummy_test.go | 15 ++------------- example/dummy/helpers.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 example/dummy/helpers.go diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index fbc095e6d..751a2e910 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -10,7 +10,6 @@ import ( abcicli "github.com/tendermint/abci/client" "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" @@ -79,10 +78,9 @@ func TestPersistentDummyInfo(t *testing.T) { t.Fatal(err) } dummy := NewPersistentDummyApplication(dir) + InitDummy(dummy) height := uint64(0) - dummy.InitChain(types.RequestInitChain{[]*types.Validator{randVal(0)}}) - resInfo := dummy.Info(types.RequestInfo{}) if resInfo.LastBlockHeight != height { t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) @@ -105,12 +103,6 @@ func TestPersistentDummyInfo(t *testing.T) { } -func randVal(i int) *types.Validator { - pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() - power := cmn.RandInt() - return &types.Validator{pubkey, uint64(power)} -} - // add a validator, remove a validator, update a validator func TestValSetChanges(t *testing.T) { dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO @@ -122,10 +114,7 @@ func TestValSetChanges(t *testing.T) { // init with some validators total := 10 nInit := 5 - vals := make([]*types.Validator, total) - for i := 0; i < total; i++ { - vals[i] = randVal(i) - } + vals := RandVals(total) // iniitalize with the first nInit dummy.InitChain(types.RequestInitChain{vals[:nInit]}) diff --git a/example/dummy/helpers.go b/example/dummy/helpers.go new file mode 100644 index 000000000..55c464de0 --- /dev/null +++ b/example/dummy/helpers.go @@ -0,0 +1,34 @@ +package dummy + +import ( + "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + cmn "github.com/tendermint/tmlibs/common" +) + +// RandVal creates one random validator, with a key derived +// from the input value +func RandVal(i int) *types.Validator { + pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() + power := cmn.RandUint16() + 1 + return &types.Validator{pubkey, uint64(power)} +} + +// RandVals returns a list of cnt validators for initializing +// the application. Note that the keys are deterministically +// derived from the index in the array, while the power is +// random (Change this if not desired) +func RandVals(cnt int) []*types.Validator { + res := make([]*types.Validator, cnt) + for i := 0; i < cnt; i++ { + res[i] = RandVal(i) + } + return res +} + +// InitDummy initializes the dummy app with some data, +// which allows tests to pass and is fine as long as you +// don't make any tx that modify the validator state +func InitDummy(app *PersistentDummyApplication) { + app.InitChain(types.RequestInitChain{RandVals(1)}) +} From 9883013adf78a4d07d1f79224bc308d52603d063 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 18 Oct 2017 12:48:19 -0400 Subject: [PATCH 12/28] use cobra, closes #101 --- cmd/abci-cli/abci-cli.go | 379 ++++++++++++++++++--------------------- cmd/abci-cli/main.go | 5 + glide.yaml | 2 +- 3 files changed, 183 insertions(+), 203 deletions(-) create mode 100644 cmd/abci-cli/main.go diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index c73169499..acee3ea69 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -7,13 +7,15 @@ import ( "fmt" "io" "os" + "os/exec" "strings" abcicli "github.com/tendermint/abci/client" "github.com/tendermint/abci/types" - "github.com/tendermint/abci/version" + //"github.com/tendermint/abci/version" "github.com/tendermint/tmlibs/log" - "github.com/urfave/cli" + + "github.com/spf13/cobra" ) // Structure for data passed to print response. @@ -38,149 +40,135 @@ var client abcicli.Client var logger log.Logger -func main() { +// flags +var ( + address string + abci string + verbose bool - //workaround for the cli library (https://github.com/urfave/cli/issues/565) - cli.OsExiter = func(_ int) {} + path string + height int + prove bool +) - app := cli.NewApp() - app.Name = "abci-cli" - app.Usage = "abci-cli [command] [args...]" - app.Version = version.Version - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "address", - Value: "tcp://127.0.0.1:46658", - Usage: "address of application socket", - }, - cli.StringFlag{ - Name: "abci", - Value: "socket", - Usage: "socket or grpc", - }, - cli.BoolFlag{ - Name: "verbose", - Usage: "print the command and results as if it were a console session", - }, - } - app.Commands = []cli.Command{ - { - Name: "batch", - Usage: "Run a batch of abci commands against an application", - Action: func(c *cli.Context) error { - return cmdBatch(app, c) - }, - }, - { - Name: "console", - Usage: "Start an interactive abci console for multiple commands", - Action: func(c *cli.Context) error { - return cmdConsole(app, c) - }, - }, - { - Name: "echo", - Usage: "Have the application echo a message", - Action: func(c *cli.Context) error { - return cmdEcho(c) - }, - }, - { - Name: "info", - Usage: "Get some info about the application", - Action: func(c *cli.Context) error { - return cmdInfo(c) - }, - }, - { - Name: "set_option", - Usage: "Set an option on the application", - Action: func(c *cli.Context) error { - return cmdSetOption(c) - }, - }, - { - Name: "deliver_tx", - Usage: "Deliver a new tx to application", - Action: func(c *cli.Context) error { - return cmdDeliverTx(c) - }, - }, - { - Name: "check_tx", - Usage: "Validate a tx", - Action: func(c *cli.Context) error { - return cmdCheckTx(c) - }, - }, - { - Name: "commit", - Usage: "Commit the application state and return the Merkle root hash", - Action: func(c *cli.Context) error { - return cmdCommit(c) - }, - }, - { - Name: "query", - Usage: "Query application state", - Action: func(c *cli.Context) error { - return cmdQuery(c) - }, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "path", - Value: "/store", - Usage: "Path to prefix the query with", - }, - cli.IntFlag{ - Name: "height", - Value: 0, - Usage: "Height to query the blockchain at", - }, - cli.BoolFlag{ - Name: "prove", - Usage: "Whether or not to return a merkle proof of the query result", - }, - }, - }, - } - app.Before = before - err := app.Run(os.Args) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } +var RootCmd = &cobra.Command{ + Use: "abci-cli", + Short: "", + Long: "", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if logger == nil { + logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError()) + } + if client == nil { + var err error + client, err = abcicli.NewClient(address, abci, false) + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + client.SetLogger(logger.With("module", "abci-client")) + if _, err := client.Start(); err != nil { + return err + } + } + return nil + }, +} +func Execute() { + addGlobalFlags() + addCommands() + RootCmd.Execute() //err? } -func before(c *cli.Context) error { - if logger == nil { - logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError()) - } - if client == nil { - var err error - client, err = abcicli.NewClient(c.GlobalString("address"), c.GlobalString("abci"), false) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - client.SetLogger(logger.With("module", "abci-client")) - if _, err := client.Start(); err != nil { - return err - } - } - return nil +func addGlobalFlags() { + RootCmd.PersistentFlags().StringVarP(&address, "address", "", "tcp://127.0.0.1:46658", "address of application socket") + RootCmd.PersistentFlags().StringVarP(&abci, "abci", "", "socket", "socket or grpc") + RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "print the command and results as if it were a console session") +} + +func addQueryFlags() { + queryCmd.PersistentFlags().StringVarP(&path, "path", "", "/store", "Path to prefix query with") + queryCmd.PersistentFlags().IntVarP(&height, "height", "", 0, "Height to query the blockchain at") + queryCmd.PersistentFlags().BoolVarP(&prove, "prove", "", false, "Whether or not to return a merkle proof of the query result") +} + +func addCommands() { + RootCmd.AddCommand(batchCmd) + RootCmd.AddCommand(consoleCmd) + RootCmd.AddCommand(echoCmd) + RootCmd.AddCommand(infoCmd) + RootCmd.AddCommand(setOptionCmd) + RootCmd.AddCommand(deliverTxCmd) + RootCmd.AddCommand(checkTxCmd) + RootCmd.AddCommand(commitCmd) + addQueryFlags() + RootCmd.AddCommand(queryCmd) } -// badCmd is called when we invoke with an invalid first argument (just for console for now) -func badCmd(c *cli.Context, cmd string) { - fmt.Println("Unknown command:", cmd) - fmt.Println("Please try one of the following:") - fmt.Println("") - cli.DefaultAppComplete(c) +var batchCmd = &cobra.Command{ + Use: "batch", + Short: "Run a batch of abci commands against an application", + Long: "", + Run: cmdBatch, } -//Generates new Args array based off of previous call args to maintain flag persistence +var consoleCmd = &cobra.Command{ + Use: "console", + Short: "Start an interactive abci console for multiple commands", + Long: "", + ValidArgs: []string{"batch", "echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"}, + Run: cmdConsole, +} + +var echoCmd = &cobra.Command{ + Use: "echo", + Short: "", + Long: "Have the application echo a message", + Run: cmdEcho, +} +var infoCmd = &cobra.Command{ + Use: "info", + Short: "Get some info about the application", + Long: "", + Run: cmdInfo, +} +var setOptionCmd = &cobra.Command{ + Use: "set_option", + Short: "Set an options on the application", + Long: "", + Run: cmdSetOption, +} + +var deliverTxCmd = &cobra.Command{ + Use: "deliver_tx", + Short: "Deliver a new tx to the application", + Long: "", + Run: cmdDeliverTx, +} + +var checkTxCmd = &cobra.Command{ + Use: "check_tx", + Short: "Validate a tx", + Long: "", + Run: cmdCheckTx, +} + +var commitCmd = &cobra.Command{ + Use: "commit", + Short: "Commit the application state and return the Merkle root hash", + Long: "", + Run: cmdCommit, +} + +var queryCmd = &cobra.Command{ + Use: "query", + Short: "Query the application state", + Long: "", + Run: cmdQuery, +} + +// Generates new Args array based off of previous call args to maintain flag persistence func persistentArgs(line []byte) []string { // generate the arguments to run from original os.Args @@ -196,154 +184,142 @@ func persistentArgs(line []byte) []string { //-------------------------------------------------------------------------------- -func cmdBatch(app *cli.App, c *cli.Context) error { +func cmdBatch(cmd *cobra.Command, args []string) { bufReader := bufio.NewReader(os.Stdin) for { line, more, err := bufReader.ReadLine() if more { - return errors.New("Input line is too long") + ifExit(errors.New("Input line is too long")) } else if err == io.EOF { break } else if len(line) == 0 { continue } else if err != nil { - return err + ifExit(err) } - args := persistentArgs(line) - app.Run(args) //cli prints error within its func call + pArgs := persistentArgs(line) + out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() + if err != nil { + panic(err) + } + fmt.Println(string(out)) } - return nil } -func cmdConsole(app *cli.App, c *cli.Context) error { - // don't hard exit on mistyped commands (eg. check vs check_tx) - app.CommandNotFound = badCmd +func cmdConsole(cmd *cobra.Command, args []string) { for { fmt.Printf("\n> ") bufReader := bufio.NewReader(os.Stdin) line, more, err := bufReader.ReadLine() if more { - return errors.New("Input is too long") + ifExit(errors.New("Input is too long")) } else if err != nil { - return err + ifExit(err) } - args := persistentArgs(line) - app.Run(args) //cli prints error within its func call + pArgs := persistentArgs(line) + out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() + if err != nil { + panic(err) + } + fmt.Println(string(out)) } } // Have the application echo a message -func cmdEcho(c *cli.Context) error { - args := c.Args() +func cmdEcho(cmd *cobra.Command, args []string) { if len(args) != 1 { - return errors.New("Command echo takes 1 argument") + ifExit(errors.New("Command echo takes 1 argument")) } resEcho := client.EchoSync(args[0]) - printResponse(c, response{ + printResponse(cmd, args, response{ Data: resEcho.Data, }) - return nil } // Get some info from the application -func cmdInfo(c *cli.Context) error { - args := c.Args() +func cmdInfo(cmd *cobra.Command, args []string) { var version string if len(args) == 1 { version = args[0] } resInfo, err := client.InfoSync(types.RequestInfo{version}) if err != nil { - return err + ifExit(err) } - printResponse(c, response{ + printResponse(cmd, args, response{ Data: []byte(resInfo.Data), }) - return nil } // Set an option on the application -func cmdSetOption(c *cli.Context) error { - args := c.Args() +func cmdSetOption(cmd *cobra.Command, args []string) { if len(args) != 2 { - return errors.New("Command set_option takes 2 arguments (key, value)") + ifExit(errors.New("Command set_option takes 2 arguments (key, value)")) } resSetOption := client.SetOptionSync(args[0], args[1]) - printResponse(c, response{ + printResponse(cmd, args, response{ Log: resSetOption.Log, }) - return nil } // Append a new tx to application -func cmdDeliverTx(c *cli.Context) error { - args := c.Args() +func cmdDeliverTx(cmd *cobra.Command, args []string) { if len(args) != 1 { - return errors.New("Command deliver_tx takes 1 argument") + ifExit(errors.New("Command deliver_tx takes 1 argument")) } - txBytes, err := stringOrHexToBytes(c.Args()[0]) + txBytes, err := stringOrHexToBytes(args[0]) if err != nil { - return err + ifExit(err) } res := client.DeliverTxSync(txBytes) - printResponse(c, response{ + printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, }) - return nil } // Validate a tx -func cmdCheckTx(c *cli.Context) error { - args := c.Args() +func cmdCheckTx(cmd *cobra.Command, args []string) { if len(args) != 1 { - return errors.New("Command check_tx takes 1 argument") + ifExit(errors.New("Command check_tx takes 1 argument")) } - txBytes, err := stringOrHexToBytes(c.Args()[0]) + txBytes, err := stringOrHexToBytes(args[0]) if err != nil { - return err + ifExit(err) } res := client.CheckTxSync(txBytes) - printResponse(c, response{ + printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, }) - return nil } // Get application Merkle root hash -func cmdCommit(c *cli.Context) error { +func cmdCommit(cmd *cobra.Command, args []string) { res := client.CommitSync() - printResponse(c, response{ + printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, }) - return nil } // Query application state -func cmdQuery(c *cli.Context) error { - args := c.Args() - +func cmdQuery(cmd *cobra.Command, args []string) { if len(args) != 1 { - return errors.New("Command query takes 1 argument, the query bytes") + ifExit(errors.New("Command query takes 1 argument, the query bytes")) } queryBytes, err := stringOrHexToBytes(args[0]) if err != nil { - return err + ifExit(err) } - path := c.String("path") - height := c.Int("height") - prove := c.Bool("prove") - resQuery, err := client.QuerySync(types.RequestQuery{ Data: queryBytes, Path: path, @@ -351,9 +327,9 @@ func cmdQuery(c *cli.Context) error { Prove: prove, }) if err != nil { - return err + ifExit(err) } - printResponse(c, response{ + printResponse(cmd, args, response{ Code: resQuery.Code, Log: resQuery.Log, Query: &queryResponse{ @@ -363,17 +339,14 @@ func cmdQuery(c *cli.Context) error { Proof: resQuery.Proof, }, }) - return nil } //-------------------------------------------------------------------------------- -func printResponse(c *cli.Context, rsp response) { - - verbose := c.GlobalBool("verbose") +func printResponse(cmd *cobra.Command, args []string, rsp response) { if verbose { - fmt.Println(">", c.Command.Name, strings.Join(c.Args(), " ")) + fmt.Println(">", cmd.Use, strings.Join(args, " ")) } if !rsp.Code.IsOK() { @@ -401,11 +374,6 @@ func printResponse(c *cli.Context, rsp response) { fmt.Printf("-> proof: %X\n", rsp.Query.Proof) } } - - if verbose { - fmt.Println("") - } - } // NOTE: s is interpreted as a string unless prefixed with 0x @@ -426,3 +394,10 @@ func stringOrHexToBytes(s string) ([]byte, error) { return []byte(s[1 : len(s)-1]), nil } + +func ifExit(err error) { + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/abci-cli/main.go b/cmd/abci-cli/main.go new file mode 100644 index 000000000..736ef3102 --- /dev/null +++ b/cmd/abci-cli/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + Execute() +} diff --git a/glide.yaml b/glide.yaml index e8cf8302c..cd8c994ce 100644 --- a/glide.yaml +++ b/glide.yaml @@ -18,7 +18,7 @@ import: - log - merkle - process -- package: github.com/urfave/cli +- package: github.com/spf13/cobra - package: golang.org/x/net subpackages: - context From f67e43625bf524e044bfb1d3a37dce68ccb53c71 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 18 Oct 2017 14:21:16 -0400 Subject: [PATCH 13/28] Makefile: fix linter --- Makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 6c72d0632..588e12df5 100644 --- a/Makefile +++ b/Makefile @@ -70,13 +70,13 @@ metalinter_test: tools --enable=vetshadow \ ./... - #--enable=dupl \ - #--enable=errcheck \ - #--enable=gocyclo \ - #--enable=golint \ <== comments on anything exported - #--enable=gotype \ - #--enable=interfacer \ - #--enable=unparam \ - #--enable=vet \ + #--enable=dupl \ + #--enable=errcheck \ + #--enable=gocyclo \ + #--enable=golint \ <== comments on anything exported + #--enable=gotype \ + #--enable=interfacer \ + #--enable=unparam \ + #--enable=vet \ .PHONY: all build test fmt get_deps tools From 56f7d9627f82f5c767ed968641a3d56aff9d99ad Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 18 Oct 2017 14:27:39 -0400 Subject: [PATCH 14/28] update deps --- glide.lock | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/glide.lock b/glide.lock index cc94dbd55..49795959b 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 876bc65024f66612325ebafcedeb3e4d5014d46b339cf7583f1c00c6bac6e32c -updated: 2017-10-23T14:04:02.596189966+02:00 +hash: 1530ad93695fa2861f1572e3e1eef1b6604beb548fd4832985f6c6350260c2b3 +updated: 2017-10-18T14:27:16.428209213-04:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -30,12 +30,18 @@ imports: - ptypes/any - name: github.com/golang/snappy version: 553a641470496b2327abcac10b36396bd98e45c9 +- name: github.com/inconshreveable/mousetrap + version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/kr/logfmt version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d +- name: github.com/spf13/cobra + version: 4cdb38c072b86bf795d2c81de50784d9fdd6eb77 +- name: github.com/spf13/pflag + version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 - name: github.com/syndtr/goleveldb version: 8c81ea47d4c41a385645e133e15510fc6a2a74b4 subpackages: @@ -72,8 +78,6 @@ imports: - log - merkle - process -- name: github.com/urfave/cli - version: 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c - name: golang.org/x/crypto version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e subpackages: From df5d9ac1bbf08439367fc5fc002162ae5903dc4b Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 18 Oct 2017 15:00:23 -0400 Subject: [PATCH 15/28] consolidate counter/dummy into the binary, #95 --- cmd/abci-cli/abci-cli.go | 99 ++++++++++++++++++++++++++++++++++++++++ cmd/counter/main.go | 41 ----------------- cmd/dummy/main.go | 50 -------------------- 3 files changed, 99 insertions(+), 91 deletions(-) delete mode 100644 cmd/counter/main.go delete mode 100644 cmd/dummy/main.go diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index acee3ea69..93b00543b 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -11,8 +11,12 @@ import ( "strings" abcicli "github.com/tendermint/abci/client" + "github.com/tendermint/abci/example/counter" + "github.com/tendermint/abci/example/dummy" + "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" //"github.com/tendermint/abci/version" + cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" "github.com/spf13/cobra" @@ -42,13 +46,23 @@ var logger log.Logger // flags var ( + // global address string abci string verbose bool + // query path string height int prove bool + + // counter + addrC string + serial bool + + // dummy + addrD string + persist string ) var RootCmd = &cobra.Command{ @@ -93,6 +107,15 @@ func addQueryFlags() { queryCmd.PersistentFlags().BoolVarP(&prove, "prove", "", false, "Whether or not to return a merkle proof of the query result") } +func addCounterFlags() { + counterCmd.PersistentFlags().StringVarP(&addrC, "addr", "", "tcp://0.0.0.0:46658", "Listen address") + counterCmd.PersistentFlags().BoolVarP(&serial, "serial", "", false, "Enforce incrementing (serial) transactions") +} + +func addDummyFlags() { + dummyCmd.PersistentFlags().StringVarP(&addrD, "addr", "", "tcp://0.0.0.0:46658", "Listen address") + dummyCmd.PersistentFlags().StringVarP(&persist, "persist", "", "", "Directory to use for a database") +} func addCommands() { RootCmd.AddCommand(batchCmd) RootCmd.AddCommand(consoleCmd) @@ -104,6 +127,12 @@ func addCommands() { RootCmd.AddCommand(commitCmd) addQueryFlags() RootCmd.AddCommand(queryCmd) + + // examples + addCounterFlags() + RootCmd.AddCommand(counterCmd) + addDummyFlags() + RootCmd.AddCommand(dummyCmd) } var batchCmd = &cobra.Command{ @@ -168,6 +197,20 @@ var queryCmd = &cobra.Command{ Run: cmdQuery, } +var counterCmd = &cobra.Command{ + Use: "counter", + Short: "ABCI demo example", + Long: "", + Run: cmdCounter, +} + +var dummyCmd = &cobra.Command{ + Use: "dummy", + Short: "ABCI demo example", + Long: "", + Run: cmdDummy, +} + // Generates new Args array based off of previous call args to maintain flag persistence func persistentArgs(line []byte) []string { @@ -341,6 +384,62 @@ func cmdQuery(cmd *cobra.Command, args []string) { }) } +func cmdCounter(cmd *cobra.Command, args []string) { + + app := counter.NewCounterApplication(serial) + + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + + // Start the listener + srv, err := server.NewServer(addrC, abci, app) + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + srv.SetLogger(logger.With("module", "abci-server")) + if _, err := srv.Start(); err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + + // Wait forever + cmn.TrapSignal(func() { + // Cleanup + srv.Stop() + }) +} + +func cmdDummy(cmd *cobra.Command, args []string) { + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + + // Create the application - in memory or persisted to disk + var app types.Application + if persist == "" { + app = dummy.NewDummyApplication() + } else { + app = dummy.NewPersistentDummyApplication(persist) + app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy")) + } + + // Start the listener + srv, err := server.NewServer(addrD, abci, app) + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + srv.SetLogger(logger.With("module", "abci-server")) + if _, err := srv.Start(); err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + + // Wait forever + cmn.TrapSignal(func() { + // Cleanup + srv.Stop() + }) +} + //-------------------------------------------------------------------------------- func printResponse(cmd *cobra.Command, args []string, rsp response) { diff --git a/cmd/counter/main.go b/cmd/counter/main.go deleted file mode 100644 index aa55778cc..000000000 --- a/cmd/counter/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/tendermint/abci/example/counter" - "github.com/tendermint/abci/server" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" -) - -func main() { - - addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address") - abciPtr := flag.String("abci", "socket", "ABCI server: socket | grpc") - serialPtr := flag.Bool("serial", false, "Enforce incrementing (serial) txs") - flag.Parse() - app := counter.NewCounterApplication(*serialPtr) - - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - - // Start the listener - srv, err := server.NewServer(*addrPtr, *abciPtr, app) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - srv.SetLogger(logger.With("module", "abci-server")) - if _, err := srv.Start(); err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - - // Wait forever - cmn.TrapSignal(func() { - // Cleanup - srv.Stop() - }) - -} diff --git a/cmd/dummy/main.go b/cmd/dummy/main.go deleted file mode 100644 index 85bbca18d..000000000 --- a/cmd/dummy/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/tendermint/abci/example/dummy" - "github.com/tendermint/abci/server" - "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" -) - -func main() { - - addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address") - abciPtr := flag.String("abci", "socket", "socket | grpc") - persistencePtr := flag.String("persist", "", "directory to use for a database") - flag.Parse() - - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - - // Create the application - in memory or persisted to disk - var app types.Application - if *persistencePtr == "" { - app = dummy.NewDummyApplication() - } else { - app = dummy.NewPersistentDummyApplication(*persistencePtr) - app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy")) - } - - // Start the listener - srv, err := server.NewServer(*addrPtr, *abciPtr, app) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - srv.SetLogger(logger.With("module", "abci-server")) - if _, err := srv.Start(); err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - - // Wait forever - cmn.TrapSignal(func() { - // Cleanup - srv.Stop() - }) - -} From f9e14ad61be9b56147d65b40dcf53ffc9cad41d2 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 18 Oct 2017 15:23:39 -0400 Subject: [PATCH 16/28] disable PersistenPreRun for counter/dummy --- cmd/abci-cli/abci-cli.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 93b00543b..11a64432b 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -15,7 +15,6 @@ import ( "github.com/tendermint/abci/example/dummy" "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" - //"github.com/tendermint/abci/version" cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" @@ -70,6 +69,13 @@ var RootCmd = &cobra.Command{ Short: "", Long: "", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + + switch cmd.Use { + // for the examples apps, don't pre-run + case "counter", "dummy": + return nil + } + if logger == nil { logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError()) } From 631844895ff8a69c17cc21f8b197afe5527c02df Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Wed, 18 Oct 2017 15:32:34 -0400 Subject: [PATCH 17/28] fixes --- README.md | 6 +++--- scripts/dist_build.sh | 46 ++++++++++++++++++++---------------------- tests/test_cli/test.sh | 10 ++++----- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index f1b2ebb37..33b037da0 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,9 @@ The `abci-cli` tool wraps any ABCI client and can be used for probing/testing an See [the documentation](http://tendermint.readthedocs.io/en/master/) for more details. Multiple example apps are included: -- the `counter` application, which illustrates nonce checking in txs -- the `dummy` application, which illustrates a simple key-value merkle tree -- the `dummy --persistent` application, which augments the dummy with persistence and validator set changes +- the `abci-cli counter` application, which illustrates nonce checking in txs +- the `abci-cli dummy` application, which illustrates a simple key-value merkle tree +- the `abci-cli dummy --persistent` application, which augments the dummy with persistence and validator set changes ## Specification diff --git a/scripts/dist_build.sh b/scripts/dist_build.sh index 0f5e3e3b0..adaca24a8 100755 --- a/scripts/dist_build.sh +++ b/scripts/dist_build.sh @@ -24,30 +24,28 @@ make tools # Get VENDORED dependencies make get_vendor_deps -BINARIES=( "abci-cli" "dummy" "counter" ) - -for binary in ${BINARIES[@]}; do - # Build! - echo "==> Building..." - "$(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}}/$binary" \ - -tags="${BUILD_TAGS}" \ - github.com/tendermint/abci/cmd/$binary - - # Zip all the files. - echo "==> Packaging..." - for PLATFORM in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type d); do - OSARCH=$(basename "${PLATFORM}") - echo "--> ${OSARCH}" - - pushd "$PLATFORM" >/dev/null 2>&1 - zip "../${OSARCH}.zip" ./* - popd >/dev/null 2>&1 - done +BINARY="abci-cli" + +# Build! +echo "==> Building..." +"$(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}}/$BINARY" \ + -tags="${BUILD_TAGS}" \ + github.com/tendermint/abci/cmd/$BINARY + +# Zip all the files. +echo "==> Packaging..." +for PLATFORM in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type d); do + OSARCH=$(basename "${PLATFORM}") + echo "--> ${OSARCH}" + + pushd "$PLATFORM" >/dev/null 2>&1 + zip "../${OSARCH}.zip" ./* + popd >/dev/null 2>&1 done diff --git a/tests/test_cli/test.sh b/tests/test_cli/test.sh index 4266dd16f..81b06a0ec 100644 --- a/tests/test_cli/test.sh +++ b/tests/test_cli/test.sh @@ -11,13 +11,13 @@ cd "$DIR" || exit function testExample() { N=$1 INPUT=$2 - APP=$3 + APP="$3 $4" - echo "Example $N" + echo "Example $N: $APP" $APP &> /dev/null & sleep 2 abci-cli --verbose batch < "$INPUT" > "${INPUT}.out.new" - killall "$APP" + killall $3 pre=$(shasum < "${INPUT}.out") post=$(shasum < "${INPUT}.out.new") @@ -34,8 +34,8 @@ function testExample() { rm "${INPUT}".out.new } -testExample 1 tests/test_cli/ex1.abci dummy -testExample 2 tests/test_cli/ex2.abci counter +testExample 1 tests/test_cli/ex1.abci abci-cli dummy +testExample 2 tests/test_cli/ex2.abci abci-cli counter echo "" echo "PASS" From 3330cb4856fe6e33ccf07a9fa44fb2b33d4c9516 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Mon, 23 Oct 2017 17:16:49 -0400 Subject: [PATCH 18/28] cleanup --- cmd/abci-cli/abci-cli.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 11a64432b..906520f0d 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -102,9 +102,9 @@ func Execute() { } func addGlobalFlags() { - RootCmd.PersistentFlags().StringVarP(&address, "address", "", "tcp://127.0.0.1:46658", "address of application socket") - RootCmd.PersistentFlags().StringVarP(&abci, "abci", "", "socket", "socket or grpc") - RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "print the command and results as if it were a console session") + RootCmd.PersistentFlags().StringVarP(&address, "address", "", "tcp://127.0.0.1:46658", "Address of application socket") + RootCmd.PersistentFlags().StringVarP(&abci, "abci", "", "socket", "Either socket or grpc") + RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the command and results as if it were a console session") } func addQueryFlags() { @@ -158,8 +158,8 @@ var consoleCmd = &cobra.Command{ var echoCmd = &cobra.Command{ Use: "echo", - Short: "", - Long: "Have the application echo a message", + Short: "Have the application echo a message", + Long: "", Run: cmdEcho, } var infoCmd = &cobra.Command{ @@ -170,21 +170,21 @@ var infoCmd = &cobra.Command{ } var setOptionCmd = &cobra.Command{ Use: "set_option", - Short: "Set an options on the application", + Short: "Set an option on the application", Long: "", Run: cmdSetOption, } var deliverTxCmd = &cobra.Command{ Use: "deliver_tx", - Short: "Deliver a new tx to the application", + Short: "Deliver a new transaction to the application", Long: "", Run: cmdDeliverTx, } var checkTxCmd = &cobra.Command{ Use: "check_tx", - Short: "Validate a tx", + Short: "Validate a transaction", Long: "", Run: cmdCheckTx, } @@ -250,7 +250,7 @@ func cmdBatch(cmd *cobra.Command, args []string) { pArgs := persistentArgs(line) out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() if err != nil { - panic(err) + ifExit(err) } fmt.Println(string(out)) } @@ -271,7 +271,7 @@ func cmdConsole(cmd *cobra.Command, args []string) { pArgs := persistentArgs(line) out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() if err != nil { - panic(err) + ifExit(err) } fmt.Println(string(out)) } @@ -280,7 +280,7 @@ func cmdConsole(cmd *cobra.Command, args []string) { // Have the application echo a message func cmdEcho(cmd *cobra.Command, args []string) { if len(args) != 1 { - ifExit(errors.New("Command echo takes 1 argument")) + ifExit(errors.New("Command echo takes only 1 argument")) } resEcho := client.EchoSync(args[0]) printResponse(cmd, args, response{ @@ -306,7 +306,7 @@ func cmdInfo(cmd *cobra.Command, args []string) { // Set an option on the application func cmdSetOption(cmd *cobra.Command, args []string) { if len(args) != 2 { - ifExit(errors.New("Command set_option takes 2 arguments (key, value)")) + ifExit(errors.New("Command set_option takes exactly 2 arguments (key, value)")) } resSetOption := client.SetOptionSync(args[0], args[1]) printResponse(cmd, args, response{ @@ -317,7 +317,7 @@ func cmdSetOption(cmd *cobra.Command, args []string) { // Append a new tx to application func cmdDeliverTx(cmd *cobra.Command, args []string) { if len(args) != 1 { - ifExit(errors.New("Command deliver_tx takes 1 argument")) + ifExit(errors.New("Command deliver_tx takes only 1 argument")) } txBytes, err := stringOrHexToBytes(args[0]) if err != nil { @@ -334,7 +334,7 @@ func cmdDeliverTx(cmd *cobra.Command, args []string) { // Validate a tx func cmdCheckTx(cmd *cobra.Command, args []string) { if len(args) != 1 { - ifExit(errors.New("Command check_tx takes 1 argument")) + ifExit(errors.New("Command check_tx takes only 1 argument")) } txBytes, err := stringOrHexToBytes(args[0]) if err != nil { @@ -361,7 +361,7 @@ func cmdCommit(cmd *cobra.Command, args []string) { // Query application state func cmdQuery(cmd *cobra.Command, args []string) { if len(args) != 1 { - ifExit(errors.New("Command query takes 1 argument, the query bytes")) + ifExit(errors.New("Command query takes only 1 argument, the query bytes")) } queryBytes, err := stringOrHexToBytes(args[0]) From 36de70be10867da3737c8b3388d94e778cf7ceee Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Mon, 23 Oct 2017 19:35:02 -0400 Subject: [PATCH 19/28] console: fix output, closes #93 --- cmd/abci-cli/abci-cli.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 906520f0d..e098b9a38 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -259,7 +259,7 @@ func cmdBatch(cmd *cobra.Command, args []string) { func cmdConsole(cmd *cobra.Command, args []string) { for { - fmt.Printf("\n> ") + fmt.Printf("> ") bufReader := bufio.NewReader(os.Stdin) line, more, err := bufReader.ReadLine() if more { @@ -454,12 +454,16 @@ func printResponse(cmd *cobra.Command, args []string, rsp response) { fmt.Println(">", cmd.Use, strings.Join(args, " ")) } - if !rsp.Code.IsOK() { - fmt.Printf("-> code: %s\n", rsp.Code.String()) - } + // Always print the status code. + fmt.Printf("-> code: %s\n", rsp.Code.String()) + if len(rsp.Data) != 0 { - fmt.Printf("-> data: %s\n", rsp.Data) - fmt.Printf("-> data.hex: %X\n", rsp.Data) + // Do no print this line when using the commit command + // because the string comes out as gibberish + if cmd.Use != "commit" { + fmt.Printf("-> data: %s\n", rsp.Data) + } + fmt.Printf("-> data.hex: 0x%X\n", rsp.Data) } if rsp.Log != "" { fmt.Printf("-> log: %s\n", rsp.Log) From 4479e957095fb4616a86be325c6ee4e568ff624e Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Mon, 23 Oct 2017 19:54:38 -0400 Subject: [PATCH 20/28] console: fix tests --- tests/test_cli/ex1.abci.out | 22 +++++++++++++++------- tests/test_cli/ex2.abci.out | 8 +++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index 21c778c71..6e3440712 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -1,36 +1,44 @@ > echo hello +-> code: OK -> data: hello --> data.hex: 68656C6C6F +-> data.hex: 0x68656C6C6F > info +-> code: OK -> data: {"size":0} --> data.hex: 7B2273697A65223A307D +-> data.hex: 0x7B2273697A65223A307D > commit +-> code: OK > deliver_tx "abc" +-> code: OK > info +-> code: OK -> data: {"size":1} --> data.hex: 7B2273697A65223A317D +-> data.hex: 0x7B2273697A65223A317D > commit --> data: IßÑ\ͬޮ—(ËûµèhŒ¥‹‘ --> data.hex: 49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 +-> code: OK +-> data.hex: 0x49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 > query "abc" +-> code: OK -> log: exists -> height: 0 -> value: abc -> value.hex: 616263 > deliver_tx "def=xyz" +-> code: OK > commit --> data: p-³"€7?¿?Ÿ‰Ú* Î,Ö+ --> data.hex: 70102DB32280373FBF3F9F89DA2A20CE2CD62B0B +-> code: OK +-> data.hex: 0x70102DB32280373FBF3F9F89DA2A20CE2CD62B0B > query "def" +-> code: OK -> log: exists -> height: 0 -> value: xyz diff --git a/tests/test_cli/ex2.abci.out b/tests/test_cli/ex2.abci.out index 202861cf4..40e10f83e 100644 --- a/tests/test_cli/ex2.abci.out +++ b/tests/test_cli/ex2.abci.out @@ -1,22 +1,28 @@ > set_option serial on +-> code: OK > check_tx 0x00 +-> code: OK > check_tx 0xff +-> code: OK > deliver_tx 0x00 +-> code: OK > check_tx 0x00 -> code: BadNonce -> log: Invalid nonce. Expected >= 1, got 0 > deliver_tx 0x01 +-> code: OK > deliver_tx 0x04 -> code: BadNonce -> log: Invalid nonce. Expected 2, got 4 > info +-> code: OK -> data: {"hashes":0,"txs":2} --> data.hex: 7B22686173686573223A302C22747873223A327D +-> data.hex: 0x7B22686173686573223A302C22747873223A327D From 6c41ec65bcd86489041fb3bf3a7c56cbe9e70dcf Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 25 Oct 2017 23:04:20 -0400 Subject: [PATCH 21/28] server: use cmn.ProtocolAndAddress --- server/grpc_server.go | 4 +--- server/socket_server.go | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/server/grpc_server.go b/server/grpc_server.go index ac3d728ac..077f0e525 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -2,7 +2,6 @@ package server import ( "net" - "strings" "google.golang.org/grpc" @@ -23,8 +22,7 @@ type GRPCServer struct { // NewGRPCServer returns a new gRPC ABCI server func NewGRPCServer(protoAddr string, app types.ABCIApplicationServer) cmn.Service { - parts := strings.SplitN(protoAddr, "://", 2) - proto, addr := parts[0], parts[1] + proto, addr := cmn.ProtocolAndAddress(protoAddr) s := &GRPCServer{ proto: proto, addr: addr, diff --git a/server/socket_server.go b/server/socket_server.go index 304a2c7f7..adc7516c6 100644 --- a/server/socket_server.go +++ b/server/socket_server.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net" - "strings" "sync" "github.com/tendermint/abci/types" @@ -30,8 +29,7 @@ type SocketServer struct { } func NewSocketServer(protoAddr string, app types.Application) cmn.Service { - parts := strings.SplitN(protoAddr, "://", 2) - proto, addr := parts[0], parts[1] + proto, addr := cmn.ProtocolAndAddress(protoAddr) s := &SocketServer{ proto: proto, addr: addr, From b6a4ca6b3c4203802f0143b2cb407c10baf75a0e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 25 Oct 2017 23:15:57 -0400 Subject: [PATCH 22/28] remove testutil --- testutil/messages.go | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 testutil/messages.go diff --git a/testutil/messages.go b/testutil/messages.go deleted file mode 100644 index 0cdddb443..000000000 --- a/testutil/messages.go +++ /dev/null @@ -1,17 +0,0 @@ -package testutil - -import ( - "github.com/tendermint/abci/types" - "github.com/tendermint/go-crypto" -) - -//---------------------------------------- - -// UTILITY -func Validator(secret string, power uint64) *types.Validator { - privKey := crypto.GenPrivKeyEd25519FromSecret([]byte(secret)) - return &types.Validator{ - PubKey: privKey.PubKey().Bytes(), - Power: power, - } -} From 4884747eb76608ee799f5d0bf51694c441cf9f62 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 25 Oct 2017 23:23:10 -0400 Subject: [PATCH 23/28] tests: add simple client/server test with no addr prefix --- tests/client_server_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/client_server_test.go diff --git a/tests/client_server_test.go b/tests/client_server_test.go new file mode 100644 index 000000000..cc946fcef --- /dev/null +++ b/tests/client_server_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + abciclient "github.com/tendermint/abci/client" + "github.com/tendermint/abci/example/dummy" + abciserver "github.com/tendermint/abci/server" +) + +func TestClientServerNoAddrPrefix(t *testing.T) { + addr := "localhost:46658" + transport := "socket" + app := dummy.NewDummyApplication() + + server, err := abciserver.NewServer(addr, transport, app) + assert.NoError(t, err, "expected no error on NewServer") + _, err = server.Start() + assert.NoError(t, err, "expected no error on server.Start") + + client, err := abciclient.NewClient(addr, transport, true) + assert.NoError(t, err, "expected no error on NewClient") + _, err = client.Start() + assert.NoError(t, err, "expected no error on client.Start") +} From a0e38dc58374f485481ea07b23659d85f670a694 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 25 Oct 2017 23:34:37 -0400 Subject: [PATCH 24/28] dummy: verify pubkey is go-crypto encoded in DeliverTx. closes #51 --- example/dummy/persistent_dummy.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index 15fe150d5..4c4801755 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -149,15 +150,25 @@ func isValidatorTx(tx []byte) bool { // format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result { tx = tx[len(ValidatorSetChangePrefix):] + + //get the pubkey and power pubKeyAndPower := strings.Split(string(tx), "/") if len(pubKeyAndPower) != 2 { return types.ErrEncodingError.SetLog(cmn.Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower)) } pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] + + // decode the pubkey, ensuring its go-crypto encoded pubkey, err := hex.DecodeString(pubkeyS) if err != nil { return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%s) is invalid hex", pubkeyS)) } + _, err = crypto.PubKeyFromBytes(pubkey) + if err != nil { + return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%X) is invalid go-crypto encoded", pubkey)) + } + + // decode the power power, err := strconv.Atoi(powerS) if err != nil { return types.ErrEncodingError.SetLog(cmn.Fmt("Power (%s) is not an int", powerS)) From 461191d2f7b60b98e2705363cacf9651334cfeb0 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Thu, 26 Oct 2017 08:37:42 -0400 Subject: [PATCH 25/28] cli: clean up error handling --- cmd/abci-cli/abci-cli.go | 133 ++++++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 56 deletions(-) diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index e098b9a38..294c88cfb 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -83,8 +83,7 @@ var RootCmd = &cobra.Command{ var err error client, err = abcicli.NewClient(address, abci, false) if err != nil { - logger.Error(err.Error()) - os.Exit(1) + return err } client.SetLogger(logger.With("module", "abci-client")) if _, err := client.Start(); err != nil { @@ -98,7 +97,7 @@ var RootCmd = &cobra.Command{ func Execute() { addGlobalFlags() addCommands() - RootCmd.Execute() //err? + RootCmd.Execute() } func addGlobalFlags() { @@ -145,7 +144,9 @@ var batchCmd = &cobra.Command{ Use: "batch", Short: "Run a batch of abci commands against an application", Long: "", - Run: cmdBatch, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdBatch(cmd, args) + }, } var consoleCmd = &cobra.Command{ @@ -153,68 +154,88 @@ var consoleCmd = &cobra.Command{ Short: "Start an interactive abci console for multiple commands", Long: "", ValidArgs: []string{"batch", "echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"}, - Run: cmdConsole, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdConsole(cmd, args) + }, } var echoCmd = &cobra.Command{ Use: "echo", Short: "Have the application echo a message", Long: "", - Run: cmdEcho, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdEcho(cmd, args) + }, } var infoCmd = &cobra.Command{ Use: "info", Short: "Get some info about the application", Long: "", - Run: cmdInfo, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdInfo(cmd, args) + }, } var setOptionCmd = &cobra.Command{ Use: "set_option", Short: "Set an option on the application", Long: "", - Run: cmdSetOption, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdSetOption(cmd, args) + }, } var deliverTxCmd = &cobra.Command{ Use: "deliver_tx", Short: "Deliver a new transaction to the application", Long: "", - Run: cmdDeliverTx, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdDeliverTx(cmd, args) + }, } var checkTxCmd = &cobra.Command{ Use: "check_tx", Short: "Validate a transaction", Long: "", - Run: cmdCheckTx, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdCheckTx(cmd, args) + }, } var commitCmd = &cobra.Command{ Use: "commit", Short: "Commit the application state and return the Merkle root hash", Long: "", - Run: cmdCommit, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdCommit(cmd, args) + }, } var queryCmd = &cobra.Command{ Use: "query", Short: "Query the application state", Long: "", - Run: cmdQuery, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdQuery(cmd, args) + }, } var counterCmd = &cobra.Command{ Use: "counter", Short: "ABCI demo example", Long: "", - Run: cmdCounter, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdCounter(cmd, args) + }, } var dummyCmd = &cobra.Command{ Use: "dummy", Short: "ABCI demo example", Long: "", - Run: cmdDummy, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdDummy(cmd, args) + }, } // Generates new Args array based off of previous call args to maintain flag persistence @@ -233,95 +254,100 @@ func persistentArgs(line []byte) []string { //-------------------------------------------------------------------------------- -func cmdBatch(cmd *cobra.Command, args []string) { +func cmdBatch(cmd *cobra.Command, args []string) error { bufReader := bufio.NewReader(os.Stdin) for { line, more, err := bufReader.ReadLine() if more { - ifExit(errors.New("Input line is too long")) + return errors.New("Input line is too long") } else if err == io.EOF { break } else if len(line) == 0 { continue } else if err != nil { - ifExit(err) + return err } pArgs := persistentArgs(line) out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() if err != nil { - ifExit(err) + return err } fmt.Println(string(out)) } + return nil } -func cmdConsole(cmd *cobra.Command, args []string) { +func cmdConsole(cmd *cobra.Command, args []string) error { for { fmt.Printf("> ") bufReader := bufio.NewReader(os.Stdin) line, more, err := bufReader.ReadLine() if more { - ifExit(errors.New("Input is too long")) + return errors.New("Input is too long") } else if err != nil { - ifExit(err) + return err } pArgs := persistentArgs(line) out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() if err != nil { - ifExit(err) + return err } fmt.Println(string(out)) } + return nil } // Have the application echo a message -func cmdEcho(cmd *cobra.Command, args []string) { +func cmdEcho(cmd *cobra.Command, args []string) error { if len(args) != 1 { - ifExit(errors.New("Command echo takes only 1 argument")) + return errors.New("Command echo takes only 1 argument") } resEcho := client.EchoSync(args[0]) printResponse(cmd, args, response{ Data: resEcho.Data, }) + return nil } // Get some info from the application -func cmdInfo(cmd *cobra.Command, args []string) { +func cmdInfo(cmd *cobra.Command, args []string) error { var version string if len(args) == 1 { version = args[0] } resInfo, err := client.InfoSync(types.RequestInfo{version}) if err != nil { - ifExit(err) + return err } printResponse(cmd, args, response{ Data: []byte(resInfo.Data), }) + return nil } // Set an option on the application -func cmdSetOption(cmd *cobra.Command, args []string) { +func cmdSetOption(cmd *cobra.Command, args []string) error { if len(args) != 2 { - ifExit(errors.New("Command set_option takes exactly 2 arguments (key, value)")) + return errors.New("Command set_option takes exactly 2 arguments (key, value)") } resSetOption := client.SetOptionSync(args[0], args[1]) printResponse(cmd, args, response{ Log: resSetOption.Log, }) + return nil } // Append a new tx to application -func cmdDeliverTx(cmd *cobra.Command, args []string) { +func cmdDeliverTx(cmd *cobra.Command, args []string) error { if len(args) != 1 { - ifExit(errors.New("Command deliver_tx takes only 1 argument")) + return errors.New("Command deliver_tx takes only 1 argument") } txBytes, err := stringOrHexToBytes(args[0]) if err != nil { - ifExit(err) + return err } res := client.DeliverTxSync(txBytes) printResponse(cmd, args, response{ @@ -329,16 +355,17 @@ func cmdDeliverTx(cmd *cobra.Command, args []string) { Data: res.Data, Log: res.Log, }) + return nil } // Validate a tx -func cmdCheckTx(cmd *cobra.Command, args []string) { +func cmdCheckTx(cmd *cobra.Command, args []string) error { if len(args) != 1 { - ifExit(errors.New("Command check_tx takes only 1 argument")) + return errors.New("Command check_tx takes only 1 argument") } txBytes, err := stringOrHexToBytes(args[0]) if err != nil { - ifExit(err) + return err } res := client.CheckTxSync(txBytes) printResponse(cmd, args, response{ @@ -346,27 +373,29 @@ func cmdCheckTx(cmd *cobra.Command, args []string) { Data: res.Data, Log: res.Log, }) + return nil } // Get application Merkle root hash -func cmdCommit(cmd *cobra.Command, args []string) { +func cmdCommit(cmd *cobra.Command, args []string) error { res := client.CommitSync() printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, }) + return nil } // Query application state -func cmdQuery(cmd *cobra.Command, args []string) { +func cmdQuery(cmd *cobra.Command, args []string) error { if len(args) != 1 { - ifExit(errors.New("Command query takes only 1 argument, the query bytes")) + return errors.New("Command query takes only 1 argument, the query bytes") } queryBytes, err := stringOrHexToBytes(args[0]) if err != nil { - ifExit(err) + return err } resQuery, err := client.QuerySync(types.RequestQuery{ @@ -376,7 +405,7 @@ func cmdQuery(cmd *cobra.Command, args []string) { Prove: prove, }) if err != nil { - ifExit(err) + return err } printResponse(cmd, args, response{ Code: resQuery.Code, @@ -388,9 +417,10 @@ func cmdQuery(cmd *cobra.Command, args []string) { Proof: resQuery.Proof, }, }) + return nil } -func cmdCounter(cmd *cobra.Command, args []string) { +func cmdCounter(cmd *cobra.Command, args []string) error { app := counter.NewCounterApplication(serial) @@ -399,13 +429,11 @@ func cmdCounter(cmd *cobra.Command, args []string) { // Start the listener srv, err := server.NewServer(addrC, abci, app) if err != nil { - logger.Error(err.Error()) - os.Exit(1) + return err } srv.SetLogger(logger.With("module", "abci-server")) if _, err := srv.Start(); err != nil { - logger.Error(err.Error()) - os.Exit(1) + return err } // Wait forever @@ -413,9 +441,10 @@ func cmdCounter(cmd *cobra.Command, args []string) { // Cleanup srv.Stop() }) + return nil } -func cmdDummy(cmd *cobra.Command, args []string) { +func cmdDummy(cmd *cobra.Command, args []string) error { logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) // Create the application - in memory or persisted to disk @@ -430,13 +459,11 @@ func cmdDummy(cmd *cobra.Command, args []string) { // Start the listener srv, err := server.NewServer(addrD, abci, app) if err != nil { - logger.Error(err.Error()) - os.Exit(1) + return err } srv.SetLogger(logger.With("module", "abci-server")) if _, err := srv.Start(); err != nil { - logger.Error(err.Error()) - os.Exit(1) + return err } // Wait forever @@ -444,6 +471,7 @@ func cmdDummy(cmd *cobra.Command, args []string) { // Cleanup srv.Stop() }) + return nil } //-------------------------------------------------------------------------------- @@ -503,10 +531,3 @@ func stringOrHexToBytes(s string) ([]byte, error) { return []byte(s[1 : len(s)-1]), nil } - -func ifExit(err error) { - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} From f013ee5cf99ee74c0dad568cd0668fa14031f213 Mon Sep 17 00:00:00 2001 From: Zach Ramsay Date: Thu, 26 Oct 2017 08:51:43 -0400 Subject: [PATCH 26/28] cli: use cobra's new ExactArgs() feature --- cmd/abci-cli/abci-cli.go | 27 +++++++++++---------------- glide.lock | 8 ++++---- glide.yaml | 1 + 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 294c88cfb..1beb08507 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -144,6 +144,7 @@ var batchCmd = &cobra.Command{ Use: "batch", Short: "Run a batch of abci commands against an application", Long: "", + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdBatch(cmd, args) }, @@ -153,6 +154,7 @@ var consoleCmd = &cobra.Command{ Use: "console", Short: "Start an interactive abci console for multiple commands", Long: "", + Args: cobra.ExactArgs(0), ValidArgs: []string{"batch", "echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"}, RunE: func(cmd *cobra.Command, args []string) error { return cmdConsole(cmd, args) @@ -163,6 +165,7 @@ var echoCmd = &cobra.Command{ Use: "echo", Short: "Have the application echo a message", Long: "", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdEcho(cmd, args) }, @@ -171,6 +174,7 @@ var infoCmd = &cobra.Command{ Use: "info", Short: "Get some info about the application", Long: "", + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdInfo(cmd, args) }, @@ -179,6 +183,7 @@ var setOptionCmd = &cobra.Command{ Use: "set_option", Short: "Set an option on the application", Long: "", + Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { return cmdSetOption(cmd, args) }, @@ -188,6 +193,7 @@ var deliverTxCmd = &cobra.Command{ Use: "deliver_tx", Short: "Deliver a new transaction to the application", Long: "", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdDeliverTx(cmd, args) }, @@ -197,6 +203,7 @@ var checkTxCmd = &cobra.Command{ Use: "check_tx", Short: "Validate a transaction", Long: "", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdCheckTx(cmd, args) }, @@ -206,6 +213,7 @@ var commitCmd = &cobra.Command{ Use: "commit", Short: "Commit the application state and return the Merkle root hash", Long: "", + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdCommit(cmd, args) }, @@ -215,6 +223,7 @@ var queryCmd = &cobra.Command{ Use: "query", Short: "Query the application state", Long: "", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdQuery(cmd, args) }, @@ -224,6 +233,7 @@ var counterCmd = &cobra.Command{ Use: "counter", Short: "ABCI demo example", Long: "", + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdCounter(cmd, args) }, @@ -233,6 +243,7 @@ var dummyCmd = &cobra.Command{ Use: "dummy", Short: "ABCI demo example", Long: "", + Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdDummy(cmd, args) }, @@ -302,9 +313,6 @@ func cmdConsole(cmd *cobra.Command, args []string) error { // Have the application echo a message func cmdEcho(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return errors.New("Command echo takes only 1 argument") - } resEcho := client.EchoSync(args[0]) printResponse(cmd, args, response{ Data: resEcho.Data, @@ -330,9 +338,6 @@ func cmdInfo(cmd *cobra.Command, args []string) error { // Set an option on the application func cmdSetOption(cmd *cobra.Command, args []string) error { - if len(args) != 2 { - return errors.New("Command set_option takes exactly 2 arguments (key, value)") - } resSetOption := client.SetOptionSync(args[0], args[1]) printResponse(cmd, args, response{ Log: resSetOption.Log, @@ -342,9 +347,6 @@ func cmdSetOption(cmd *cobra.Command, args []string) error { // Append a new tx to application func cmdDeliverTx(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return errors.New("Command deliver_tx takes only 1 argument") - } txBytes, err := stringOrHexToBytes(args[0]) if err != nil { return err @@ -360,9 +362,6 @@ func cmdDeliverTx(cmd *cobra.Command, args []string) error { // Validate a tx func cmdCheckTx(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return errors.New("Command check_tx takes only 1 argument") - } txBytes, err := stringOrHexToBytes(args[0]) if err != nil { return err @@ -389,10 +388,6 @@ func cmdCommit(cmd *cobra.Command, args []string) error { // Query application state func cmdQuery(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return errors.New("Command query takes only 1 argument, the query bytes") - } - queryBytes, err := stringOrHexToBytes(args[0]) if err != nil { return err diff --git a/glide.lock b/glide.lock index 49795959b..8ee12dc75 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: 1530ad93695fa2861f1572e3e1eef1b6604beb548fd4832985f6c6350260c2b3 -updated: 2017-10-18T14:27:16.428209213-04:00 +hash: 3c8680f0a289567a29f737be5f1d5f242c7e2afd84bdd023dd74596b88508fc2 +updated: 2017-10-26T08:45:51.300025559-04:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -39,7 +39,7 @@ imports: - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/spf13/cobra - version: 4cdb38c072b86bf795d2c81de50784d9fdd6eb77 + version: 2df9a531813370438a4d79bfc33e21f58063ed87 - name: github.com/spf13/pflag version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 - name: github.com/syndtr/goleveldb @@ -69,7 +69,7 @@ imports: subpackages: - data - name: github.com/tendermint/iavl - version: 721710e7aa59f61dbfbf558943a207ba3fe6b926 + version: 595f3dcd5b6cd4a292e90757ae6d367fd7a6e653 - name: github.com/tendermint/tmlibs version: 8e5266a9ef2527e68a1571f932db8228a331b556 subpackages: diff --git a/glide.yaml b/glide.yaml index cd8c994ce..ccd41cdc3 100644 --- a/glide.yaml +++ b/glide.yaml @@ -19,6 +19,7 @@ import: - merkle - process - package: github.com/spf13/cobra + version: master - package: golang.org/x/net subpackages: - context From d973cb5df983bf2c7ed780bc111e3bb8c25c422e Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 27 Oct 2017 12:12:07 -0400 Subject: [PATCH 27/28] changelog and version --- CHANGELOG.md | 12 ++++++++++++ version/version.go | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91bd06494..5ed93b91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.7.0 (October 27, 2017) + +BREAKING CHANGES: + - [cli] consolidate example apps under a single `abci-cli` binary + +IMPROVEMENTS: + - [cli] use spf13/cobra instead of urfave/cli + - [dummy] use iavl instead of merkleeyes, and add support for historical queries + +BUG FIXES: + - [client] fix deadlock on StopForError + ## 0.6.0 (September 22, 2017) BREAKING CHANGES: diff --git a/version/version.go b/version/version.go index 34b1230ed..bbea51bcb 100644 --- a/version/version.go +++ b/version/version.go @@ -3,7 +3,7 @@ package version // NOTE: we should probably be versioning the ABCI and the abci-cli separately const Maj = "0" -const Min = "6" +const Min = "7" const Fix = "0" -const Version = "0.6.0" +const Version = "0.7.0" From c9612f094b8181c3986a07f85cd8a8a07c9676c8 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 27 Oct 2017 12:13:16 -0400 Subject: [PATCH 28/28] glide --- glide.lock | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/glide.lock b/glide.lock index 8ee12dc75..2a992d724 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ hash: 3c8680f0a289567a29f737be5f1d5f242c7e2afd84bdd023dd74596b88508fc2 -updated: 2017-10-26T08:45:51.300025559-04:00 +updated: 2017-10-27T12:12:58.940745472-04:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -24,10 +24,13 @@ imports: - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf - version: 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8 + version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 subpackages: - proto + - ptypes - ptypes/any + - ptypes/duration + - ptypes/timestamp - name: github.com/golang/snappy version: 553a641470496b2327abcac10b36396bd98e45c9 - name: github.com/inconshreveable/mousetrap @@ -39,9 +42,9 @@ imports: - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d - name: github.com/spf13/cobra - version: 2df9a531813370438a4d79bfc33e21f58063ed87 + version: 7b2c5ac9fc04fc5efafb60700713d4fa609b777b - name: github.com/spf13/pflag - version: e57e3eeb33f795204c1ca35f56c44f83227c6e66 + version: 80fe0fb4eba54167e2ccae1c6c950e72abf61b73 - name: github.com/syndtr/goleveldb version: 8c81ea47d4c41a385645e133e15510fc6a2a74b4 subpackages: @@ -63,15 +66,15 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: 8e7f0e7701f92206679ad093d013b9b162427631 + version: db5603e37435933c13665a708055fadd18222f5f - name: github.com/tendermint/go-wire - version: 26ee079df7fca1958da8995c727b59759b197534 + version: 8ee84b5b2581530168daf66fc89c548d27403c57 subpackages: - data - name: github.com/tendermint/iavl version: 595f3dcd5b6cd4a292e90757ae6d367fd7a6e653 - name: github.com/tendermint/tmlibs - version: 8e5266a9ef2527e68a1571f932db8228a331b556 + version: 092eb701c7276907cdbed258750e22ce895b6735 subpackages: - common - db @@ -88,7 +91,7 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: feeb485667d1fdabe727840fe00adc22431bc86e + version: cd69bc3fc700721b709c3a59e16e24c67b58f6ff subpackages: - context - http2 @@ -105,21 +108,24 @@ imports: - unicode/bidi - unicode/norm - name: google.golang.org/genproto - version: 411e09b969b1170a9f0c467558eb4c4c110d9c77 + version: f676e0f3ac6395ff1a529ae59a6670878a8371a6 subpackages: - googleapis/rpc/status - name: google.golang.org/grpc - version: 844f573616520565fdc6fb4db242321b5456fd6d + version: f7bf885db0b7479a537ec317c6e48ce53145f3db subpackages: + - balancer - codes + - connectivity - credentials - - grpclb/grpc_lb_v1 + - grpclb/grpc_lb_v1/messages - grpclog - internal - keepalive - metadata - naming - peer + - resolver - stats - status - tap