この記事は、Substrate Tutorial
https://www.shawntabrizi.com/substrate-collectables-workshop/
を実行する上で、知っておくと進めやすそうな情報を要約する趣旨である。
Substrateとは?
新しいブロックチェーンをカスタムして作ることが出来るフレームワークである。言語はRustが用いられている。
Webアプリを作る時にExpressなどを用いてサーバーの実装が簡単に出来るように、ブロックチェーンを作る際にP2P通信やデータストレージなどの低レイヤーな概念を気にせずに実装できる。
Substrateの構成
大雑把に言うと、Substrate Coreの上にSubstrate Runtime Module Libraryが乗っかっていて、これらを用いてブロックチェーンを作る。
Substrate Core
ブロックチェーンを作る上での最低限の機能が実装されている。暗号関数やp2p通信、コンセンサスなど。
参考:https://coinchoice.net/describe-the-components-of-substrate/#Substrate_Core
Substrate Runtime Module Library
Substrate Coreに組み合わせることで、様々な機能を付与する。暗号通貨の残高を管理するアカウント機能や、スマートコントラクト機能など色々ある。
参考:https://coinchoice.net/describe-the-components-of-substrate/#Substrate_Runtime_Module_LibrarySRML
Substrate Runtimeの構成は上の図のようになっており、Substrate Runtime Module Libraryを組み合わせてRuntimeを作成する。(construct_runtime!マクロで行う)
また、RuntimeのみのUpdateであれば、管理者ユーザーによって既存のチェーンを壊さずに行える(ハードフォークしない)
カスタムモジュールの定義
チュートリアルでは、既存のSRMLも利用して自らモジュールを定義することになる。
よく出てくるマクロについて解説する。マクロなので、通常のRustとは違う構文になることに注意。
decl_storage!
ブロックチェーンに保存するデータを定義する。
基本的な構文は以下のようになる。値を使うことも、mapを使うこともできる。(それぞれuse support::StoreValue,use support::StoreMapが必要である)
decl_storage! {
trait Store for Module<T: Trait> as MyStore {
MyValue : u32;
MyMap: map u32 => u32;
}
}
wasmコンパイルされると、javascriptからは
runtime.mysrml.myValue
runtime.mysrml.myMap(1)
のように呼び出せる。先頭が小文字になるので注意。
decl_module!
ユーザーが最終的に呼び出すことになるpublicな関数を定義する。(Polkadot UIで言うExtrinct)
基本的な構文は以下のようになる。これはdecl_storage!で定義したMyValueとMyMapに値を設定する関数である。
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn set_my_value(origin, my_value: u32) -> Result {
let _sender = ensure_signed(origin)?;
<MyValue<T>>::put(my_value);
Ok(())
}
fn set_my_map(origin, key: u32, val: u32) -> Result {
let _sender = ensure_signed(origin)?;
<MyMap<T>>::insert(key,Val);
Ok(())
}
}
}
- pub struct〜の定義はおまじないのようにほぼそのまま書くことになると思われる。
- originは関数を実行しているアカウントを指すので、関数を定義する際に必要となる。関数定義にoriginの型指定がないが、(Rustでは関数定義の際に必要)これはマクロなのでなんか上手いことやってくれいてる。
というのも、マクロが展開されると内部的にはCallというenumが作られ、それを呼び出すことになる。
pub enum Call<T: Trait> {
set_my_value(u32),
set_my_map(u32,u32),
}
wasmコンパイルされると、javascriptからは
call.mysrml.setMyValue(1)
call.mysrml.setMyMap(1,2)
のように呼び出せるようになる。(命名規則に注意)
参考記事
-
ParityによるSubstrateの紹介記事
https://medium.com/paritytech/what-is-substrate-29af4231d7e0 -
Substrate公式ドキュメント
https://docs.substrate.dev/ -
Substrateチュートリアル
https://www.shawntabrizi.com/substrate-collectables-workshop/#/ -
Substrate Github