-
Notifications
You must be signed in to change notification settings - Fork 586
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
chore: add defensive check to ensure metadata does not change when reopening an active channel #847
Changes from 7 commits
a0386ec
e67068d
5521ee3
1d5bf68
21adb6c
2f2f4dc
3fdc6de
3559f2d
146c7fa
bebbfa7
e7b48ca
0f422e2
4c2c0f3
42557b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,24 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { | |
}, | ||
true, | ||
}, | ||
{ | ||
"success - previous active channel closed", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there an error testcase for when previous metadata is different? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unreachable, but I might as well add one |
||
func() { | ||
suite.chainA.GetSimApp().ICAControllerKeeper.SetActiveChannelID(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) | ||
|
||
counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) | ||
channel := channeltypes.Channel{ | ||
State: channeltypes.CLOSED, | ||
Ordering: channeltypes.ORDERED, | ||
Counterparty: counterparty, | ||
ConnectionHops: []string{path.EndpointA.ConnectionID}, | ||
Version: TestVersion, | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
path.EndpointA.SetChannel(channel) | ||
}, | ||
true, | ||
}, | ||
{ | ||
"invalid order - UNORDERED", | ||
func() { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||||
package keeper | ||||||
|
||||||
import ( | ||||||
"fmt" | ||||||
"strings" | ||||||
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types" | ||||||
|
@@ -47,8 +48,20 @@ func (k Keeper) OnChanOpenTry( | |||||
return "", err | ||||||
} | ||||||
|
||||||
if activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionHops[0], counterparty.PortId); found { | ||||||
return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID) | ||||||
activeChannelID, found := k.GetActiveChannelID(ctx, connectionHops[0], counterparty.PortId) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this whole block of code is the same as the one in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is fine to leave as is/be explicit. There's still a lot of duplicate code between OpenInit and OpenTry |
||||||
if found { | ||||||
channel, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelID) | ||||||
if !found { | ||||||
panic(fmt.Sprintf("active channel mapping set for %s but channel does not exist in channel store", activeChannelID)) | ||||||
} | ||||||
|
||||||
if channel.State == channeltypes.OPEN { | ||||||
return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated on controller and host |
||||||
} | ||||||
|
||||||
if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) { | ||||||
return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version") | ||||||
} | ||||||
} | ||||||
|
||||||
// On the host chain the capability may only be claimed during the OnChanOpenTry | ||||||
|
@@ -83,9 +96,9 @@ func (k Keeper) OnChanOpenConfirm( | |||||
} | ||||||
|
||||||
// It is assumed the controller chain will not allow multiple active channels to be created for the same connectionID/portID | ||||||
// If the controller chain does allow multiple active channels to be created for the same connectionID/portID, | ||||||
// If the controller chain does allow multiple active channels to be created for the same connectionID/portID, | ||||||
// disallowing overwriting the current active channel guarantees the channel can no longer be used as the controller | ||||||
// and host will disagree on what the currently active channel is | ||||||
// and host will disagree on what the currently active channel is | ||||||
k.SetActiveChannelID(ctx, channel.ConnectionHops[0], channel.Counterparty.PortId, channelID) | ||||||
|
||||||
return nil | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,17 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { | |
}, | ||
true, | ||
}, | ||
{ | ||
"success - reopening closed active channel", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. test case for error when the previous channel has different metadata? |
||
func() { | ||
// create a new channel and set it in state | ||
ch := channeltypes.NewChannel(channeltypes.CLOSED, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointA.ConnectionID}, TestVersion) | ||
suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, ch) | ||
|
||
// set the active channelID in state | ||
suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) | ||
}, true, | ||
}, | ||
{ | ||
"invalid order - UNORDERED", | ||
func() { | ||
|
@@ -140,7 +151,7 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { | |
func() { | ||
// create a new channel and set it in state | ||
ch := channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID), []string{path.EndpointA.ConnectionID}, ibctesting.DefaultChannelVersion) | ||
suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID, ch) | ||
suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, ch) | ||
|
||
// set the active channelID in state | ||
suite.chainB.GetSimApp().ICAHostKeeper.SetActiveChannelID(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID, path.EndpointB.ChannelID) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,21 @@ func NewMetadata(version, controllerConnectionID, hostConnectionID, accAddress, | |
} | ||
} | ||
|
||
// IsMetadataEqual compares a metadata to a pevious version string set in a channel struct. | ||
// It ensure all fields are equal except the Address string | ||
colin-axner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
func IsPreviousMetadataEqual(previousVersion string, metadata Metadata) bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion... We already have code to unmarhsall the version string here and the same code is found in And if you do that then you could also change this function so that it has the The you can invoke these functions like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like your suggestion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer @crodriguezvega's suggestion too, but given this will be removed in a couple of months hopefully, then I think we should just leave it as is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree with @damiannolan |
||
var previousMetadata Metadata | ||
if err := ModuleCdc.UnmarshalJSON([]byte(previousVersion), &previousMetadata); err != nil { | ||
return false | ||
} | ||
|
||
return (previousMetadata.Version == metadata.Version && | ||
previousMetadata.ControllerConnectionId == metadata.ControllerConnectionId && | ||
previousMetadata.HostConnectionId == metadata.HostConnectionId && | ||
previousMetadata.Encoding == metadata.Encoding && | ||
previousMetadata.TxType == metadata.TxType) | ||
} | ||
|
||
// ValidateControllerMetadata performs validation of the provided ICS27 controller metadata parameters | ||
func ValidateControllerMetadata(ctx sdk.Context, channelKeeper ChannelKeeper, connectionHops []string, metadata Metadata) error { | ||
if !isSupportedEncoding(metadata.Encoding) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be missing something, but the
version
that is passed here, isn't it the same that is unmarshalled tometadata
above? So here:If that's the case, wouldn't this check here just redundant?
Oh, wait... Or shouldn't you be using here
channel.Version
instead?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch, it should be channel.Version 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed