refactor: channel handshake version improvements#1283
Conversation
|
|
||
| // Write channel into state | ||
| k.ChannelKeeper.WriteOpenInitChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, msg.Channel.Version) | ||
| k.ChannelKeeper.WriteOpenInitChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, version) |
There was a problem hiding this comment.
Changing this causes the fee tests to break. Looking into it 👀
Codecov Report
@@ Coverage Diff @@
## main #1283 +/- ##
=======================================
Coverage 80.27% 80.28%
=======================================
Files 166 166
Lines 12023 12044 +21
=======================================
+ Hits 9652 9670 +18
- Misses 1916 1918 +2
- Partials 455 456 +1
|
| return "", err | ||
| } | ||
|
|
||
| if strings.TrimSpace(version) == "" { |
There was a problem hiding this comment.
I can add a test case for this
Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
| ### API Breaking | ||
|
|
||
| * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. | ||
| * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) `OnChanOpenInit` now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). |
There was a problem hiding this comment.
Open to improvements on the changelog message.
There was a problem hiding this comment.
Nice work, @seantking!
I just noticed that in ICA we don't use any types.Version like we have for transfer (ics20-1) or fee. Was there a reason not use one there?
| // call underlying app's OnChanOpenInit callback with the appVersion | ||
| return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, | ||
| chanCap, counterparty, versionMetadata.AppVersion) | ||
| return string(versionBytes), nil |
There was a problem hiding this comment.
Why was the call to underlying app's OnChanOpenInit removed here?
There was a problem hiding this comment.
Its moved to above on line 53 so that the returned application version (for example: ics20-1) can be inserted into the AppVersion field of types.Metadata, and re-marshalled to a JSON encoded version string. Otherwise we would return directly from the app callback (writing ics20-1 as the channel version into state), we would expect ics29 to be enabled but subsequent handshake callbacks on would fail as the channel version in state would not be the metadata object:
{
"AppVersion": "ics20-1",
"FeeVersion": "ics29-1",
}Does that make sense?
| "empty version string", func() { | ||
| channel.Version = "" | ||
| }, true, | ||
| }, |
There was a problem hiding this comment.
Can you also add a test case when channel.Version is not empty but it's a string that does not match the expected types.Version?
There was a problem hiding this comment.
oh, sorry. I missed it.
damiannolan
left a comment
There was a problem hiding this comment.
Nice work! LGTM today, my only concern is the ICA auth module handling of the version string and if it should be given the opportunity to modify it, my initial thinking is no.
Other than that just some minor nits
| ### API Breaking | ||
|
|
||
| * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. | ||
| * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) `OnChanOpenInit` now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). |
There was a problem hiding this comment.
Some sugar coating?
| * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) `OnChanOpenInit` now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). | |
| * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now supports version selection and returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). |
There was a problem hiding this comment.
Added the first part but left out the version selection. I found that term confusing personally.
| // call underlying app's OnChanOpenInit callback with the passed in version | ||
| return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, | ||
| chanCap, counterparty, version) |
There was a problem hiding this comment.
This gives an opportunity to the interchain accounts auth module to modify the version string, or perhaps mistakenly return the incorrect string, right?
Is this something we want to support? i.e. providing the auth module the ability to mutate this?
Currently the only expectation from this callback is the claiming of the channel capability.
The code below would complain about appVersion declared but not used...
| // call underlying app's OnChanOpenInit callback with the passed in version | |
| return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, | |
| chanCap, counterparty, version) | |
| // call underlying app's OnChanOpenInit callback with the passed in version | |
| appVersion, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, | |
| chanCap, counterparty, version) | |
| if err != nil { | |
| return "", err | |
| } | |
| return version, nil |
There was a problem hiding this comment.
Not really following your point with the code example.
What would be the alternative here?
There was a problem hiding this comment.
Agreed if ibc-auth is expected not to change the version at all. Then we should ignore it's return value. And if relayer passes in empty string, then just return our default version
There was a problem hiding this comment.
Sorry if that was confusing, like @AdityaSripal says, we should ignore the appVersion field from the code example above by discarding it, as we don't want to depend on ica-auth to return the correct string(version) or risk modifying it:
_, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty version)
if err != nil {
return "", err
}
And if relayer passes in empty string, then just return our default version
But for ICA a relayer is never expected to initiate the channel handshake, it should be from some on-chain mechanism, correct?
There was a problem hiding this comment.
But for ICA a relayer is never expected to initiate the channel handshake, it should be from some on-chain mechanism, correct?
In our implementation of the controller module, yes. The version string will always be the Metadata struct
There was a problem hiding this comment.
Updated this. Good catch 👍
| ) | ||
|
|
||
| if tc.expPass { | ||
| expMetaData := icatypes.NewMetadata( |
There was a problem hiding this comment.
minor nit: casing
| expMetaData := icatypes.NewMetadata( | |
| expMetadata := icatypes.NewMetadata( |
| // call underlying app's OnChanOpenInit callback with the appVersion | ||
| return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, | ||
| chanCap, counterparty, versionMetadata.AppVersion) | ||
| return string(versionBytes), nil |
There was a problem hiding this comment.
Its moved to above on line 53 so that the returned application version (for example: ics20-1) can be inserted into the AppVersion field of types.Metadata, and re-marshalled to a JSON encoded version string. Otherwise we would return directly from the app callback (writing ics20-1 as the channel version into state), we would expect ics29 to be enabled but subsequent handshake callbacks on would fail as the channel version in state would not be the metadata object:
{
"AppVersion": "ics20-1",
"FeeVersion": "ics29-1",
}Does that make sense?
|
|
||
| suite.Require().NoError(err, "unexpected error from version: %s", tc.version) | ||
| } else { | ||
| suite.Require().Error(err, "error not returned for version: %s", tc.version) |
There was a problem hiding this comment.
Could we also assert version is empty here too?
| suite.Require().NoError(err) | ||
| suite.Require().Equal(types.Version, version) | ||
| } else { | ||
| suite.Require().Error(err) |
There was a problem hiding this comment.
ditto on empty version assertion
AdityaSripal
left a comment
There was a problem hiding this comment.
Looks good so far. The default version logic you have in transfer should be extended to the other applications
| ### API Breaking | ||
|
|
||
| * (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used. | ||
| * (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) `OnChanOpenInit` now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629). |
There was a problem hiding this comment.
I would add that it may return a default version string if relayers pass in empty version
There was a problem hiding this comment.
I left this out as I don't think the default is applicable to all modules.
There was a problem hiding this comment.
Hence the word may, i think it could still be useful but maybe we want to leave that suggestion elsewhere (e.g. release notes or something)
| return "", err | ||
| } | ||
|
|
||
| if strings.TrimSpace(version) == "" { |
There was a problem hiding this comment.
Shouldn't all of the applications/middleware have a similar code block?
| ) error { | ||
| ) (string, error) { | ||
| var versionMetadata types.Metadata | ||
| if err := types.ModuleCdc.UnmarshalJSON([]byte(version), &versionMetadata); err != nil { |
There was a problem hiding this comment.
This will not enable fee by default. If provided string is empty then, get default version from underlying app and wrap with fee version.
If underlying app returns error with empty version then return error as well
There was a problem hiding this comment.
Do we want to enable fees by default? Otherwise there's no way to only use the default version of the base application. I'd think middleware applications must be explicitly activated or, the versionMetadata should be specified with an empty fee version
There was a problem hiding this comment.
Yes, this was my assumption also. What is the benefit of enabling the fee middleware by default with an empty version passed in?
There was a problem hiding this comment.
I do think fees should be enabled by default. My preference is that relayers get the default version of the stack if they don't explicitly specify otherwise. Some middleware will want to be activated by default and some may want to be explicitly activated. For adoption purposes, I think it would be good to make incentivization the default rather than having to explicitly enable it. Because as I think the number of applications scale, most relayers will only be passing in empty strings and use non-empty strings only in very special cases (otherwise they would need to have context on every single port they relay for).
So a relayer that always defaults to what the application prefers will be opening incentivized channels.
Of course, if the relayer wants to explicitly disable fees then they can by passing in a version without the feeVersion. But we should design for a future where relayers are rarely passing in specific strings
There was a problem hiding this comment.
Sounds good to me. In favor of @AdityaSripal's approach. It should just be well documented that ics29 is an exceptional middleware application that we believe should be enabled by default, but that other applications (who might be copy/pasting our code) should give good consideration to whether their application should be enabled by default
There was a problem hiding this comment.
Thanks for the explanation @AdityaSripal. Makes sense to me!
| // call underlying app's OnChanOpenInit callback with the passed in version | ||
| return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, | ||
| chanCap, counterparty, version) |
There was a problem hiding this comment.
Agreed if ibc-auth is expected not to change the version at all. Then we should ignore it's return value. And if relayer passes in empty string, then just return our default version
I left the default only for ics20. I think ics29 should not be enabled by default as @colin-axner suggests & relayers do not pass a version for ics-27. The controller for ics27 module always passes a metaData struct as a version to the |
Here :) |
| // call underlying app's OnChanOpenInit callback with the passed in version | ||
| if _, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version); err != nil { | ||
| return "", err | ||
| } |
There was a problem hiding this comment.
Could be useful to have a small explanation of why this is ignored in the comment.
2f640f3 to
d30f887
Compare
AdityaSripal
left a comment
There was a problem hiding this comment.
Some testing and documentation nits :)
Would appreciate having them fixed, but doesn't need to happen in this PR
| isFeeEnabled := suite.chainA.GetSimApp().IBCFeeKeeper.IsFeeEnabled(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) | ||
| if isFeeEnabled { |
There was a problem hiding this comment.
This is a strange way to test here because you're relying on the result of the callback execution to create your expected value. If the callback incorrectly creates a fee version and incorrectly sets fee enabled you won't catch it here. Similarly if the callback incorrectly doesn't set fee version and incorrectly doesn't set fee enabled you won't catch it.
I think we should add a boolean in the test cases that says feeEnabled. You then can add the expected value for each test case and then check if the feeEnabled flag is true and check if the version contains a fee version
There was a problem hiding this comment.
Yup good catch. Thanks for the feedback 🤝
| // If the provided version string is non-empty, OnChanOpenInit should return | ||
| // the version string if valid or an error if the provided version is invalid. |
There was a problem hiding this comment.
Do we require that Init returns the exact same version if version is non-empty? I don't believe that is the case. Applications may want to modify the version string even if it is non-empty
There was a problem hiding this comment.
I took this directly from the spec: https://github.com/cosmos/ibc/pull/629/files#diff-508b3e7784a300436fbeb6940be22f31c74e958270a36bb851d06a8782ad7e7aR50
Should we update both? Agree with your assessment.
There was a problem hiding this comment.
Yes I agree we should change the spec as well
AdityaSripal
left a comment
There was a problem hiding this comment.
Nice work! Thanks @seantking
Fixes cosmos#1283 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit Refactor: - Improvement: Enhanced the transaction handling process in the `TxMempool` module. Transactions are now more accurately filtered based on their gas and data size limits, ensuring that only valid transactions are processed. This update improves the overall efficiency and reliability of transaction processing. Tests: - Test: Added a new test, `TestTxMempoolTxLargerThanMaxBytes`, to verify the correct handling of large transactions. This ensures the robustness of the system when dealing with transactions of varying sizes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Ganesha Upadhyaya <gupadhyaya@Ganeshas-MacBook-Pro-2.local>
Description
closes: #722
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.
docs/) or specification (x/<module>/spec/)godoccomments.Unreleasedsection inCHANGELOG.mdFiles changedin the Github PR explorerCodecov Reportin the comment section below once CI passes