Boilerplateを使ったDapps(分散型アプリケーション)の作成(2)

前回の続きです。 前回 -> sendeetech.hatenablog.com

ブロックチェーンをコントロールする

前回の作業ですでにEthereumのAPIであるgethにコマンドを送ることで、Ethereumが起動した状態になっています。
その状態でマイニングをスタートしてみます。

> miner.start()
true

マイニングが行われているかどうかは下記コマンドで確認できます。

> miner.hashrate
500450 //ゼロじゃなかったらマイニングされている状態

ストップは下記です。

> miner.stop()
true

今回はマイニングをしたまま開発を進めていきます。

アプリケーションの全体像

フォルダ構成は(抜粋すると)下記のようになっているかと思います。

├── client
│   ├── collections.js
│   ├── index.js
│   ├── lib
│   │   ├── compatibility
│   │   │   └── bootstrap.js
│   │   ├── contracts
│   │   │   └── MultiplyContract.sol
│   │   ├── helpers
│   │   │   ├── helperFunctions.js
│   │   │   └── templateHelpers.js
│   │   └── thirdparty
│   │       ├── chance.min.js
│   │       └── web3
│   │           └── web3.js
│   ├── meta.js
│   ├── routes.js
│   ├── stylesheets
│   └── templates
│       ├── components
│       │   ├── accounts.html
│       │   ├── accounts.js
│       │   ├── balance.html
│       │   ├── balance.js
│       │   ├── multiplyContract.html
│       │   ├── multiplyContract.js
│       │   ├── networkHealth.html
│       │   └── networkHealth.js
│       ├── index.html
│       ├── layout
│       │   ├── _footer.html
│       │   ├── _header.html
│       │   ├── main.html
│       │   └── notFound.html
│       └── views
│           ├── view1.html
│           ├── view1.js
│           ├── view2.html
│           └── view2.js
├── i18n
├── project-tap.i18n
├── public
│   ├── fonts
│   └── images
├── settings.json
├── test-genesis.json
└── tests
    └── mocha
        └── client
            └── MultiplyContract.js

Meteorでよく見かけるのは、ServerとClientにディレクトリを分けて、それぞれのサイドにおける開発を進めていく形でしょうか。
今回は、serverフォルダは存在せずに、Client側からだけで(実質的には)開発が可能なのMeteorの特徴が現れてています。

その他、簡単にピックアップして説明すると、

  • Meteorのデファクトスタンダードなルーティング用ライブラリ「iron-router」でルーティングが行われている
  • Viewは、 layout/main.html から views/view1 or views/view2 を呼び出し
  • views/view1 or views/view2 から components/ 以下の各テンプレートファイルを呼び出し
  • Componentsフォルダの各htmlファイル名に対応してJSファイルが作成される
  • (基本的には)JSファイル内に、各Viewで呼び出すためのhelperやイベントを記載していく

上記は主にMeteorの知識ですが、今回の特徴は、 Smart Contract を記載しているアプリであることです。
SmartContractは、デフォルトでは、 client/lib/contracts 以下に記載されています。
Meteorは独特の読み込みルールがあるため、それを意識した書き方が必要になります。
(参考:Meteor 開発者がおさえておきたい「ファイルの読み込み順番(File Load Order)」 )

SmartContractの中身

  • .sol という拡張子で保存されています。
  • Congractは「Solidity」という専用の言語で記載されています。

client/lib/contracts/multiplyContract.sol の中身は下記の通りです。

contract MultiplyContract {
    function multiply(uint a) returns(uint d) {
        return a * 7;
    }
}

上記のコードは、見たままではありますが、

  • MultiplyContract という契約を宣言
  • 変数aと戻り値bを宣言して、引数を7倍したuint(符号なし整数)を戻す

ということを記述しています。

JSベースの言語で、チューリング完全を謳っており、どんな複雑な契約でもプログラミングにおとしこめるものであれば理論上は実現できます(ということになっています)。

SmartContractの動作確認

Cloneしたままの状態で、Meteorを起動すると、View2へのリンクがあるはずです。
View2を開くとこのような画面が出るはずです。

Screen Shot 2016-05-16 at 17.55.18.png

この画面に対応するhtmlとjsファイルは、 multiplyContract.htmlmultiplyContact.js です。

下記は、multiplyContract.jsの抜粋です。

Template['components_multiplyContract'].events({

    /**
    On "Create New Contract" click
    
    @event (click .btn-default)
    */

    "click .btn-default": function(event, template){ // Create Contract
        TemplateVar.set('state', {isMining: true});
        
        // Set coinbase as the default account
        web3.eth.defaultAccount = web3.eth.coinbase;
        
        // assemble the tx object w/ default gas value
        var transactionObject = {
            data: MultiplyContract.bytecode, 
            gasPrice: web3.eth.gasPrice,
            gas: 500000,
            from: web3.eth.accounts[0]
        };
        
        // estimate gas cost then transact new MultiplyContract
        web3.eth.estimateGas(transactionObject, function(err, estimateGas){
            // multiply by 10 hack for testing
            if(!err)
                transactionObject.gas = estimateGas * 10;
            
            MultiplyContract.new(transactionObject, 
                                 function(err, contract){
                if(err)
                    return TemplateVar.set(template, 'state', {isError: true, error: String(err)});
                
                if(contract.address) {
                    TemplateVar.set(template, 'state', {isMined: true, address: contract.address, source: source});
                    contractInstance = contract;
                }
            });
        });
    },

    
    /**
    On Multiply Number Input keyup
    
    @event (keyup #multiplyValue)
    */

    "keyup #multiplyValue": function(event, template){
        // the input value
        var value = template.find("#multiplyValue").value;  
        
        // call MultiplyContract method `multiply` which should multiply the `value` by 7
        contractInstance.multiply.call(value, function(err, result){
            TemplateVar.set(template, 'multiplyResult'
                            , result.toNumber(10));
            
            if(err)
                TemplateVar.set(template, 'multplyResult'
                                , String(err));
        });
    },
});

こちらも簡単にですが説明すると、

  • .btn-default がクリックされた際にイベントを発生させる
  • Web3というJavaScript APIを用いて、ブロックチェーンにアクセスしたり色んなアクションを発生させたりする
  • Web3についてはこちら(JavaScript API)
  • .sol で記載したコントラクトを MultiplyContract クラスのように扱うことができる
  • コントラクトが実行されるには、(testnetで)マイニングがされていることと、適切に取引時のgasを設定することが必要

あとは通常のJSが扱えれば理解は出来るかと思います

動作後の画面

実際にボタンを押してみると下記のように取引実行後の画面が表示されます

Screen Shot 2016-05-16 at 18.31.55.png

Contractがブロックチェーン上に流された結果、Contractのaddressが生成され、実行できるようになりました。

「Type a value here to multiply」に数字を入力すると、(実際にはクライアント側での動作ですが)記載した契約通りに7倍された数字が戻ってくるのが分かるかと思います。


今回もデフォルトのBoilerplateの説明に終始してしましましたが、次回は最後に、ContractやViewをカスタマイズして独自のDappを作成してみたいと思います。