Sub Dev 分享 | Substrate Based區塊鏈上線實戰經驗

《從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,造成節點間無法互聯。

 

但我覺得區塊鏈運維,最終還是要對整體區塊鏈有足夠了解,才能在關鍵時候作出正確的選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章