运行时版本控制是基于 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,
}
spec_version
用于表示共识关键逻辑是否发生变化,而impl_version
用于表示不会影响网络共识的变化。例如,如果一个函数的行为在运行时发生变化,您必须增加spec_version
以注意这个版本的运行时不会与另一个版本的运行时达成共识。然而,如果只对函数进行了优化,但结果输出是相同的,那么只impl_version
需要碰撞。
使用spec_version
,节点能够确定运行时的本机版本(实际运行节点的本机可执行文件)是否与运行时的 Wasm 版本(存储在链上并且网络已达成共识)匹配。
如果运行时的 native spec_name
、authoring_version
和与 Wasm 运行时的版本匹配,则使用原生运行时而不是 Wasm 运行时,因为它的执行速度更快。在不完全匹配的情况下,节点将回退到使用运行时的 Wasm 版本,确保节点与网络的其余部分保持一致。spec_version
spec_version
如果您想遵循发生这种情况的代码路径,您可以从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
}
...
}
然后如果你进入core/executor/native_executor.rs
,你会看到该can_call_with
函数用于确定是否可以使用本机运行时。
编辑:重要的是要注意,块构造执行引擎始终默认为 Wasm,而导入执行引擎尽可能使用本机,使用上述逻辑。