diff --git a/client/context/context.go b/client/context/context.go index ffdd0f7bc..d28cc34f8 100644 --- a/client/context/context.go +++ b/client/context/context.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/viper" - tendermintLite "github.com/tendermint/tendermint/lite" + tmlite "github.com/tendermint/tendermint/lite" rpcclient "github.com/tendermint/tendermint/rpc/client" ) @@ -33,7 +33,7 @@ type CLIContext struct { Async bool JSON bool PrintResponse bool - Certifier tendermintLite.Certifier + Certifier tmlite.Certifier } // NewCLIContext returns a new initialized CLIContext with parameters from the @@ -121,7 +121,7 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext { } // WithCertifier - return a copy of the context with an updated Certifier -func (ctx CLIContext) WithCertifier(certifier tendermintLite.Certifier) CLIContext { +func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext { ctx.Certifier = certifier return ctx } diff --git a/client/context/query.go b/client/context/query.go index aac0c9030..47390d787 100644 --- a/client/context/query.go +++ b/client/context/query.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" abci "github.com/tendermint/tendermint/abci/types" cmn "github.com/tendermint/tendermint/libs/common" - tendermintLiteProxy "github.com/tendermint/tendermint/lite/proxy" + tmliteProxy "github.com/tendermint/tendermint/lite/proxy" rpcclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" "strings" @@ -325,12 +325,8 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro // verifyProof perform response proof verification func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { - // TODO: Later we consider to return error for missing valid certifier to verify data from untrusted node if ctx.Certifier == nil { - if ctx.Logger != nil { - io.WriteString(ctx.Logger, fmt.Sprintf("Missing valid certifier to verify data from untrusted node\n")) - } - return nil + return fmt.Errorf("missing valid certifier to verify data from untrusted node") } node, err := ctx.GetNode() @@ -338,11 +334,8 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { return err } - // TODO: need improvement - // If the the node http client connect to a full node which can't produce or receive new blocks, - // then here the code will wait for a while and return error if time is out. // AppHash for height H is in header H+1 - commit, err := tendermintLiteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier) + commit, err := tmliteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier) if err != nil { return err } @@ -356,7 +349,7 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error { // Validate the substore commit hash against trusted appHash substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName, - multiStoreProof.CommitIDList, commit.Header.AppHash) + multiStoreProof.StoreInfos, commit.Header.AppHash) if err != nil { return errors.Wrap(err, "failed in verifying the proof against appHash") } @@ -376,7 +369,6 @@ func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([ // isQueryStoreWithProof expects a format like /// // queryType can be app or store -// if subpath equals to "/store" or "/key", then return true func isQueryStoreWithProof(path string) bool { if !strings.HasPrefix(path, "/") { return false @@ -385,9 +377,8 @@ func isQueryStoreWithProof(path string) bool { if len(paths) != 3 { return false } - // Currently, only when query subpath is "/store" or "/key", will proof be included in response. - // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go - if paths[2] == "store" || paths[2] == "key" { + + if store.RequireProof(paths[2]) { return true } return false diff --git a/store/multistoreproof.go b/store/multistoreproof.go index 5ca214bc7..62cc30ddf 100644 --- a/store/multistoreproof.go +++ b/store/multistoreproof.go @@ -2,48 +2,33 @@ package store import ( "bytes" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/pkg/errors" "github.com/tendermint/iavl" cmn "github.com/tendermint/tendermint/libs/common" ) -// commitID of substores, such as acc store, gov store -type SubstoreCommitID struct { - Name string `json:"name"` - Version int64 `json:"version"` - CommitHash cmn.HexBytes `json:"commit_hash"` -} - -// proof of store which have multi substores +// MultiStoreProof defines a collection of store proofs in a multi-store type MultiStoreProof struct { - CommitIDList []SubstoreCommitID `json:"commit_id_list"` - StoreName string `json:"store_name"` - RangeProof iavl.RangeProof `json:"range_proof"` + StoreInfos []storeInfo + StoreName string + RangeProof iavl.RangeProof } -// build MultiStoreProof based on iavl proof and storeInfos -func BuildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) ([]byte, error) { +// buildMultiStoreProof build MultiStoreProof based on iavl proof and storeInfos +func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) ([]byte, error) { var rangeProof iavl.RangeProof err := cdc.UnmarshalBinary(iavlProof, &rangeProof) if err != nil { return nil, err } - var multiStoreProof MultiStoreProof - for _, storeInfo := range storeInfos { - - commitID := SubstoreCommitID{ - Name: storeInfo.Name, - Version: storeInfo.Core.CommitID.Version, - CommitHash: storeInfo.Core.CommitID.Hash, - } - multiStoreProof.CommitIDList = append(multiStoreProof.CommitIDList, commitID) + msp := MultiStoreProof{ + StoreInfos: storeInfos, + StoreName: storeName, + RangeProof: rangeProof, } - multiStoreProof.StoreName = storeName - multiStoreProof.RangeProof = rangeProof - proof, err := cdc.MarshalBinary(multiStoreProof) + proof, err := cdc.MarshalBinary(msp) if err != nil { return nil, err } @@ -51,28 +36,15 @@ func BuildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []store return proof, nil } -// verify multiStoreCommitInfo against appHash -func VerifyMultiStoreCommitInfo(storeName string, multiStoreCommitInfo []SubstoreCommitID, appHash []byte) ([]byte, error) { +// VerifyMultiStoreCommitInfo verify multiStoreCommitInfo against appHash +func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHash []byte) ([]byte, error) { var substoreCommitHash []byte - var storeInfos []storeInfo var height int64 - for _, multiStoreCommitID := range multiStoreCommitInfo { - - if multiStoreCommitID.Name == storeName { - substoreCommitHash = multiStoreCommitID.CommitHash - height = multiStoreCommitID.Version + for _, storeInfo := range storeInfos { + if storeInfo.Name == storeName { + substoreCommitHash = storeInfo.Core.CommitID.Hash + height = storeInfo.Core.CommitID.Version } - storeInfo := storeInfo{ - Name: multiStoreCommitID.Name, - Core: storeCore{ - CommitID: sdk.CommitID{ - Version: multiStoreCommitID.Version, - Hash: multiStoreCommitID.CommitHash, - }, - }, - } - - storeInfos = append(storeInfos, storeInfo) } if len(substoreCommitHash) == 0 { return nil, cmn.NewError("failed to get substore root commit hash by store name") @@ -89,7 +61,7 @@ func VerifyMultiStoreCommitInfo(storeName string, multiStoreCommitInfo []Substor return substoreCommitHash, nil } -// verify iavl proof +// VerifyRangeProof verify iavl RangeProof func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error { // Validate the proof to ensure data integrity. @@ -99,13 +71,13 @@ func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof * } if len(value) != 0 { - // Validate existence proof + // Verify existence proof err = rangeProof.VerifyItem(key, value) if err != nil { return errors.Wrap(err, "failed in existence verification") } } else { - // Validate absence proof + // Verify absence proof err = rangeProof.VerifyAbsence(key) if err != nil { return errors.Wrap(err, "failed in absence verification") @@ -114,3 +86,13 @@ func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof * return nil } + +// RequireProof return whether proof is require for the subpath +func RequireProof(subpath string) bool { + // Currently, only when query subpath is "/store" or "/key", will proof be included in response. + // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212 + if subpath == "/store" || subpath == "/key" { + return true + } + return false +} diff --git a/store/multistoreproof_test.go b/store/multistoreproof_test.go index 153891567..b4e8a84b1 100644 --- a/store/multistoreproof_test.go +++ b/store/multistoreproof_test.go @@ -14,55 +14,79 @@ func TestVerifyMultiStoreCommitInfo(t *testing.T) { substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828") storeName := "acc" - var multiStoreCommitInfo []SubstoreCommitID + var storeInfos []storeInfo gocRootHash, _ := hex.DecodeString("62c171bb022e47d1f745608ff749e676dbd25f78") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "gov", - Version: 689, - CommitHash: gocRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "gov", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: gocRootHash, + }, + }, }) - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "main", - Version: 689, - CommitHash: nil, + storeInfos = append(storeInfos, storeInfo{ + Name: "main", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: nil, + }, + }, }) accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "acc", - Version: 689, - CommitHash: accRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "acc", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: accRootHash, + }, + }, }) - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "ibc", - Version: 689, - CommitHash: nil, + storeInfos = append(storeInfos, storeInfo{ + Name: "ibc", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: nil, + }, + }, }) stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "stake", - Version: 689, - CommitHash: stakeRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "stake", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: stakeRootHash, + }, + }, }) slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e") - multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{ - Name: "slashing", - Version: 689, - CommitHash: slashingRootHash, + storeInfos = append(storeInfos, storeInfo{ + Name: "slashing", + Core: storeCore{ + CommitID: CommitID{ + Version: 689, + Hash: slashingRootHash, + }, + }, }) - commitHash, err := VerifyMultiStoreCommitInfo(storeName, multiStoreCommitInfo, appHash) + commitHash, err := VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash) assert.Nil(t, err) assert.Equal(t, commitHash, substoreRootHash) appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3") - _, err = VerifyMultiStoreCommitInfo(storeName, multiStoreCommitInfo, appHash) + _, err = VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash) assert.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo") } diff --git a/store/rootmultistore.go b/store/rootmultistore.go index c5ce52b0b..5f6b08283 100644 --- a/store/rootmultistore.go +++ b/store/rootmultistore.go @@ -292,19 +292,16 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery { req.Path = subpath res := queryable.Query(req) - // Currently, only when query subpath is "/store" or "/key", will proof be included in response. - // If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go - if !req.Prove || subpath != "/store" && subpath != "/key" { + if !req.Prove || !RequireProof(subpath) { return res } - //Load commit info from db commitInfo, errMsg := getCommitInfo(rs.db, res.Height) if errMsg != nil { return sdk.ErrInternal(errMsg.Error()).QueryResult() } - res.Proof, errMsg = BuildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) + res.Proof, errMsg = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos) if errMsg != nil { return sdk.ErrInternal(errMsg.Error()).QueryResult() }