diff --git a/.changelog/3360.breaking.1.md b/.changelog/3360.breaking.1.md new file mode 100644 index 00000000000..76acdf432ac --- /dev/null +++ b/.changelog/3360.breaking.1.md @@ -0,0 +1,14 @@ +Compare protocol versions according to SemVer 2.0.0 + +As described in our [Versioning] document, we bumped the protocol versions to +version 1.0.0 with the release of [Oasis Core 20.10]. + +Hence, we also need to modify how we compare and detect backward-incompatible +changes to follow SemVer 2.0.0 rules. + +From now onwards, only a change in a protocol's major version signifies +a backward-incompatible change. + +[Versioning]: docs/versioning.md#version-100 +[Oasis Core 20.10]: + https://github.com/oasisprotocol/oasis-core/blob/v20.10/CHANGELOG.md diff --git a/.changelog/3360.breaking.2.md b/.changelog/3360.breaking.2.md new file mode 100644 index 00000000000..b6662adc10f --- /dev/null +++ b/.changelog/3360.breaking.2.md @@ -0,0 +1 @@ +go/common/version: Remove `MajorMinor()` method from `Version` type diff --git a/.changelog/3360.doc.md b/.changelog/3360.doc.md new file mode 100644 index 00000000000..96875d7b82d --- /dev/null +++ b/.changelog/3360.doc.md @@ -0,0 +1 @@ +Rename Versioning scheme document to Versioning and include it in the index diff --git a/.changelog/3360.feature.md b/.changelog/3360.feature.md new file mode 100644 index 00000000000..e31bd1db978 --- /dev/null +++ b/.changelog/3360.feature.md @@ -0,0 +1 @@ +go/common/version: Add `MaskNonMajor()` method to `Version` type diff --git a/docs/index.md b/docs/index.md index b0507fa2b3e..4ddddacf675 100644 --- a/docs/index.md +++ b/docs/index.md @@ -81,3 +81,4 @@ implementations. * [Architectural Decision Records](adr/index.md) * [Release Process](release-process.md) +* [Versioning](versioning.md) diff --git a/docs/toc.md b/docs/toc.md index 28b108ebcbc..971b2fe3ea7 100644 --- a/docs/toc.md +++ b/docs/toc.md @@ -48,3 +48,4 @@ * [Architectural Decision Records](adr/index.md) * [Release Process](release-process.md) +* [Versioning](versioning.md) diff --git a/docs/versioning.md b/docs/versioning.md index 2cd93e81967..0862ac46fcc 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -1,4 +1,4 @@ -# Versioning scheme +# Versioning ## Oasis Core @@ -67,21 +67,13 @@ the `MINOR` version must be bumped. When only backwards compatible bug fixes are made to a protocol, the `PATCH` version should be bumped. -### Pre-Mainnet protocol versioning +### Version 1.0.0 -Until Oasis Network has reached the Mainnet phase, the `MAJOR` version of all -protocols version is set to 0. This indicates that this is not yet a production -version of the protocols and backwards incompatible changes may happen -frequently. - -For this reason, Oasis Core currently considers a change in protocol’s minor -version, a breaking change. - -### Mainnet and version 1.0.0 - -When we will prepare an Oasis Core release for the Mainnet, we will bump the -protocol versions to version 1.0.0 which will [signify that they are ready for -production use](https://semver.org/#how-do-i-know-when-to-release-100). +With the release of [Oasis Core 20.10], we bumped the protocol versions to +version 1.0.0 which [signified that they are ready for production use]( +https://semver.org/#how-do-i-know-when-to-release-100). [CalVer]: http://calver.org [SemVer]: https://semver.org/ +[Oasis Core 20.10]: + https://github.com/oasisprotocol/oasis-core/blob/v20.10/CHANGELOG.md diff --git a/go/common/version/version.go b/go/common/version/version.go index 712a0b2a443..a8ecc6eb68f 100644 --- a/go/common/version/version.go +++ b/go/common/version/version.go @@ -1,4 +1,7 @@ // Package version implements Oasis protocol and runtime versioning. +// +// For a more detailed explanation of Oasis Core's versioning, see: +// https://docs.oasis.dev/oasis-core/processes/versioning. package version import ( @@ -12,7 +15,7 @@ import ( // NOTE: This should be kept in sync with runtime/src/common/version.rs. -// Version is a protocol or a runtime version. +// Version is a protocol version. type Version struct { Major uint16 `json:"major,omitempty"` Minor uint16 `json:"minor,omitempty"` @@ -38,14 +41,15 @@ func (v Version) String() string { return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) } -// MajorMinor extracts major and minor segments of the Version only. +// MaskNonMajor masks all non-major version segments to 0 and returns a new +// protocol version. // -// This is useful for comparing protocol version since the patch segment can be -// ignored. -func (v Version) MajorMinor() Version { +// This is useful for comparing protocol versions for backward-incompatible +// changes. +func (v Version) MaskNonMajor() Version { return Version{ Major: v.Major, - Minor: v.Minor, + Minor: 0, Patch: 0, } } @@ -74,10 +78,21 @@ var ( // the epochtime, beacon, registry, roothash, etc. modules that are // backend by consensus. // - // NOTE: Any change in the major or minor versions are considered - // breaking changes for the protocol. + // NOTE: Consensus protocol version compatibility is currently not directly + // checked in Oasis Core. + // It is converted to TendermintAppVersion whose compatibility is checked + // via Tendermint's version checks. ConsensusProtocol = Version{Major: 1, Minor: 0, Patch: 0} + // TendermintAppVersion is Tendermint ABCI application's version computed by + // masking non-major consensus protocol version segments to 0 to be + // compatible with Tendermint's version checks. + // + // NOTE: Tendermint's version checks compare the whole version uint64 + // directly. For example: + // https://github.com/tendermint/tendermint/blob/1635d1339c73ae6a82e062cd2dc7191b029efa14/state/validation.go#L21-L22. + TendermintAppVersion = ConsensusProtocol.MaskNonMajor().ToU64() + // Tendermint exposes the tendermint core version. Tendermint = parseSemVerStr(version.TMCoreSemVer) diff --git a/go/common/version/version_test.go b/go/common/version/version_test.go index 41662dd2f8d..09d26ea08f6 100644 --- a/go/common/version/version_test.go +++ b/go/common/version/version_test.go @@ -6,16 +6,16 @@ import ( "github.com/stretchr/testify/require" ) -func TestMajorMinor(t *testing.T) { +func TestMaskNonMajor(t *testing.T) { require := require.New(t) v1 := Version{1, 1, 0} v2 := Version{1, 1, 5} - v3 := Version{1, 1, 10} - require.Equal(v1.MajorMinor(), v2.MajorMinor(), "version.MajorMinor() should match") - require.Equal(v2.MajorMinor(), v3.MajorMinor(), "version.MajorMinor() should match") - v4 := Version{1, 2, 0} - require.NotEqual(v1.MajorMinor(), v4.MajorMinor(), "version.MajorMinor() should not match") + v3 := Version{1, 4, 10} + require.Equal(v1.MaskNonMajor(), v2.MaskNonMajor(), "version.MaskNonMajor() should match") + require.Equal(v2.MaskNonMajor(), v3.MaskNonMajor(), "version.MaskNonMajor() should match") + v4 := Version{2, 1, 0} + require.NotEqual(v1.MaskNonMajor(), v4.MaskNonMajor(), "version.MaskNonMajor() should not match") } func TestParseSemVer(t *testing.T) { diff --git a/go/consensus/tendermint/abci/mux.go b/go/consensus/tendermint/abci/mux.go index dfb581358c0..0ecd25b4336 100644 --- a/go/consensus/tendermint/abci/mux.go +++ b/go/consensus/tendermint/abci/mux.go @@ -270,7 +270,7 @@ func (mux *abciMux) registerHaltHook(hook func(context.Context, int64, epochtime func (mux *abciMux) Info(req types.RequestInfo) types.ResponseInfo { return types.ResponseInfo{ - AppVersion: version.ConsensusProtocol.ToU64(), + AppVersion: version.TendermintAppVersion, LastBlockHeight: mux.state.BlockHeight(), LastBlockAppHash: mux.state.BlockHash(), } @@ -767,7 +767,7 @@ func (mux *abciMux) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock { // Update version to what we are actually running. resp.ConsensusParamUpdates = &types.ConsensusParams{ Version: &tmproto.VersionParams{ - AppVersion: version.ConsensusProtocol.ToU64(), + AppVersion: version.TendermintAppVersion, }, } diff --git a/go/consensus/tendermint/api/genesis.go b/go/consensus/tendermint/api/genesis.go index f58b813fdf6..ff2663ebadb 100644 --- a/go/consensus/tendermint/api/genesis.go +++ b/go/consensus/tendermint/api/genesis.go @@ -111,7 +111,7 @@ func genesisToTendermint(d *genesis.Document) (*tmtypes.GenesisDoc, error) { PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, }, Version: tmproto.VersionParams{ - AppVersion: version.ConsensusProtocol.ToU64(), + AppVersion: version.TendermintAppVersion, }, }, AppState: b, diff --git a/go/consensus/tendermint/full/statesync.go b/go/consensus/tendermint/full/statesync.go index b802b391228..959e83c6696 100644 --- a/go/consensus/tendermint/full/statesync.go +++ b/go/consensus/tendermint/full/statesync.go @@ -59,7 +59,7 @@ func (sp *stateProvider) State(ctx context.Context, height uint64) (tmstate.Stat InitialHeight: sp.genesisDocument.InitialHeight, } // XXX: This will fail in case an upgrade happened in-between. - state.Version.Consensus.App = version.ConsensusProtocol.ToU64() + state.Version.Consensus.App = version.TendermintAppVersion // The snapshot height maps onto the state heights as follows: // diff --git a/go/consensus/tendermint/seed/seed.go b/go/consensus/tendermint/seed/seed.go index 2b0c629e92c..26616c1b7cd 100644 --- a/go/consensus/tendermint/seed/seed.go +++ b/go/consensus/tendermint/seed/seed.go @@ -341,7 +341,7 @@ func New(dataDir string, identity *identity.Identity, genesisProvider genesis.Pr ProtocolVersion: p2p.NewProtocolVersion( tmversion.P2PProtocol, tmversion.BlockProtocol, - version.ConsensusProtocol.ToU64(), + version.TendermintAppVersion, ), DefaultNodeID: nodeKey.ID(), ListenAddr: viper.GetString(tmcommon.CfgCoreListenAddress), diff --git a/go/consensus/tendermint/tests/genesis/genesis.go b/go/consensus/tendermint/tests/genesis/genesis.go index 9e1e5d76149..1cf9f20b6af 100644 --- a/go/consensus/tendermint/tests/genesis/genesis.go +++ b/go/consensus/tendermint/tests/genesis/genesis.go @@ -93,7 +93,7 @@ func NewTestNodeGenesisProvider(identity *identity.Identity) (genesis.Provider, AppState: b, } tmDoc.ConsensusParams.Version = tmproto.VersionParams{ - AppVersion: version.ConsensusProtocol.ToU64(), + AppVersion: version.TendermintAppVersion, } nodeID := identity.ConsensusSigner.Public() diff --git a/go/runtime/host/protocol/connection.go b/go/runtime/host/protocol/connection.go index 36550cc546d..93ec458a8e2 100644 --- a/go/runtime/host/protocol/connection.go +++ b/go/runtime/host/protocol/connection.go @@ -530,7 +530,7 @@ func (c *connection) InitHost(ctx context.Context, conn net.Conn) (*version.Vers } info := rsp.RuntimeInfoResponse - if ver := version.FromU64(info.ProtocolVersion); ver.MajorMinor() != version.RuntimeHostProtocol.MajorMinor() { + if ver := version.FromU64(info.ProtocolVersion); ver.Major != version.RuntimeHostProtocol.Major { c.logger.Error("runtime has incompatible protocol version", "version", ver, "expected_version", version.RuntimeHostProtocol, diff --git a/go/worker/common/p2p/p2p.go b/go/worker/common/p2p/p2p.go index 61d58642e27..b694756617e 100644 --- a/go/worker/common/p2p/p2p.go +++ b/go/worker/common/p2p/p2p.go @@ -161,9 +161,9 @@ func (p *P2P) handleConnection(conn core.Conn) { } func (p *P2P) topicIDForRuntime(runtimeID common.Namespace) string { - return fmt.Sprintf("%s/%s/%s", + return fmt.Sprintf("%s/%d/%s", p.chainContext, - version.RuntimeCommitteeProtocol.MajorMinor().String(), + version.RuntimeCommitteeProtocol.Major, runtimeID.String(), ) } diff --git a/runtime/src/common/version.rs b/runtime/src/common/version.rs index de5f7695086..b34cab84c2e 100644 --- a/runtime/src/common/version.rs +++ b/runtime/src/common/version.rs @@ -30,17 +30,6 @@ impl Version { patch: patch, } } - - /// Extract major and minor segments of the Version only. - /// - /// This is useful for comparing protocol version since the patch segment can be ignored. - pub fn major_minor(&self) -> Version { - Version { - major: self.major, - minor: self.minor, - patch: 0, - } - } } // Returns the version as a platform-dependent u64.