diff --git a/lib/runtime/version.go b/lib/runtime/version.go index 9b0f3aadd3..fba9720303 100644 --- a/lib/runtime/version.go +++ b/lib/runtime/version.go @@ -4,6 +4,7 @@ package runtime import ( + "errors" "fmt" "strings" @@ -54,6 +55,11 @@ func (v *Version) Encode() (encoded []byte, err error) { return scale.Marshal(toEncode) } +var ( + ErrDecodingVersion = errors.New("decoding version") + ErrDecodingLegacyVersion = errors.New("decoding legacy version") +) + // DecodeVersion scale decodes the encoded version data and returns an error. // It first tries to decode the data using the current version format. // If that fails with an EOF error, it then tries to decode the data @@ -65,15 +71,18 @@ func DecodeVersion(encoded []byte) (version Version, err error) { } if !strings.Contains(err.Error(), "EOF") { - // TODO io.EOF should be wrapped in scale - return version, err + // TODO io.EOF should be wrapped in scale and + // ErrDecodingVersion should be removed once this is done. + return version, fmt.Errorf("%w: %s", ErrDecodingVersion, err) } // TODO: kusama seems to use the legacy version format var legacy legacyData err = scale.Unmarshal(encoded, &legacy) if err != nil { - return version, fmt.Errorf("decoding legacy version: %w", err) + // TODO sentinel error should be wrapped in scale and + // ErrDecodingLegacyVersion should be removed once this is done. + return version, fmt.Errorf("%w: %s", ErrDecodingLegacyVersion, err) } return Version{ diff --git a/lib/runtime/version_test.go b/lib/runtime/version_test.go index 1671c0174e..a88761c758 100644 --- a/lib/runtime/version_test.go +++ b/lib/runtime/version_test.go @@ -10,7 +10,134 @@ import ( "github.com/stretchr/testify/require" ) -func Test_VersionData_Scale(t *testing.T) { +func Test_Version_Encode(t *testing.T) { + t.Parallel() + + someVersion := Version{ + SpecName: []byte{1}, + ImplName: []byte{2}, + AuthoringVersion: 3, + SpecVersion: 4, + ImplVersion: 5, + APIItems: []APIItem{{ + Name: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + Ver: 6, + }}, + TransactionVersion: 7, + } + + testCases := map[string]struct { + version Version + encoding []byte + errWrapped error + errMessage string + }{ + "not legacy": { + version: someVersion, + encoding: []byte{ + 0x4, 0x1, 0x4, 0x2, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, + 0x5, 0x0, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x6, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0}, + }, + "legacy": { + version: someVersion.WithLegacy(), + encoding: []byte{ + 0x4, 0x1, 0x4, 0x2, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, + 0x5, 0x0, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x6, 0x0, 0x0, 0x0}, + }, + } + + for name, testCase := range testCases { + testCase := testCase + t.Run(name, func(t *testing.T) { + t.Parallel() + + encoded, err := testCase.version.Encode() + + assert.ErrorIs(t, err, testCase.errWrapped) + if testCase.errWrapped != nil { + require.EqualError(t, err, testCase.errMessage) + } + assert.Equal(t, testCase.encoding, encoded) + }) + } +} + +func Test_DecodeVersion(t *testing.T) { + t.Parallel() + + testCases := map[string]struct { + encoded []byte + version Version + errWrapped error + errMessage string + }{ + "unmarshal success": { + encoded: []byte{ + 0x4, 0x1, 0x4, 0x2, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, + 0x5, 0x0, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x6, 0x0, 0x0, 0x0, 0x7, 0x0, 0x0, 0x0}, + version: Version{ + SpecName: []byte{1}, + ImplName: []byte{2}, + AuthoringVersion: 3, + SpecVersion: 4, + ImplVersion: 5, + APIItems: []APIItem{{ + Name: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + Ver: 6, + }}, + TransactionVersion: 7, + }, + }, + "unmarshal error": { + encoded: []byte{255, 255}, + errWrapped: ErrDecodingVersion, + errMessage: "decoding version: could not decode invalid integer, field: []", + }, + "legacy unmarshal error": { + encoded: []byte{0}, + errWrapped: ErrDecodingLegacyVersion, + errMessage: "decoding legacy version: EOF, field: []", + }, + "legacy unmarshal success": { + encoded: []byte{ + 0x4, 0x1, 0x4, 0x2, 0x3, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, + 0x5, 0x0, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x6, 0x0, 0x0, 0x0}, + version: Version{ + SpecName: []byte{1}, + ImplName: []byte{2}, + AuthoringVersion: 3, + SpecVersion: 4, + ImplVersion: 5, + APIItems: []APIItem{{ + Name: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + Ver: 6, + }}, + legacy: true, + }, + }, + } + + for name, testCase := range testCases { + testCase := testCase + t.Run(name, func(t *testing.T) { + t.Parallel() + + version, err := DecodeVersion(testCase.encoded) + + assert.ErrorIs(t, err, testCase.errWrapped) + if testCase.errWrapped != nil { + require.EqualError(t, err, testCase.errMessage) + } + assert.Equal(t, testCase.version, version) + }) + } +} + +func Test_Version_Scale(t *testing.T) { t.Parallel() testCases := map[string]struct {