Chapter 8-1: Truffleフレームワークの活用

Truffle

Truffle(トリュフ)は、スマートコントラクトの開発に必要となる、コンパイル、リンク、デプロイ、バイナリ管理の機能を持つ統合開発環境フレームワークです。

デプロイやマイグレーションスクリプトで管理することができます。

Solidityを使用したスマートコントラクト開発のデファクトスタンダートになり得ます(※2018/04/13時点)。

truffleframework.com

インストール方法

Truffleはnpmでインストールすることができます。

$ npm install -g truffle

プロジェクト作成

$ truffle init

を実行するとプロジェクトを作成することができます。

$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test

コマンドの実行が完了すると、以下のディレクトリとファイルが作成されます。

名前 説明
contracts/ スマートコントラクトのディレクト
migrations/ スクリプトを記述できるデプロイメントファイルのディレクト
test/ テストファイルのディレクト
truffle-config.js Truffleの設定ファイル
truffle.js Truffleの設定ファイルの雛形

Ganache

イーサリアム開発用のパーソナルブロックチェーン

アプリケーションがブロックチェーンに与える影響をGUIで確認することができる。

Ganache | Truffle Suite

Truffle Develop

Truffleには、開発用のブロックチェーンとしてTruffle Developが組み込まれています。

$ truffle develop

で実行することができます。

インタラクティブなプロンプトが表示され、対話式でコマンドを実行することができます。

コントラクトのコンパイル

$ truffle compile

上記のコマンドでソースコードコンパイルできます。

truffle(develop)> compile

Truffle Developからコンパイルすることも可能です。

Truffleはコンパイル時間を短くするため、差分コンパイルが採用されています。

差分コンパイルではなく、全ファイルをコンパイルし直したい場合は、allオプションを付けます。

$ truffle compile --all

マイグレーション

マイグレーションファイルは、イーサリアムネットワークにコントラクトをデプロイする際に使用されます。

プロジェクトに新たなコントラクトを追加する際には、新規でスクリプトを追加します。

実行されたマイグレーションの履歴は、マイグレーションコントラクトによってブロックチェーン上に記録されます。

$ truffle migrate

上記のコマンドでマイグレーションが実行されます。

以前にマイグレーションが正常に実行されている場合、truffle migrateは最後に実行されたマイグレーションから実行を開始し、新たに作成されたマイグレーションのみを実行します。

新たなマイグレーションが存在しない場合は何も実行しません。

マイグレーションを最初から実行したい場合は、resetオプションを付けます。

$ truffle migrate --reset

公式サンプルMetaCoin

Truffleフレームワークには、独自コインを作成してアカウント間でやり取りするコントラクトのサンプルが用意されています。

サンプルプロジェクトのダウンロード

ディレクトリを作成して、その中でtruffle unboxコマンドを実行することでサンプルを取得することができます。

$ mkdir metacoin
$ cd metacoin
$ truffle unbox metacoin

truffle unboxコマンドは、Truffleフレームワークが定期ィオうするサンプルをローかつ環境に展開するコマンドです。

こちらに様々なサンプルが用意されています。

truffleframework.com

コンパイルマイグレーションの実行

$ truffle develop
truffle(develop)> migrate
Using network 'develop'.
Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xe993a882da8ba0d176a7feffe95e0f5fb2b417d0a8f07320bdfa722004360851
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Deploying ConvertLib...
  ... 0xb097805eae8952a028f633d8eb76256fb00782cac3a4989c59615f571f83add8
  ConvertLib: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
  Linking ConvertLib to MetaCoin
  Deploying MetaCoin...
  ... 0x678ce1cfd0903e0fb7ec5d293858c32f428184c18ccaea408e64f20ef1194e82
  MetaCoin: 0xf25186b5081ff5ce73482ad761db0eb0d25abfbf
Saving successful migration to network...
  ... 0x059cf1bbc372b9348ce487de910358801bbbd1c89182853439bec0afaee6c7db
Saving artifacts...
truffle(develop)> m = MetaCoin.at("0xf25186b5081ff5ce73482ad761db0eb0d25abfbf")

マイグレーションの実行が完了すると、上記のようなログが出力されます。

実行環境によって、出力される値は違います。

MetaCoinコントラクトの参照

マイグレーション時に出力されたログのMetaCoin: 0xf25186b5081ff5ce73482ad761db0eb0d25abfbfというところから、MetaCoinのアドレスを取得することができます。

at()にMetaCoinのアドレスを指定することで、MetaCoinのコントラクトを変数から参照できます。

truffle(develop)> m = MetaCoin.at("0xf25186b5081ff5ce73482ad761db0eb0d25abfbf")

getBalanceの呼び出し

truffle(develop)> m.getBalance(web3.eth.accounts[0])
{ [String: '10000'] s: 1, e: 4, c: [ 10000 ] }
truffle(develop)> m.getBalance(web3.eth.accounts[1])
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }

sendCoinでコインを送る

truffle(develop)> m.sendCoin(web3.eth.accounts[1], 1000)
{ tx: '0x6b650d826e20aba52c82636f3f2947a263a66714f0684975253527e6f810d1ea',
  receipt:
   { transactionHash: '0x6b650d826e20aba52c82636f3f2947a263a66714f0684975253527e6f810d1ea',
     transactionIndex: 0,
     blockHash: '0xd27c08f5cf5efd1c47ba15b451ac78643dba5af026812de3b77e51eddf038e5a',
     blockNumber: 6,
     gasUsed: 51024,
     cumulativeGasUsed: 51024,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom: '0x00000000000000000000000000000000010000000000000000000010000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000002000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0x6b650d826e20aba52c82636f3f2947a263a66714f0684975253527e6f810d1ea',
       blockHash: '0xd27c08f5cf5efd1c47ba15b451ac78643dba5af026812de3b77e51eddf038e5a',
       blockNumber: 6,
       address: '0xf25186b5081ff5ce73482ad761db0eb0d25abfbf',
       type: 'mined',
       event: 'Transfer',
       args: [Object] } ] }
truffle(develop)> m.getBalance(web3.eth.accounts[0])
{ [String: '9000'] s: 1, e: 3, c: [ 9000 ] }
truffle(develop)> m.getBalance(web3.eth.accounts[1])
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }

残高を確認する

truffle(develop)> m.getBalance(web3.eth.accounts[0])
{ [String: '9000'] s: 1, e: 3, c: [ 9000 ] }
truffle(develop)> m.getBalance(web3.eth.accounts[1])
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }
truffle(develop)> m.sendCoin(web3.eth.accounts[1], 10000)
{ tx: '0x175c04f4e568c865ef3735bc5ffd041b8e03b7832889ac4f9b7547cecdc2c3da',
  receipt:
   { transactionHash: '0x175c04f4e568c865ef3735bc5ffd041b8e03b7832889ac4f9b7547cecdc2c3da',
     transactionIndex: 0,
     blockHash: '0x529962199f9efb27c9111da7d4340df033b0eb659cb3a20a5f2949ca57cb7df4',
     blockNumber: 7,
     gasUsed: 23561,
     cumulativeGasUsed: 23561,
     contractAddress: null,
     logs: [],
     status: '0x01',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs: [] }
truffle(develop)> m.getBalance(web3.eth.accounts[0])
{ [String: '9000'] s: 1, e: 3, c: [ 9000 ] }
truffle(develop)> m.getBalance(web3.eth.accounts[1])
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }

テストコード

テストコードは以下になります。

metacoin/metacoin.js at master · akifumi/metacoin · GitHub

truffle(develop)> test

testコマンドでテストを実行することができます。

テストを記述しておけば、正常に動作することをチェックすることができます。

お金を取り扱うコントラクトを作成するのであれば、十分すぎるほどテストを実行しておくことをおすすめします。