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

Add IBC hooks for every IBC method #2296

Closed
wants to merge 19 commits into from

Conversation

nicolaslara
Copy link
Contributor

Description

This introduces a middleware for IBC that allows users to write their own hooks.

This was developed to allow the packet forward middleware send the tokens back if a hop fails, but it useful in general for simplifying middleware development.


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.
  • Wrote unit and integration tests
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/)
  • Added relevant godoc comments.
  • Added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • Re-reviewed Files changed in the Github PR explorer
  • Review Codecov Report in the comment section below once CI passes

Copy link
Contributor

@crodriguezvega crodriguezvega left a comment

Choose a reason for hiding this comment

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

Thanks for this new middleware, @nicolaslara! I have left some comments after doing a first review.

As a general remark, we would appreciate if you can groups the import like this:

import (
    // standard libraries
  
    // external libraries

    // ibc-go
}

This is just the code style we are trying to keep in the project. :)

It would be also nice to add documentation for this new middleware. And we also need a changelog entry (I would say under Features).

Looks also like gofumpt is complaining a bit on CI as well.

}

type IBCAppHooksOnChanOpenInitOverride interface {
OnChanOpenInitOverride(im IBCMiddleware, ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, error)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: do you mind to put each argument on a new line (like we do here)? I think it's easier for readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

changed it to only one line specifically for readability (so it's easy to scan which methods are defined on each interface, considering the arguments are the same as for the functions they override), but happy to change it back to one arg per line

OnChanCloseConfirmAfterHook(ctx sdk.Context, portID, channelID string, err error)
}

// OnAcknowledgementPacket Hooks
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I would change the order and put the OnRecvPacket hooks before the OnAcknowledgementPacket hooks.

chainC *ibctesting.TestChain

path *ibctesting.Path
pathAToC *ibctesting.Path
Copy link
Contributor

Choose a reason for hiding this comment

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

I think chainC and pathAToC are not used, right? So maybe you can just remove them...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes! that was left over from copy pasting a transfer test. Removed.

}

// Recv
type TestRecvOverrides struct{ Status *Status }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
type TestRecvOverrides struct{ Status *Status }
type TestRecvOverrideHooks struct{ Status *Status }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed

}

// Send
type TestSendOverrides struct{ Status *Status }
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
type TestSendOverrides struct{ Status *Status }
type TestSendOverrideHooks struct{ Status *Status }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed

ibcexported "github.com/cosmos/ibc-go/v5/modules/core/exported"
)

type IBCAppHooks interface {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wondering if we could shave off the IBCApp prefix from all these types...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

renamed

testCases := []struct {
msg string
malleate func(*testutils.Status)
recvIsSource bool // the receiving chain is the source of the coin originally
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you actually need to test the scenario of the receiving chain being the original source of the tokens? If not, maybe this can be removed to simplify the logic of the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call! simplifying.

}

// Recv
type TestRecvOverrides struct{ Status *Status }
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a nit, but I think that you could also make Status unexported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you can... but then you have to add a NewTestRecvOverrideHooks, which I find less clean. Since it's only used in testing, I don't see the harm in having it be exported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't feel strongly either way, though. Happy to change it if you do

return err
}

type TestSendBeforeAfterHooks struct{ Status *Status }
Copy link
Contributor

Choose a reason for hiding this comment

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

Both TestSendOverrides and TestSendBeforeAfterHooks are not used in the tests. Do you plan to write tests for them as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was planning to add those, but realized that that's quite hard to test because the ICS4Middlware (that should contain the hooks) is inside the IBCFeeKeeper (which doesn't export the ics4Wrapper).

The easiest way to test this would be to add the testing hook directly on simapp, but I'm not sure if that's too intrusive.

I've removed those for now. We will probably test all of these functions with an app that uses them (i.e.: the packet forwarding middleware)

@@ -0,0 +1,142 @@
package ibc_hooks
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to move this file inside the types folder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that would create an import cycle, as ibc_module.go depends on the hooks and the hooks on the middleware struct defined in that file

@nicolaslara nicolaslara changed the title Add IBC for every IBC method Add IBC hooks for every IBC method Sep 18, 2022
@codecov-commenter
Copy link

Codecov Report

Merging #2296 (4142d48) into main (9fa6008) will decrease coverage by 0.70%.
The diff coverage is 23.56%.

❗ Current head 4142d48 differs from pull request most recent head 1a6a518. Consider uploading reports for the commit 1a6a518 to get more accurate results

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2296      +/-   ##
==========================================
- Coverage   79.52%   78.82%   -0.71%     
==========================================
  Files         175      177       +2     
  Lines       12069    12226     +157     
==========================================
+ Hits         9598     9637      +39     
- Misses       2047     2152     +105     
- Partials      424      437      +13     
Impacted Files Coverage Δ
modules/apps/hooks/ibc_module.go 21.08% <21.08%> (ø)
modules/apps/hooks/ics4_middleware.go 60.00% <60.00%> (ø)
modules/apps/27-interchain-accounts/module.go 52.57% <0.00%> (+2.06%) ⬆️

Copy link
Member

@AdityaSripal AdityaSripal left a comment

Choose a reason for hiding this comment

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

Hi @nicolaslara, thanks for your PR! It seems to me like the intention of this middleware is to make writing middleware more standardized. Since people now implement the before/after/override for each function (most will be no-op) and your middleware then orders the calls.

My concern is that to implement the hook interface, we triple the number of functions expected to be implemented.

Why is this approach better than just having folks implement the interface as-is, and documenting how they can use the callback to execute logic before/after the underlying layer or override entirely? Especially since this middleware is not doing anything other than ordering the logic for them.

type OnChanOpenInitOverrideHooks interface {
OnChanOpenInitOverride(im IBCMiddleware, ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string) (string, error)
}
type OnChanOpenInitBeforeHooks interface {
Copy link
Member

Choose a reason for hiding this comment

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

Why don't the before and after hooks return errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

maybe they should. I can update them to return errors

@AdityaSripal
Copy link
Member

Hey @nicolaslara can you respond to the above? Seems like this can be closed, thanks

@nicolaslara
Copy link
Contributor Author

hey @AdityaSripal, yeah, this can be closed. I still like this way of extending the ibc module better but we can implement it on our end if we want (and so can anyone else who prefers it).

My concern is that to implement the hook interface, we triple the number of functions expected to be implemented.

I think the opposite is true. Since we're matching based on the interface, you can implement only the functions you want to override, instead of implementing a whole IBCModule/ICSWrapper structs. The structs in testing_hooks.go are an example of what a user would need to implement.

Now, after re-reading this, I think if we want to provide an interface to better extend the core IBC modules, it doesn't make sense to do it as a middleware, the hooks could instead be baked in on the core implementation

@crodriguezvega
Copy link
Contributor

Thank you, @nicolaslara.

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

Successfully merging this pull request may close these issues.

4 participants