Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Judge if trust-node predefined before create certifier add verification for getBlock, queryTx and getValidators #2210

Merged
merged 21 commits into from
Sep 14, 2018
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 14 additions & 5 deletions client/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
tmlite "github.com/tendermint/tendermint/lite"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
"os"
)

const ctxAccStoreName = "acc"
Expand Down Expand Up @@ -69,32 +70,40 @@ func NewCLIContext() CLIContext {
}

func createCertifier() tmlite.Certifier {
trustNodeDefined := viper.IsSet(client.FlagTrustNode)
if !trustNodeDefined {
return nil
}

trustNode := viper.GetBool(client.FlagTrustNode)
if trustNode {
return nil
}

chainID := viper.GetString(client.FlagChainID)
home := viper.GetString(cli.HomeFlag)
nodeURI := viper.GetString(client.FlagNode)

var errMsg bytes.Buffer
if chainID == "" {
errMsg.WriteString("chain-id ")
errMsg.WriteString("--chain-id ")
}
if home == "" {
errMsg.WriteString("home ")
errMsg.WriteString("--home ")
}
if nodeURI == "" {
errMsg.WriteString("node ")
errMsg.WriteString("--node ")
}
// errMsg is not empty
if errMsg.Len() != 0 {
panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String()))
fmt.Printf("must specify these options: %s when --trust-node is false\n", errMsg.String())
os.Exit(1)
}

certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI)
if err != nil {
panic(err)
}

return certifier
}

Expand Down
8 changes: 8 additions & 0 deletions client/context/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,11 @@ func ErrInvalidAccount(addr sdk.AccAddress) error {
return errors.Errorf(`No account with address %s was found in the state.
Are you sure there has been a transaction involving it?`, addr)
}

// ErrVerifyCommit returns a common error reflecting that the blockchain commit at a given
// height can't be verified. The reason is that the base checkpoint of the certifier is
// newer than the given height
func ErrVerifyCommit(height int64) error {
return errors.Errorf(`The height of base truststore in gaia-lite is higher than height %d.
Can't verify blockchain proof at this height. Please set --trust-node to true and try again`, height)
}
8 changes: 5 additions & 3 deletions client/context/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
}

// Data from trusted node or subspace query doesn't need verification
// Data from trusted node or subspace query doesn't need verification.
if ctx.TrustNode || !isQueryStoreWithProof(path) {
return resp.Value, nil
}
Expand Down Expand Up @@ -348,15 +348,17 @@ func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
}

// Verify the substore commit hash against trusted appHash
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName,
multiStoreProof.StoreInfos, commit.Header.AppHash)
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(
multiStoreProof.StoreName, multiStoreProof.StoreInfos, commit.Header.AppHash)
if err != nil {
return errors.Wrap(err, "failed in verifying the proof against appHash")
}

err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof)
if err != nil {
return errors.Wrap(err, "failed in the range proof verification")
}

return nil
}

Expand Down
5 changes: 2 additions & 3 deletions client/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ var LineBreak = &cobra.Command{Run: func(*cobra.Command, []string) {}}
// GetCommands adds common flags to query commands
func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
for _, c := range cmds {
// TODO: make this default false when we support proofs
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for responses")
c.Flags().Bool(FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
Expand All @@ -62,7 +61,7 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
c.Flags().Bool(FlagTrustNode, true, "Trust connected full node (don't verify proofs for responses)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref #2322

c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
}
return cmds
Expand Down
4 changes: 2 additions & 2 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func TestBlock(t *testing.T) {

// --

res, body = Request(t, port, "GET", "/blocks/1", nil)
res, body = Request(t, port, "GET", "/blocks/2", nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change?

Copy link
Author

@HaoyangLiu HaoyangLiu Sep 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a comment about the reason above. When gaia-lite is launched, it will fetch the latest height as its trust basement. Then it can only verify blocks or transactions in later height.
Here gaia-lite is launched after a new block is created, please refer to the code. The wait is necessary. If the height of gaia node is zero, gaia-lite will be aborted for fetching block failure. So here gaia-lite will be start later and it will get block 2 as its trust basement. As a result, it can't verify block 1. As I clear here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, we should update gaia lite so that you can easily start it with a separate root-of-trust.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref #2323

require.Equal(t, http.StatusOK, res.StatusCode, body)

err = wire.Cdc.UnmarshalJSON([]byte(body), &resultBlock)
Expand Down Expand Up @@ -210,7 +210,7 @@ func TestValidators(t *testing.T) {

// --

res, body = Request(t, port, "GET", "/validatorsets/1", nil)
res, body = Request(t, port, "GET", "/validatorsets/2", nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)

err = cdc.UnmarshalJSON([]byte(body), &resultVals)
Expand Down
4 changes: 2 additions & 2 deletions client/lcd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command {

cmd.Flags().String(flagListenAddr, "tcp://localhost:1317", "The address for the server to listen on")
cmd.Flags().String(flagCORS, "", "Set the domains that can make CORS requests (* for all)")
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
cmd.Flags().Bool(client.FlagTrustNode, false, "Whether trust connected full node")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")

return cmd
}
Expand Down
4 changes: 4 additions & 0 deletions client/lcd/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
// XXX: Need to set this so LCD knows the tendermint node address!
viper.Set(client.FlagNode, config.RPC.ListenAddress)
viper.Set(client.FlagChainID, genDoc.ChainID)
viper.Set(client.FlagTrustNode, false)
dir, err := ioutil.TempDir("", "lcd_test")
require.NoError(t, err)
viper.Set(cli.HomeFlag, dir)

node, err := startTM(config, logger, genDoc, privVal, app)
require.NoError(t, err)
Expand Down
27 changes: 25 additions & 2 deletions client/rpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (

"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tmliteErr "github.com/tendermint/tendermint/lite/errors"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
)

//BlockCommand returns the verified block data for a given heights
Expand All @@ -21,8 +24,8 @@ func BlockCommand() *cobra.Command {
RunE: printBlock,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
return cmd
}

Expand All @@ -41,6 +44,26 @@ func getBlock(cliCtx context.CLIContext, height *int64) ([]byte, error) {
return nil, err
}

trustNode := viper.GetBool(client.FlagTrustNode)
if !trustNode {
check, err := tmliteProxy.GetCertifiedCommit(*height, node, cliCtx.Certifier)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine this with similar instances below (DRY)

if tmliteErr.IsCommitNotFoundErr(err) {
return nil, context.ErrVerifyCommit(*height)
} else if err != nil {
return nil, err
}

err = tmliteProxy.ValidateBlockMeta(res.BlockMeta, check)
if err != nil {
return nil, err
}

err = tmliteProxy.ValidateBlock(res.Block, check)
if err != nil {
return nil, err
}
}

// TODO move maarshalling into cmd/rest functions
// output, err := tmwire.MarshalJSON(res)
output, err := cdc.MarshalJSON(res)
Expand Down
24 changes: 22 additions & 2 deletions client/rpc/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ import (
"github.com/gorilla/mux"
"github.com/spf13/cobra"

"bytes"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/viper"
tmliteErr "github.com/tendermint/tendermint/lite/errors"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
tmTypes "github.com/tendermint/tendermint/types"
tmtypes "github.com/tendermint/tendermint/types"
)

Expand All @@ -25,8 +30,8 @@ func ValidatorCommand() *cobra.Command {
RunE: printValidators,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
return cmd
}

Expand Down Expand Up @@ -70,6 +75,21 @@ func getValidators(cliCtx context.CLIContext, height *int64) ([]byte, error) {
return nil, err
}

trustNode := viper.GetBool(client.FlagTrustNode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fetched from the CLIContext instead


if !trustNode {
check, err := tmliteProxy.GetCertifiedCommit(*height, node, cliCtx.Certifier)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DRY

if tmliteErr.IsCommitNotFoundErr(err) {
return nil, context.ErrVerifyCommit(*height)
} else if err != nil {
return nil, err
}

if !bytes.Equal(check.ValidatorsHash(), tmTypes.NewValidatorSet(validatorsRes.Validators).Hash()) {
return nil, fmt.Errorf("got invalid validatorset")
}
}

outputValidatorsRes := ResultValidatorsOutput{
BlockHeight: validatorsRes.BlockHeight,
Validators: make([]ValidatorOutput, len(validatorsRes.Validators)),
Expand Down
21 changes: 18 additions & 3 deletions client/tx/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
tmliteErr "github.com/tendermint/tendermint/lite/errors"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
)

// QueryTxCmd implements the default command for a tx query.
Expand All @@ -45,9 +47,8 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
}

cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")

// TODO: change this to false when we can
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
return cmd
}

Expand All @@ -72,6 +73,20 @@ func queryTx(cdc *wire.Codec, cliCtx context.CLIContext, hashHexStr string, trus
return nil, err
}

if !trustNode {
check, err := tmliteProxy.GetCertifiedCommit(info.Height, node, cliCtx.Certifier)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DRY with above/below

if tmliteErr.IsCommitNotFoundErr(err) {
return nil, context.ErrVerifyCommit(info.Height)
} else if err != nil {
return nil, err
}

err = res.Proof.Validate(check.Header.DataHash)
if err != nil {
return nil, err
}
}

return wire.MarshalJSONIndent(cdc, info)
}

Expand Down
21 changes: 18 additions & 3 deletions client/tx/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"

tmliteErr "github.com/tendermint/tendermint/lite/errors"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)

Expand Down Expand Up @@ -62,9 +64,8 @@ $ gaiacli tendermint txs --tag test1,test2 --any
}

cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")

// TODO: change this to false once proofs built in
cmd.Flags().Bool(client.FlagTrustNode, true, "Don't verify proofs for responses")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
cmd.Flags().StringSlice(flagTags, nil, "Comma-separated list of tags that must match")
cmd.Flags().Bool(flagAny, false, "Return transactions that match ANY tag, rather than ALL")
return cmd
Expand Down Expand Up @@ -93,7 +94,21 @@ func searchTxs(cliCtx context.CLIContext, cdc *wire.Codec, tags []string) ([]Inf
if err != nil {
return nil, err
}
if prove {
for _, tx := range res.Txs {
check, err := tmliteProxy.GetCertifiedCommit(tx.Height, node, cliCtx.Certifier)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DRY with above

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be cached so the loop is OK I think

if tmliteErr.IsCommitNotFoundErr(err) {
return nil, context.ErrVerifyCommit(tx.Height)
} else if err != nil {
return nil, err
}

err = tx.Proof.Validate(check.Header.DataHash)
if err != nil {
return nil, err
}
}
}
info, err := FormatTxResults(cdc, res.Txs)
if err != nil {
return nil, err
Expand Down