【问题标题】:How to correctly upgrade a runtime on Substrate node?如何正确升级 Substrate 节点上的运行时?
【发布时间】:2019-09-14 07:33:50
【问题描述】:

在创建第一个底物链之后一切正常。

然后我想更进一步在demo.rs 文件上自定义我的,这就是我正在做的事情:

  1. demo.rs中的代码完全替换为代码here,现在涉及事件 .

  2. 更新 lib.rs
Demo: demo::{Module, Call, Storage, Event<T>},  

impl demo::Trait for Runtime {
    type Event = Event;
}
  1. 运行./scripts/build.rs
  2. 运行./target/release/node-name --dev

然后我看到我更新的外部函数没有在Polkadot Web App 上列出,或者按照step 5 on tutorial 上传substrate_node_template_runtime_wasm.compact.wasm 文件

所以我必须运行以下代码来进行更新:

rm -rf ./target
cargo build --release
./target/release/node-name --dev

通过与@shawntabrizi 讨论,他建议使用以下命令

./scripts/build.sh
cargo build --release
./target/release/node-name purge-chain --dev
./target/release/node-name --dev

似乎没有purge-chainsubstrate_node_template_runtime_wasm.compact.wasm./target/release/node-name 都不会更新。

引用here

通过升级运行时,您只需切换将接收外部数据和读取存储的代码块。

但我想更深入地了解,当升级运行时节点时,build.shcargo build 背后的区别是什么?那是因为substrate_node_template_runtime_wasm.compact.wasm 和/或./target/release/node-name 二进制文件在上述情况下没有更新吗?

【问题讨论】:

标签: substrate


【解决方案1】:

让我们尝试解决您提出的几个不同主题:

build.sh 和 cargo build 有什么区别

Substrate 运行时被编译为 Native 二进制文件和 Wasm blob。在 Substrate v1.0 中,这些编译步骤是分开的。 build.sh 将你的运行时编译为 Wasm,而 cargo build 编译你的整个节点(如 CLI、数据库等),包括运行时的本机版本。

似乎没有清除链,substrate_node_template_runtime_wasm.compact.wasm./target/release/node-name 都不会更新。

了解这里背景中发生的细节很重要。当你运行一个节点时,一个数据库存储在本地,它具有你的链状态。因此,如果您使用 ./target/release/node-name --dev 启动一个节点 50 个块,停止该节点,然后重新启动它,它将从您离开的地方继续(在第 51 个块)。

请记住,作为节点创世配置的一部分,Runtime Wasm 存储在链上,used to determine which version 是您应该运行的运行时(本机与 Wasm)。

如果你重新编译你的 Wasm 和你的 Native 二进制文件,并且不做任何其他事情就运行它,你不会看到任何差异。即使您的节点二进制文件是全新的和更新的,它也使用与旧链状态相同的数据库。这意味着在您的数据库中,您还拥有旧的 Wasm,当节点检查要使用的版本时,它将回退到使用数据库中的 Wasm!

如果您希望您的节点提取您所做的最新更改,您可以执行以下两项操作之一:

  1. 触发 Wasm 运行时的链上升级。这将使您的数据库具有最新的运行时代码,因此您的节点将使用最新的更改。

  2. 清除您的链以重新启动您的创世。这将删除您的 Substrate 区块链的任何旧状态,并最终使用最新的 Wasm 运行时填充链状态,这应该与您的节点一致。

我的建议:

./scripts/build.sh
cargo build --release
./target/release/node-name purge-chain --dev
./target/release/node-name --dev

将执行第二种方法,清理数据库,并在每次升级运行时逻辑时从块 0 重新启动节点。这通常是您在开发运行时时最容易做的事情,因为在执行运行时升级时有许多因素可能导致意外行为。

我更改了大部分代码,并在其中添加了 Event。

很遗憾,您没有在此处共享任何代码,这可能有助于调试此问题。虽然重要的是要注意,您不能对运行时的每次更新都使用运行时升级功能。

您应该将您的区块链视为两个独立的部分,它们一起工作:

  1. 区块链存储
  2. 区块链逻辑

当您进行升级时,您基本上是将区块链逻辑从一件事换到另一件事。从技术上讲,您可以将任何东西换成任何东西。但实际上,这并不意味着它会起作用。如果你的新逻辑不理解你当前的区块链存储,你就会断链。

因此,假设您对一个函数进行了更改,该函数假设您拥有与以前完全不同的存储项目....好吧,事情不会好转。

一般来说,附加更改非常适合运行时升级。由于新功能不会影响旧功能,因此您的存储应该始终能够与新运行时良好配合。但是,如果您进行运行时升级并假设您的区块链存储发生了某些变化,您将需要在任何运行时逻辑实际执行之前触发这些存储项的迁移。您可以通过一次性的on_initialize 调用来完成此操作,这会将一组存储项目转换为新格式,但是当您谈论迁移大量数据时,实施细节开始发挥作用......

无论如何,总而言之,升级运行时有太多可能导致问题的因素,可能就像您所看到的那样。一般来说,您应该不要使用运行时升级进行初始开发。相反,您通常应该在运行时的迭代之间清除链并从头开始。

【讨论】:

  • 更新了代码链接。当我回头看时,我发现我们甚至更改了存储名称,这应该会导致问题。最好不要使用运行时升级进行初始开发!
猜你喜欢
  • 2016-04-21
  • 2020-06-29
  • 1970-01-01
  • 2023-02-18
  • 1970-01-01
  • 2019-04-07
  • 1970-01-01
  • 2015-03-23
  • 2023-04-09
相关资源
最近更新 更多