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

multihop: some improvements (naming, documentation, errors) #41

Conversation

crodriguezvega
Copy link

@crodriguezvega crodriguezvega commented Dec 1, 2023

Description

Some (hopefully) improvements to align with idc-go's code guidelines (e.g. regarding error reporting).
Renamed some variables, functions to (hopefully) more clarifying names (at least for me 😄).
Added extra comments and godocs.

I will open more PRs as I continue to go through the code.

closes: #XXXX

Commit Message / Changelog Entry

type: commit message

see the guidelines for commit messages. (view raw markdown for examples)


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Targeted PR against correct branch (see CONTRIBUTING.md).
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the module structure standards and Go style guide.
  • Wrote unit and integration tests.
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/).
  • Added relevant godoc comments.
  • Provide a commit message to be used for the changelog entry in the PR description for review.
  • Re-reviewed Files changed in the Github PR explorer.
  • Review Codecov Report in the comment section below once CI passes.

@@ -152,57 +152,34 @@ func (k Keeper) ChanOpenTry(
)
}

// check version support
versionCheckFunc := func(connection *connectiontypes.ConnectionEnd) error {
Copy link
Author

Choose a reason for hiding this comment

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

I turned this into a function in line 732 below.

return nil, err
}
} else {
panic("") // TODO: is this reachable?
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 this, but it should not reach here, right? So would it be fine to panic?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, this looks correct to me.

The alternative would be to pass in and return the known counterparty consensus state if there are no intermediate connection proofs? Possibly could help merge the single-hop vs multi-hop logic?

var connectionEnd ConnectionEnd
if len(m.ConnectionProofs) > 0 {
// connection proofs are ordered from executing chain to counterparty,
// so the last hop connection end is the value of last connection proof
if err := cdc.Unmarshal(m.ConnectionProofs[len(m.ConnectionProofs)-1].Value, &connectionEnd); err != nil {
return nil, err
}
} else {
Copy link
Author

Choose a reason for hiding this comment

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

Is the else statement reachable? If it is, I don't understand how returning the same connection end as the function received as a parameter would be correct...

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, it's been a bit since I wrote this, but I believe I designed the multi-hop code so that it could also work for the case of a single-hop. In that case, no extra connection proofs are required because we already store the IBC connection for the counterparty. i.e. this is handling the degenerate case when multi-hop works like single-hop.

I was hoping that somehow the single-hop and multi-hop verification code could merge one day.

Copy link
Author

Choose a reason for hiding this comment

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

I was hoping that somehow the single-hop and multi-hop verification code could merge one day.

Yes, that would be great! I was also thinking about it the other day. It would make the code easier to reason about. I will try to see if I can come up with something, or ask later on the rest of the team if they would have any ideas.

Copy link
Member

Choose a reason for hiding this comment

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

Currently the connectionKeeper interface has verification methods for each separate proof type (channel try/ack, recv packer, ack packet, etc). But really they are only needed because the derived key/values are passed in and need to be computed differently for each case. The multihop verification method allows passing in a key/value generation function which could generalize this.

The next issue is the proof format being different, but if verification could work similarly given a single-hop or multi-hop proof method its seems possible to collapse all the methods down to: VerifyMembership and VerifyNonmembership.

Anyway, these were a few thoughts I had a while back.

Comment on lines +178 to 190
// parse the client ID from the the consensusState key path
clientID, err := parseClientIDFromKey(consensusProof.PrefixedKey.KeyPath)
if err != nil {
return err
}

// check that the client ID matches the client ID in the connectionEnd on the same hop.
if connectionEnd.ClientId != clientID {
return fmt.Errorf("consensus state client id (%s) does not match expected client id (%s)",
connectionEnd.ClientId,
clientID,
)
}
Copy link
Author

Choose a reason for hiding this comment

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

I moved this validation here from verifyIntermediateStates because it's not verifying any proofs.

// from the executing chain (but excluding it) to the counterparty.
// - connectionHops contains the connection IDs for the hops from the executing chain to the counterparty, but it does not include the
// connection ID for the first hop on the executing chain.
func validateIntermediateStates(
Copy link
Author

Choose a reason for hiding this comment

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

I renamed the function to use the word validate instead of verify because it does not do proof verification. It's a distinction that we like to make in ibc-go. :)

Comment on lines +398 to 402
prefix := lastHopConnectionEnd.GetCounterparty().GetPrefix()
path, err := commitmenttypes.ApplyPrefix(prefix, commitmenttypes.NewMerklePath(key))
if err != nil {
return err
}
Copy link
Author

Choose a reason for hiding this comment

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

Instead of passing prefix and key to VerifyMultihopMembership and VerifyMultihopNonMembership I decided to construct the path here and pass only one parameter to those two functions.

Copy link
Member

@dshiell dshiell left a comment

Choose a reason for hiding this comment

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

This looks great!!

var connectionEnd ConnectionEnd
if len(m.ConnectionProofs) > 0 {
// connection proofs are ordered from executing chain to counterparty,
// so the last hop connection end is the value of last connection proof
if err := cdc.Unmarshal(m.ConnectionProofs[len(m.ConnectionProofs)-1].Value, &connectionEnd); err != nil {
return nil, err
}
} else {
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, it's been a bit since I wrote this, but I believe I designed the multi-hop code so that it could also work for the case of a single-hop. In that case, no extra connection proofs are required because we already store the IBC connection for the counterparty. i.e. this is handling the degenerate case when multi-hop works like single-hop.

I was hoping that somehow the single-hop and multi-hop verification code could merge one day.

return nil, err
}
} else {
panic("") // TODO: is this reachable?
Copy link
Member

Choose a reason for hiding this comment

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

Yes, this looks correct to me.

The alternative would be to pass in and return the known counterparty consensus state if there are no intermediate connection proofs? Possibly could help merge the single-hop vs multi-hop logic?

@dshiell dshiell merged commit b5d5877 into polymerdao:polymer/multihop-main Dec 5, 2023
18 of 19 checks passed
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.

2 participants