如何正确升级Substrate节点上的运行时版本?

8

已经成功创建了第一个Substrate链。

现在我想进一步定制我的demo.rs文件,以下是我的操作:

  1. 完全替换demo.rs中的代码,使用这里的代码,现在涉及到事件。

  2. 更新lib.rs文件

Demo: demo::{Module, Call, Storage, Event<T>},  

and

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

然后我发现我的更新外部方法在Polkadot Web App上未列出,或者按照教程第五步上传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-chain 命令,substrate_node_template_runtime_wasm.compact.wasm./target/release/node-name 将不会被更新。
引自这里
升级运行时只是简单地更换将接收交易和读取存储的代码块。
但是我想深入了解一步,在升级运行时节点时,使用 build.shcargo build 有什么区别?难道以上情况中 substrate_node_template_runtime_wasm.compact.wasm 和/或 ./target/release/node-name 二进制文件没有更新吗?

有关Substrate如何选择执行时(Wasm vs Native)的一些相关信息可以在此处找到:https://dev59.com/DbTna4cB1Zd3GeqPBeGL - Shawn Tabrizi
1个回答

6

让我们尝试回答你提出的几个不同的问题:

build.sh和cargo build之间的区别是什么

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

似乎在不使用purge-chain的情况下,substrate_node_template_runtime_wasm.compact.wasm./target/release/node-name都没有被更新。

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

记住,作为节点创世配置的一部分,运行时Wasm存储在链上,并用于确定您应该运行哪个版本(本地与Wasm)(链接1)
如果重新编译Wasm和本地二进制文件并直接运行,你将看不到任何区别。尽管您的节点二进制文件是全新的和更新的,但它仍然使用旧的链状态的数据库。这意味着在您的数据库中,您也有旧的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重新启动节点。当您正在开发运行时时,这通常是最容易做的事情,因为执行运行时升级时可能会导致意外行为的多个因素。

我改变了大部分代码,并添加了事件。

不幸的是,您没有在此处分享任何代码,这可能有助于调试此问题。虽然重要的是要注意,您不能对每个运行时更新使用运行时升级功能。
您应该将自己的区块链视为两个相互配合的独立部分:
  1. 区块链存储
  2. 区块链逻辑
当您进行升级时,您基本上是将区块链逻辑从一种东西换成另一种东西。从技术上讲,您可以字面上将任何东西与任何东西交换。但实际上,这并不意味着它会起作用。如果您的新逻辑不理解当前的区块链存储,则会破坏您的链。
因此,想象一下,您对一个函数进行了更改,该函数假定您具有完全不同的存储项....好吧,事情不会顺利进行。

一般来说,对于运行时升级而言,添加性更改是可以的。由于新特性不会影响旧特性,因此您的存储应该始终能够良好地与新运行时配合使用。但是,如果您进行了一次假定某些内容已经更改了区块链存储的运行时升级,则需要在任何运行时逻辑实际执行之前触发这些存储项的迁移。您可以通过一次性的on_initialize调用来完成这个操作,该调用将一个存储项集转换为新格式,但当您谈论迁移大量数据时,实现细节开始变得重要...

总之,在升级运行时方面有太多的因素可能会引起问题,就像您正在看到的问题一样。一般情况下,您不应该使用运行时升级进行初始开发。相反,在运行时迭代之间,您通常应该清除您的链并从头开始。


1
更新了代码链接。回顾过去,我发现我们甚至改变了存储名称,这应该是问题的原因。最好的做法是不要使用运行时升级来进行初始开发! - Haven

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接