diff --git a/client/commands/proofs/get.go b/client/commands/proofs/get.go index 4edbd90b59..645aba47d5 100644 --- a/client/commands/proofs/get.go +++ b/client/commands/proofs/get.go @@ -12,59 +12,81 @@ import ( "github.com/tendermint/go-wire/data" lc "github.com/tendermint/light-client" "github.com/tendermint/light-client/proofs" + "github.com/tendermint/merkleeyes/iavl" "github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/basecoin/client/commands" ) -// GetAndParseAppProof does most of the work of the query commands, but is quite -// opinionated, so if you want more control, set up the items and call GetProof +// Get does most of the work of the query commands, but is quite +// opinionated, so if you want more control, set up the items and call Get // directly. Notably, it always uses go-wire.ReadBinaryBytes to deserialize, // and Height and Node from standard flags. // // It will try to get the proof for the given key. If it is successful, // it will return the proof and also unserialize proof.Data into the data // argument (so pass in a pointer to the appropriate struct) -func GetAndParseAppProof(key []byte, data interface{}) (lc.Proof, error) { - height := GetHeight() - node := commands.GetNode() - - prover := proofs.NewAppProver(node) - - proof, err := GetProof(node, prover, key, height) +func GetParsed(key []byte, data interface{}, prove bool) (uint64, error) { + bs, h, err := Get(key, prove) if err != nil { - return proof, err + return 0, err } - - err = wire.ReadBinaryBytes(proof.Data(), data) - return proof, err + err = wire.ReadBinaryBytes(bs, data) + if err != nil { + return 0, err + } + return h, nil } -// GetProof performs the get command directly from the proof (not from the CLI) -func GetProof(node client.Client, prover lc.Prover, key []byte, height int) (proof lc.Proof, err error) { - proof, err = prover.Get(key, uint64(height)) +func Get(key []byte, prove bool) (data.Bytes, uint64, error) { + if !prove { + node := commands.GetNode() + resp, err := node.ABCIQuery("/key", key, false) + return data.Bytes(resp.Value), resp.Height, err + } + val, h, _, err := GetWithProof(key) + return val, h, err +} + +func GetWithProof(key []byte) (data.Bytes, uint64, *iavl.KeyExistsProof, error) { + node := commands.GetNode() + + resp, err := node.ABCIQuery("/key", key, true) if err != nil { - return + return nil, 0, nil, err + } + ph := int(resp.Height) + + // make sure the proof is the proper height + if !resp.Code.IsOK() { + return nil, 0, nil, errors.Errorf("Query error %d: %s", resp.Code, resp.Code.String()) + } + // TODO: Handle null proofs + if len(resp.Key) == 0 || len(resp.Value) == 0 || len(resp.Proof) == 0 { + return nil, 0, nil, lc.ErrNoData() + } + if ph != 0 && ph != int(resp.Height) { + return nil, 0, nil, lc.ErrHeightMismatch(ph, int(resp.Height)) } - // short-circuit with no proofs - if viper.GetBool(commands.FlagTrustNode) { - return proof, err - } - - ph := int(proof.BlockHeight()) check, err := GetCertifiedCheckpoint(ph) if err != nil { - return + return nil, 0, nil, err + } + + proof := new(iavl.KeyExistsProof) + err = wire.ReadBinaryBytes(resp.Proof, &proof) + if err != nil { + return nil, 0, nil, err } // validate the proof against the certified header to ensure data integrity - err = proof.Validate(check) + err = proof.Verify(resp.Key, resp.Value, check.Header.AppHash) if err != nil { - return + return nil, 0, nil, err } - return proof, err + return data.Bytes(resp.Value), resp.Height, proof, nil } // GetCertifiedCheckpoint gets the signed header for a given height diff --git a/client/commands/proofs/state.go b/client/commands/proofs/state.go index 06c4ffe3dd..01a1947814 100644 --- a/client/commands/proofs/state.go +++ b/client/commands/proofs/state.go @@ -1,15 +1,9 @@ package proofs import ( - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/go-wire/data" - lc "github.com/tendermint/light-client" - "github.com/tendermint/merkleeyes/iavl" - "github.com/tendermint/basecoin/client/commands" ) @@ -32,56 +26,11 @@ func keyQueryCmd(cmd *cobra.Command, args []string) error { if err != nil { return err } - prove := viper.GetBool(commands.FlagTrustNode) + prove := !viper.GetBool(commands.FlagTrustNode) - // get the proof -> this will be used by all prover commands - node := commands.GetNode() - - //////////////// - resp, err := node.ABCIQuery("/key", key, prove) + val, h, err := Get(key, prove) if err != nil { return err } - ph := int(resp.Height) - - // short-circuit with no proofs - if !prove { - return OutputProof(data.Bytes(resp.Value), resp.Height) - } - - // make sure the proof is the proper height - if !resp.Code.IsOK() { - return errors.Errorf("Query error %d: %s", resp.Code, resp.Code.String()) - } - // TODO: Handle null proofs - if len(resp.Key) == 0 || len(resp.Value) == 0 || len(resp.Proof) == 0 { - return lc.ErrNoData() - } - if ph != 0 && ph != int(resp.Height) { - return lc.ErrHeightMismatch(ph, int(resp.Height)) - } - - check, err := GetCertifiedCheckpoint(ph) - if err != nil { - return err - } - - proof := new(iavl.KeyExistsProof) - err = wire.ReadBinaryBytes(resp.Proof, &proof) - if err != nil { - return err - } - - // validate the proof against the certified header to ensure data integrity - err = proof.Verify(resp.Key, resp.Value, check.Header.AppHash) - if err != nil { - return err - } - - // state just returns raw hex.... - info := data.Bytes(resp.Value) - - // we can reuse this output for other commands for text/json - // unless they do something special like store a file to disk - return OutputProof(info, resp.Height) + return OutputProof(val, h) } diff --git a/modules/coin/commands/query.go b/modules/coin/commands/query.go index 1faabb6214..2eba053042 100644 --- a/modules/coin/commands/query.go +++ b/modules/coin/commands/query.go @@ -3,6 +3,7 @@ package commands import ( "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/spf13/viper" lc "github.com/tendermint/light-client" @@ -32,12 +33,13 @@ func accountQueryCmd(cmd *cobra.Command, args []string) error { key := stack.PrefixedKey(coin.NameCoin, act.Bytes()) acc := coin.Account{} - proof, err := proofcmd.GetAndParseAppProof(key, &acc) + prove := !viper.GetBool(commands.FlagTrustNode) + height, err := proofcmd.GetParsed(key, &acc, prove) if lc.IsNoDataErr(err) { return errors.Errorf("Account bytes are empty for address %s ", addr) } else if err != nil { return err } - return proofcmd.OutputProof(acc, proof.BlockHeight()) + return proofcmd.OutputProof(acc, height) } diff --git a/modules/coin/rest/handlers.go b/modules/coin/rest/handlers.go index 60f5d7b2de..f645e87d84 100644 --- a/modules/coin/rest/handlers.go +++ b/modules/coin/rest/handlers.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/gorilla/mux" + "github.com/spf13/viper" "github.com/tendermint/basecoin" "github.com/tendermint/basecoin/client/commands" @@ -47,7 +48,8 @@ func doQueryAccount(w http.ResponseWriter, r *http.Request) { actor = coin.ChainAddr(actor) key := stack.PrefixedKey(coin.NameCoin, actor.Bytes()) account := new(coin.Account) - proof, err := proofs.GetAndParseAppProof(key, account) + prove := !viper.GetBool(commands.FlagTrustNode) + height, err := proofs.GetParsed(key, account, prove) if lightclient.IsNoDataErr(err) { err := fmt.Errorf("account bytes are empty for address: %q", signature) common.WriteError(w, err) @@ -57,7 +59,7 @@ func doQueryAccount(w http.ResponseWriter, r *http.Request) { return } - if err := proofs.FoutputProof(w, account, proof.BlockHeight()); err != nil { + if err := proofs.FoutputProof(w, account, height); err != nil { common.WriteError(w, err) } } diff --git a/modules/ibc/commands/query.go b/modules/ibc/commands/query.go index 38c3d01e1a..461b5aa0b1 100644 --- a/modules/ibc/commands/query.go +++ b/modules/ibc/commands/query.go @@ -12,8 +12,6 @@ import ( "github.com/tendermint/basecoin/modules/ibc" "github.com/tendermint/basecoin/stack" "github.com/tendermint/go-wire/data" - "github.com/tendermint/light-client/proofs" - "github.com/tendermint/merkleeyes/iavl" ) // TODO: query seeds (register/update) @@ -86,17 +84,19 @@ func init() { func ibcQueryCmd(cmd *cobra.Command, args []string) error { var res ibc.HandlerInfo key := stack.PrefixedKey(ibc.NameIBC, ibc.HandlerKey()) - proof, err := proofcmd.GetAndParseAppProof(key, &res) + prove := !viper.GetBool(commands.FlagTrustNode) + h, err := proofcmd.GetParsed(key, &res, prove) if err != nil { return err } - return proofcmd.OutputProof(res, proof.BlockHeight()) + return proofcmd.OutputProof(res, h) } func chainsQueryCmd(cmd *cobra.Command, args []string) error { list := [][]byte{} key := stack.PrefixedKey(ibc.NameIBC, ibc.ChainsKey()) - proof, err := proofcmd.GetAndParseAppProof(key, &list) + prove := !viper.GetBool(commands.FlagTrustNode) + h, err := proofcmd.GetParsed(key, &list, prove) if err != nil { return err } @@ -107,7 +107,7 @@ func chainsQueryCmd(cmd *cobra.Command, args []string) error { res[i] = string(list[i]) } - return proofcmd.OutputProof(res, proof.BlockHeight()) + return proofcmd.OutputProof(res, h) } func chainQueryCmd(cmd *cobra.Command, args []string) error { @@ -118,12 +118,13 @@ func chainQueryCmd(cmd *cobra.Command, args []string) error { var res ibc.ChainInfo key := stack.PrefixedKey(ibc.NameIBC, ibc.ChainKey(arg)) - proof, err := proofcmd.GetAndParseAppProof(key, &res) + prove := !viper.GetBool(commands.FlagTrustNode) + h, err := proofcmd.GetParsed(key, &res, prove) if err != nil { return err } - return proofcmd.OutputProof(res, proof.BlockHeight()) + return proofcmd.OutputProof(res, h) } func assertOne(from, to string) error { @@ -154,12 +155,13 @@ func packetsQueryCmd(cmd *cobra.Command, args []string) error { } var res uint64 - proof, err := proofcmd.GetAndParseAppProof(key, &res) + prove := !viper.GetBool(commands.FlagTrustNode) + h, err := proofcmd.GetParsed(key, &res, prove) if err != nil { return err } - return proofcmd.OutputProof(res, proof.BlockHeight()) + return proofcmd.OutputProof(res, h) } func packetQueryCmd(cmd *cobra.Command, args []string) error { @@ -174,6 +176,7 @@ func packetQueryCmd(cmd *cobra.Command, args []string) error { if seq < 0 { return errors.Errorf("--%s must be a non-negative number", FlagSequence) } + prove := !viper.GetBool(commands.FlagTrustNode) var key []byte if from != "" { @@ -185,24 +188,16 @@ func packetQueryCmd(cmd *cobra.Command, args []string) error { // Input queue just display the results if from != "" { var packet ibc.Packet - proof, err := proofcmd.GetAndParseAppProof(key, &packet) + h, err := proofcmd.GetParsed(key, &packet, prove) if err != nil { return err } - return proofcmd.OutputProof(packet, proof.BlockHeight()) + return proofcmd.OutputProof(packet, h) } // output queue, create a post packet var packet ibc.Packet - proof, err := proofcmd.GetAndParseAppProof(key, &packet) - if err != nil { - return err - } - - // TODO: oh so ugly. fix before merge! - // wait, i want to change go-merkle too.... - appProof := proof.(proofs.AppProof) - extractedProof, err := iavl.ReadProof(appProof.Proof) + bs, height, proof, err := proofcmd.GetWithProof(key) if err != nil { return err } @@ -210,10 +205,10 @@ func packetQueryCmd(cmd *cobra.Command, args []string) error { // create the post packet here. post := ibc.PostPacketTx{ FromChainID: commands.GetChainID(), - FromChainHeight: proof.BlockHeight(), + FromChainHeight: height, Key: key, Packet: packet, - Proof: extractedProof, + Proof: proof, } // print json direct, as we don't need to wrap with the height diff --git a/modules/nonce/commands/query.go b/modules/nonce/commands/query.go index 405b0ea94a..d3dc4fcf58 100644 --- a/modules/nonce/commands/query.go +++ b/modules/nonce/commands/query.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/spf13/viper" lc "github.com/tendermint/light-client" @@ -33,23 +34,21 @@ func nonceQueryCmd(cmd *cobra.Command, args []string) error { return err } - seq, proof, err := doNonceQuery(signers) + seq, height, err := doNonceQuery(signers) if err != nil { return err } - return proofcmd.OutputProof(seq, proof.BlockHeight()) + return proofcmd.OutputProof(seq, height) } -func doNonceQuery(signers []basecoin.Actor) (sequence uint32, proof lc.Proof, err error) { - +func doNonceQuery(signers []basecoin.Actor) (sequence uint32, height uint64, err error) { key := stack.PrefixedKey(nonce.NameNonce, nonce.GetSeqKey(signers)) - - proof, err = proofcmd.GetAndParseAppProof(key, &sequence) + prove := !viper.GetBool(commands.FlagTrustNode) + height, err = proofcmd.GetParsed(key, &sequence, prove) if lc.IsNoDataErr(err) { // no data, return sequence 0 - return 0, proof, nil + return 0, 0, nil } - return } diff --git a/modules/roles/commands/query.go b/modules/roles/commands/query.go index 6a333f211a..4bb65c20af 100644 --- a/modules/roles/commands/query.go +++ b/modules/roles/commands/query.go @@ -2,6 +2,7 @@ package commands import ( "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/tendermint/basecoin/client/commands" proofcmd "github.com/tendermint/basecoin/client/commands/proofs" @@ -28,10 +29,11 @@ func roleQueryCmd(cmd *cobra.Command, args []string) error { var res roles.Role key := stack.PrefixedKey(roles.NameRole, role) - proof, err := proofcmd.GetAndParseAppProof(key, &res) + prove := !viper.GetBool(commands.FlagTrustNode) + height, err := proofcmd.GetParsed(key, &res, prove) if err != nil { return err } - return proofcmd.OutputProof(res, proof.BlockHeight()) + return proofcmd.OutputProof(res, height) }