文章内容持续更新中...
本文目标
掌握如何创建我们自己的区块链网络。
操作步骤
- 先看看效果——启动Alice 和 Bob两个节点的区块链网络
- 依葫芦画瓢——定制并启动我们自己的区块链网络
前提条件
本文的操作是基于substrate-node-template v2.0.0和前端界面substrate-front-end-template构建的环境,如果我们还没有构建好,请参考之前的文章【Substrate入门】搭建第一条substrate链
开始吧!
一、启动Alice和Bob两个节点的区块链网络
在官方的学习教程里,为了我们学习的便利性,特意做了些设计,比如预置了Alice、Bob、Dave...这些虚拟的人物,并为每个人物预先分配了账号(即公私钥),这里所说的启动Alice和Bob两个节点的区块链网络,是指用Alice和Bob的私钥分别启动两个区块链节点,并组成一个区块链网络,Alice和Bob都作为验证人参与出块。通过官方内置的数据,快速创建一个样板网络,来看看效果。
启动Alice节点
废话少说,先把创世节点拉起来:
cd substrate-node-template //以我们clone时的目录所在位置为准
# Start Alice's node
./target/release/node-template
--base-path /tmp/alice
--chain local
--alice
--port 30333
--ws-port 9945
--rpc-port 9933
--node-key 0000000000000000000000000000000000000000000000000000000000000001
--telemetry-url 'wss://telemetry.polkadot.io/submit/ 0'
--validator
如果我们之前有启动过Alice这个测试节点,建议先把老数据清理一下:
# Purge any chain data from previous runs
# You will be prompted to type `y`
./target/release/node-template purge-chain --base-path /tmp/alice --chain local
purge-chain
参数的作用:清理老的区块数据。
当Alice的节点启动起来后,我们能看到如下内容:
Dec 31 10:13:09.212 INFO Substrate Node
Dec 31 10:13:09.212 INFO ✌️ version 2.0.0-655bfdc-x86_64-linux-gnu //substrate版本号
Dec 31 10:13:09.212 INFO ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2020
Dec 31 10:13:09.212 INFO Chain specification: Local Testnet //当前区块链节点所在网络名称
Dec 31 10:13:09.212 INFO Node name: Alice //节点名称
Dec 31 10:13:09.212 INFO Role: AUTHORITY
Dec 31 10:13:09.212 INFO Database: RocksDb at /tmp/alice/chains/local_testnet/db //数据库类型与当前节点数据保存位置
Dec 31 10:13:09.212 INFO ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1)
Dec 31 10:13:10.095 INFO Initializing Genesis block/state (state: 0x2751…2e34, header-hash: 0x67cf…dc66) //创世区块的哈希值
Dec 31 10:13:10.123 INFO Loading GRANDPA authority set from genesis on what appears to be first startup.
Dec 31 10:13:10.208 INFO ⏱ Loaded block-time = 6000 milliseconds from genesis on first-launch
Dec 31 10:13:10.208 WARN Using default protocol ID "sup" because none is configured in the chain specs
Dec 31 10:13:10.221 INFO Local node identity is: 12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp //Alice节点ID (legacy representation: 12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp)
Dec 31 10:13:10.405 INFO Highest known block at #0
Dec 31 10:13:10.406 INFO 〽️ Prometheus server started at 127.0.0.1:9615 //普罗米修斯 节点监控端口
Dec 31 10:13:10.446 INFO Listening for new connections on 127.0.0.1:9945. //websocket监听端口
Dec 31 10:13:15.449 INFO Idle (0 peers), best: #0 (0x67cf…dc66), finalized #0 (0x67cf…dc66), ⬇ 0 ⬆ 0
Dec 31 10:13:20.449 INFO Idle (0 peers), best: #0 (0x67cf…dc66), finalized #0 (0x67cf…dc66), ⬇ 0 ⬆ 0
Initializing Genesis block/state (state: 0x2751…2e34, header-hash: 0x67cf…dc66)告知开发者节点正在使用哪个创世块。 当我们启动下一个节点时,注意验证这些值是否相等,确保是在同一个区块链网络。
Local node identity is: 12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp...显示Alice的节点ID, 启动Bob节点时需要它。 这个值是由--node-key决定的,该值之前用来启动Alice的节点。
针对以上启动创世节点时的命令参数,这里展开学习一下,对后续创建自己的节点有帮助:
标签名 | 描述 |
---|---|
--base-path | 指定一个目录,Substrate 将用它来存储与此链有关的所有数据。 如果未指定目录,将使用默认路径。 如果目录不存在,将创建它。 若该路径下已经存在其它区块链的数据,系统将会报错。 在该情况下,请清除此目录,或选择不同的目录。 |
--chain local | 指定要使用的链的规范。 这里有一些预设的选项,包括 local development 和 staging ,但通常由开发者指定自己的chain spec文件。 我们将在后续阶段指定自己的文件。 |
--alice | --name Alice --validator的快捷写法,将预定义的Alice密钥(用于产生区块和达到最终确定性) 存入节点的密钥库。 一般来说,开发者应该自己生成密钥,并通过RPC调用插入。 我们将在后续阶段指定自己的密钥。 这个 flag 也可将 Alice 作为验证节点。 |
--port 30333 | 指定用于监听 p2p 流量的节点端口。 30333 是默认端口,若无需更改,可以忽略该 flag。 如果Bob的节点也运行在同一个物理机上,我们需要明确地为其指定一个不同的端口。 |
--ws-port 9945 | 指定节点用于监听 WebSocket 的端口。 默认端口为 9944 。 该示例使用了一个自定义的web socket端口(9945). |
-rpc-port 9933 | 指定节点监听RPC的端口。 9933 是默认值,因此该参数也可忽略。 |
--node-key <key> | 用于libp2p联网的Ed25519密钥。 该值被解析为一个十六进制编码的Ed25519 32字节密钥,即64个十六进制字符。 警告:作为命令行参数提供的隐私信息很容易被暴露。 该选项的使用应仅限于开发和测试。 |
--telemetry-url | 告诉节点向某个特定服务器发送监测数据。 我们在此选择的是由Parity托管,任何人都可以使用的服务器。 也可以选择自有的服务器(超出该本文描述的范围)或完全省略这个 flag。 |
--validator | 意味着我们也要参与区块的生产和达到最终确定性,而不仅仅是同步区块链网络。 |
更多帮助信息,可以通过./target/release/node-template --help
查看 。
连接UI
从UI界面上来看看Alice单节点网络的状况,通过浏览器(chorme)访问Polkadot-JS Apps(在后续文章中简称Apps),如下图所示操作:
先填写本地监听端口(即上述命令中的--ws-port 9945
),然后点击“转换”,切换到本地测试网络。
在上图中,我们可以了解到,当前网络中只有Alice一个节点,虽然产生了创世区块,但并没有正常出块,等待别的节点加入后,再开始生产区块。
启动Bob节点
接下来将Bob加入到Alice创建的区块链网络当中, 命令与启动Alice相似,如下:
./target/release/node-template
--base-path /tmp/bob
--chain local
--bob
--port 30334
--ws-port 9946
--rpc-port 9934
--telemetry-url 'wss://telemetry.polkadot.io/submit/ 0'
--validator
--bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
由于我们是在本地同一台物理机上运行多个节点,所以启动Bob节点时,需要指定不同的数据保存路径和端口号,如--base-path
, --port
, --ws-port
, 和 --rpc-port
的值。
值得一提的是:Bob添加了--bootnodes
标志,并指定了一个单一的引导节点,即Alice节点。 --bootnodes
包含以下三项信息且必须填写正确:
- Alice的IP地址:127.0.0.1
- Alice的p2p端口:30333
- 回到Alice节点启动窗口,在启动输出信息中寻找她的Peer ID,即这一行内容:
Dec 31 10:13:10.221 INFO Local node identity is: 12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp...
如果顺利,节点之间很快就会匹配同步,并开始生产和确认区块。 在启动Alice节点的窗口中,我们看到如下行的输出:
Dec 31 10:19:40.551 INFO Idle (0 peers), best: #0 (0x67cf…dc66), finalized #0 (0x67cf…dc66), ⬇ 0 ⬆ 0
Dec 31 10:19:45.552 INFO Idle (1 peers), best: #0 (0x67cf…dc66), finalized #0 (0x67cf…dc66), ⬇ 0.8kiB/s ⬆ 0.8kiB/s
Dec 31 10:19:45.669 INFO Discovered new external address for our node: /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
Dec 31 10:19:45.712 INFO Discovered new external address for our node: /ip4/192.168.112.129/tcp/30333/p2p/12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp
Dec 31 10:19:48.022 INFO Starting consensus session on top of parent 0x67cfc2c0511495e9e6e37d2dc3fc80ef64e7655f88d89a4a1c1984ae3501dc66
Dec 31 10:19:48.150 INFO Prepared block for proposing at 1 [hash: 0x4b0b94d2fbc5e23bb09fac8ed5e69f4ea30f6d8478ae31b24bf046c5b59103cd; parent_hash: 0x67cf…dc66; extrinsics (1): [0xe2b9…d17c]]
Dec 31 10:19:48.159 INFO Pre-sealed block for proposal at 1. Hash now 0xe2093722a2dd957c93e9e112c541560f903e569bade04b31cd9ec03f75378e39, previously 0x4b0b94d2fbc5e23bb09fac8ed5e69f4ea30f6d8478ae31b24bf046c5b59103cd.
Dec 31 10:19:48.160 INFO ✨ Imported #1 (0xe209…8e39)
Dec 31 10:19:50.552 INFO Idle (1 peers), best: #1 (0xe209…8e39), finalized #0 (0x67cf…dc66), ⬇ 1.0kiB/s ⬆ 1.0kiB/s
Dec 31 10:19:54.037 INFO ✨ Imported #2 (0xcd1c…2eb2)
Dec 31 10:19:55.553 INFO Idle (1 peers), best: #2 (0xcd1c…2eb2), finalized #0 (0x67cf…dc66), ⬇ 0.7kiB/s ⬆ 0.6kiB/s
Dec 31 10:20:00.007 INFO Starting consensus session on top of parent 0xcd1c76cbfc68aa36610a7be76d8619581866b06aad90135b1befcf91da952eb2
Dec 31 10:20:00.014 INFO Prepared block for proposing at 3 [hash: 0x3db32650e4de15c7cd3464f52f0848505f0f1f8c596b29841ae581fd09e25de1; parent_hash: 0xcd1c…2eb2; extrinsics (1): [0x1fab…ddf1]]
Dec 31 10:20:00.020 INFO Pre-sealed block for proposal at 3. Hash now 0x2abd02122de9ed1d69f26d49413fb7919be2ca5f5b5a98f3126a4eb2ee7e851f, previously 0x3db32650e4de15c7cd3464f52f0848505f0f1f8c596b29841ae581fd09e25de1.
Dec 31 10:20:00.023 INFO ✨ Imported #3 (0x2abd…851f)
Dec 31 10:20:00.554 INFO Idle (1 peers), best: #3 (0x2abd…851f), finalized #0 (0x67cf…dc66), ⬇ 0.7kiB/s ⬆ 0.7kiB/s
Dec 31 10:20:05.555 INFO Idle (1 peers), best: #3 (0x2abd…851f), finalized #1 (0xe209…8e39), ⬇ 1.0kiB/s ⬆ 1.0kiB/s
Dec 31 10:20:06.073 INFO ✨ Imported #4 (0x9999…9ead)
Dec 31 10:20:10.556 INFO Idle (1 peers), best: #4 (0x9999…9ead), finalized #2 (0xcd1c…2eb2), ⬇ 1.0kiB/s ⬆ 0.9kiB/s
Dec 31 10:20:12.012 INFO Starting consensus session on top of parent 0x999952111675724c17472c1abce528f2e5b67b7a27a5c29ac26d9993407a9ead
Dec 31 10:20:12.030 INFO Prepared block for proposing at 5 [hash: 0xb0f8c3b7c298dc923ac53902d8d2c047ffece5cdd737389229377192f1e47a23; parent_hash: 0x9999…9ead; extrinsics (1): [0xfa35…2f8c]]
Dec 31 10:20:12.048 INFO Pre-sealed block for proposal at 5. Hash now 0x64c2fa010acea784e56870fdeae0ef326b66646d7c92d7c4f6c9a853075988ab, previously 0xb0f8c3b7c298dc923ac53902d8d2c047ffece5cdd737389229377192f1e47a23.
在启动Bob节点的窗口中,也可看到类似的内容:
Dec 31 10:19:44.180 INFO Substrate Node
Dec 31 10:19:44.180 INFO ✌️ version 2.0.0-655bfdc-x86_64-linux-gnu
Dec 31 10:19:44.180 INFO ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2020
Dec 31 10:19:44.180 INFO Chain specification: Local Testnet
Dec 31 10:19:44.180 INFO Node name: Bob
Dec 31 10:19:44.180 INFO Role: AUTHORITY
Dec 31 10:19:44.198 INFO Database: RocksDb at /tmp/bob/chains/local_testnet/db
Dec 31 10:19:44.198 INFO ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1)
Dec 31 10:19:44.673 INFO Initializing Genesis block/state (state: 0x2751…2e34, header-hash: 0x67cf…dc66)
Dec 31 10:19:44.699 INFO Loading GRANDPA authority set from genesis on what appears to be first startup.
Dec 31 10:19:44.859 INFO ⏱ Loaded block-time = 6000 milliseconds from genesis on first-launch
Dec 31 10:19:44.859 WARN Using default protocol ID "sup" because none is configured in the chain specs
Dec 31 10:19:44.882 INFO Local node identity is: 12D3KooWGH5WggsCgqMc2Ko6edTrdS48iaofkU39s8M5bZ6QzSjL (legacy representation: 12D3KooWGH5WggsCgqMc2Ko6edTrdS48iaofkU39s8M5bZ6QzSjL)
Dec 31 10:19:45.126 INFO Highest known block at #0
Dec 31 10:19:45.129 INFO Listening for new connections on 127.0.0.1:9946.
Dec 31 10:19:45.648 INFO Discovered new external address for our node: /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWGH5WggsCgqMc2Ko6edTrdS48iaofkU39s8M5bZ6QzSjL
Dec 31 10:19:45.713 INFO Discovered new external address for our node: /ip4/192.168.112.129/tcp/30334/p2p/12D3KooWGH5WggsCgqMc2Ko6edTrdS48iaofkU39s8M5bZ6QzSjL
Dec 31 10:19:48.189 INFO ✨ Imported #1 (0xe209…8e39)
Dec 31 10:19:50.131 INFO Idle (1 peers), best: #1 (0xe209…8e39), finalized #0 (0x67cf…dc66), ⬇ 1.7kiB/s ⬆ 1.7kiB/s
Dec 31 10:19:54.007 INFO Starting consensus session on top of parent 0xe2093722a2dd957c93e9e112c541560f903e569bade04b31cd9ec03f75378e39
Dec 31 10:19:54.014 INFO Prepared block for proposing at 2 [hash: 0x670067dcd5af9a627db98ab749da641fb8b42c3e2a32fb60766f3e73d7c91df0; parent_hash: 0xe209…8e39; extrinsics (1): [0xf843…8809]]
Dec 31 10:19:54.022 INFO Pre-sealed block for proposal at 2. Hash now 0xcd1c76cbfc68aa36610a7be76d8619581866b06aad90135b1befcf91da952eb2, previously 0x670067dcd5af9a627db98ab749da641fb8b42c3e2a32fb60766f3e73d7c91df0.
Dec 31 10:19:54.023 INFO ✨ Imported #2 (0xcd1c…2eb2)
Dec 31 10:19:55.132 INFO Idle (1 peers), best: #2 (0xcd1c…2eb2), finalized #0 (0x67cf…dc66), ⬇ 0.6kiB/s ⬆ 0.7kiB/s
Dec 31 10:20:00.069 INFO ✨ Imported #3 (0x2abd…851f)
Dec 31 10:20:00.133 INFO Idle (1 peers), best: #3 (0x2abd…851f), finalized #0 (0x67cf…dc66), ⬇ 0.7kiB/s ⬆ 0.7kiB/s
Dec 31 10:20:05.134 INFO Idle (1 peers), best: #3 (0x2abd…851f), finalized #1 (0xe209…8e39), ⬇ 1.0kiB/s ⬆ 0.9kiB/s
Dec 31 10:20:06.006 INFO Starting consensus session on top of parent 0x2abd02122de9ed1d69f26d49413fb7919be2ca5f5b5a98f3126a4eb2ee7e851f
Dec 31 10:20:06.013 INFO Prepared block for proposing at 4 [hash: 0x462ae509e11577a31fa92fc5cb974925e42da123b1ce8c63b3d4e2b666cd4599; parent_hash: 0x2abd…851f; extrinsics (1): [0x0608…9a0c]]
Dec 31 10:20:06.020 INFO Pre-sealed block for proposal at 4. Hash now 0x999952111675724c17472c1abce528f2e5b67b7a27a5c29ac26d9993407a9ead, previously 0x462ae509e11577a31fa92fc5cb974925e42da123b1ce8c63b3d4e2b666cd4599.
通过以上演示,我们快速地搭建了一个样板网络,了解了substrate区块链网络的基本原理和命令行选项,接下来轮到创建我们自己的区块链网络了,这里先将Alice和Bob节点都停掉(在节点窗口中ctrl+c即可)。
接下来依葫芦画瓢,定制并启动我们自己的区块链网络。
二、定制并启动我们自己的区块链网络
在本节中,主要需要修改两块内容:
- 将Alice和Bob的密钥替换成我们自己的
- 创建自定义的创世区块配置文件(chain spec文件)
规划网络
节点名称 | 数据保存路径 | p2p端口 | ws端口 | rpc端口 |
---|---|---|---|---|
MyNode01 | /tmp/node01 | 30333 | 9945 | 9933 |
MyNode02 | /tmp/node02 | 30334 | 9946 | 9934 |
实际上可以是任意节点个数,这里我们以两个为例,取代Alice和Bob。
生成密钥
先来生成自己的密钥,官方提供了两种方式:
- 通过subkey工具生成
- 通过Polkadot-JS Apps生成
分别来介绍一下。
1、通过subkey工具生成
我们需要先安装subkey:
cargo install --force subkey --git https://github.com/paritytech/substrate --version 2.0.0
编译成功后,就可以使用subkey来生成密钥了。想了解更多,可查看Substrate 帮助。
一个节点需要有两种不同类型的密钥:sr25519
和ed25519
,sr25519
密钥用于 Aura 生产区块,ed25519
密钥用于 GRANDPA 达成区块的最终确定性。
换句话理解, 每个节点都需要添加两种类型的密钥:Aura 和 GRANDPA 密钥。 区块生成需要 Aura 密钥; 而区块达到最终性则需要 GRANDPA 密钥。
我们先来为MyNode01
节点生成sr25519
类型的密钥(本文是测试,就直接把密钥公开了):
subkey generate --scheme sr25519
//如下:
Secret phrase `engine cube pioneer firm thought exhibit carbon dumb exotic pulse noodle ceiling` is account:
Secret seed: 0x88eb6714e47c8ce4ef6017e92dcb4b9ae268de2ef8161127e7740dc3a53d5d98
Public key (hex): 0x00301f5ae5f5e5f5067fb10728e963680704c96ee5472e30e370faf1e49d843e
Account ID: 0x00301f5ae5f5e5f5067fb10728e963680704c96ee5472e30e370faf1e49d843e
SS58 Address: 5C4x9oLkgS6fQfgnZ4dHAQ2riLFa5xN3TCXuzo9GZ6DeXM7B
再通过上面的助记词engine cube pioneer firm thought exhibit carbon dumb exotic pulse noodle ceiling
查看ed25519
密钥:
subkey inspect --scheme ed25519 "engine cube pioneer firm thought exhibit carbon dumb exotic pulse noodle ceiling"
//如下:
Secret phrase `engine cube pioneer firm thought exhibit carbon dumb exotic pulse noodle ceiling` is account:
Secret seed: 0x88eb6714e47c8ce4ef6017e92dcb4b9ae268de2ef8161127e7740dc3a53d5d98
Public key (hex): 0x063f488785f1f63ecaf7dd74cce9b73a91904f3349ecfebb1e1dc0abf8f8b5dd
Account ID: 0x063f488785f1f63ecaf7dd74cce9b73a91904f3349ecfebb1e1dc0abf8f8b5dd
SS58 Address: 5CCtwgKn6b2MTuWWrwFcFEa5LpbcNtdfqhXXvmQzo6B4UCZM
将上述信息安全地记录下来,一个节点的密钥就生成完毕了,重复上面的操作为MyNode02
生成密钥:
subkey generate --scheme sr25519
Secret phrase `blind plug install hair scene profit drill scorpion clock spoon fence aware` is account:
Secret seed: 0xc5806750ba7725af85ef9284881c41c81db1000a8d2c44e803ae3128512ba1ae
Public key (hex): 0x66b8a5ed292cdc8c71d7c13818b7e25c3893ce12b8e85ac5ab426a258579d510
Account ID: 0x66b8a5ed292cdc8c71d7c13818b7e25c3893ce12b8e85ac5ab426a258579d510
SS58 Address: 5EPPbNJxMD3hAVr7zNmtyVfCKPEGc3iuhiUrj9M48yjULtHZ
subkey inspect --scheme ed25519 "blind plug install hair scene profit drill scorpion clock spoon fence aware"
Secret phrase `blind plug install hair scene profit drill scorpion clock spoon fence aware` is account:
Secret seed: 0xc5806750ba7725af85ef9284881c41c81db1000a8d2c44e803ae3128512ba1ae
Public key (hex): 0xe8993b725606b8c1631b900ec25f10b6be8db74dece1a051fd3265cbdd1dee77
Account ID: 0xe8993b725606b8c1631b900ec25f10b6be8db74dece1a051fd3265cbdd1dee77
SS58 Address: 5HKgV8n5uU3PVzCqYSNLnaXsHQHnV4XttBvSpfzedc2yEcr7
2、通过Polkadot-JS Apps生成密钥
为了安全,使用Polkadot-JS Apps生成密钥时,建议断网。
这里简单介绍一下,在“ Accounts”选项栏上,点击"Add account"。如下图所示操作:
注意妥善保管助记词,为了安全,不建议将此种方法生成的密钥用于生产环境。
创建自定义的创世区块配置文件
这个文件官方称之为Chain Spec文件,个人理解就是区块链的创世区块配置文件。这个文件不需要我们全新编写,只需要从现有项目中导出来做修改即可。
通过如下命令,将 chain spec 导出到一个名为 customSpec.json
的文件中:
cd substrate-node-template
./target/release/node-template build-spec --disable-default-bootnode --chain local > customSpec.json
Dec 30 16:41:56.554 INFO Building chain spec
在IDE中打开这个文件,我们可以找到如下部分的内容进行替换(参见注释内容):
{
//-- snip --
"genesis": {
"runtime": {
"frameSystem": {
"changesTrieConfig": null
//-- snip --
"code":"..."
},
"palletAura": {
"authorities": [
"5C4x9oLkgS6fQfgnZ4dHAQ2riLFa5xN3TCXuzo9GZ6DeXM7B", <=== 把这里替换成MyNode01的sr25519类型的SS58 Address
"5EPPbNJxMD3hAVr7zNmtyVfCKPEGc3iuhiUrj9M48yjULtHZ" <=== 把这里替换成MyNode02的sr25519类型的SS58 Address
]
},
"palletGrandpa": {
"authorities": [
[
"5CCtwgKn6b2MTuWWrwFcFEa5LpbcNtdfqhXXvmQzo6B4UCZM", <=== 把这里替换成MyNode01的ed25519类型的SS58 Address
1 <=== 作为验证节点的权重值,了解下
],
[
"5HKgV8n5uU3PVzCqYSNLnaXsHQHnV4XttBvSpfzedc2yEcr7", <=== 把这里替换成MyNode02的ed25519类型的SS58 Address
1 <=== 作为验证节点的权重值,了解下
]
]
},
//-- snip --
}
}
}
以上内容是已经替换好的效果。"palletAura" 字段显示,是用于创建区块的 Aura 权限;"palletGrandpa" 字段显示,用于最终确定区块的 GRANDPA 权限。另外,我们还可以看到code
字段里有很多16进制数据, 就是 runtime 的 Wasm 二进制文件内容,它是之前运行 cargo build --release
命令时构建的。
将修改好的 customSpec.json
文件保存,我们使用命令将其转换为 "原生"的chain spec文件:
./target/release/node-template build-spec --chain=customSpec.json --raw --disable-default-bootnode > customSpecRaw.json
最后,将 customSpecRaw.json
与网络中的所有其他验证节点共享。
chain spec 应该由一人单独创建,并将生成的
customSpecRaw.json
文件共享给其他要加入网络的验证节点。因为 Rust -> Wasm 的优化构建并不 "可重现 ",所以每个人都会得到一个略有不同的 Wasm 二进制代码块,如果每个参与者都自己生成文件,将无法达成共识。
启动创世节点MyNode01
启动MyNode01
节点 :
./target/release/node-template
--base-path /tmp/node01
--chain ./customSpecRaw.json
--port 30333
--ws-port 9945
--rpc-port 9933
--telemetry-url 'wss://telemetry.polkadot.io/submit/ 0'
--validator
--rpc-methods Unsafe
--name MyNode01
命令和参数与启动Alice节点是类似的,但有不同之处,如下:
--alice
我们省略了该 flag,但很快我们就会通过 RPC 将自己的密钥加入密钥库中。--chain
该 flag 选项已更改,以使用我们自定义的 chain spec。--name
添加了该 flag,让我们可以在 telemetry 界面给该节点命名。--rpc-methods Unsafe
加了这个可选的 flag。 顾名思义,在生产环境中使用该 flag 并不安全,生产环境该怎么使用等待我们探索。
在MyNode01
节点窗口中我们应该可以看到如下内容:
Dec 31 18:12:37.491 INFO Substrate Node
Dec 31 18:12:37.517 INFO ✌️ version 2.0.0-655bfdc-x86_64-linux-gnu
Dec 31 18:12:37.517 INFO ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2020
Dec 31 18:12:37.517 INFO Chain specification: Local Testnet
Dec 31 18:12:37.517 INFO Node name: MyNode01
Dec 31 18:12:37.517 INFO Role: AUTHORITY
Dec 31 18:12:37.517 INFO Database: RocksDb at /tmp/node01/chains/local_testnet/db
Dec 31 18:12:37.517 INFO ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1)
Dec 31 18:12:38.711 INFO Initializing Genesis block/state (state: 0x052a…8812, header-hash: 0x190a…e2d0)
Dec 31 18:12:38.776 INFO Loading GRANDPA authority set from genesis on what appears to be first startup.
Dec 31 18:12:38.986 INFO ⏱ Loaded block-time = 6000 milliseconds from genesis on first-launch
Dec 31 18:12:39.014 WARN Using default protocol ID "sup" because none is configured in the chain specs
Dec 31 18:12:39.075 INFO Local node identity is: 12D3KooWN967iQjeSWxxPuQTtmmM6woxRyJzPrNSxyHWhg9Y6jC1 (legacy representation: 12D3KooWN967iQjeSWxxPuQTtmmM6woxRyJzPrNSxyHWhg9Y6jC1)
Dec 31 18:12:39.413 INFO Highest known block at #0
Dec 31 18:12:39.414 INFO 〽️ Prometheus server started at 127.0.0.1:9615
Dec 31 18:12:39.471 INFO Listening for new connections on 127.0.0.1:9945.
Dec 31 18:12:44.473 INFO Idle (0 peers), best: #0 (0x190a…e2d0), finalized #0 (0x190a…e2d0), ⬇ 0 ⬆ 0
Dec 31 18:12:49.474 INFO Idle (0 peers), best: #0 (0x190a…e2d0), finalized #0 (0x190a…e2d0), ⬇ 0 ⬆ 0
将密钥添加到密钥库
MyNode01
节点开始运行,我们会再次发现没有区块生成。 此时,我们应该将节点的密钥加进密钥库里。 注意:我们需要在网络中的每一个节点都完成这些步骤,记得操作时切换不同节点的端口。
添加方式有两种可选:1、通过命令curl的方式;2、通过Apps界面的方式。分别来介绍一下。
选项一:通过curl的方式
先通过命令curl的方式操作,这也是官方推荐的方式,因为在生产环境安全性是最重要的,所以必须采取一切可能的预防措施。 这意味着在不要在任何地方留下密钥的痕迹,比如在终端的历史记录中。 创建一个文件,用于定义 curl 请求的内容:
{
"jsonrpc":"2.0",
"id":1,
"method":"author_insertKey",
"params": [
"填写aura或gran,必填",
"填写生成密钥时的助记词,必填",
"对应的公钥,必填"
]
}
这里笔者在当前目录下,创建了一个专门的目录mykey
用于存储这些文件:
如:mykey/node01_aura.json
、mykey/node01_gran.json
内容分别为:
mykey/node01_aura.json文件内容:
{
"jsonrpc":"2.0",
"id":1,
"method":"author_insertKey",
"params": [
"aura",
"engine cube pioneer firm thought exhibit carbon dumb exotic pulse noodle ceiling",
"0x00301f5ae5f5e5f5067fb10728e963680704c96ee5472e30e370faf1e49d843e"
]
}
mykey/node01_gran.json文件内容:
{
"jsonrpc":"2.0",
"id":1,
"method":"author_insertKey",
"params": [
"gran",
"engine cube pioneer firm thought exhibit carbon dumb exotic pulse noodle ceiling",
"0x063f488785f1f63ecaf7dd74cce9b73a91904f3349ecfebb1e1dc0abf8f8b5dd"
]
}
分别执行如下命令,将MyNode01
节点的密钥导入密钥库,这里的端口为MyNode01
节点的rpc端口:
curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d "@/home/simon/polkadot/substrate-node-template/mykey/node01_aura.json"
curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d "@/home/simon/polkadot/substrate-node-template/mykey/node01_gran.json"
如果命令和参数输入正确,则节点将返回如下的 JSON 响应:
{ "jsonrpc": "2.0", "result": null, "id": 1 }
这样我们对MyNode01
节点的密钥操作就完成了。
选项二:通过Apps界面的方式
重复以上步骤添加其他节点的密钥到密钥库。
启动其他节点MyNode02
./target/release/node-template
--base-path /tmp/node02
--chain ./customSpecRaw.json
--port 30334
--ws-port 9946
--rpc-port 9934
--telemetry-url 'wss://telemetry.polkadot.io/submit/ 0'
--validator
--rpc-methods Unsafe
--name MyNode02
--bootnodes /ip4/127.0.0.1/tcp/30333/p2p/12D3KooWN967iQjeSWxxPuQTtmmM6woxRyJzPrNSxyHWhg9Y6jC1
和之前一样,我们指定了另一个 base-path 和不同端口,给它另一个 name 参数,并指定此节点为 validator。
接下来重复MyNode01使用curl方式导入密钥的操作,对MyNode02节点的密钥进行导入,但是这里操作不当就会有坑,重点强调一下:除了文件和内容都换成MyNode02节点之外,在执行curl命令时,记得切换rpc端口。
我们会注意到,即使在为第二个节点添加密钥之后,依然没有区块完成最终确定性 (finalized #0)。 Substrate节点在添加 GRANDPA 密钥后需要重启。 使用与之前相同的命令,关闭节点并重启他们,此时区块就可以达到最终确定性。
查看MyNode01节点,我们可以看到网络正常出块并确认区块了:
Dec 31 19:51:56.644 INFO Substrate Node
Dec 31 19:51:56.644 INFO ✌️ version 2.0.0-655bfdc-x86_64-linux-gnu
Dec 31 19:51:56.644 INFO ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2020
Dec 31 19:51:56.644 INFO Chain specification: Local Testnet
Dec 31 19:51:56.644 INFO Node name: MyNode01
Dec 31 19:51:56.644 INFO Role: AUTHORITY
Dec 31 19:51:56.644 INFO Database: RocksDb at /tmp/node01/chains/local_testnet/db
Dec 31 19:51:56.644 INFO ⛓ Native runtime: node-template-1 (node-template-1.tx1.au1)
Dec 31 19:51:57.090 WARN Using default protocol ID "sup" because none is configured in the chain specs
Dec 31 19:51:57.126 INFO Local node identity is: 12D3KooWN967iQjeSWxxPuQTtmmM6woxRyJzPrNSxyHWhg9Y6jC1 (legacy representation: 12D3KooWN967iQjeSWxxPuQTtmmM6woxRyJzPrNSxyHWhg9Y6jC1)
Dec 31 19:51:57.128 INFO Highest known block at #35
Dec 31 19:51:57.131 INFO Listening for new connections on 127.0.0.1:9945.
Dec 31 19:51:57.665 INFO Discovered new external address for our node: /ip4/192.168.112.129/tcp/30333/p2p/12D3KooWN967iQjeSWxxPuQTtmmM6woxRyJzPrNSxyHWhg9Y6jC1
Dec 31 19:52:00.027 INFO Starting consensus session on top of parent 0xb89d8e723827f5f45e767f130a701a799a885f9165dd3ef99272b20a6db64c23
Dec 31 19:52:00.539 WARN Timeout fired waiting for transaction pool at block #35. Proceeding with production.
Dec 31 19:52:00.549 INFO Prepared block for proposing at 36 [hash: 0xf86be25cc39a2f384eabce077ee3407a16c9254e594988c8d8de783aaa9de7e6; parent_hash: 0xb89d…4c23; extrinsics (1): [0x0cd8…9a43]]
Dec 31 19:52:00.561 INFO Pre-sealed block for proposal at 36. Hash now 0x5bd9428b7042eece65a7163313b6a035853b5ee18045cd91f3cc71a8d3faa804, previously 0xf86be25cc39a2f384eabce077ee3407a16c9254e594988c8d8de783aaa9de7e6.
Dec 31 19:52:00.562 INFO ✨ Imported #36 (0x5bd9…a804)
Dec 31 19:52:02.132 INFO Idle (1 peers), best: #36 (0x5bd9…a804), finalized #33 (0xa869…8356), ⬇ 1.5kiB/s ⬆ 1.5kiB/s
Dec 31 19:52:06.140 INFO ✨ Imported #37 (0xa0fc…b6ce)
Dec 31 19:52:07.133 INFO Idle (1 peers), best: #37 (0xa0fc…b6ce), finalized #34 (0x4a7d…2924), ⬇ 1.0kiB/s ⬆ 1.0kiB/s
Dec 31 19:52:12.002 INFO Starting consensus session on top of parent 0xa0fc3ee234c172933d314f5a7c03355d81fda692b228ab204a14f7f13cdeb6ce
Dec 31 19:52:12.005 INFO Prepared block for proposing at 38 [hash: 0x41137065ca473208f88e75f297da0de7b771be192df00c41df8c8a1f9e8a63f1; parent_hash: 0xa0fc…b6ce; extrinsics (1): [0x5052…8ef6]]
Dec 31 19:52:12.008 INFO Pre-sealed block for proposal at 38. Hash now 0x2b47d55f994bb91e5a1c5346f6403cfdcabb5785d4cba1209d4104051707cfd7, previously 0x41137065ca473208f88e75f297da0de7b771be192df00c41df8c8a1f9e8a63f1.
好了,到此就大功告成了!
小结
通过本文的学习,我们熟悉并掌握了怎样创建一个自己的区块链网络,包括学会了生成自己的账号密钥、导入密钥到密钥库,并创建一个使用该密钥对的自定义创世区块配置文件(chain spec),离“使用substrate创建的区块链网络用于生产环境”又更近了一步了。
参考:
Creating Your Private Network · Substrate Developer Hub