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

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

merged 21 commits into from
Sep 14, 2018

Conversation

abelliumnt
Copy link

New solution for the issue in #2209
Besides, add verification in getting blocks, transactions and validator sets.
@alexanderbez @cwgoes

@codecov
Copy link

codecov bot commented Sep 2, 2018

Codecov Report

Merging #2210 into develop will decrease coverage by 0.59%.
The diff coverage is 66.66%.

@@            Coverage Diff             @@
##           develop    #2210     +/-   ##
==========================================
- Coverage    64.23%   63.63%   -0.6%     
==========================================
  Files          140      140             
  Lines         8575     8542     -33     
==========================================
- Hits          5508     5436     -72     
- Misses        2690     2738     +48     
+ Partials       377      368      -9

@abelliumnt
Copy link
Author

I noticed some todos: getBlock, queryTx and getValidators. The authors want the gaia-lite could verify the proof from response by default. So here I implement the verification functionality and set distrust-node option to true.
However, currently sometimes some errors will be reported, for instance:

lhy@lhy-ubuntu:~$ gaiacli tendermint validator-set 1 --chain-id test-chain-uIS9nF
ERROR: The height of base truststore in gaia-lite is higher than height 1. 
Can't verify blockchain proof at this height. Please set --distrust-node false and try again

The reason is that:

  • when the gaia-lite is started, it will fetch the latest commit as its base checkpoint. Here we mark the latest commit height as A.
  • it can only verify proof from height which is higher than A.
  • if user want to verify blocks or transactions on prior height this error will be reported.

Do you think this is accptable? If not, could you give me some suggestions about how to improve this?

@abelliumnt abelliumnt changed the title WIP: Replace trust-node option with distrust-node option, and add verification WIP: Replace trust-node option with distrust-node option, and add verification for getBlock, queryTx and getValidators Sep 2, 2018
@abelliumnt abelliumnt changed the title WIP: Replace trust-node option with distrust-node option, and add verification for getBlock, queryTx and getValidators R4R: Replace trust-node option with distrust-node option, and add verification for getBlock, queryTx and getValidators Sep 3, 2018
@alexanderbez
Copy link
Contributor

alexanderbez commented Sep 4, 2018

@HaoyangLiu, I like the approach here, but before going too in depth into a review, I think the nomenclature of distrust-node is a bit confusing and would lead to a slightly distasteful UX.

I think we should keep trust-node somehow while allowing any commands that do not need to rely on proofs still work as-is (e.g. gaiacli status).

Alternatively, to keep things simple. We could have trust-node as a persistent/root level flag and/or require anything that uses a CLIConext to use trust-node (including gaiacli status).

lmk your thoughts @cwgoes

@abelliumnt
Copy link
Author

@alexanderbez
Good idea. I never thought that we add a root flag.
I changed the code, please help take a look at this PR again.

@abelliumnt
Copy link
Author

@alexanderbez
I found a better way to decide whether to create certifier. If --trust-node is not predefined, then it indicates that certifier is not required. So only when --trust-node is predefined and its value is set to false, will the certifie rbe created. And the response proof will be verified too.
How do you think about this?

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

@abelliumnt abelliumnt changed the title R4R: Replace trust-node option with distrust-node option, and add verification for getBlock, queryTx and getValidators R4R: Judge if turst-node predefined before create certifier add verification for getBlock, queryTx and getValidators Sep 5, 2018
Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

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

@HaoyangLiu I like this approach better. I left some minor feedback. Otherwise, I tested this and it seems to work. Thanks!

@@ -69,32 +70,40 @@ func NewCLIContext() CLIContext {
}

func createCertifier() tmlite.Certifier {
flagPredefined := viper.IsSet(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.

trustNodeDefined?


// 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, "Don't verify proofs for query responses")
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems we're inconsistent with this flag's description. Can we update all occurrences to something like: Trust connected full node (don't verify proofs for responses)?

// 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, "Don't verify proofs for query responses")
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
Copy link
Contributor

Choose a reason for hiding this comment

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

Chain ID of Tendermint node*

Copy link
Contributor

@alexanderbez alexanderbez left a comment

Choose a reason for hiding this comment

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

tested ACK -- thanks!

@rigelrozanski rigelrozanski changed the title R4R: Judge if turst-node predefined before create certifier add verification for getBlock, queryTx and getValidators R4R: Judge if trust-node predefined before create certifier add verification for getBlock, queryTx and getValidators Sep 5, 2018
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

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

Capitalize and add trailing period please.

Copy link
Author

Choose a reason for hiding this comment

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

I'm sorry. Could you clarify trailing period please?

Copy link
Contributor

Choose a reason for hiding this comment

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

@HaoyangLiu I think he is stating that it should be reverted back to a sentence with a period.

Copy link
Author

Choose a reason for hiding this comment

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

Got it! Thanks

Copy link
Contributor

Choose a reason for hiding this comment

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

my pleasure 👍

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

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

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

See comments, mostly DRY, we can save other changes for later PRs.

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

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

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.

DRY

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

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

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

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

Ref #2323

@cwgoes cwgoes mentioned this pull request Sep 13, 2018
23 tasks
// trustNode defaults to true
if err != nil {
trustNode = true
}

Copy link
Author

@abelliumnt abelliumnt Sep 13, 2018

Choose a reason for hiding this comment

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

I remove this because if rest-server is stared with trust-node option, then we can't verify tx proof even if the request requires proof.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK 👍

Copy link
Contributor

@cwgoes cwgoes left a comment

Choose a reason for hiding this comment

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

Almost ready, one more suggested change.

func formatTxResult(cdc *wire.Codec, res *ctypes.ResultTx) (Info, error) {
// TODO: verify the proof if requested
func formatTxResult(cdc *wire.Codec, cliCtx context.CLIContext, res *ctypes.ResultTx) (Info, error) {
if !cliCtx.TrustNode {
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic is fine but I think it's confusing to put it in a function called formatTxResult - at first I thought you deleted the proof verification because I expected formatTxResult to only do formatting! Can we separate this into a different function - maybe validateTxResult or something?

Copy link
Author

Choose a reason for hiding this comment

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

I added the verification logic here because I noticed the TODO.
How about I create a new function named validateTxResult and call it in formatTxResult, like this:

func formatTxResult(cdc *wire.Codec, cliCtx context.CLIContext, res *ctypes.ResultTx) (Info, error) {
     if !cliCtx.TrustNode {
          if err := validateTxResult(cliCtx , res); err !=nil {
                 return ni, err
          }
     }
     ....
}

Copy link
Author

Choose a reason for hiding this comment

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

I'm sorry for misunderstanding. I have changed the code move the tx verification out of tx format.

// trustNode defaults to true
if err != nil {
trustNode = true
}

Copy link
Contributor

Choose a reason for hiding this comment

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

OK 👍

@cwgoes
Copy link
Contributor

cwgoes commented Sep 13, 2018

Also merge develop to fix the file conflicts.

@abelliumnt
Copy link
Author

The test_sim_modulues failure seems have no connection with my changes.

@alexanderbez
Copy link
Contributor

The test_sim_modulues failure seems have no connection with my changes.

Correct 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants