Day 5: 基本原則からのDAppテスト

2017/06/14

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

この記事は、基本的なツールチェーンでDAppを構築して実行するためのエンドツーエンドの手順を提供することを目的としています。私たちは、何が裏で起こっているのかを示すために、ラッパースクリプトを使用するのではなく、イーサリアムノード、ウェブサーバー、およびDAppブラウザーを直接使用します。

私たちは、既存のSolidity Remix IDEの「寄付」チュートリアルに基づいており、ツールの現状態(2017年6月)に合わせて更新しました。

必要なインフラは、イーサリアムノード(私たちはgethを選びました)、静的ファイルをホストするための標準ウェブサーバー(私たちはpython -m SimpleHTTPServerを使用しました)およびDAppブラウザー(私たちはMistを選びました)です。

この種のDAppのアーキテクチャは、DAppブラウザー(Mist)が静的HTML、JS、およびCSSファイルをウェブサーバーからロードし、標準DOMに加えて、注入されたweb3.jsオブジェクトを介してイーサリアムノード(geth)へのアクセスを提供するというものです。本質的に、ウェブページはイーサリアムブロックチェーンと通常のウェブの両方と相互作用できます。

Gethを開発モードで開始し、アカウントを作成し、ブロックをマイニングする

このようなDAppでは、単にgeth --devを実行すれば、単一ノードのイーサリアムテストネットワークを設定し、いくつかの便利なオプションを伴います。

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

gethが実行されている間に、テストアカウントを作成します。

> personal.newAccount()Passphrase:Repeat passphrase:INFO [06-25|00:51:55] New wallet appeared                      url=keystore:///tmp… status=Locked"0x42a3f741fa25e52c618854e7a002ff7c7985b044”>

次に、マイナーを開始していくつかのブロックをマイニングします。コインベースは自動的にテストアカウントに設定されるため、マイニングされたEtherはそこで預けられます。eth.coinbaseを実行してこれを確認できます。

> miner.start()INFO [06-25|00:52:45] Updated mining threads

数秒後、マイナーを停止します。

> miner.stop()INFO [06-25|00:52:53] Commit new mining work                   number=9 txs=0 uncles=0 elapsed=2.002strue

次に、テストアカウントの残高を確認してください。

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

私たちのテストアカウントには40 Etherがあり、1ブロックあたり5 Etherであるため、8秒で8ブロックをマイニングしたことになります。これにはDAGの生成も含まれます。

Mistブラウザーをgeth開発インスタンスに対して起動することもできます。IPCエンドポイントを指定してください(Mistコマンドラインオプションは--rpcですが、IPCであることに注意してください)。もし「ピアを探しています」で停止する場合は、Mistのスプラッシュ画面で「アプリケーションを起動」をクリックする必要があるかもしれません。

Linux:

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

Mac:

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

‍私たちのテストウォレットで40 Etherの残高を見ることができます。Mistは、これがパブリックイーサリアムネットワークではないことを示す「プライベートネット」という明るい赤いインジケーターを左下に表示します。

Mist wallet on geth dev instance

テストネット代替案

geth開発モードの代わりに、プライベートテストネットワークで実行することも選択できました。私たちは[コンセンサス2017ハッカソン]({{ site.baseurl }}{% link _posts/2017-05-12-daysofblock-03-consensus-hackathon.md %})の時にそれを試みましたが、いくつかの問題に直面しました。

公共のテストネットワークの一つで実行することもできますが、それは私たちのスマートコントラクトをそのネットワークに公開することを意味し、公共のテストネットワークに関連付けられるパフォーマンスおよびキャパシティの影響を伴います。

代わりに、メインネットワークで実行することもできますが、これは高価になります(2017年6月:イーサリアムのトランザクションは約0.30米ドルです)。

Geth開発モードの説明

これがどれほど速いかに私たちは驚きました。プライベートテストネットワークで実行するためにgethを設定する際には、ジェネシスブロックを作成し、正しいオプションでgethを実行する全プロセスがあります。もし低い難易度でgethを起動すると、すぐにマイニングが行われ、アルゴリズムは迅速に調整され、すぐにブロックがマイニングに数十秒、さらには数分かかるようになります。

gethにはこれを回避する方法があります。合意アルゴリズムのためにプルーフ・オブ・オーソリティに切り替えるか、gethソースコードを改造することで対処できます。しかし、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}

本質的に、これは単一ノードネットワークであり、他のノードによる発見は許可されていません。

同じファイルのさらに下では、開発モードのジェネシスブロックがどこから来ているのかを確認でき、デフォルトでガス価格は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設定は、開発モードのプルーフ・オブ・ワークアルゴリズムが設定されていることを示唆しています。このフラグをethash.goにたどっていくと、なぜマイニングが短時間で行われ、難易度が開発モードで上がらないのか見ることができます。

‍コードを読むだけでも、DAG(キャッシュ)サイズがいつも小さい1024/4 = 256 uint32値に制限されるため、ブロックが非常に迅速にマイニングされることが示されています。

寄付DApp

DAppのために作成する必要がある二つのファイルがあります:

  • Donation.solはSolidityスマートコントラクトです。

  • index.htmlはDAppウェブページです。

そのリンクのウェブページのソースコードはスパースに見えますが、Mistや他の最新のブラウザーでも正常に機能します。

index.htmlと同じディレクトリに、ウェブサーバーを起動します。標準のPythonインストールがある場合、python -m SimpleHTTPServerを実行するだけで、デフォルトでポート8000でリッスンします。

DAppのテスト

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

Chrome does not support DApps natively

今度はMistブラウザーでindex.htmlを開いてください。上部のナビゲーションバーをクリックして、https://wallet.ethereum.orgと言っている部分を見つけて、index.htmlをホストしているローカルウェブサーバのアドレスに置き換えてください。たとえば、http://localhost:8000です。

Mist browser displaying index.html of the Donation DApp

「与える」をクリックすると、何も起こらないことがわかります。その背後でエラーが発生しますが、今回は必須フィールドが入力されていないためです。Mistは、Chromeブラウザーをラップしたもので、追加のイーサリアムサポート(web3.js、gethへのIPC接続など)を提供し、標準の開発者ツールが利用可能です。「開発」=>「開発者ツールを切り替える」=> localhost:8000を試してください。

Mist browser with error on index.html

スマートコントラクトをブロックチェーンに読み込む

Mistには、Develop => Open Remix IDEからアクセスできるRemix Solidity IDEも含まれています。チュートリアルの次のステップに従い、Remixを使用してDonation.solスマートコントラクトを、私たちのgeth開発ノード内で実行されているブロックチェーンにデプロイします。

Remix IDEの右上のフォルダアイコンをクリックしてDonation.solを開きます。未使用の変数に関する(意図的な)警告や欠落したpragmaステートメントに関する警告がいくつか表示されることに注意してください。これは、チュートリアルの目的には無視しても構いません。

Remix with Donation.sol pre-deployment

環境は「Injected Web3」で、geth開発ノードへのIPC接続を示し、アカウントは私たちが作成したテストウォレットです。

右側のペインの中央にあるピンクの「作成」ボタンをクリックして、スマートコントラクトをブロックチェーンに読み込みます。

Confirm smart contract deployment

「トランザクションを送信」をクリックした後、何も起こらないように見えます。なぜなら、Mistがトランザクションを次にマイニングされるブロックに含めるのを待っているからです。私たちは、以前のステップでgethでマイニングを手動で有効にしてから無効にしましたが、少なくとも1つのブロックがマイニングされるまで再びminer.start()を使用する必要があります。数秒後にminer.stop()を実行します。

‍Mistでは、展開されたコントラクトの詳細が表示され、そのアドレス0xeb4578083c1d0928d634298e84313104f1f8bda2を含みます。これを「アドレスのコピー」をクリックしてどこかに貼り付けてください。

Remix with Donation.sol post-deployment
gethヘルパースクリプト

gethコンソールは基本的に、web3.jsが埋め込まれたJavascriptのリード・評価・印刷ループです。テストを容易にするために自動化できることの1つは、トランザクションが保留中のときにのみマイニングをトリガーすることです。マイナーを開始および停止する必要がなくなるため、コンソールとgeth開発モードのブロックチェーンデータフォルダーが不必要に埋まることを避けます。

ここに、私たちが役立つと考えるgethスクリプトのコレクションがあります。

// 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();

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

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

これで、トランザクションが送信されるたびに、マイナーは自動的に開始および停止して、新しいブロックに含まれます。

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

Mistで、寄付契約フォームのフィールド「契約アドレス」に、以前にコピーした展開されたDonation.solのアドレスを入力します。「与える」ボタンの左側に、「from」にウォレットアドレスを、 「amount」に1000000000000000000(これが1 Ether in Weiです)を入力します。

Donation form filled out in Mist

「与える」をクリックし、次に「トランザクションを送信」をクリックします。

Confirm donation in Mist

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

> INFO [06-25|03:23:21] Submitted transaction                    fullhash=0xbbc31070d5c88e510b7e9ec8fafd1df9bbcdff8c55aea71f1c72c7227dd473c1 recipient=0xeb4578083c1d0928d634298e84313104f1f8bda2== Pending transactions! Mining...INFO [06-25|03:23:22] Updated mining threads                   threads=1INFO [06-25|03:23:22] Transaction pool price threshold updated price=0INFO [06-25|03:23:22] Starting mining operationINFO [06-25|03:23:22] Commit new mining work                   number=16 txs=1 uncles=0 elapsed=309.925µs...INFO [06-25|03:23:22] Successfully sealed new block            number=16 hash=7eb36c…e08f40INFO [06-25|03:23:22] 🔨 mined potential block                  number=16 hash=7eb36c…e08f40INFO [06-25|03:23:22] Commit new mining work                   number=17 txs=0 uncles=0 elapsed=192.606µs== No transactions! Mining stopped

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

トランザクションのデバッグはRemix IDEでトランザクションハッシュが必要で、これは現在Mistブラウザーのindex.htmlの下部「ログ」セクションにあります。または、gethコンソールの「提出されたトランザクション」行の「fullhash」値(上記参照)として確認できます。私たちの例では0xbbc31070d5c88e510b7e9ec8fafd1df9bbcdff8c55aea71f1c72c7227dd473c1です。

Remix IDEで右上の「デバッガ」タブをクリックし、トランザクションハッシュ値を「トランザクションインデックスまたはハッシュ」フィールドに貼り付け、再生アイコンをクリックします。ボタンやスライダーを使用してコードをステップスルーすることができます。

Debug deployed Donation.sol in Remix

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

結論

私たちはここで議論を終えます。元のチュートリアルもここで終了しました。geth開発モードは、テストイーサリアムブロックチェーンで迅速に運用を開始するための素晴らしい方法であり、geth、Mist、およびシンプルなウェブサーバーの組み合わせが基本的なDApp開発のための完全なツールチェーンを提供します。