技术 | Substrate 2.0 搭建私有区块链网络
相信很多朋友已经在使用Substrate 2.0
构建自己的runtime
模块,但官方Substrate
开发者中心还没有2.0
版本的教程。
在本文中,我整理总结了如何使用Substrate 2.0
启动一个区块链网络,并使用你选择的验证者/管理者集合。
你需要:
-
一个
Linux
或Mac
操作系统下的命令行客户端 -
Git
你将学习到:
-
从源代码编译一个
Substrate
节点 -
为区块链网络中的验证人生成
ed25519
密钥对 -
创建和编辑
chainspec json
文件
编译所需工具
Substrate
是一个开源区块链开发框架,用来构建你自己的区块链,以及可以用来开发各种各样的去中心化应用程序。
目前Substrate
没有提供二进制安装包,因此必须从源代码中编译它,这可能是一个耗时的过程。
Substrate
仓库会经常更新,请确保参加此网络的每个节点都有同样版本的Substrate
以保证成功。在实践中,类似但不完全相同的版本通常可以正常工作,但是依靠这个通常会让人感到沮丧。
我们将使用master
分支的这个commit
(c63ee7ad8fef5aba30930e56b82e282e2f14d1d5
)来获取更多的一致性。
首次操作
首先,我们将通过git clone
下载Substrate
代码。目前还没有v2.0
的分支。
git clone https://github.com/paritytech/substrate
cd substrate
仓库中包含一个名为subkey
的工具,我们需要用它来生成和检查密钥对。让我们先编译它。--force
选项意味着我们将移除之前安装的版本,重新安装此版本。
cargo install --force --path subkey subkey
现在让我们编译我们将要运行的区块链节点。由于Substrate
是一个框架,使用它编写自定义的runtime
代码。之前写过文章详细涵盖了这方面的内容。
Substrate
仓库本身已经有两个随时可以运行的节点环境。
第一个在node
目录,它包含了许多功能,可以构建实际可运行的区块链。事实上,它看起来和Polkadot
类似,它也是基于Substrate
构建的。
第二个是在node-template
目录下的最小化runtime
代码。我们将在本文中使用节点模板node-template
,因为它比较简单,通常是编写自定义runtime
的起点。
# 切换到 node-template 目录
cd node-template
# 确保你的 rust toolchain 是最新的
./scripts/init.sh
# 编译本地节点版本
cargo build
下次更新
更新或改变Substrate
版本时,这个过程类似,但构建速度更快。
cd node-template
./scripts/init.sh
cargo build
提示:如果想要node-template
安装在可执行文件路径下,你可以在上一步使用cargo install
代替cargo build
。
Alice 和 Bob 启动区块链
在我们生成自己的密钥并启动一个真正特定的Substrate
网络之前,让我们了解下基础知识,首先使用一个预先定义的网络规范,称为local
,使用两个预先定义的密钥,称为Alice
和Bob
。
Alice 首先启动
Alice
应该从Substrate
仓库的根目录运行此命令。
# 如果你仍然在 node-template/ 目录
cd ..
# 启动节点
./target/debug/node-template \
--base-path /tmp/alice \
--chain=local \
--alice
我们了解一下这些命令选项的含义:
-
--base-path
指定一个目录,Substrate
用它来存储与此链有关的所有数据。如果目录不存在,将创建它。如果已经存在其它区块链的数据,启动将会报错。这种情况下,要么清除目录,要么选择不同的目录。 -
--chain=local
指定要使用的链规范。有几个预先准备的选项,包括local
,dev
等,但我们要指定自己的chainspec
文件。 -
--alice
指定我们正在使用预定义的Alice
密钥作为此节点的验证者。这里是和v1.0
的不同之处,v2.0
使用这个快捷方式替代v1.0
中--name Alice --validator
,同时Alice
的会话密钥会被添加到keystore
文件中。
chainspec
文件和keystore
文件,这两个我们将在稍后阶段说明。
当节点启动后,你应该看到类似下面的输出:
2019-09-04 07:25:11 Substrate Node
2019-09-04 07:25:11 version 2.0.0-d8589ad-x86_64-macos
2019-09-04 07:25:11 by Anonymous, 2017, 2018
2019-09-04 07:25:11 Chain specification: Local Testnet
2019-09-04 07:25:11 Node name: Alice
2019-09-04 07:25:11 Roles: AUTHORITY
2019-09-04 07:25:11 Initializing Genesis block/state (state: 0x2b2e…9b06, header-hash: 0x7d3d…f9e9)
2019-09-04 07:25:11 Loading GRANDPA authority set from genesis on what appears to be first startup.
2019-09-04 07:25:11 Loaded block-time = BabeConfiguration { slot_duration: 10000, c: (1, 4), median_required_blocks: 1000 } seconds from genesis on first-launch
2019-09-04 07:25:11 Creating empty BABE epoch changes on what appears to be first startup.
2019-09-04 07:25:11 Highest known block at #0
2019-09-04 07:25:11 Using default protocol ID "sup" because none is configured in the chain specs
2019-09-04 07:25:11 Local node identity is: QmbqmYrUEMcPFqnKjBAjZXgZBgpFs9Xsp5zhpbPXtENngE
2019-09-04 07:25:16 Idle (0 peers), best: #0 (0x7d3d…f9e9), finalized #0 (0x7d3d…f9e9), ⬇ 0 ⬆ 0
你可以通过节点在命令行中产生的输出了解很多信息。需要注意的几行:
-
Node name: Alice
显示指定的节点名称,这里是预定义的Alice
-
Local node identity is: QmbqmYrUEMcPFqnKjBAjZXgZBgpFs9Xsp5zhpbPXtENngE
节点ID,Bob
节点启动时需要依赖此ID
还有一些选项,大家可以通过./target/debug/node-template --help
去了解,比如:
-
--port 30333
指定节点将监听的p2p
端口。默认是30333
,如果Bob
的节点在同一物理机上运行,就需要明确指定一个不同的端口。 -
--ws-external
默认情况下,节点监听9944
端口上的RPC
连接,只有本地主机的连接会被接受,但你可以通过指定它改变此行为。你也可以通过指定--ws-port 12345
更改端口。 -
--rpc-cors
指定允许访问HTTP
和WS RPC
服务器的浏览器来源Origins
。它是以逗号分隔的来源列表。all
值将禁用来源验证。默认是允许localhost
,https://polkadot.js.org
和https://substrate-ui.parity.io
这些来源。此处有个坑! 在--dev
模式下运行时,默认设置为允许所有来源。
连接UI
有一个很好的图形用户界面,称为 Polkadot Js Apps UI,可以用它连接你的节点。之前写过文章详细涵盖了这方面的内容。
点击链接会跳转到该UI的官方页面,非常方便,但与你正在运行的Substrate
版本相比可能已经过时。在UI页面过期的情况下,你可以通过从github
获取代码在本地运行该应用。一般来说,其仓库中的指令将是你的最佳指南,但大致过程应该是这样的。
# 抓取代码
git clone https://github.com/polkadot-js/apps
cd apps
# 安装依赖
yarn
# 启动项目
yarn run start
你会注意到,在命令行和用户界面中,还没有产生任何块。一旦另一个验证者加入网络,将开始生成区块。
Bob 加入
现在,Alice
节点已经启动并运行,Bob
可以通过引导节点来加入网络。他的启动命令类似下面:
./target/debug/node-template \
--base-path /tmp/bob \
--chain=local \
--bob \
--bootnodes /ip4//tcp//p2p/
上面已经解释了大多数这些选项,但有几个要注意的地方:
-
如果这两个节点在同一物理机器上运行,
Bob
必须指定一个不同的路径--base-path
和端口--port
。 -
--bootnodes
选项,Bob
必须正确指定以下三项(这三项Alice
可以为他提供):-
Alice的IP地址,格式
192.168.1.1
-
Alice的端口,可能为
30333
-
Alice节点ID,从上面日志输出中复制 (QmbqmYrUEMcPFqnKjBAjZXgZBgpFs9Xsp5zhpbPXtENngE)
-
如果所有进展顺利,在几秒之后,节点应该相互连接,开始生成区块。你应该看到类似下面的内容:
Idle (1 peers), best: #1 (0x9f1b…9b57), finalized #1 (0x28be…45e5), ⬇ 1.7kiB/s ⬆ 1.4kiB/s
此行显示,Bob
有对等节点Alice
(1 peers)
,它们产生了一个区块(best: #1 (0x9f1b…9b57))
,并且区块已被最终确定/敲定(finalized #1 (0x28be…45e5))
。
这也是v2.0和v1.0的区别之处。v2.0
的节点模板中增加引用了Grandpa
模块来做最终一致性,而在v1.0
的网络中,只有创世区块会被最终敲定,v1.0
的节点模板中没有最终一致性模块(finality gadget)。
生成密钥
现在我们知道了基本原理和命令行选项,是时候生成我们自己的密钥而不是使用众所周知的Alice
和Bob
密钥。
每个想要加入这个区块链网络的人,都可以使用我们之前提到的subkey
工具,或Polkadot JS Apps UI
生成自己的密钥。在本文中,我们将使用RPC
调用。该小节是本文更有价值的一部分内容。
生成 key
对于大多数想要运行验证节点的用户,可以使用author_rotateKeys
这个RPC
调用。该RPC
调用将生成会话密钥session key
,并返回其公钥public key
。命令如下:
curl -H 'Content-Type: application/json' --data '{“jsonrpc”:“2.0”,“method”:“author_rotateKeys”,“id”:1}' localhost:9933
导入 keystore
如果会话密钥需要匹配固定种子seed
,则可以按类型单独设置它们。RPC
调用需要密钥种子和密钥类型。此处列出了Substrate
中默认支持的类型。命令如下:
curl -H 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"author_insertKey", "params":["KEY_TYPE", "SEED", "PUBLIC"],"id":1 }' localhost:9933
-
KEY_TYPE
- 需要用4个字符的类型标识符替换,比如:ed25
-
SEED
- 是密钥的种子seed
-
PUBLIC
- 给定密钥的公钥
启动你的私有区块链
上一次,我们使用--chain=local
这是一个预定义的chainspec
,它将Alice
和Bob
指定为验证人以及许多其他的默认值。本节将介绍如何创建自己的chainspec
。
创建 chainspec
我们不是从头开始完全编写chainpec
,而是对我们之前使用的那个进行一些修改。
首先,我们需要将chainspec
导出到json
文件。
./target/debug/node-template build-spec --chain=local > customSpec.json
我们刚创建的文件包含几个字段,人们可以通过探索它们来学习很多东西。目前,最长的字段是一个十六进制编码的数据,它是我们runtime
的wasm
的二进制。
我们感兴趣的部分,是像这样的验证人地址:
"consensus": {
"authorities": [
"5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu",
"5GoNkf6WdbxCFnPdAnYYQyCjAKPJgLNxXwPjwTh6DGg6gN3E",
],
"code":
}
我们需要做的就是将列出的验证人地址(当前为Alice
和Bob
)更改为我们在上一步中生成的地址。
注意:应该由一个人执行这些步骤,并共享生成的文件给其他验证人。因为从rust - > wasm
的构建不是“可重现的”,每个人都会得到一个略有不同的wasm blob
,如果每个参与者自己生成文件,这将破坏共识。
准备好chainspec
后,将其转换为“raw”chainspec
。 regular
和raw
之间的区别只是所有字段在"raw" chainspec
中编码为了十六进制。
./target/debug/node-template build-spec --chain customSpec.json --raw > customSpecRaw.json
最后与网络中的所有其他验证人共享customSpecRaw.json
。
启动链
你已完成所有必要的准备工作,现在准备好启动链。此过程非常类似于之前以Alice
和Bob
的身份启动链。
从干净的目录开始非常重要,如果你打算使用之前的目录,请删除该目录中的所有内容。
第一位参与者启动节点:
./target/debug/node-template \
--chain ./customSpecRaw.json \
--validator \
--name lester
以下是我们启动Alice
时的一些不同之处。
-
--validator
表示节点将参与出块而不是仅仅同步网络数据。 -
--name
给节点取个可读性高的名字。
后续验证人现在可以像Bob
之前一样加入网络,确保使用新的chainspec
和密钥。你可以使用网络中任意已有的节点引导,而不仅是之前的节点。
小结
恭喜你!你已启动了自己的区块链!
在本文中,你学会了编译节点模板,生成自己的公私钥对,创建一个自定义的链,使用这些密钥对,并根据自定义chainspec
和节点模板启动了一个私有区块链网络。