开发 Substrate 的准备工作

  • 胡键
  • 更新于 2020-06-19 18:54
  • 阅读 3574

磨刀不误砍柴工,准备好了,才能写好 Substrate 应用。

前一篇,我们对“什么是 Substrate”有了感观上的认识,但这并不足以让你可以轻松地开发出符合自己需要的区块链。开发 Substrate 区块链应用也并非一个低门槛的工作,缺乏必备的知识将让人一头雾水摸不着头脑。

鉴于此,本文将作为一篇“过渡文章”,谈谈开发前的准备工作。至于实际的开发示例,将放在本系列的第三篇。

总的来讲,本文的内容将分为三部分:

  • 需要了解的 Rust 知识
  • 开发 Substrate 必备的基本概念
  • Node-Template 基本结构

需要了解的 Rust 知识

开发 Substrate 应用, Rust 是开发人员必须迈过的第一道坎。然而,Rust 的学习曲线陡峭,入门并不简单,这里我稍稍整理了一下知识脉络,希望能减少大家的障碍。

对于 IDE,我建议大家不要把时间浪费在这个上面去做各种比较,先选择一个还不错的直接开始上手编写代码。我们的目标是尽快掌握 Rust 开发,不是去做工具的评测。本文推荐:vscode + rust 插件。如果你喜欢 IntelliJ IDEA,它同样也有 rust 插件。

同时,熟悉 Cargo,最好在写完 Rust 版 “Hello World!”后就尝试用 Cargo 去编译和构建。 必须要掌握的命令:

  • cargo install
  • cargo build
  • cargo run
  • cargo test
  • cargo update
  • cargo --list

对于每一个 Rust 工程,典型的过程如下:

  • cargo new --binary,假设是可执行文件
  • 编辑 cargo.toml 引入依赖
  • 工程组织:
    • main.rs + 各个 lib.rs
    • src 目录下放源文件,单元测试与源文件在一起
    • tests 目录下放集成测试
  • cargo test
  • cargo build —release

典型的 cargo 工程的目录组织如下图(摘自这里),并且也请重点理解一下 cargo workspace 的概念。

cargo-project

开发 Substrate 应用必须掌握的 Rust 语言基础知识(没列出的常规使用可以比照你已经掌握的语言):

  • 宏的使用,但作为新手不要去纠结如何编写宏。
  • 属性(Attribute)的含义和使用。
  • 打印和 format! 的显示规范,尤其比如:{:?}
  • 可变和不可变变量绑定,同时理解 & 以及 & mut,比如:String 和 &str 的区别。
  • 典型集合类型:数组、Vector、Slice、Tuple。
  • 静态结构定义和动态行为的添加:Struct + Traits 组合,同时了解 Trait 的类型约束,以及 + 和 where 的使用。
  • 类型别名 type。
  • 两类特殊的 Enum 类型:Option 和 Result。
  • match 以及如何捕获 match 变量。
  • 函数、闭包、高阶函数
  • Rust 禁止隐式转换,实现类型之间转换的 From 和 Into Trait。
  • 错误处理,以及 ? 的使用。
  • 模块系统和 Crate。

真正让 Rust 大放异彩的实际上是跟内存安全相关的知识点:

  • 理解指针和引用,有 C / C++ 的程序员应该不陌生。
  • 理解 borrow 和 ownership。
  • 变量直接赋值和类型的关系:
    • 原始类型(标量类型、布尔、字符、数组、元组)或实现了 Copy Trait 的类型,赋值就是 copy,不涉及 ownership 转移
    • 否则,ownership 将转移。
  • 理解生命周期,熟悉 'static
  • 利用 Drop Trait 释放资源,类似 C++ 的析构函数。
  • 熟悉 Box、Rc、Cell、RefCell、Arc 等智能指针。

下图可以帮助大家理解 borrow 和 ownership,摘自 rust borrow 和 ownership 图解

borrow and ownership

以上内容就是 Substrate 开发必备的 Rust 知识。当然,在开发过程中,还少不了要了解标准库和其他工具包的使用,但这些跟使用其他语言开发系统差别不大,在此略过不提。

至于其他功能,比如 GUI、网络、微服务、Web 和并发编程,有了以上的基础也能很快上手。

在结束本节之前,推荐几个链接:

最后,一个特别推荐:24 days of Rust

开发 Substrate 必备的基本概念

前文说过,Substrate 可被视为区块链世界的 Spring Boot。既然如此,其文档就有必要至少通读一遍。话虽如此,但读文档并不是一件让人心情特别愉悦的事情,这里我列出主要纲要,希望能帮助各位快速建立全局概念,以便在读文档时可以更有针对性。

Substrate 的主要概念:

  • extrinsics,上链信息(注:虽然社区将其称为【交易】,但个人觉得称其为【上链信息】更合适),来自链外,保存于区块之中。链上自己产生的事件不属于此列,它们统一被称为:intrinsics,链内信息。extrinsics 分为三类:
    • inherents,无签名、直接插入,同时也不会在网络上传播或存在于 tx 队列。它们代表一类简单的“事实”,如时戳。
    • signed tx,带有发起交易的账户的签名,在链上保存交易时需支付费用。等同于以太坊交易。
    • unsigned tx,无签名,无 nonce,也无费用。使用时,需注意在交易队列中防止 spam。典型例子如:代表心跳的 tx。
  • tx pool,包含所有已被本地节点接收并验证的广播到网络之上的交易(签名和未签名)
    • tx pool 负责验证 tx 的有效性,其逻辑可配置。
    • 若有效性得到验证,tx pool 将 tx 分为两组:ready queue,可直接插入到新块;future queue,未来有效的 tx,如 nonce 太高的 tx,它要等到前面 tx 被插入之后方能 ready。
    • tx 的顺序和依赖有三个参数决定:requires(前提)、provides(输出)、priority(优先级)。
  • tx weight,用于管理验证区块花费的时间,其中初衷是限制存储 IO 和计算,但对于存储本身和内存大小的管理并不是其目标。
  • 账户抽象
    • 两类账户
    • stash key,大资金账户,私钥需要绝对安全,建议用冷钱包保存。
    • controller key,授权账户,代表 stash 账户做决策,只保留必要的资金(如交易费用),私钥需要安全保存。
    • session key,保存于验证者客户端,用来签名验证者操作,从不持有资金,也不是为资金用途服务。
  • offline worker,链下工作机,本质上相当于把预言机嵌入到了 substrate 节点中,集成更紧密,也越安全,使用上也越简单。其主要作用如下图,其运行环境也与 runtime 分离,互不干扰。

offchain worker

所谓开发 Substrate,其本质就是开发自己的 Runtime,它包含了区块链行为的业务逻辑,定义了用户可以派发的存储项和函数。每个 Runtime 包含了一组特定的 Pallet,每个 Pallet 定义了特定的功能业务逻辑以及所需的存储项。

Substrate 内置了一组预定义的 Pallet,这些 Pallet 及其支持库的全集被称为 FRAME。因此,FRAME 和 Runtime 的关系也就是全集和子集的关系,见下图。

FRAME and Runtime

当预定义的 Pallet 不足以满足业务需要时,开发者可以选择自行开发 Pallet。因此,整个开发工作也就成了:选择合适的 Pallet + 开发自己的 Pallet。

Pallet 的开发并没有想象中那么神秘,主要把握以下几点就行:

  • 理解 Substrate 的数据类型,主要分为核心类型和 FRAME 类型。
  • 理解 Pallet 的 5 个结构组合:依赖、配置、事件(通知外部)、存储(内部使用的存储项目)、声明(方便外部调用)。
  • 熟悉相应的宏,它们充当了 DSL 的作用。

最后,就是掌握 Runtime 的构建,得到最终可用的 Node。至于如何与 Node 交互,只需查看对应的 client (如 polkadot.js)说明就好了,并不复杂。

Node-Template 基本结构

为了简化开发,Substrate 提供了工程模板:Node-Template。它本身是一个 cargo workspace,由三部分组成:

  • node,定义整个节点的行为、cli、对外提供的服务,它是一个二进制工程,启动文件在此。
  • runtime,自定义 Runtime,指定包含的 pallet,包括你定义的 pallet。它是一个 lib 工程。
  • pallets,包含了 pallet 模板工程,一个 lib 工程。

整个 workspace 的级别依次是: node 包含 runtime 包含 pallet。并且,你可以创建多个 pallet,启用的话,则是将其在 runtime 中引用即可。

使用 pallets/template 开发 pallet 非常直观,基本上就是按照对应位置填写对应的逻辑就行了,关于具体做法,将在后文详述。

总结

希望本文能帮你建立对于 Substrate 开发的整体印象和直观感觉,虽说 Substrate 开发有一定的门槛,但毕竟不是火箭科学,熟悉 Rust 和 Substrate 的基本概念和结构之后,具体的开发跟其他应用系统的开发没有本质区别。

最后,在下一篇文章中,会展示一个实际的例子,同时演示如何与之交互,敬请期待,?。

原文链接

点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
胡键
胡键
CSM / 架构师 / 创业者,先后就职于中兴和 SAP,现专注于工业物联网、机器学习和区块链。同时,作为机器学习和区块链技术活动的组织者和分享者活跃于本地社区。