トップへ戻る
公開日
2017年6月14日
筆者:Curvegrid
ジェフ・ウェントワース

5日目:第一原理からのDAppのテスト

この投稿は、基本的なツールチェーン上でDAppを起動して実行するためのエンドツーエンドのウォークスルーを提供することを目的としています。

Ethereumノード+ウェブサーバー+分散型アプリ(DApp)ブラウザ

この記事では、基本的なツールチェーン上でDAppを立ち上げて実行する方法をエンドツーエンドで説明します。ラッパースクリプトを使用するのではなく、Ethereumノード、Webサーバ、DApブラウザを直接操作して、裏で何が起こっているのかを説明します。

既存のSolidity Remix IDE「Donation」チュートリアルをベースに、ツールの現状(2017年6月)に合わせたアップデートを加えて構築します。

必要不可欠なインフラは、Ethereumノード(私たちはethを選びました)、静的ファイルをホストするための標準的なWebサーバー(私たちはpython -m SimpleHTTPServerを使用しました)、そしてDAppブラウザ(私たちはMistを選びました)です。

この種のDAppのアーキテクチャは、DAppブラウザ(Mist)がWebサーバから静的なHTML、JS、CSSファイルを読み込み、標準のDOMに加えて、注入されたweb3.jsオブジェクトを介してEthereumノード(eth)へのアクセスを提供するというものです。基本的にウェブページは、通常のウェブと同様にEthereumブロックチェーンと対話することができます。

開発モードでゲスを開始し、アカウントを作成し、いくつかのブロックを採掘します。

このようにシンプルなDAppの場合、geth --devを実行するだけで、シングルノードのEthereumテストネットワークを設定してくれます。


mkdir test-chain-dir$ geth --dev --datadir test-chain-dir console


gethが起動したら、テストアカウントを作成します。


> personal.newAccount()Passphrase:Repeat passphrase:INFO [06-25|00:51:55] 新しい財布が登場 url=keystore:///tmp... status=Locked"0x42a3f741fa25e52c618854e7a002ff7c7985b044">


その後、マイナーを起動していくつかのブロックを採掘します。コインベースは自動的にテストアカウントに設定されているので、採掘したイーサはそこに入金されます。eth.coinbaseを実行することで確認できます。


> miner.start()INFO [06-25|00:52:45] マイニング スレッドを更新しました=0INFO [06-25|00:52:45] トランザクション プール価格のしきい値を更新しました=0INFO [06-25|00:52:45] マイニング操作を開始しますnull> INFO [06-25|00:52:45] 新規マイニング作業をコミットしました number=1 txs=0 uncles=0 elapsed=103.893µsINFO [06-25|00:52:45] 進行中のDAGの生成 epoch=0 percentage=0 elapsed=68.374µsINFO [06-25|00:52:45] Generating DAG in progress epoch=0 percentage=3 elapsed=137.968µs...


そして数秒後に鉱夫を止める。


> miner.stop()INFO [06-25|00:52:53] 新規マイニング作業のコミット number=9 txs=0 uncles=0 経過=2.002strue>。


では、テスト口座の残高を確認してみましょう。


> web3.fromWei(eth.getBalance(personal.listAccounts[0]), "ether")40>>。


私たちのテストアカウントには40イーサが入っていますが、これはブロックあたり5イーサで、DAGの生成を含めて、現代のiMacで8秒で8ブロックを採掘したことを意味します。

なお、IPCエンドポイントを指定することで、geth devインスタンスに対してMistブラウザを起動することもできます(IPCであるにもかかわらず、Mistのコマンドラインオプションは--rpcとなっていることに注意してください)。もし、"Looking for peers"で停止した場合は、Mistのスプラッシュ画面で"Launch Application"をクリックする必要があるかもしれません。

Linuxです。


mist --rpc test-chain-dir/geth.ipc


マックです。


$ /Applications/Mist.app/Contents/MacOS/Mist --rpc test-chain-dir/geth.ipc


テストウォレットに40イーサの残高が表示されています。また、Mistでは左下に「Private-net」という真っ赤なインジケーターが表示され、これが公開されているEthereumネットワークではないことを示しています。

geth devインスタンスのミストウォレット

ネットワークの選択肢をテストする

geth devモードの代わりに、プライベートテストネットワークで実行するという選択もありました。Consensus 2017 Hackathon]({{ site.baseurl }}{% link _posts/2017-05-12-daysofblock-03-consensus-hackathon.md %})のときにそれを試してみましたが、いくつかの問題に遭遇しました。

公衆テストネットワークのいずれかで実行することもできますが、その場合、スマートコントラクトをそのネットワークにさらすことになり、さらに公衆テストネットワークに関連したパフォーマンスや容量の影響をすべて受けることになります。

あるいはメインネットワーク上で実行することもできますが、それだと高額になってしまいます(2017年6月:Ethereumの取引コストはそれぞれ約0.30米ドル)。

Geth devモードの説明

その速さに驚きました。プライベートテストネットワーク上で実行するために geth を設定する場合、ジェネシスブロックを作成し、正しいオプションで geth を実行するというプロセスがあります。難易度を低くして素早く採掘できるようにすると、アルゴリズムが素早く調整され、すぐにブロックが数十秒から数分かかるようになります。

geth の場合、コンセンサスアルゴリズムを Proof of Authority に切り替えたり、geth のソースコードをハックしたりすることで回避する方法があります。しかし、gethの開発モードでは、ブロックは常に数秒で採掘されます。

何が起こっているのか、ゲスのソースコードを調べてみることにしました。

flags.goでは、geth --devが他の多くのオプションを設定するトリガーとなっていることがわかります。


if ctx.GlobalBool(DevModeFlag.Name) {    // --dev mode can't use p2p networking.    cfg.MaxPeers = 0    cfg.ListenAddr = ":0"    cfg.DiscoveryV5Addr = ":0"    cfg.NoDiscovery = true    cfg.DiscoveryV5 = false}


基本的にこれはシングルノードネットワークであり、他のノードからのディスカバリは許可されていません。

同じファイルのさらに下の方では、devモードのジェネシスブロックがどこから来ているのかがわかり、デフォルトではガス価格が0に設定されています。


case ctx.GlobalBool(DevModeFlag.Name):    cfg.Genesis = core.DevGenesisBlock()    if !ctx.GlobalIsSet(GasPriceFlag.Name) {        cfg.GasPrice = new(big.Int)    }    cfg.PowTest = true}


cfg.PowTestの設定は、devモードの作業証明アルゴリズムが設定されていることを示唆しています。このフラグをethash.goに通せば、なぜマイニングに時間がかからず、開発者モードでは難易度が上がらないのかを確認することができます。


コードを読んだだけでは、DAG(キャッシュ)サイズは常に1024/4 = 256 uint32の小さな値に制限されているように見えますが、これはブロックが非常に速く採掘されることを示唆しています。

寄付金DApp

DApp用に作成するファイルは2つあります。

そのリンク先のWebページのソースコードはまばらに見えますが、Mistやその他の最新のブラウザでは問題なく動作します。

index.htmlと同じディレクトリで、Webサーバを起動します。標準のPythonがインストールされていると仮定して、python -m SimpleHTTPServerを実行するだけです。

DAppのテスト

Webブラウザでindex.htmlを開き、「与える」ボタンをクリックします。標準のWebブラウザではweb3.jsライブラリとgethへの接続が存在しないため、何も起こりません。

Chrome は DApps をネイティブにサポートしていません

ここで、Mistブラウザでindex.htmlを開きます。上部のナビゲーションバーをクリックして、https://wallet.ethereum.org と表示されていると思われる場所をクリックし、index.html をローカルのウェブサーバがホストしているindex.html に置き換えます。例えば、http://localhost:8000。

寄付DAppのindex.htmlを表示するミストブラウザ

今から「give」をクリックしても何も起こらず、裏でエラーが出ていますが、今回は必須項目が入力されていないことが原因です。MistはChromeブラウザのラッパーにEthereumのサポート(web3.js、gethへのIPC接続など)を追加したものなので、標準の開発者ツールが利用できます。試しにDevelop => 開発者ツールの切り替え => localhost:8000にしてみます。

index.htmlでエラーが出るミストブラウザ

ブロックチェーン上にスマートコントラクトをロードする

MistにはRemixSolidity IDEも含まれており、これはDevelop => Open Remix IDEからアクセスできます。チュートリアルの次のステップ][mist-deploy-contract]では、Remixを使用してDonation.solのスマートコントラクトをgethのdevノード内のブロックチェーンにデプロイします。

Remix IDEの右上にあるフォルダアイコンをクリックしてDonation.solを開きます。すると、使用されていない変数に関する(意図的な)警告と、pragma文の欠落に関する警告が表示されていることに気づくでしょう。このチュートリアルでは、これらの警告は無視して構いません。

Donation.solのプレ デプロイメントでリミックス

環境は「Injected Web3」となっており、geth devノードへのIPC接続を示しており、アカウントは先ほど作成したテストウォレットであることに注意してください。

右ペインの中央にあるピンク色の「作成」ボタンをクリックすると、スマートコントラクトがブロックチェーン上にロードされます。

スマートコントラクトのデプロイメントを確認

トランザクションの送信」をクリックしても何も表示されません。これは、少なくとも1つのブロックが採掘された後、数秒後にminer.start()に続いてminer.stop()を実行する必要があります。


Mistでは、アドレス0xeb4578083c1d0928d634298e84313104f1f8bda2を含む展開された契約の詳細が表示されます。アドレスをコピー」をクリックしてどこかに貼り付けてメモしておきます。

Donation.solのポストデプロイでリミックス

geth ヘルパースクリプト

geth コンソールは、基本的には web3.js が埋め込まれた Javascript の read-eval-print ループです。テストを簡単にするために自動化できることの1つは、トランザクションが保留中の場合にのみマイニングをトリガーすることです。マイナーを起動したり停止したりする必要がなくなり、コンソールと geth dev モードのブロックチェーンデータフォルダが不必要にいっぱいになることもなくなります。

ここでは、私たちが便利だと感じたgeth スクリプトをまとめています。

オンデマンド マイニングを行うには、次の Javascript スニペットをファイルにコピーしてください。miner.stop() がパラメータを取らなくなったことと、現在 StackExchange にあるスクリプトは動作しないため、以下に完全なソースを含めています。


// modified version of: https://ethereum.stackexchange.com/questions/2531/common-useful-javascript-snippets-for-geth/2541#2541var mining_threads = 1function checkWork() {    if (eth.getBlock("pending").transactions.length > 0) {        if (eth.mining) return;        console.log("== Pending transactions! Mining...");        miner.start(mining_threads);    } else {        miner.stop();        console.log("== No transactions! Mining stopped.");    }}eth.filter("latest", function(err, block) { checkWork(); });eth.filter("pending", function(err, block) { checkWork(); });checkWork();


exit と入力して geth を終了し、以下のように再起動してヘルパースクリプトを含めます。


geth --dev --preload ./geth-helper-scripts.js --datadir test-chain-dir console


今では、トランザクションが送信されるたびに、鉱夫が自動的に開始して停止し、新しいブロックに含めるようになりました。

スマートコントラクトにトランザクションを送信する

Mistでは、寄付契約フォームの「契約アドレス」の欄に、先ほどコピーしたDonation.solを展開したアドレスを記入します。give」ボタンの左には、「from」にウォレットのアドレスを、「金額」には魏の1イーサを10000000000000と記入します。

ミストに記入された寄付フォーム

give」をクリックし、「Send Transaction」をクリックします。

ミストで寄付を確認

前のセクションでマイニングヘルパースクリプトを有効にした場合、数秒後にDAppのポップアップでトランザクションが確認されるはずです。gethコンソールには、新しくマイニングされたブロックにトランザクションが追加されたことも表示されます。


INFO [06-25|03:23:21] Submitted transaction fullhash=0xbbc31070d5c88e510b7e9ec8fafd1df9bbcdff8c55aea71f1c72c7227dd473c1 recipient=0xeb4578083c1d0928d634298e84313104f1f8bda2==保留中のトランザクションです!>INFO [06-25|03:23:22] Transaction pool price threshold updated price=0INFO [06-25|03:23:22] トランザクションプールの価格閾値を更新しました。マイニング...info [06-25|03:23:22] マイニングスレッド更新 threads=1info [06-25|03:23:22] トランザクションプール価格閾値更新 price=0info [06-25|03:23:22] マイニング作業開始info [06-25|03:23:22] コミット新規マイニング作業番号=16 txs=1 uncles=0 経過=309.925μs...INFO [06-25|03:23:22] 新規ブロック番号=16 hash=7eb36c...e08f40INFO [06-25|03:23:22]🔨 マイニング可能なブロック番号=16 hash=7eb36c...e08f40INFO [06-25|03:23:22] コミット新規マイニング作業番号=17 txs=0 uncles=0 elapsed=192.606µs== 取引がありません!マイニングが停止しました。


トランザクションのデバッグ

Remix IDEでトランザクションをデバッグするためには、トランザクションハッシュが必要となります。あるいは、gethコンソールの"Submitted transaction"行の"fullhash"の値(上図参照)で確認することができます。この例では、0xbbc31070d5c88e510b7e9ec8fafd1df9bbcdff8c55aea71f1c72c7227dd473c1となっています。

Remix IDEで右上の"Debugger"タブをクリックし、"Transaction index or hash"フィールドにトランザクションハッシュ値を貼り付け、再生アイコンをクリックします。ボタンやスライダーを使ってコードをステップスルーすることができます。

RemixにデプロイされたDonation.solをデバッグ

デバッガで前にも後ろにも進むことができるのは、Remixがトランザクションの前後のブロックチェーンの状態全体にアクセスできるからです。リアルタイムのデバッグとは対照的に、アイスホッケーのゴールの瞬間的なリプレイのように、すでに起こったことをステップスルーしているのです。

結論

元のチュートリアルが同様に終わったところで、私たちはここで物事を残します。Geth dev modeはテスト用のEthereumブロックチェーンを使って素早く立ち上げて実行するのに最適な方法であり、GethとMistとシンプルなWebサーバーの組み合わせは、基本的なDApp開発のための完全なツールチェーンです。