Help us understand the problem. What is going on with this article?

Substrateでブロックチェーンとアプリケーションを作る Runtimeの設定から〜ゲームPlayまで

More than 1 year has passed since last update.

こんにちは、Stakedの渡辺創太です。

前回こちらの記事で、Substrateのインストールからアカウントの作成までを行いました。この記事はその続きです。Gavin Woodの Web3 Summitでのプレゼンを参考にしています。

Runtimeモジュールを作成する

RuntimeとはSubstrateにおけるブロック処理ロジックなどを決める機能です。State Transaction Functiuonとも言われるときもあり、WebAssemblyバイナリーでオンチェーンに記載さてています。詳しくはScraoboxに記載しています。

前回、substrate-node-templateをインストールしましたが、./runtime/src/demo.rsのフォルダに記載していきます。

Screen Shot 2019-02-13 at 11.09.02.png

作成したdemo.rsにいくつかのライブラリーをインストールします。

use parity_codec::Encode;
use support::{StorageValue, dispatch::Result, decl_module, decl_storage};
use runtime_primitives::traits::Hash;
use {balances, system::{self, ensure_signed}};

pub trait Trait: balance::Trait {}

Web3 Summitのプレゼンでは、簡単な賭けゲームを作成していました。ゲームに勝てば、Potに溜まっていた金額を得ることができ、負ければPotに没収されるという簡単な仕組みです。

ライブラリーをインストールしたので、次に、モジュールを宣言する必要があります。(module declaration)

decl_module! {
    pub struct Module<T: Trait> for enum Call where origin: T::Origin {
        fn play(origin) -> Result{
            //ゲームをプレイするロジック
        }

        fn set_payment(_origin, value: T::Balance) -> Result{
            //ゲームのpaymentの仕様
        }
    }
}
decl_storage! {
  trait Store for Module<T: Trait> as Demo {
    Payment get(payment): Option<T::Balance>;
    Pot get(pot): T::Balance;
  }
}

strageモジュールはオンチェーンに載せる情報を定義するために使用します。

次に、モジュール内のロジックを書いていきます。

ゲームをプレイするロジック

fn play(origin) -> Result {

  let sender = ensure_signed(origin)?;
  //decl_strage!で宣言しているからpaymentが使える
  let payment = Self::payment().ok_or("Must have payment amount set")?;
 //senderの残高を減少させる
  <balances::Module<T>>::decrease_free_balance(&sender, payment)?;

  //ハッシュ関数を通してハッシュ値の最初のbyteが128以下であれば勝ち。potにあった金額がSenderに払われる
  if (<system::Module<T>>::random_seed(), &sender)
  .using_encoded(<T as system::Trait>::Hashing::hash)
  .using_encoded(|e| e[0] < 128)
  {
    <balances::Module<T>>::increase_free_balance_creating(&sender, <Pot<T>>::take());
  }
 
  //結果どうあれ、senderが賭けに参加した金額がデポジットされる
  <Pot<T>>::mutate(|pot| *pot += payment);

  Ok(())
}

ゲーム内のPaymentのロジック

fn set_payment(_origin, value: T::Balance) -> Result {
 //イニシャルpaymentがセットされていない場合の処理
  if Self::payment().is_none() {

    <Payment<T>>::put(value);
    <Pot<T>>::put(value);
  }

  Ok(())
}

変更をアップデートする

上記でModuleを設定しました。変更を実行するために./runtime/src/lib.rsを編集します。

mod demo;の追記。

Screen Shot 2019-02-14 at 13.48.58.png

impl demo::Trait for Runtime {}の追記

Screen Shot 2019-02-14 at 14.20.39.png

Demo: demo::{Module, Call, Storage},の追記

Screen Shot 2019-02-14 at 13.55.29.png

上記で新しいRuntimeモジュールを作成したので、次にブロックチェーンのアップデートをします。

Substrate-node-templateのディレクトリでビルド
substrate-node-template $ ./build.sh

Screen Shot 2019-02-14 at 14.21.40.png

ビルド後、substrate-uiのnpm run devで接続したlocalhost8000にて一番下にRuntime Upgradeができるので、Select Runtimeを押し、

./runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm

を選択する。これでRuntimeのアップデートができました。Developer Consoleでみると動いていることがわかります。

Screen Shot 2019-02-14 at 14.58.08.png

UIを整える

UIを整えるにはsubstrate-uiレポジトリーを編集する必要があります。
./substrate-ui/src/app.jsxを編集します。

新しく以下のセクションを追加します。

<Divider hidden />
<Segment style={{margin: '1em'}} padded>
  <Header as='h2'>
    <Icon name='game' />
    <Header.Content>
      Play the game
      <Header.Subheader>Play the game here!</Header.Subheader>
    </Header.Content>
  </Header>
  <div style={{paddingBottom: '1em'}}>
    <div style={{fontSize: 'small'}}>player</div>
    <SignerBond bond={this.player}/>
    <If condition={this.player.ready()} then={<span>
      <Label>Balance
        <Label.Detail>
          <Pretty value={runtime.balances.balance(this.player)}/>
        </Label.Detail>
      </Label>
    </span>}/>
  </div>
  <TransactButton
    content="Play"
    icon='game'
    tx={{
      sender: this.player,
      call: calls.demo.play()
    }}
  />
  <Label>Pot Balance
    <Label.Detail>
      <Pretty value={runtime.demo.pot}/>
    </Label.Detail>
  </Label>
</Segment>

同時に、exportの部分にthis.player = new Bond;を追記します。

................
this.seedAccount.use()
this.runtime = new Bond;
//これ
this.player = new Bond;
}

これでUIを構築することができ、ゲームをPlayすることができます。

Screen Shot 2019-02-14 at 15.21.10.png

Source: https://www.youtube.com/watch?v=0IoUZdDi5Is&t=22s

SotaWatanabe
Twitter (@WatanabeSota) : https://twitter.com/WatanabeSota?lang=en
https://medium.com/@watanabesouta
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away