はじめてのEthereum DApp開発の環境づくり

ブロックチェーン関係のプロダクトがアツいということで分散型アプリケーション Dapp 開発もやってみたいと思う方向けに,役立つかはわかりませんが,私自身忘れる可能性が高いので記事にしておこうと思います.

やっておいたほうがいいこと

  • Dapps の概念に関して色んなサイトや人にあたる
  • JavaScript の基本のおさらい
  • Solidity の基本のおさらい

CryptoZombies を 6 章まで進めただけで,DApp が何かを語るほどには理解が深くないので,そこはもっと詳しいサイトを参照してください.

Solidity の学習に関して,CryptoZombies はとてもわかりやすいです.ただ,JavaScript 含め,プログラミング言語にあまり触れたことがない方もこれと同じ感想を抱くのかはわかりません.

PC 環境

Macbook Air (2017) に環境を構築します.

私の普段使っている Windows (デスクトップ PC) にも入れようと思えば可能ですが,Linux とか macOS に比べるとなんとなくめんどくさい雰囲気が出ていたので...

Windows って事あるごとにハブられてる感じがして悲しいですね...

開発環境の構築

Dapp を運用できるプラットフォームは限られていて,今回は最もメジャーである Ethereum を対象にします.Ethereum の概念や開発環境の整え方は Ethereum 入門を参考にしています.長いのでピックアップしていますが,もっと詳しく知りたいことがあればそちらをご覧ください.

開発を行うにあたって,プライベートネットを用意するところから始めます.Ethereum 上の Dapps の特徴として,プログラムはブロックチェーン上にコントラクトとして書き込まれるので,最初から本番環境 (メインネット) で開発することはできないからです.

インストール

Dapps 開発のためには Ethereum の P2P ネットワークに参加する必要があります.Geth というクライアントをインストールするとノードとしてネットワークに参加できます.

参加すると,マイニングや送金,スマートコントラクトの生成,トランザクションの生成など,Dapp に必要な機能が揃います.

インストールには Homebrew を利用します.

terminal
$ brew tap ethereum/ethereum
$ brew install ethereum

プライベートネットの構築と起動

まず,genesis ファイル myGenesis.json を作成します.ブロックチェーンの最初のブロックを genesis ブロックと呼び,ここを起点としてブロックが連なっていきます.

terminal
$ mkdir /Users/hoge/eth_private_net

任意の場所にプライベートネットに関する情報を格納するディレクトリを上記のように作成し,このディレクトリ内に genesis ファイルを保存します.

myGenesis.json
{
  "config": {
    "chainId": 15
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "",
  "gasLimit": "0x8000000",
  "difficulty": "0x40",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}

difficulty でマイニングの難易度を調整しています.

genesis ファイルができたら genesis ブロックを初期化し,geth を起動します.

terminal
$ geth --datadir /Users/hoge/eth_private_net init /Users/hoge/eth_private_net/myGenesis.json
$ geth --networkid "15" --nodiscover --datadir "/Users/hoge/eth_private_net" console 2>> /Users/hoge/eth_private_net/geth_err.log

  • --datadir:データ格納先のディレクトリの指定
  • --networkid:ライブネットと異なるネットワークを立ち上げるときに使う (genesis ファイルの chainId と一致させる)
  • --nodiscover:geth は自動的に Ethereum ネットワークのノードに接続するため,接続先を探さないようにする
  • console:geth を起動したときにコンソールが立ち上がる
Welcome to the Geth JavaScript console!

instance; ...
 modules: ...

>

上記のような画面が表示されたら,環境構築は終了です.

Ether のマイニングと送金

環境構築が割と簡単に終わってしまったので,どうやって動いてるのか簡単に触ってみようと思います.

Ethereum ネットワーク上では,Ether がなければ何もできません.まず,マイニングによって,プライベートネット上でのみ使える Ether を入手します.

アカウントの作成

Ethereum には EOA (Externally Owned Account) と Contract の二種類のアカウントがあります.ユーザーが直接操作するのは EOA で,Contract は EOA により生成されたトランザクションによって自動的に実行されるような存在です.

Ether を扱いたいので EOA を作成します.

> eth.accounts
[]

> personal.newAccount("hogehoge01")
'0x24afe6c0c64821349bc1bfa73110512b33fa18e1'

> personal.newAccount("hogehoge02")
'0x59c444d6c4f4187d1dd1875ad74a558a2a3e20b6'

> eth.accounts
['0x24afe6c0c64821349bc1bfa73110512b33fa18e1', '0x59c444d6c4f4187d1dd1875ad74a558a2a3e20b6']

personal.newAccount("password") で EOA が作成できます.パスワードは再発行できないので注意しましょう.

アカウントを作成する前と後では eth.accounts の返す結果が変わっていることがわかります.後で利用するため,アカウントを二つ作っています.

マイニング

マイニングすると etherbase (coinbase) に登録されているアカウントにその報酬が入っていきます.

> eth.coinbase
'0x24afe6c0c64821349bc1bfa73110512b33fa18e1'

> eth.coinbase == eth.accounts[0]
true

> miner.setEtherbase(eth.accounts[1])

eth.coinbase で etherbase に指定されているアカウントのアドレスが出力されます.今は eth.accounts[0] を指定していますが, miner.setEtherbase() で変更することもできます.

マイニングは次のようにして行います.

> miner.start()
null

> eth.mining
true

> eth.hashrate // マイニング実行時
445445

> miner.stop()
true

> eth.mining
false

一番最初に実行したときは,最初の数十分間 DAG を生成しているため,マイニングを行いません.

マイニングによって生成されたブロックは eth.getBlock(index)によって中身を見ることができます.(index はブロックの番号)

ある程度の時間が経ったら,実際に得られた報酬を確認してみます.

> eth.coinbase == eth.accounts[0]
true

> eth.getBalance(eth.accounts[0])
'515000000000000000000'

> eth.getBalance(eth.accounts[1])
'0'

> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
'515'

表記は Ether の最小単位である Wei で返ってきますが,web3 を使えば変換できます.(1 Ether = 10^18 Wei)

送金

現在の状態では accounts[0] しか Ether を保有していないので, accounts[1] に送金してみます.送金するために,最初に送金元アカウントのロックを解除します.

また,トランザクションがブロックに取り入れられることで取引が承認されたことになるので,マイニングを実行している必要があります.

> personal.unlockAccount(eth.accounts[0])
Pathphrase:
true

> eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(5, "ether")})
'0xc86c2a5bdf651f54095eca87e487d4f68f12030dd559f0377e9e7bf1566b9b28'

トランザクションを送信すると,その ID が返ってきます.

最後に

この後もコントラクトの作成などありましたが書くのに疲れてしまったので,ここらへんで止めておきます.

コンソールでプライベートネットを構築するのもいいですが,Ganache などを使うと GUI で簡単に操作できるようなので,そっちの構築も試してみたいと思います.