查看原文
其他

Sub Dev 分享 | Substrate Based区块链上线实战经验

程剑宇 一块Plus社区 2020-11-11

一块链习是首家区块链技术学习社区,提供最系统的区块链技术课程学习,定期出品有深度的技术观察 + 评论。


《从0到1学会Substrate区块链应用开发》是由Parity 和一块+ 联合出品的全球首个Parity 官方合作课程。

每周日晚8点,作为课程内容知识拓展——助教技术分享会,由各位第一期的助教们自发轮流在线上进行分享,为学员们详细解读一个 Substrate 技术相关内容。


上周日晚,由RIODEFI INC.   CTO ——程剑宇在直播间为大家带来第一讲基于Substrate的常见运维操作,内容复盘如下。

当我们使用Substrate开发区块链时,从开发到生产环境上线一条区块链,中间会有哪些额外的步骤和实际的需要注意的地方(坑)?

基于我自己过去一段时间的研究和RioChain Beta(https://www.riochain.io/,由RioDefi开发的Substrate Based区块链)上线两个月以来实际的运维经验,为大家分享一些我们所积累的实际操作经验。


.01

多节点配置


线上环境的多节点配置上是大家非常关心的内容,一般开发的时候,根据教程我们会使用--dev来运行一条开发环境的区块链,或者根据--chain local来运行一条本地测试网络。


配置 Chain spec

这两条都是内置的测试网络,实际是在chain spec中配置的。需要注意的是,这两条都是仅能用于测试的网络,到生产环境的话,需要增加自己的网络。这就需要修改对应的chain spec的代码了。


chain spec是Substrate的区块链初始配置,类似于其他区块链的genesis。具体的实现一般放在chain_spec.rs中,具体的位置根据节点的目录结构而有所不同,在node template下是在node/src/chain_spec.rs中。


最核心的原因,是因为dev 和 local testnet 使用的出块密钥都是well-known keys,也就是一些约定俗成的密钥,像是Alice,Bob。而在生产环境,我们需要添加网络将其修改为我们自己私底下生成的节点的密钥,并且只将公钥放到上面。


观察chain_spec.rs文件,我们可以找到 dev 网络的出块节点配置,一般来说是像下面这个样子

testnet_genesis( // initial_authorities vec![ authority_keys_from_seed("Alice"), ], // root_key get_account_id_from_seed::<sr25519::Public>("Alice"), // endowed_accounts vec![ get_account_id_from_seed::<sr25519::Public>("Alice"), get_account_id_from_seed::<sr25519::Public>("Bob"), get_account_id_from_seed::<sr25519::Public>("Alice//stash"), get_account_id_from_seed::<sr25519::Public>("Bob//stash"), ], true, )


其中,testnet_genesis的第一个参数就是初始的出块节点,第二个参数是root key,第三个参数是初始的活跃账户,第四个参数这里不需要管。


其中有两个方法值得注意,第一个是其中authority_keys_from_seed,第二个是get_account_id_from_seed,这两个函数都是从seed生成对应所需要的公钥的函数。其中authority_keys_from_seed稍微复杂一点,由多组密钥组成。


修改过后的配置文件,应该是类似于下面这个样子。

beta_genesis( // initial_authorities vec![( // 5FBod7BC86ahPWt6U1sxqEozt1MF8m48soYEJkvWTLkAQBje hex!["8a1ed431fa78b83f195e228c47777cc4661916fd8b1571ac4e9801ae56560952"].unchecked_into(), // 5FR2ttJ17Nn7KivDHMJsU7fadgSmCHgHvnZ3F9hqv3K6eygH hex!["9435b260b98343ac8f42cdb0047e54d6c7229b3d6d24667bdf48a9a4e2f83aae"].unchecked_into(), ), ( // 5FEyMs3XyiUq87iC7RVB1gUX1vBhpL2n6UdaCsm6RyuJsVBn hex!["8c8957e6c33e1faef273f27283c0d2567f776d1fa487f8c310e7d88305f03b27"].unchecked_into(), // 5DDw6Z8ZgFWYU2rpVqkSLjP8GPRR7K8vSqXWKohMF7EyKLoa hex!["3346028b09c81cadd77853fc363f23a9dcdfe20132229a3298073f7c5c3fa45b"].unchecked_into(), )], // root_key hex!["20cd1afa4f95b59b7f61a97360e8bc74a26a6fc13712e6f2eef3a1e020bbcd68"].into(), // 5CoiKRg4hQopwaHxvjdk7C2Gq1pbdvJhsLiYrVHAcsHNkV8m // endowed_accounts vec![ // 5Ca8HLb1EkJgsDMSpifh33rprTCn9m1DpRkjXNTe7czU1UA5 hex!["167056fa07ae7bc1d36da5520dd8c4c06cb5a5db557986f0c6ae2af0030d4c44"].into(), // 5G9xD8Bn32KALTZWafYP97e9TwnnzqacwUgSNdLB8mvbvRt1 hex!["b4f179ee3e5e2498eb6d59d1d899bcb0157a917f9cfd8523101e4f78c8a52050"].into() ], true,)


请注意,这里将authority_keys_from_seed变成了由两组密钥组成的元组,原因是因为本身authority_keys_from_seed就是根据session keys的格式组装出来的,有可能由2个key组成,也有可能由其他数量的key组成,具体需要参照runtime中session keys的定义。


在这里,session keys是由aura和grandpa的密钥组成,分别由sr25519 和 ed25519进行加密。因此在上面的一个元组中,第一个元素为AuraId的公钥,第二个元素为grandpa的公钥。


一般我们可以通过subkey或者polkadot.js或者更安全的工具来生成Substrate相关的密钥,根据需求需要提前生成sr25519或者ed25519的密钥。


在上述代码中,还使用了hex!这个宏将相应代码转化为十六进制的格式,因此我们需要注意去掉所生成密钥的公钥开头的0x。hex!引用自hex_literal,所以还需要在文件最上方加上

use hex_literal::hex;


并且添加相关的Cargo依赖。这样,我们就为一个网络添加了指定的出块节点的密钥。


接下来要做的一件事情,就是将节点密钥与运行中的节点进行绑定了,这样链上才知道当前正在运行的节点,是什么样的身份。而在做到这一点之前,我们需要了解一个概念- Session Keys


Seesion Keys

简单来说,Session Keys 用于验证节点签名共识相关的消息。Session Keys 由多个Key组成,具体定义在runtime中可以看到。不同类型的Key可能由不同的算法实现,比如sr25519 或 ed25519。为了安全,Session Keys记得进行定时更换。


一般生成Session Keys有两种方式:

  • 从节点RPC接口去插入对应的keys

  • 从节点RPC接口生成Session Keys


前者的做法,适用于需要指定相关的密钥的区块,一般是搭建初始的出块节点或提前生成好相关的密钥的区块。后者的情况,则更适用与转入POS后搭建新的节点的区块,因为还需要额外发起一个链上交易,来绑定节点的密钥。


前者的实现主要是调用RPC接口中的author_rotateKeys,其可参考的cURL代码如下:

curl -H 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"author_rotateKeys", "id":1 }' http://localhost:9933


调用完成后,系统会返回一串json,其中包含的就是Session Keys。


前者的实现主要是调用RPC接口中的author_insertKey的方法,,后者的可参考cURL实现如下:

curl http://localhost:9933 -H "Content-Type:application/json;charset=utf-8" -d \'{"jsonrpc":"2.0","id":1, "method":"author_insertKey", "params": [ "<aura/gran>", "<mnemonic phrase>", "<public key>"] }'


在做完该项绑定后,应该正常区块下会开始出块。


Node key

大家运行node-template --help的话,一般会出现一条关于node-key的信息。libp2p是由ipfs主导开发的一个p2p的网络模块,这里的Node key,主要是p2plib在直接使用。


一般需要注意的是,种子节点需要指定固定的Node key,以防止identity发生变化,导致外部无法连接。



.02

出块节点和数据同步节点


这里给出一个参照的运行命令。需要注意的主要有,--pool-limit是交易池的大小,可以适当调整大。--ws-max-connections是提升websocket的可连接数。


出块节点的参考命令

node-template —-chain local --node-key b6800b71239ae4a7b1792f3f19239eb65229b6277d2453a2890639cc91e499f2 --name substrate-n1--base-path /home/node/data/--pruning=archive --validator--telemetry-url ws://172.31.200.11:8000/submit--pool-limit 10000—execution=NativeElseWasm


数据同步节点的参照命令

node-template —-chain local--name substrate-data-node-0--port 30333--node-key 7cec6023c2e8e7d70354d413b4361634dbb87eecec0b05bd114a6bdc669c23bd --base-path /home/node/data/--rpc-external--ws-external--rpc-cors=all--pruning=archive--bootnodes /ip4/172.31.200.5/tcp/30333/p2p/QmYgcaAUKXAnX9CpyEDWaVbjWmhZVwzTCA7D22fNb6aV8t -- telemetry-url ws://172.31.200.11:8000/submit--ws-max-connections 2048 --pool-limit 10000


使用pm2来运行节点

pm2 --name n1 start -x ‘./bin/node-template' -- --chain local --node-key b6800b71239ae4a7b1792f3f19239eb65229b6277d2453a2890639cc91e499f2 --name substrate-n1--base-path /home/node/data/--pruning=archive --validator--telemetry-url ws://172.31.200.11:8000/submit --pool-limit 10000—execution=NativeElseWasm


使用systemd来运行节点

可参照官网的教程

https://wiki.polkadot.network/docs/en/maintain-guides-how-to-systemd


负载优化

RPC比WebSocket更方便实际的缓存与优化,在海量用户访问中尤其明显。但在Polkadot Js中,对RPC的支持不够完善,因此我们想了一个相对hack的方式,自己组装Storage Key来调用相关的接口。具体代码请参照

https://github.com/RioDefi/rpc_example/blob/master/index.js



.03

链上升级


在这里,为大家提供一个可参考的链上升级流程。

1、请先确保在staging环境测试升级

2、修改runtime module业务代码

3、修改runtime/lib.rs中的version,这个主要是一个参考的作用,

4、执行cargo build --release

5、输出的wasm默认在:

./target/release/wbuild/node-template-runtime/node- template_runtime.compact.wasm

6、打开polkadot ui中通过sudo,打开system模块的setCode方法,上传刚才编译的wasm文件,提交交易 交易打包执行成功后,应该可以观察到version已经更新到相应的版本。


需要注意的是,链上升级时注意不要修改到Chain Spec,否则可能会影响genesis hash,造成节点间无法互联。


但我觉得区块链运维,最终还是要对整体区块链有足够了解,才能在关键时候作出正确的选择。

 

扫码进直播间,回看完整分享!


这么干货的分享,这是门什么样的课?


  • 体系完善的技术开发课——在2个月的时间内,致力于通过每周1/2次的线上课程+高强度的课后代码作业任务,帮助课程中的每一位成员,实现具备入门Substrate开发的能力。


  • 有含金量的烧脑课——虽然这是入门课,四位老师在课程中也尽量用最直白的语言讲解,并多穿插案例,但是如果想要完全理解,需要花工夫多思考和补充学习。


  • 循序渐进的视频课 ——我们将课程按知识模块安排成12节内容,使用视频的形式,方便同学们利用碎片化时间学习;每周更新1/2节,保证之前听的能够有时间消化,循序渐进地学习。



第一期课程报名开启一周,100个席位全部抢占完。
第二期课程报名通道提前开放,已经有开发者率先占座。席位有限,报名请抓紧!


欢迎扫码了解更多和课程报名!

       



更多阅读:
来,带你认识一个了不起的90后链圈女开发者
终于来了!Parity官方多位核心导师联合授课,Substrate技术爱好者速戳!
100位开发者已加入的Substrate课程导读视频奉上

扫码关注公众号,回复“1”加入开发者社群


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存