目前Substrate的文档十分缺乏,本文的介绍相当于是Substrate的一种文档。

本文首发于知乎专栏 金狗喵喵喵的区块链研习,版权属于 @金晓 @chainx团队(@岳利鹏)

如需转载,需取得同意并标明出处,并涵盖版权信息!

Substrate的项目结构

截至2019年2月初,Substrate的修改速度已经减缓,开始添加一些测试工具。可以看作1.0beta的Substrate走向稳定了。本文尝试以于master分支上的提交bfd040ef0e5272cdb0dc56106786861cdbe8a397进行项目结构的分析。

根级目录

  • ci github 运行ci的脚本
  • coreSubstrate Core目录,涵盖了上一篇文章描述的“链的系统基础部分”的功能,是该框架提供的核心功能
  • node Substrate项目框架中自带的一个使用实例,启动一条新链除Runtime部分之外可以直接把这里的代码拷贝过去,同时也是熟悉框架的案例,调试框架的入口点。
  • node-template 一个更精简的node,似乎用来测试,作用不大,参考node更好
  • scripts 一些项目构建脚本,一般情况下无需关心
  • srml Substrate默认提供的一些Runtime的模块,其中在启动自己的链时有一些Runtime模块是必须的,有一些模块可以不用。但是要注意模块之间是有依赖关系的,在是否采用Substrate提供的模块是必须深入考虑,这是一个比较重要的坑,要注意。ps:srmlSubstrate Runtime Module library 的缩写。构建自己的链时命名可以参考这个缩写。
  • subkey 生成公私钥的小工具
  • test-utils 测试工具集合
  • 在根目录下最重要的目录就是coresrml这两个目录,分别代表了Substrate框架提供的“区块链基础设置”与“Substrate Runtime”两个模块。node目录下的是运行框架的示例,也是框架的入口。

注意在根目录下的Cargo.toml中:

[[bin]]
name = "substrate"  # node 将会编译成 substrate 可以执行文件,位于 target/(debug|release)/目录下
path = "node/src/main.rs"  # bin 指向的是node目录

[package]
name = "substrate"
version = "0.10.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
# ...

所以在Substrate目录下直接执行cargo run 运行起来的程序是node节点,调试跟踪的时候注意这一点。

接下来详细介绍 coresrml目录

core目录

core目录挑一些重要的进行介绍。注意如果在熟悉依赖的情况下,实际上可以在自己的项目中对引用不被依赖束缚的的模块进行扩充。

  • 共识相关组件
  • basic-authorship 提供进入共识模块的提议者Proposer的构建,可以理解为这个节点的出块者,将会作为参数传入共识组件中。
  • consensus Substrate提出的新共识的核心aura,事实上这个共识模块能够进行扩充,其首先定义了一些共识阶段所需要的基础接口,然后使用aura算法实现了这里的共识接口。目前这部分比较耦合,若想采用自己设计的共识可能需要考虑直接fork Substrate项目在这个目录下进行更改。
  • finality-grandpaaura配对的区块一致性认证,与aura联系紧密。若不采用aura算法则这部分可以舍弃。
  • cli 命令行输入的解析。若需要添加自己的命令参考node里的cli进行构架,不需要更改这部分。
  • client client 是节点的存储与当前运行节点区块与状态。可以理解为是一个节点启动后代表当前节点的实例。client实例将会传入到交易池,网络连接等组件中,整个程序运行周期中只有一个client。(ps:client的这个抽象集合与以太坊的命名与功能类似)
  • executor执行器,包含了wasm的执行构建功能。
  • inherents 内部交易的一些工具定义,暂时不在本文中详细解释
  • keystorekeyring 前者是提供公私钥工具,后者提供一些默认的私钥
  • networknetwork-libp2p 底层网络设置,运用了著名的libp2p。若不涉及底层网络管理的事情无需关心这部分
  • primitives 原语定义。substrate 很多定义基础数据结构的命名都以 primitives 定义。这里需要注意这个目录定义的是substrate-primitives 后续还会出现 runtime-primitives。这里的primitives代表的是整个substrate的原语定义。
  • rpcrpc-servers rpcwebsocket 的功能,另外指出,substrate提供的rpc只含的很原始的rpc接口,无法对原始数据做一定包装。今后的文章会剖析如何利用rpc完成自己的功能。
  • service 链一些定义的数据结构 与 各项服务启动的入口。所有的服务线程(交易池,p2p,共识…)都是在这个模块中启动。
  • transaction-pool 交易池。
  • trie modified merkle patricia trie,MPT,“世界状态”。substrate在这一块沿用了以太坊的设计,不过在substrate里面只有状态树,即使是合约的功能也不专门存在合约的存储树。
  • state-dbstate-machine 前者包含状态数据库,且有对状态进行裁剪的功能,后者是“世界状态”的变化修改,与以太坊的模式类似。
  • Runtime相关的定义。在 Substrate的发展中一开始命名为Runtime,后续命名为Substrate Runtime,故缩写为 sr,在代码中沿用之前的写法会出现 把 sr前缀 重命名为 runtime的情况。
  • sr-stdsr-primitivessr-io 定义了 兼容 std/wasm 的std 库 ,在 runtime中使用的原语,能够允许std/wasm范围相同存储的io库。这里的sr-primitives 就是 runtime-primitivessubstrate-primitivesruntime-primitives 的子集。
  • sr-sandbox 运用于 wasm 执行器的沙盒
  • sr-api-macrossr-version 前者是提供Runtime的一些宏,后者是wasm与native执行时的版本判定的一些相关组件

srml 目录

srml是Substrate默认提供的 runtime module。部分模块不可缺少,其他的可以根据自己需求使用。

这里说不可缺少也并不是绝对的,如果自己的需求超出了当前这套以k-v为基石的模型,那么构建一套Runtime的基础设施也是可以的,如果没有这个需求和能力的话那就使用Substrate提供的Runtime的这些工具就好了。

本章同样只挑选重要的进行讲解。

首先列举核心的module

  • systemsupportmetadata 。这三个模块不可缺少的原因是它们负责了一些核心组件,并且部分被隐藏在Runtime module 定义一些结构的宏里。如果使用Substrate Runtime提供的工具,那么这些模块不可缺少。system用于和“区块”,“交易”相关,例如有一些Event定义,当前区块的hash,prev hash等等。support重点在于提供Runtime Module数据结构的宏的定义,提供了decl_storage!这个最关键的宏,这个模块很关键也很复杂,后续文章会进行讲解。metadata是用于导出Runtime Module的一些描述定义。
  • timestamp 提供区块时间戳,runtime时间的模块。由于Substrate设计为Header里面不包含时间戳,而是使用一条交易包含时间,所以这个模块一般需要引入。
  • balanceassets 前者用于定义和资金相关的模块,后者定义类似token的相关模块。由于balance在很多地方都存在依赖关系,建议引入。
  • consensus,auragrandpa 共识相关模块,可以理解为可以反馈一些底层共识的信息与设置一些参数,提供内部交易等,不是共识算法的逻辑。
  • sessionstaking 定义区块的session间隔与权益相关的计算
  • councildemocracytreasury民主提议,财政等相关
  • sudo sudo 权限,可以指定一个账户去执行 root 交易,后续文章会做介绍。
  • indices 数字账户系统,相当于给公钥分配一个数字。
  • contract 合约模块。这个模块与以太坊的智能合约功能近似。
  • example 顾名思义,提供 Runtime Module 的编写示例。

总结srml

如果考虑采用Substrate 提供的Runtime的工具集及它的模型,则需要引入一些必须的模块。若不使用,则需要构建许多Runtime Module 的基础工具集合且需要对整个框架有比较深入了解。而其他的模块可以根据自己链的需求进行选择。对于Runtime Module 的编写后续文章会进行介绍。

node目录

node是Substrate的一个示例。这里要首先指出,对于一条链而言,首先需要编译出Runtime的wasm代码,然后需要把wasm的执行文件一同编译进入节点,成为genesis中的数据。

  • cli 针对 node的一些命令行,及genesis的定义
  • executor 执行器的定义,注意这里需要读取wasm的执行文件并引入
  • primitives node 的原语,进行了许多基础类型的定义。
  • runtime 一条链的Runtime,在这个Runtime中引入了这条链需要的Runtime Module。注意这个模块下有srcwasm两个目录,其中Runtime的代码由src编译而来,而wasm使用src的代码编译出了wasm的执行文件。编译wasm需要切换到 wasm的路径下,并执行这个路径下的build.sh脚本。编译后会在wasm/target/wasm32-unknown-unknown/release 目录下发现一个node_runtime.compact.wasm文件,这个文件就是Runtime的wasm执行文件。由于不同的机子编译出的wasm会在符号上有一些不一致,所以注意这个文件需要进入git的管理 ,以防止由于需要引入wasm到genesis中导致生成的genesis不一致。

以上为本文内容,具体介绍了Substrate的项目结构。

在对项目结构有一定了解后,就可以开始进行了解Substrate了。