From 58ea995032ccb4098fe56b904a41f34de879981e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 10 Jan 2017 15:49:26 +0100 Subject: [PATCH] Begin adding proof calls --- client/client.go | 2 ++ client/grpc_client.go | 18 ++++++++++++++++++ client/local_client.go | 17 +++++++++++++++++ client/socket_client.go | 15 +++++++++++++++ cmd/abci-cli/tmsp-cli.go | 19 +++++++++++++++++++ example/chain_aware/chain_aware_app.go | 4 ++++ example/counter/counter.go | 4 ++++ example/dummy/dummy.go | 4 ++++ example/dummy/persistent_dummy.go | 4 ++++ example/nil/nil_app.go | 4 ++++ server/socket_server.go | 3 +++ types/application.go | 8 ++++++++ types/messages.go | 12 ++++++++++++ types/types.proto | 19 +++++++++++++++++-- 14 files changed, 131 insertions(+), 2 deletions(-) diff --git a/client/client.go b/client/client.go index 8ea29593..a8bc8ea8 100644 --- a/client/client.go +++ b/client/client.go @@ -21,6 +21,7 @@ type Client interface { DeliverTxAsync(tx []byte) *ReqRes CheckTxAsync(tx []byte) *ReqRes QueryAsync(tx []byte) *ReqRes + ProofAsync(tx []byte) *ReqRes CommitAsync() *ReqRes FlushSync() error @@ -30,6 +31,7 @@ type Client interface { DeliverTxSync(tx []byte) (res types.Result) CheckTxSync(tx []byte) (res types.Result) QuerySync(tx []byte) (res types.Result) + ProofSync(tx []byte) (res types.Result) CommitSync() (res types.Result) InitChainAsync(validators []*types.Validator) *ReqRes diff --git a/client/grpc_client.go b/client/grpc_client.go index 566ee183..740623c6 100644 --- a/client/grpc_client.go +++ b/client/grpc_client.go @@ -182,6 +182,15 @@ func (cli *grpcClient) QueryAsync(query []byte) *ReqRes { return cli.finishAsyncCall(req, &types.Response{&types.Response_Query{res}}) } +func (cli *grpcClient) ProofAsync(key []byte) *ReqRes { + req := types.ToRequestProof(key) + res, err := cli.client.Proof(context.Background(), req.GetProof(), grpc.FailFast(true)) + if err != nil { + cli.StopForError(err) + } + return cli.finishAsyncCall(req, &types.Response{&types.Response_Proof{res}}) +} + func (cli *grpcClient) CommitAsync() *ReqRes { req := types.ToRequestCommit() res, err := cli.client.Commit(context.Background(), req.GetCommit(), grpc.FailFast(true)) @@ -301,6 +310,15 @@ func (cli *grpcClient) CheckTxSync(tx []byte) (res types.Result) { return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log} } +func (cli *grpcClient) ProofSync(key []byte) (res types.Result) { + reqres := cli.ProofAsync(key) + if res := cli.checkErrGetResult(); res.IsErr() { + return res + } + resp := reqres.Response.GetProof() + return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log} +} + func (cli *grpcClient) QuerySync(query []byte) (res types.Result) { reqres := cli.QueryAsync(query) if res := cli.checkErrGetResult(); res.IsErr() { diff --git a/client/local_client.go b/client/local_client.go index b787eb36..8c092cec 100644 --- a/client/local_client.go +++ b/client/local_client.go @@ -99,6 +99,16 @@ func (app *localClient) QueryAsync(tx []byte) *ReqRes { ) } +func (app *localClient) ProofAsync(key []byte) *ReqRes { + app.mtx.Lock() + res := app.Application.Proof(key) + app.mtx.Unlock() + return app.callback( + types.ToRequestProof(key), + types.ToResponseQuery(res.Code, res.Data, res.Log), + ) +} + func (app *localClient) CommitAsync() *ReqRes { app.mtx.Lock() res := app.Application.Commit() @@ -192,6 +202,13 @@ func (app *localClient) QuerySync(query []byte) (res types.Result) { return res } +func (app *localClient) ProofSync(key []byte) (res types.Result) { + app.mtx.Lock() + res = app.Application.Proof(key) + app.mtx.Unlock() + return res +} + func (app *localClient) CommitSync() (res types.Result) { app.mtx.Lock() res = app.Application.Commit() diff --git a/client/socket_client.go b/client/socket_client.go index 9b4f9aed..252c8777 100644 --- a/client/socket_client.go +++ b/client/socket_client.go @@ -255,6 +255,10 @@ func (cli *socketClient) QueryAsync(query []byte) *ReqRes { return cli.queueRequest(types.ToRequestQuery(query)) } +func (cli *socketClient) ProofAsync(key []byte) *ReqRes { + return cli.queueRequest(types.ToRequestProof(key)) +} + func (cli *socketClient) CommitAsync() *ReqRes { return cli.queueRequest(types.ToRequestCommit()) } @@ -345,6 +349,15 @@ func (cli *socketClient) QuerySync(query []byte) (res types.Result) { return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log} } +func (cli *socketClient) ProofSync(key []byte) (res types.Result) { + reqres := cli.queueRequest(types.ToRequestProof(key)) + cli.FlushSync() + if err := cli.Error(); err != nil { + return types.ErrInternalError.SetLog(err.Error()) + } + resp := reqres.Response.GetProof() + return types.Result{Code: resp.Code, Data: resp.Data, Log: resp.Log} +} func (cli *socketClient) CommitSync() (res types.Result) { reqres := cli.queueRequest(types.ToRequestCommit()) cli.FlushSync() @@ -437,6 +450,8 @@ func resMatchesReq(req *types.Request, res *types.Response) (ok bool) { _, ok = res.Value.(*types.Response_Commit) case *types.Request_Query: _, ok = res.Value.(*types.Response_Query) + case *types.Request_Proof: + _, ok = res.Value.(*types.Response_Proof) case *types.Request_InitChain: _, ok = res.Value.(*types.Response_InitChain) case *types.Request_BeginBlock: diff --git a/cmd/abci-cli/tmsp-cli.go b/cmd/abci-cli/tmsp-cli.go index 39dace9f..d40b510b 100644 --- a/cmd/abci-cli/tmsp-cli.go +++ b/cmd/abci-cli/tmsp-cli.go @@ -131,6 +131,13 @@ func main() { return cmdQuery(c) }, }, + { + Name: "proof", + Usage: "Get proof for a key", + Action: func(c *cli.Context) error { + return cmdProof(c) + }, + }, } app.Before = before err := app.Run(os.Args) @@ -305,6 +312,18 @@ func cmdQuery(c *cli.Context) error { return nil } +// Prove application state +func cmdProof(c *cli.Context) error { + args := c.Args() + if len(args) != 1 { + return errors.New("Command proof takes 1 argument") + } + keyBytes := stringOrHexToBytes(c.Args()[0]) + res := client.ProofSync(keyBytes) + printResponse(c, res, string(res.Data), true) + return nil +} + //-------------------------------------------------------------------------------- func printResponse(c *cli.Context, rsp *response) { diff --git a/example/chain_aware/chain_aware_app.go b/example/chain_aware/chain_aware_app.go index e3543f13..387a88e8 100644 --- a/example/chain_aware/chain_aware_app.go +++ b/example/chain_aware/chain_aware_app.go @@ -61,6 +61,10 @@ func (app *ChainAwareApplication) Query(query []byte) types.Result { return types.NewResultOK([]byte(Fmt("%d,%d", app.beginCount, app.endCount)), "") } +func (app *ChainAwareApplication) Proof(key []byte) types.Result { + return types.NewResultOK(nil, Fmt("Proof is not supported")) +} + func (app *ChainAwareApplication) BeginBlock(hash []byte, header *types.Header) { app.beginCount += 1 return diff --git a/example/counter/counter.go b/example/counter/counter.go index 90be6d92..e5b17992 100644 --- a/example/counter/counter.go +++ b/example/counter/counter.go @@ -83,3 +83,7 @@ func (app *CounterApplication) Query(query []byte) types.Result { return types.ErrUnknownRequest.SetLog(Fmt("Invalid nonce. Expected hash or tx, got %v", queryStr)) } + +func (app *CounterApplication) Proof(key []byte) types.Result { + return types.NewResultOK(nil, Fmt("Proof is not supported")) +} diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 6fdf8785..2336add8 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -53,6 +53,10 @@ func (app *DummyApplication) Query(query []byte) types.Result { return types.NewResultOK(wire.JSONBytes(queryResult), "") } +func (app *DummyApplication) Proof(key []byte) types.Result { + return types.NewResultOK(nil, Fmt("TODO: support proof!")) +} + type QueryResult struct { Index int `json:"index"` Value string `json:"value"` diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index fa730bcb..bb8783ee 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -93,6 +93,10 @@ func (app *PersistentDummyApplication) Query(query []byte) types.Result { return app.app.Query(query) } +func (app *PersistentDummyApplication) Proof(key []byte) types.Result { + return types.NewResultOK(nil, Fmt("TODO: support proof!")) +} + // Save the validators in the merkle tree func (app *PersistentDummyApplication) InitChain(validators []*types.Validator) { for _, v := range validators { diff --git a/example/nil/nil_app.go b/example/nil/nil_app.go index cd57f0d9..a4d181c0 100644 --- a/example/nil/nil_app.go +++ b/example/nil/nil_app.go @@ -34,3 +34,7 @@ func (app *NilApplication) Commit() types.Result { func (app *NilApplication) Query(query []byte) types.Result { return types.NewResultOK(nil, "") } + +func (app *NilApplication) Proof(key []byte) types.Result { + return types.NewResultOK(nil, "") +} diff --git a/server/socket_server.go b/server/socket_server.go index bd26a18a..046b55ed 100644 --- a/server/socket_server.go +++ b/server/socket_server.go @@ -186,6 +186,9 @@ func (s *SocketServer) handleRequest(req *types.Request, responses chan<- *types case *types.Request_Query: res := s.app.Query(r.Query.Query) responses <- types.ToResponseQuery(res.Code, res.Data, res.Log) + case *types.Request_Proof: + res := s.app.Proof(r.Proof.Key, r.Proof.Height) + responses <- types.ToResponseProof(res.Code, res.Data, res.Log) case *types.Request_InitChain: if app, ok := s.app.(types.BlockchainAware); ok { app.InitChain(r.InitChain.Validators) diff --git a/types/application.go b/types/application.go index 4da5e6f7..95f35d4a 100644 --- a/types/application.go +++ b/types/application.go @@ -22,6 +22,9 @@ type Application interface { // Query for state Query(query []byte) Result + // Get proof for state + Proof(key []byte, blockHeight int) Result + // Return the application Merkle root hash Commit() Result } @@ -82,6 +85,11 @@ func (app *GRPCApplication) Query(ctx context.Context, req *RequestQuery) (*Resp return &ResponseQuery{r.Code, r.Data, r.Log}, nil } +func (app *GRPCApplication) Proof(ctx context.Context, req *RequestProof) (*ResponseQuery, error) { + r := app.app.Proof(req.Key, req.Height) + return &ResponseProof{r.Code, r.Data, r.Log}, nil +} + func (app *GRPCApplication) Commit(ctx context.Context, req *RequestCommit) (*ResponseCommit, error) { r := app.app.Commit() return &ResponseCommit{r.Code, r.Data, r.Log}, nil diff --git a/types/messages.go b/types/messages.go index 84e6ee0b..b445c535 100644 --- a/types/messages.go +++ b/types/messages.go @@ -55,6 +55,12 @@ func ToRequestQuery(queryBytes []byte) *Request { } } +func ToRequestProof(key []byte, blockHeight int) *Request { + return &Request{ + Value: &Request_Proof{&RequestProof{key, blockHeight}}, + } +} + func ToRequestInitChain(validators []*Validator) *Request { return &Request{ Value: &Request_InitChain{&RequestInitChain{validators}}, @@ -129,6 +135,12 @@ func ToResponseQuery(code CodeType, data []byte, log string) *Response { } } +func ToResponseProof(code CodeType, data []byte, log string) *Response { + return &Response{ + Value: &Response_Proof{&ResponseProof{code, data, log}}, + } +} + func ToResponseInitChain() *Response { return &Response{ Value: &Response_InitChain{&ResponseInitChain{}}, diff --git a/types/types.proto b/types/types.proto index b3ff1655..09a2af8f 100644 --- a/types/types.proto +++ b/types/types.proto @@ -6,7 +6,7 @@ package types; //---------------------------------------- // Message types -// Not being used +// Not being used // Could be added to request/response // so we don't have to type switch // (would be twice as fast, but we're talking about 15ns) @@ -25,6 +25,7 @@ enum MessageType { InitChain = 0x15; BeginBlock = 0x16; EndBlock = 0x17; + Proof = 0x18; } //---------------------------------------- @@ -116,6 +117,12 @@ message RequestQuery{ bytes query = 1; } +message RequestProof{ + bytes key = 1; + int64 height = 2; +} + + message RequestCommit{ } @@ -150,6 +157,7 @@ message Response { ResponseInitChain init_chain = 10; ResponseBeginBlock begin_block = 11; ResponseEndBlock end_block = 12; + ResponseProof proof = 13; } } @@ -193,6 +201,12 @@ message ResponseQuery{ string log = 3; } +message ResponseProof{ + CodeType code = 1; + bytes data = 2; + string log = 3; +} + message ResponseCommit{ CodeType code = 1; bytes data = 2; @@ -222,7 +236,7 @@ message Header { bytes last_commit_hash = 6; bytes data_hash = 7; bytes validators_hash = 8; - bytes app_hash = 9; + bytes app_hash = 9; } message BlockID { @@ -251,6 +265,7 @@ service ABCIApplication { rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx); rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx); rpc Query(RequestQuery) returns (ResponseQuery); + rpc Proof(RequestProof) returns (ResponseProof); rpc Commit(RequestCommit) returns (ResponseCommit); rpc InitChain(RequestInitChain) returns (ResponseInitChain); rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock);