IRISHUB-238: remove todo, refactor comment and refactor multistoreproof

This commit is contained in:
HaoyangLiu 2018-08-31 10:03:48 +08:00
parent 5e85a5cdcd
commit ab76fd964a
5 changed files with 92 additions and 98 deletions

View File

@ -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
}

View File

@ -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>/<storeName>/<subpath>
// 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

View File

@ -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,
msp := MultiStoreProof{
StoreInfos: storeInfos,
StoreName: storeName,
RangeProof: rangeProof,
}
multiStoreProof.CommitIDList = append(multiStoreProof.CommitIDList, commitID)
}
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
}

View File

@ -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{
storeInfos = append(storeInfos, storeInfo{
Name: "gov",
Core: storeCore{
CommitID: CommitID{
Version: 689,
CommitHash: gocRootHash,
Hash: gocRootHash,
},
},
})
multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{
storeInfos = append(storeInfos, storeInfo{
Name: "main",
Core: storeCore{
CommitID: CommitID{
Version: 689,
CommitHash: nil,
Hash: nil,
},
},
})
accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{
storeInfos = append(storeInfos, storeInfo{
Name: "acc",
Core: storeCore{
CommitID: CommitID{
Version: 689,
CommitHash: accRootHash,
Hash: accRootHash,
},
},
})
multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{
storeInfos = append(storeInfos, storeInfo{
Name: "ibc",
Core: storeCore{
CommitID: CommitID{
Version: 689,
CommitHash: nil,
Hash: nil,
},
},
})
stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4")
multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{
storeInfos = append(storeInfos, storeInfo{
Name: "stake",
Core: storeCore{
CommitID: CommitID{
Version: 689,
CommitHash: stakeRootHash,
Hash: stakeRootHash,
},
},
})
slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e")
multiStoreCommitInfo = append(multiStoreCommitInfo, SubstoreCommitID{
storeInfos = append(storeInfos, storeInfo{
Name: "slashing",
Core: storeCore{
CommitID: CommitID{
Version: 689,
CommitHash: slashingRootHash,
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")
}

View File

@ -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()
}