diff --git a/CHANGELOG.md b/CHANGELOG.md index d24699f445a..81eac3c769c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* [\#383](https://github.com/cosmos/ibc-go/pull/383) Adds helper functions for merging and splitting middleware versions from the underlying app version. + ### Features * [\#384](https://github.com/cosmos/ibc-go/pull/384) Added `NegotiateAppVersion` method to `IBCModule` interface supported by a gRPC query service in `05-port`. This provides routing of requests to the desired application module callback, which in turn performs application version negotiation. diff --git a/modules/core/04-channel/types/version.go b/modules/core/04-channel/types/version.go new file mode 100644 index 00000000000..15477635e7f --- /dev/null +++ b/modules/core/04-channel/types/version.go @@ -0,0 +1,27 @@ +package types + +import "strings" + +const ChannelVersionDelimiter = ":" + +// SplitChannelVersion splits the channel version string +// into the outermost middleware version and the underlying app version. +// It will use the default delimiter `:` for middleware versions. +// In case there's no delimeter, this function returns an empty string for the middleware version (first return argument), +// and the full input as the second underlying app version. +func SplitChannelVersion(version string) (middlewareVersion, appVersion string) { + // only split out the first middleware version + splitVersions := strings.Split(version, ChannelVersionDelimiter) + if len(splitVersions) == 1 { + return "", version + } + middlewareVersion = splitVersions[0] + appVersion = strings.Join(splitVersions[1:], ChannelVersionDelimiter) + return +} + +// MergeChannelVersions merges the provided versions together with the channel version delimiter +// the versions should be passed in from the highest-level middleware to the base application +func MergeChannelVersions(versions ...string) string { + return strings.Join(versions, ChannelVersionDelimiter) +} diff --git a/modules/core/04-channel/types/version_test.go b/modules/core/04-channel/types/version_test.go new file mode 100644 index 00000000000..4011aeade2c --- /dev/null +++ b/modules/core/04-channel/types/version_test.go @@ -0,0 +1,77 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" +) + +func TestSplitVersions(t *testing.T) { + testCases := []struct { + name string + version string + mwVersion string + appVersion string + }{ + { + "single wrapped middleware", + "fee29-1:ics20-1", + "fee29-1", + "ics20-1", + }, + { + "multiple wrapped middleware", + "fee29-1:whitelist:ics20-1", + "fee29-1", + "whitelist:ics20-1", + }, + { + "no middleware", + "ics20-1", + "", + "ics20-1", + }, + } + + for _, tc := range testCases { + mwVersion, appVersion := types.SplitChannelVersion(tc.version) + require.Equal(t, tc.mwVersion, mwVersion, "middleware version is unexpected for case: %s", tc.name) + require.Equal(t, tc.appVersion, appVersion, "app version is unexpected for case: %s", tc.name) + } +} + +func TestMergeVersions(t *testing.T) { + testCases := []struct { + name string + versions []string + merged string + }{ + { + "single version", + []string{"ics20-1"}, + "ics20-1", + }, + { + "empty version", + []string{}, + "", + }, + { + "two versions", + []string{"fee29-1", "ics20-1"}, + "fee29-1:ics20-1", + }, + { + "multiple versions", + []string{"fee29-1", "whitelist", "ics20-1"}, + "fee29-1:whitelist:ics20-1", + }, + } + + for _, tc := range testCases { + actual := types.MergeChannelVersions(tc.versions...) + require.Equal(t, tc.merged, actual, "merged versions string does not equal expected value") + } +}