Substrate 具有运行时版本控制。这些的目的和用例是什么?

T9b*_*T9b 6 substrate

在基质运行时的主要部分lib.rs(以及模板节点中)有几个可以更改的版本属性 - 我猜测是为了跟踪各种构建版本 - 但目前尚不清楚我们如何在自己的项目中使用这些属性。

1)它们的用途是什么?在我们自己的项目中增加这些的期望是什么?

2) 其中任何一个或组合是否旨在表明与我们的运行时的先前版本不兼容,例如,此值的增加表明较新的版本与存储、共识或可能导致预期导致的其他方面不兼容网络分叉?

pub const VERSION: RuntimeVersion = RuntimeVersion {
    spec_name: create_runtime_str!("node"),
    impl_name: create_runtime_str!("substrate-node"),
    authoring_version: 10,
    spec_version: 99,
    impl_version: 104,
    apis: RUNTIME_API_VERSIONS,
};
Run Code Online (Sandbox Code Playgroud)

Sha*_*izi 8

运行时版本控制是基于 Substrate 的区块链“无分叉运行时升级”功能的重要组成部分。

core/sr-version发表这篇文章时开始:

/// Runtime version.
/// This should not be thought of as classic Semver (major/minor/tiny).
/// This triplet have different semantics and mis-interpretation could cause problems.
/// In particular: bug fixes should result in an increment of `spec_version` and possibly `authoring_version`,
/// absolutely not `impl_version` since they change the semantics of the runtime.
#[derive(Clone, PartialEq, Eq, Encode)]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Decode))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
pub struct RuntimeVersion {
    /// Identifies the different Substrate runtimes. There'll be at least polkadot and node.
    /// A different on-chain spec_name to that of the native runtime would normally result
    /// in node not attempting to sync or author blocks.
    pub spec_name: RuntimeString,

    /// Name of the implementation of the spec. This is of little consequence for the node
    /// and serves only to differentiate code of different implementation teams. For this
    /// codebase, it will be parity-polkadot. If there were a non-Rust implementation of the
    /// Polkadot runtime (e.g. C++), then it would identify itself with an accordingly different
    /// `impl_name`.
    pub impl_name: RuntimeString,

    /// `authoring_version` is the version of the authorship interface. An authoring node
    /// will not attempt to author blocks unless this is equal to its native runtime.
    pub authoring_version: u32,

    /// Version of the runtime specification. A full-node will not attempt to use its native
    /// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
    /// `spec_version` and `authoring_version` are the same between Wasm and native.
    pub spec_version: u32,

    /// Version of the implementation of the specification. Nodes are free to ignore this; it
    /// serves only as an indication that the code is different; as long as the other two versions
    /// are the same then while the actual code may be different, it is nonetheless required to
    /// do the same thing.
    /// Non-consensus-breaking optimizations are about the only changes that could be made which
    /// would result in only the `impl_version` changing.
    pub impl_version: u32,

    /// List of supported API "features" along with their versions.
    #[cfg_attr(feature = "std", serde(serialize_with = "apis_serialize::serialize"))]
    pub apis: ApisVec,
}
Run Code Online (Sandbox Code Playgroud)

spec_version用于表示共识关键逻辑是否发生变化,而impl_version用于表示不会影响网络共识的变化。例如,如果函数的行为在运行时发生变化,则必须增加 ,spec_version以注意此版本的运行时将不会与另一个版本的运行时达成共识。然而,如果仅对函数进行了优化,但结果输出相同,则只需impl_version修改函数即可。

使用spec_version,节点能够确定运行时的本机版本(实际运行该节点的本机可执行文件)是否与运行时的 Wasm 版本(存储在链上并且网络已达成共识)匹配。

如果运行时的本机spec_nameauthoring_version和 与Wasm 运行时spec_version的版本匹配,则使用本机运行时而不是 Wasm 运行时,因为它执行速度更快。如果spec_version不完全匹配,节点将回退到使用 Wasm 版本的运行时,确保节点与网络的其余部分保持一致。

如果您想跟踪发生这种情况的代码路径,您可以从core/sr-version.

impl RuntimeVersion {
    /// Check if this version matches other version for calling into runtime.
    pub fn can_call_with(&self, other: &RuntimeVersion) -> bool {
        self.spec_version == other.spec_version &&
        self.spec_name == other.spec_name &&
        self.authoring_version == other.authoring_version
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后,如果您进入core/executor/native_executor.rs,您将看到该can_call_with函数用于确定是否可以使用本机运行时。


编辑:需要注意的是,块构造执行引擎始终默认为 Wasm,而导入执行引擎会尝试使用本机(如果可能),并使用上述逻辑。