diff --git a/client/client.go b/client/client.go index a8bc8ea8..fd31b21a 100644 --- a/client/client.go +++ b/client/client.go @@ -21,7 +21,7 @@ type Client interface { DeliverTxAsync(tx []byte) *ReqRes CheckTxAsync(tx []byte) *ReqRes QueryAsync(tx []byte) *ReqRes - ProofAsync(tx []byte) *ReqRes + ProofAsync(key []byte, blockHeight int64) *ReqRes CommitAsync() *ReqRes FlushSync() error @@ -31,7 +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) + ProofSync(key []byte, blockHeight int64) (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 740623c6..3654c47c 100644 --- a/client/grpc_client.go +++ b/client/grpc_client.go @@ -182,8 +182,8 @@ 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) +func (cli *grpcClient) ProofAsync(key []byte, blockHeight int64) *ReqRes { + req := types.ToRequestProof(key, blockHeight) res, err := cli.client.Proof(context.Background(), req.GetProof(), grpc.FailFast(true)) if err != nil { cli.StopForError(err) @@ -310,8 +310,8 @@ 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) +func (cli *grpcClient) ProofSync(key []byte, blockHeight int64) (res types.Result) { + reqres := cli.ProofAsync(key, blockHeight) if res := cli.checkErrGetResult(); res.IsErr() { return res } diff --git a/client/local_client.go b/client/local_client.go index 8c092cec..bdc59c5a 100644 --- a/client/local_client.go +++ b/client/local_client.go @@ -99,12 +99,12 @@ func (app *localClient) QueryAsync(tx []byte) *ReqRes { ) } -func (app *localClient) ProofAsync(key []byte) *ReqRes { +func (app *localClient) ProofAsync(key []byte, blockHeight int64) *ReqRes { app.mtx.Lock() - res := app.Application.Proof(key) + res := app.Application.Proof(key, blockHeight) app.mtx.Unlock() return app.callback( - types.ToRequestProof(key), + types.ToRequestProof(key, blockHeight), types.ToResponseQuery(res.Code, res.Data, res.Log), ) } @@ -202,9 +202,9 @@ func (app *localClient) QuerySync(query []byte) (res types.Result) { return res } -func (app *localClient) ProofSync(key []byte) (res types.Result) { +func (app *localClient) ProofSync(key []byte, blockHeight int64) (res types.Result) { app.mtx.Lock() - res = app.Application.Proof(key) + res = app.Application.Proof(key, blockHeight) app.mtx.Unlock() return res } diff --git a/client/socket_client.go b/client/socket_client.go index 252c8777..cacd67bf 100644 --- a/client/socket_client.go +++ b/client/socket_client.go @@ -255,8 +255,8 @@ 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) ProofAsync(key []byte, blockHeight int64) *ReqRes { + return cli.queueRequest(types.ToRequestProof(key, blockHeight)) } func (cli *socketClient) CommitAsync() *ReqRes { @@ -349,8 +349,8 @@ 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)) +func (cli *socketClient) ProofSync(key []byte, blockHeight int64) (res types.Result) { + reqres := cli.queueRequest(types.ToRequestProof(key, blockHeight)) cli.FlushSync() if err := cli.Error(); err != nil { return types.ErrInternalError.SetLog(err.Error()) diff --git a/cmd/abci-cli/tmsp-cli.go b/cmd/abci-cli/tmsp-cli.go index d40b510b..0eae4d85 100644 --- a/cmd/abci-cli/tmsp-cli.go +++ b/cmd/abci-cli/tmsp-cli.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "strconv" "strings" "github.com/tendermint/abci/client" @@ -315,12 +316,21 @@ func cmdQuery(c *cli.Context) error { // Prove application state func cmdProof(c *cli.Context) error { args := c.Args() - if len(args) != 1 { - return errors.New("Command proof takes 1 argument") + if len(args) < 1 { + return errors.New("Command proof takes 1 or 2 arguments") } - keyBytes := stringOrHexToBytes(c.Args()[0]) - res := client.ProofSync(keyBytes) - printResponse(c, res, string(res.Data), true) + keyBytes, err := stringOrHexToBytes(c.Args()[0]) + if err != nil { + return err + } + + var height int64 + if len(args) == 2 { + height, _ = strconv.ParseInt(args[1], 10, 0) + } + res := client.ProofSync(keyBytes, height) + rsp := newResponse(res, string(res.Data), true) + printResponse(c, rsp) return nil } diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index ebce1099..fcf067dc 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -2,6 +2,7 @@ package dummy import ( "encoding/hex" + "fmt" "strings" "github.com/tendermint/abci/types" @@ -54,7 +55,15 @@ func (app *DummyApplication) Query(query []byte) types.Result { } func (app *DummyApplication) Proof(key []byte, blockHeight int64) types.Result { - return types.NewResultOK(nil, Fmt("TODO: support proof!")) + if blockHeight != 0 { + return types.ErrUnknownRequest + } + proof, exists := app.state.Proof(key) + if !exists { + fmt.Println("Didn't find nothing") + return types.NewResultOK(nil, "") + } + return types.NewResultOK(proof, "Found the key") } type QueryResult struct { diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index d2294347..8cd999c0 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -8,6 +8,7 @@ import ( . "github.com/tendermint/go-common" "github.com/tendermint/go-crypto" + merkle "github.com/tendermint/go-merkle" "github.com/tendermint/go-wire" "github.com/tendermint/abci/types" ) @@ -34,6 +35,27 @@ func testDummy(t *testing.T, dummy types.Application, tx []byte, key, value stri t.Fatalf("Got %s, expected %s", q.Value, value) } + rp := dummy.Proof([]byte(key), 0) + if rp.IsErr() { + t.Fatal(rp) + } + + p, err := merkle.LoadProof(rp.Data) + if err != nil { + t.Fatal(err) + } + + if !p.Valid() { + t.Fatal("Invalid proof") + } + + if !bytes.Equal([]byte(key), p.Key()) { + t.Fatalf("Invalid key: %s", p.Key()) + } + + if !bytes.Equal([]byte(value), p.Value()) { + t.Fatalf("Invalid key: %s", p.Value()) + } } func TestDummyKV(t *testing.T) { diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index 70c0e667..3a1ce3b5 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -94,7 +94,7 @@ func (app *PersistentDummyApplication) Query(query []byte) types.Result { } func (app *PersistentDummyApplication) Proof(key []byte, blockHeight int64) types.Result { - return types.NewResultOK(nil, Fmt("TODO: support proof!")) + return app.app.Proof(key, blockHeight) } // Save the validators in the merkle tree