上一篇文章介绍了如何通过Substrate搭建本地测试区块链网络,使用到了节点模板程序substrate-node-template,并使用其内置的Alice和Bob节点搭建了本地私有区块链网络。
Alice和Bob节点的密钥是公开的,在实际应用中所有参与区块链的用户都应该生成自己的密钥。
使用Subkey生成密钥
Subkey是与Substrate一起开发的密钥生成工具,主要功能是生成密钥对(当前支持sr25519、ed25519、secp256k1加密算法)、SS58地址编码以及从助记词和原始seed还原密钥,还可以为消息创建和验证签名。
在之前的文章:《Substrate密码学 & Subkey的安装和使用》、《Subkey功能详解》中有Subkey的安装方法和功能的详细介绍,下面生成和节点相关的密钥。
现在需要为每个节点生成两种椭圆曲线密码算法(sr25519、ed25519)的密钥。
Substrate提供Aura、BABE、PoW等多种生产区块的算法,sr25519格式的密钥及其关联的SS58地址会被Aura使用。
使用subkey generate命令生成两组sr25519格式密钥和SS58地址,我习惯加上–output-type json选项让输出看起来更清楚:
然后使用subkey inspect命令查找和sr25519密钥对应的ed25519密钥,后者会被GRANDPA用于最终确认,GRANDPA(GHOST-based Recursive ANcestor Deriving Prefix Agreement,基于GHOST的递归祖先派生前缀协议)是Polkadot中继链的最终决定性工具。
现在有了两组密钥,每组密钥的私钥对应两种格式的公钥和地址。
第一组:
keyvalue私钥0x2e5552e6f0ade747a667bb9c004cebb3affd13d06941d000e695e004bcfdf24d助记词smooth maximum truly yard rose syrup violin turkey illegal title because kneesr25519(aura)公钥0x32a11a38a5e74483ce7f604930c399297be55d4733ae69d7ef737140916ed84fSS58地址5DD67GJL3s18hG9b7VgPMpFXMGHroc26h1ngbEnGJqk9bWU7ed25519(gran)公钥0x4e847d67ca907028f2bb59d95d5c073688846cd44569a8ff2b53cb13c30ea126SS58地址5Dqex3eHnskqpHRhZTQwgvwHUn9mfmPbXdmin7YA5QUmkG5v
第二组:
keyvalue私钥0x231e30c1f83b9c303b91f9d1776471df07510fc908e3fd35ae910e391c28da0c助记词expand pattern valve oven rich mom item coast rapid guitar school inspiresr25519(aura)公钥0x4049fc72a0d7c6e4dd494584f8a491358ef916e0a3fec70c097f611da8b7cf26SS58地址5DWzuAhTYkNoEBksCVCLyXEuD836EikSyEL5UQQVKXPk6xVCed25519(gran)公钥0xe8ed386e3e453d85066b0b493d7c7f3939f1bded341b61ba7eaf8ff947dee41eSS58地址5HL7SDcNic91zqDvXQtoVwDvbALnZLc1JSCoxa3fztbWHGTS
创建自定义Chain Spec
现在区块链网络的每个参与者都有了自己的密钥,可以创建自定义链规范。
上一篇文章启动Alice和Bob节点时,使用的是内置的预定义链规范(–chain local),下面的命令将其导出到名为customSpec.json的链规范文件中:
./target/release/node-template build-spec –disable-default-bootnode –chain local > customSpec.json
这里使用了node-template build-spec子命令,用法如下
node-template build-spec [FLAGS] [OPTIONS]
使用的–disable-default-bootnode标识会禁止将默认的引导节点添加到规范中。
导出的customSpec.json文件包含一些字段,最大的字段是code,它是运行时的Wasm二进制文件,是通过cargo build –release命令所构建的一部分。
需要关注的customSpec.json文件中的部分是用于生成区块的Aura授权(由palletAura字段表示),以及用于完成区块最终性确认的GRANDPA授权(由palletGrandpa字段表示)
palletAura字段的数据如下
\”palletAura\”: { \”authorities\”: [ \”5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY\”, \”5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty\” ]}
palletGrandpa字段的数据如下
\”palletGrandpa\”: { \”authorities\”: [ [\”5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TTpu\”, 1], [\”5GoNkf6WdbxCFnPdAnYYQyCjAKPJgLNxXwPjwTh6DGg6gN3E\”, 1] ]}
palletGrandpa字段的数据更复杂一些,因为GRANDPA协议支持权重,这里每一个验证人的权重被设置为1。
下面要做的是把当前Alice和Bob节点的授权地址修改为上一步生成的地址:
palletAura字段中使用两个sr25519地址;palletGrandpa字段中使用两个ed25519地址;
可以在这两个字段中添加更多验证人信息,验证人不应该使用相同的密钥,那样会产生冲突的区块。
当chain spec准备好后,把它转换成初始(raw)chain spec,命令如下
./target/release/node-template build-spec –chain=customSpec.json –raw –disable-default-bootnode > customSpecRaw.json
customSpecRaw.json中的数据不会展示地址信息,网络中的所有验证人应共享customSpecRaw.json,因为从Rust到Wasm的构建过程是不可复制的,所以每个人都会得到一个略有不同的Wasm Blob(Binary large object,二进制大型对象),如果不使用相同的customSpecRaw.json会破坏共识。
创建自己的私有区块链网络
创建了自定义的链规范文件customSpecRaw.json并分发给所有参与者后,就可以启动自定义的私有区块链网络了,现在可以在多台计算机上启动不同的节点来构建区块链网络。
使用下面的命令启动第一个节点,如果base-path已经有链数据,需要先删除相关的链数据再启动
./target/release/node-template \\ –base-path /tmp/node01 \\ –chain ./customSpecRaw.json \\ –port 30333 \\ –ws-port 9944 \\ –rpc-port 9933 \\ –telemetry-url \’wss://telemetry.polkadot.io/submit/ 0\’ \\ –validator \\ –rpc-methods=Unsafe \\ –name MyNode01
相比于之前启动的Alice节点,这里有一些不同的地方:
没有–alice标识,因为下面会通过RPC接口把自定义的密钥插入到密钥库(keystore);–chain选项从预留值变成了自定义的链规范文件;–name <NAME>:为节点设置一个人类可读的名字;–rpc-methods <METHOD SET>:设置暴露RPC接口的方法,默认值Auto,可选值:Auto、Safe、Unsafe。这里使用了Unsafe,仅在开发环境中使用,在生产环境中应该使用JSON-RPC代理,Substrate的JSON-RPC实现是Parity JSON-RPC;
添加密钥到keystore
运行MyNode01节点后会发现没有任何区块产生,现在需要把密钥加入密钥库(keystore),需要为网络中的每个节点完成这一工作。
每个节点需要添加两种类型的密钥:
Aura密钥用于生产区块(block production);GRANDPA密钥用于区块的最终确认(block finalization);
首先创建一个文件tmp.json,文件内容如下
{ \”jsonrpc\”:\”2.0\”, \”id\”:1, \”method\”:\”author_insertKey\”, \”params\”: [ \”aura\”, \”smooth maximum truly yard rose syrup violin turkey illegal title because knee\”, \”0x32a11a38a5e74483ce7f604930c399297be55d4733ae69d7ef737140916ed84f\” ]}
然后使用curl命令行工具插入密钥
curl http://localhost:9933 -H \”Content-Type:application/json;charset=utf-8\” -d \”@tmp.json\”
如果返回如下结果则插入成功
{\”jsonrpc\”:\”2.0\”,\”result\”:null,\”id\”:1}
目前只有插入了node01节点的aura密钥,还要依次插入node01节点的GRANDPA密钥、node02节点的aura密钥、node02节点的GRANDPA密钥,插入GRANDPA密钥时第一个参数改成\”gran\”,插入完成后删除临时文件。
其他节点加入区块链网络
其他节点加入区块链网络和之间文章中Bob节点加入时类似,启动命令如下
./target/release/node-template \\ –base-path /tmp/node02 \\ –chain ./customSpecRaw.json \\ –port 30334 \\ –ws-port 9945 \\ –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/12D3KooWMmukuGu27HzEd3BWRLmGuEXF3wxyL1qJk7xJtD2stecp
–bootnodes选项的配置可以在同一台物理计算机上,也可以是不同的物理计算机。
这里设置新节点名为MyNode02,配置引导节点为MyNode01,同样为验证人节点。
可以看到,两个节点开始生产和同步区块
如果节点未添加其Aura密钥,则将无法生产区块。
只有在2/3以上的验证人将其GRANDPA密钥添加到密钥库中的情况下,才能完成区块的最终确认,目前本地私有网络配置了两个验证人节点,因此只能在第2个节点添加其GRANDPA密钥后才能进行区块最终确认(50% < 66% < 100%)。
为了保证所有验证人节点是对等的,各节点必须使用相同的链规范文件,可以通过查看genesis block和state root hash来检验节点的对等性。
你可能会发现在添加了第2个节点的密钥后仍然没有发生区块的最终确认(finalized #0),那是因为插入GRANDPA密钥后,Substrate节点需要重新启动才能生效,按下Ctrl+C结束节点运行,再使用相同命令重新启动即可。