diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 0168bea4..1b08b76a 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -17,12 +17,18 @@ import ( // Structure for data passed to print response. type response struct { - Data []byte - Code types.CodeType + // generic abci response + Data []byte + Code types.CodeType + Log string + + Query *queryResponse +} + +type queryResponse struct { Key []byte Value []byte - Log string - Height string + Height uint64 Proof []byte } @@ -281,6 +287,7 @@ func cmdCheckTx(c *cli.Context) error { func cmdCommit(c *cli.Context) error { res := client.CommitSync() printResponse(c, response{ + Code: res.Code, Data: res.Data, Log: res.Log, }) @@ -308,12 +315,14 @@ func cmdQuery(c *cli.Context) error { return err } printResponse(c, response{ - Code: resQuery.Code, - Key: resQuery.Key, - Value: resQuery.Value, - Log: resQuery.Log, - Height: fmt.Sprintf("%v", resQuery.Height), - //Proof: resQuery.Proof, + Code: resQuery.Code, + Log: resQuery.Log, + Query: &queryResponse{ + Key: resQuery.Key, + Value: resQuery.Value, + Height: resQuery.Height, + Proof: resQuery.Proof, + }, }) return nil } @@ -328,29 +337,30 @@ func printResponse(c *cli.Context, rsp response) { fmt.Println(">", c.Command.Name, strings.Join(c.Args(), " ")) } - if rsp.Code != types.CodeType_OK { + if !rsp.Code.IsOK() { 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) } - if len(rsp.Key) != 0 { - fmt.Printf("-> key: %s\n", rsp.Key) - fmt.Printf("-> key.hex: %X\n", rsp.Key) - } - if len(rsp.Value) != 0 { - fmt.Printf("-> value: %s\n", rsp.Value) - fmt.Printf("-> value.hex: %X\n", rsp.Value) - } if rsp.Log != "" { fmt.Printf("-> log: %s\n", rsp.Log) } - if rsp.Height != "" { - fmt.Printf("-> height: %s\n", rsp.Height) - } - if rsp.Proof != nil { - fmt.Printf("-> proof: %X\n", rsp.Proof) + + if rsp.Query != nil { + fmt.Printf("-> height: %d\n", rsp.Query.Height) + if rsp.Query.Key != nil { + fmt.Printf("-> key: %s\n", rsp.Query.Key) + fmt.Printf("-> key.hex: %X\n", rsp.Query.Key) + } + if rsp.Query.Value != nil { + fmt.Printf("-> value: %s\n", rsp.Query.Value) + fmt.Printf("-> value.hex: %X\n", rsp.Query.Value) + } + if rsp.Query.Proof != nil { + fmt.Printf("-> proof: %X\n", rsp.Query.Proof) + } } if verbose { diff --git a/example/counter/counter.go b/example/counter/counter.go index fa0bab58..c40541ed 100644 --- a/example/counter/counter.go +++ b/example/counter/counter.go @@ -2,10 +2,9 @@ package counter import ( "encoding/binary" - "fmt" "github.com/tendermint/abci/types" - . "github.com/tendermint/go-common" + cmn "github.com/tendermint/go-common" ) type CounterApplication struct { @@ -21,7 +20,7 @@ func NewCounterApplication(serial bool) *CounterApplication { } func (app *CounterApplication) Info() types.ResponseInfo { - return types.ResponseInfo{Data: fmt.Sprintf("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)} + return types.ResponseInfo{Data: cmn.Fmt("{\"hashes\":%v,\"txs\":%v}", app.hashCount, app.txCount)} } func (app *CounterApplication) SetOption(key string, value string) (log string) { @@ -34,13 +33,13 @@ func (app *CounterApplication) SetOption(key string, value string) (log string) func (app *CounterApplication) DeliverTx(tx []byte) types.Result { if app.serial { if len(tx) > 8 { - return types.ErrEncodingError.SetLog(fmt.Sprintf("Max tx size is 8 bytes, got %d", len(tx))) + return types.ErrEncodingError.SetLog(cmn.Fmt("Max tx size is 8 bytes, got %d", len(tx))) } tx8 := make([]byte, 8) copy(tx8[len(tx8)-len(tx):], tx) txValue := binary.BigEndian.Uint64(tx8) if txValue != uint64(app.txCount) { - return types.ErrBadNonce.SetLog(fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue)) + return types.ErrBadNonce.SetLog(cmn.Fmt("Invalid nonce. Expected %v, got %v", app.txCount, txValue)) } } app.txCount++ @@ -50,13 +49,13 @@ func (app *CounterApplication) DeliverTx(tx []byte) types.Result { func (app *CounterApplication) CheckTx(tx []byte) types.Result { if app.serial { if len(tx) > 8 { - return types.ErrEncodingError.SetLog(fmt.Sprintf("Max tx size is 8 bytes, got %d", len(tx))) + return types.ErrEncodingError.SetLog(cmn.Fmt("Max tx size is 8 bytes, got %d", len(tx))) } tx8 := make([]byte, 8) copy(tx8[len(tx8)-len(tx):], tx) txValue := binary.BigEndian.Uint64(tx8) if txValue < uint64(app.txCount) { - return types.ErrBadNonce.SetLog(fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)) + return types.ErrBadNonce.SetLog(cmn.Fmt("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)) } } return types.OK @@ -75,10 +74,10 @@ func (app *CounterApplication) Commit() types.Result { func (app *CounterApplication) Query(reqQuery types.RequestQuery) types.ResponseQuery { switch reqQuery.Path { case "hash": - return types.ResponseQuery{Value: []byte(Fmt("%v", app.hashCount))} + return types.ResponseQuery{Value: []byte(cmn.Fmt("%v", app.hashCount))} case "tx": - return types.ResponseQuery{Value: []byte(Fmt("%v", app.txCount))} + return types.ResponseQuery{Value: []byte(cmn.Fmt("%v", app.txCount))} default: - return types.ResponseQuery{Log: Fmt("Invalid query path. Expected hash or tx, got %v", reqQuery.Path)} + return types.ResponseQuery{Log: cmn.Fmt("Invalid query path. Expected hash or tx, got %v", reqQuery.Path)} } } diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index fd66250b..f88b1b20 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -1,10 +1,10 @@ package dummy import ( - "fmt" "strings" "github.com/tendermint/abci/types" + cmn "github.com/tendermint/go-common" "github.com/tendermint/go-merkle" ) @@ -20,7 +20,7 @@ func NewDummyApplication() *DummyApplication { } func (app *DummyApplication) Info() (resInfo types.ResponseInfo) { - return types.ResponseInfo{Data: fmt.Sprintf("{\"size\":%v}", app.state.Size())} + return types.ResponseInfo{Data: cmn.Fmt("{\"size\":%v}", app.state.Size())} } // tx is either "key=value" or just arbitrary bytes diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index fbbf97a5..879cf3c4 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -2,7 +2,6 @@ package dummy import ( "bytes" - "fmt" "io/ioutil" "sort" "testing" @@ -13,7 +12,7 @@ import ( "github.com/tendermint/abci/types" cmn "github.com/tendermint/go-common" "github.com/tendermint/go-crypto" - merkle "github.com/tendermint/go-merkle" + "github.com/tendermint/go-merkle" ) func testDummy(t *testing.T, app types.Application, tx []byte, key, value string) { @@ -115,7 +114,7 @@ func TestValSetChanges(t *testing.T) { nInit := 5 vals := make([]*types.Validator, total) for i := 0; i < total; i++ { - pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(fmt.Sprintf("test%d", i))).PubKey().Bytes() + pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() power := cmn.RandInt() vals[i] = &types.Validator{pubkey, uint64(power)} } diff --git a/example/dummy/dummy_test.go.orig b/example/dummy/dummy_test.go.orig deleted file mode 100644 index 5cf7eee7..00000000 --- a/example/dummy/dummy_test.go.orig +++ /dev/null @@ -1,321 +0,0 @@ -package dummy - -import ( - "bytes" - "io/ioutil" - "sort" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - . "github.com/tendermint/go-common" - "github.com/tendermint/go-crypto" - merkle "github.com/tendermint/go-merkle" - "github.com/tendermint/go-wire" -<<<<<<< HEAD - "github.com/tendermint/abci/types" -) - -func testDummy(t *testing.T, dummy types.Application, tx []byte, key, value string) { - if r := dummy.DeliverTx(tx); r.IsErr() { - t.Fatal(r) - } - if r := dummy.DeliverTx(tx); r.IsErr() { - t.Fatal(r) - } - - r := dummy.Query([]byte(key)) - if r.IsErr() { - t.Fatal(r) - } -======= - tmspcli "github.com/tendermint/tmsp/client" - "github.com/tendermint/tmsp/server" - "github.com/tendermint/tmsp/types" -) - -func testDummy(t *testing.T, app types.Application, tx []byte, key, value string) { - ar := app.AppendTx(tx) - require.False(t, ar.IsErr(), ar) - // repeating tx doesn't raise error - ar = app.AppendTx(tx) - require.False(t, ar.IsErr(), ar) ->>>>>>> Add tests for client-server proofs over socket and grpc - - // make sure query is fine - r := app.Query([]byte(key)) - require.False(t, r.IsErr(), r) - q := new(QueryResult) - err := wire.ReadJSONBytes(r.Data, q) - require.Nil(t, err) - require.Equal(t, value, q.Value) - - // make sure proof is fine - rp := app.Proof([]byte(key), 0) - require.False(t, rp.IsErr(), rp) - p, err := merkle.LoadProof(rp.Data) - require.Nil(t, err) - require.True(t, p.Valid()) - assert.Equal(t, []byte(key), p.Key()) - assert.Equal(t, []byte(value), p.Value()) -} - -func TestDummyKV(t *testing.T) { - dummy := NewDummyApplication() - key := "abc" - value := key - tx := []byte(key) - testDummy(t, dummy, tx, key, value) - - value = "def" - tx = []byte(key + "=" + value) - testDummy(t, dummy, tx, key, value) -} - -func TestPersistentDummyKV(t *testing.T) { - dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO - if err != nil { - t.Fatal(err) - } - dummy := NewPersistentDummyApplication(dir) - key := "abc" - value := key - tx := []byte(key) - testDummy(t, dummy, tx, key, value) - - value = "def" - tx = []byte(key + "=" + value) - testDummy(t, dummy, tx, key, value) -} - -func TestPersistentDummyInfo(t *testing.T) { - dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO - if err != nil { - t.Fatal(err) - } - dummy := NewPersistentDummyApplication(dir) - height := uint64(0) - - resInfo := dummy.Info() - if resInfo.LastBlockHeight != height { - t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) - } - - // make and apply block - height = uint64(1) - hash := []byte("foo") - header := &types.Header{ - Height: uint64(height), - } - dummy.BeginBlock(hash, header) - dummy.EndBlock(height) - dummy.Commit() - - resInfo = dummy.Info() - if resInfo.LastBlockHeight != height { - t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) - } - -} - -// add a validator, remove a validator, update a validator -func TestValSetChanges(t *testing.T) { - dir, err := ioutil.TempDir("/tmp", "abci-dummy-test") // TODO - if err != nil { - t.Fatal(err) - } - dummy := NewPersistentDummyApplication(dir) - - // init with some validators - total := 10 - nInit := 5 - vals := make([]*types.Validator, total) - for i := 0; i < total; i++ { - pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(Fmt("test%d", i))).PubKey().Bytes() - power := RandInt() - vals[i] = &types.Validator{pubkey, uint64(power)} - } - // iniitalize with the first nInit - dummy.InitChain(vals[:nInit]) - - vals1, vals2 := vals[:nInit], dummy.Validators() - valsEqual(t, vals1, vals2) - - var v1, v2, v3 *types.Validator - - // add some validators - v1, v2 = vals[nInit], vals[nInit+1] - diff := []*types.Validator{v1, v2} - tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power) - tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power) - - makeApplyBlock(t, dummy, 1, diff, tx1, tx2) - - vals1, vals2 = vals[:nInit+2], dummy.Validators() - valsEqual(t, vals1, vals2) - - // remove some validators - v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit] - v1.Power = 0 - v2.Power = 0 - v3.Power = 0 - diff = []*types.Validator{v1, v2, v3} - tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power) - tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power) - tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power) - - makeApplyBlock(t, dummy, 2, diff, tx1, tx2, tx3) - - vals1 = append(vals[:nInit-2], vals[nInit+1]) - vals2 = dummy.Validators() - valsEqual(t, vals1, vals2) - - // update some validators - v1 = vals[0] - if v1.Power == 5 { - v1.Power = 6 - } else { - v1.Power = 5 - } - diff = []*types.Validator{v1} - tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power) - - makeApplyBlock(t, dummy, 3, diff, tx1) - - vals1 = append([]*types.Validator{v1}, vals1[1:len(vals1)]...) - vals2 = dummy.Validators() - valsEqual(t, vals1, vals2) - -} - -func makeApplyBlock(t *testing.T, dummy types.Application, heightInt int, diff []*types.Validator, txs ...[]byte) { - // make and apply block - height := uint64(heightInt) - hash := []byte("foo") - header := &types.Header{ - Height: height, - } - - dummyChain := dummy.(types.BlockchainAware) // hmm... - dummyChain.BeginBlock(hash, header) - for _, tx := range txs { - if r := dummy.DeliverTx(tx); r.IsErr() { - t.Fatal(r) - } - } - resEndBlock := dummyChain.EndBlock(height) - dummy.Commit() - - valsEqual(t, diff, resEndBlock.Diffs) - -} - -// order doesn't matter -func valsEqual(t *testing.T, vals1, vals2 []*types.Validator) { - if len(vals1) != len(vals2) { - t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1)) - } - sort.Sort(types.Validators(vals1)) - sort.Sort(types.Validators(vals2)) - for i, v1 := range vals1 { - v2 := vals2[i] - if !bytes.Equal(v1.PubKey, v2.PubKey) || - v1.Power != v2.Power { - t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power) - } - } -} - -func makeSocketClientServer(app types.Application, name string) (tmspcli.Client, Service, error) { - // Start the listener - socket := Fmt("unix://%s.sock", name) - server, err := server.NewSocketServer(socket, app) - if err != nil { - return nil, nil, err - } - - // Connect to the socket - client, err := tmspcli.NewSocketClient(socket, false) - if err != nil { - server.Stop() - return nil, nil, err - } - client.Start() - - return client, server, err -} - -func makeGRPCClientServer(app types.Application, name string) (tmspcli.Client, Service, error) { - // Start the listener - socket := Fmt("unix://%s.sock", name) - - gapp := types.NewGRPCApplication(app) - server, err := server.NewGRPCServer(socket, gapp) - if err != nil { - return nil, nil, err - } - - client, err := tmspcli.NewGRPCClient(socket, true) - if err != nil { - server.Stop() - return nil, nil, err - } - return client, server, err -} - -func TestClientServer(t *testing.T) { - // set up socket app - dummy := NewDummyApplication() - client, server, err := makeSocketClientServer(dummy, "dummy-socket") - require.Nil(t, err) - defer server.Stop() - defer client.Stop() - - runClientTests(t, client) - - // set up grpc app - dummy = NewDummyApplication() - gclient, gserver, err := makeGRPCClientServer(dummy, "dummy-grpc") - require.Nil(t, err) - defer gserver.Stop() - defer gclient.Stop() - - runClientTests(t, gclient) -} - -func runClientTests(t *testing.T, client tmspcli.Client) { - // run some tests.... - key := "abc" - value := key - tx := []byte(key) - testClient(t, client, tx, key, value) - - value = "def" - tx = []byte(key + "=" + value) - testClient(t, client, tx, key, value) -} - -func testClient(t *testing.T, app tmspcli.Client, tx []byte, key, value string) { - ar := app.AppendTxSync(tx) - require.False(t, ar.IsErr(), ar) - // repeating tx doesn't raise error - ar = app.AppendTxSync(tx) - require.False(t, ar.IsErr(), ar) - - // make sure query is fine - r := app.QuerySync([]byte(key)) - require.False(t, r.IsErr(), r) - q := new(QueryResult) - err := wire.ReadJSONBytes(r.Data, q) - require.Nil(t, err) - require.Equal(t, value, q.Value) - - // make sure proof is fine - rp := app.ProofSync([]byte(key), 0) - require.False(t, rp.IsErr(), rp) - p, err := merkle.LoadProof(rp.Data) - require.Nil(t, err) - require.True(t, p.Valid()) - assert.Equal(t, []byte(key), p.Key()) - assert.Equal(t, []byte(value), p.Value()) -} diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index 73366c7e..48eff420 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -3,7 +3,6 @@ package dummy import ( "bytes" "encoding/hex" - "fmt" "strconv" "strings" @@ -136,7 +135,7 @@ func LoadLastBlock(db dbm.DB) (lastBlock LastBlockInfo) { wire.ReadBinaryPtr(&lastBlock, r, 0, n, err) if *err != nil { // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED - log.Crit(fmt.Sprintf("Data has been corrupted or its spec has changed: %v\n", *err)) + log.Crit(cmn.Fmt("Data has been corrupted or its spec has changed: %v\n", *err)) } // TODO: ensure that buf is completely read. } @@ -174,7 +173,7 @@ func (app *PersistentDummyApplication) Validators() (validators []*types.Validat } func MakeValSetChangeTx(pubkey []byte, power uint64) []byte { - return []byte(fmt.Sprintf("val:%X/%d", pubkey, power)) + return []byte(cmn.Fmt("val:%X/%d", pubkey, power)) } func isValidatorTx(tx []byte) bool { @@ -189,16 +188,16 @@ func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result { tx = tx[len(ValidatorSetChangePrefix):] pubKeyAndPower := strings.Split(string(tx), "/") if len(pubKeyAndPower) != 2 { - return types.ErrEncodingError.SetLog(fmt.Sprintf("Expected 'pubkey/power'. Got %v", pubKeyAndPower)) + return types.ErrEncodingError.SetLog(cmn.Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower)) } pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] pubkey, err := hex.DecodeString(pubkeyS) if err != nil { - return types.ErrEncodingError.SetLog(fmt.Sprintf("Pubkey (%s) is invalid hex", pubkeyS)) + return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%s) is invalid hex", pubkeyS)) } power, err := strconv.Atoi(powerS) if err != nil { - return types.ErrEncodingError.SetLog(fmt.Sprintf("Power (%s) is not an int", powerS)) + return types.ErrEncodingError.SetLog(cmn.Fmt("Power (%s) is not an int", powerS)) } // update @@ -211,14 +210,14 @@ func (app *PersistentDummyApplication) updateValidator(v *types.Validator) types if v.Power == 0 { // remove validator if !app.app.state.Has(key) { - return types.ErrUnauthorized.SetLog(fmt.Sprintf("Cannot remove non-existent validator %X", key)) + return types.ErrUnauthorized.SetLog(cmn.Fmt("Cannot remove non-existent validator %X", key)) } app.app.state.Remove(key) } else { // add or update validator value := bytes.NewBuffer(make([]byte, 0)) if err := types.WriteMessage(v, value); err != nil { - return types.ErrInternalError.SetLog(fmt.Sprintf("Error encoding validator: %v", err)) + return types.ErrInternalError.SetLog(cmn.Fmt("Error encoding validator: %v", err)) } app.app.state.Set(key, value.Bytes()) } diff --git a/example/example_test.go b/example/example_test.go index 9f18c421..034331d6 100644 --- a/example/example_test.go +++ b/example/example_test.go @@ -41,14 +41,14 @@ func testStream(t *testing.T, app types.Application) { // Start the listener server, err := server.NewSocketServer("unix://test.sock", app) if err != nil { - log.Fatal(fmt.Sprintf("Error starting socket server: %v", err.Error())) + log.Fatal(cmn.Fmt("Error starting socket server: %v", err.Error())) } defer server.Stop() // Connect to the socket client, err := abcicli.NewSocketClient("unix://test.sock", false) if err != nil { - log.Fatal(fmt.Sprintf("Error starting socket client: %v", err.Error())) + log.Fatal(cmn.Fmt("Error starting socket client: %v", err.Error())) } client.Start() defer client.Stop() @@ -114,14 +114,14 @@ func testGRPCSync(t *testing.T, app *types.GRPCApplication) { // Start the listener server, err := server.NewGRPCServer("unix://test.sock", app) if err != nil { - log.Fatal(fmt.Sprintf("Error starting GRPC server: %v", err.Error())) + log.Fatal(cmn.Fmt("Error starting GRPC server: %v", err.Error())) } defer server.Stop() // Connect to the socket conn, err := grpc.Dial("unix://test.sock", grpc.WithInsecure(), grpc.WithDialer(dialerFunc)) if err != nil { - log.Fatal(fmt.Sprintf("Error dialing GRPC server: %v", err.Error())) + log.Fatal(cmn.Fmt("Error dialing GRPC server: %v", err.Error())) } defer conn.Close() diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index e1e21d24..e434944a 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -19,10 +19,10 @@ -> data.hex: 750502FC7E84BBD788ED589624F06CFA871845D1 > query "abc" --> value: abc --> value.hex: 616263 -> log: exists -> height: 0 +-> value: abc +-> value.hex: 616263 > deliver_tx "def=xyz" @@ -31,8 +31,8 @@ -> data.hex: 76393B8A182E450286B0694C629ECB51B286EFD5 > query "def" --> value: xyz --> value.hex: 78797A -> log: exists -> height: 0 +-> value: xyz +-> value.hex: 78797A