Chapter 8-3: ネットワークへのデプロイ

ネットワークへのデプロイ

ERC20準拠のトークンをTruffleからGethプライベートネット、Ropstenテストネットへデプロイします。

プライベートネットへのデプロイ

Gethを使用して、マイニングを実行します。

> miner.start(1)
null
> eth.mining
true

truffle.jsを以下のように書き換えてください。

上記のコードは、ネットワーク「development」を定義しています。

ローカルの8545ポートで動作しているnetwork_idが10番のネットワークを表しています。

$ truffle migrate --network development

上記のコマンドでデプロイします。

正常でデプロイが完了すると、以下のようなログが出力されます。

$ truffle migrate --network development
Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0xa244887eacbe0ffff9d623a9b33ec898d05ae8e98ad9321eab71f8d1849ae51e
  Migrations: 0xc6606b19bee1ebe99a49c444d2c1d3999dabfdee
Saving successful migration to network...
  ... 0x34e038e5138525df91ef983bcc45aca4563e5ff884bb24ad569ff8685580d951
Saving artifacts...
Running migration: 2_deploy_dapps_token.js
  Deploying DappsToken...
  ... 0x00d2adab66b24ee0294b0dace1835f0ed796f3742802ef79da15741acb188373
  DappsToken: 0xb7b98eb1cfad29a8f19ef9f4e32aa4490409482f
Saving successful migration to network...
  ... 0x61997403b5875340f3528463a9b24ff472ca9d4c81cccad9e9632a356021a17d
Saving artifacts...

DappsToken: 0xb7b98eb1cfad29a8f19ef9f4e32aa4490409482fコントラクトのアドレスとなります。

下記のコマンドでdevelopmentネットワークに接続します。

$ truffle console --network development

動作確認

truffle(development)> d = DappsToken.at("0xb7b98eb1cfad29a8f19ef9f4e32aa4490409482f")
truffle(development)> d.name()
'DappsToken'
truffle(development)> d.symbol()
'DTKN'
truffle(development)> d.balanceOf(web3.eth.accounts[0])
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }
truffle(development)> d.balanceOf(web3.eth.accounts[1])
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
truffle(development)> d.balanceOf(web3.eth.accounts[2])
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
truffle(development)> d.transfer(web3.eth.accounts[1], 100)
{ tx: '0x94bfb6e4c8446bdd2ee16e0aa33aac46f0767f43e7e129c1ea5ed3a259052f65',
  receipt:
   { blockHash: '0xb8c4bf57f251cf4322fec3f94c23eaddbdb33f0ca6017546e154f65944a32665',
     blockNumber: 619,
     contractAddress: null,
     cumulativeGasUsed: 51519,
     from: '0x81c8e5be811f32a90e6a7143ccfd6660cdd8d971',
     gasUsed: 51519,
     logs: [ [Object] ],
     logsBloom: '0x00200000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000100000000000000000000000000000000000000000000000000002000000000010000000000000000008000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000002000000000000004000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000',
     root: '0x936e27befec4794daec189579dc35d623b488bf47d76d1b37271aad7e089bd8a',
     to: '0xb7b98eb1cfad29a8f19ef9f4e32aa4490409482f',
     transactionHash: '0x94bfb6e4c8446bdd2ee16e0aa33aac46f0767f43e7e129c1ea5ed3a259052f65',
     transactionIndex: 0 },
  logs:
   [ { address: '0xb7b98eb1cfad29a8f19ef9f4e32aa4490409482f',
       blockNumber: 619,
       transactionHash: '0x94bfb6e4c8446bdd2ee16e0aa33aac46f0767f43e7e129c1ea5ed3a259052f65',
       transactionIndex: 0,
       blockHash: '0xb8c4bf57f251cf4322fec3f94c23eaddbdb33f0ca6017546e154f65944a32665',
       logIndex: 0,
       removed: false,
       event: 'Transfer',
       args: [Object] } ] }
truffle(development)> d.balanceOf(web3.eth.accounts[0])
{ [String: '900'] s: 1, e: 2, c: [ 900 ] }
truffle(development)> d.balanceOf(web3.eth.accounts[1])
{ [String: '100'] s: 1, e: 2, c: [ 100 ] }
truffle(development)> d.balanceOf(web3.eth.accounts[2])
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }

テストネットへのデプロイ

テストネットには様々な選択肢があります。

代表的なテストネットは、Ropsten、Kovan、Rinkebyの3種ですが、それぞれブロック生成のコンセンサスアルゴリズムが違います。

テストネット コンセンサスアルゴリズム
Ropsten Proof of Work
Kovan Proof of Authority
Rinkeby Proof of Authority

ここでは、Ropstenネットワークに対してデプロイを行っていきます。

MetaMaskのインストール

MetaMaskは、Google Chromeで利用できるイーサリアムのウォレットです。

MetaMaskを利用して、Ropstenネットワークへのデプロイ準備します。

ネットワークにコントラクトをデプロイするためには、Gasコストがかかるため、ある程度の残高が必要です。

Ropstenネットワークにコントラクトをデプロイするには、RopstenネットワークのEtherが必要です。

MetaMaskを使って、Etherを入手できるサイトで残高を増やしましょう。

MetaMaskはGoogle ChromeのExtensionとして提供されています。

Google Chromeを起動して、エクステンションを追加しましょう。

MetaMask - Chrome ウェブストア

Chromeのステータスバー右にキツネのアイコンが表示されているので、クリックしましょう。

パスワードを入力し、パスワードと復元用の秘密鍵は忘れないように保存しておきましょう。

Etherの入手(MetaMask Ether Faucetへの接続)

MetaMaskの設定が完了したので、RopstenネットワークのEtherを入手しましょう。

MetaMask Ether FaucetChromeで開きます。

MetaMaskのアイコンをクリックし、Repsten Test Networkネットワークに変更します。

キツネアイコンの右側をクリックすると、ネットワークの切り替えが行なえます。

f:id:akifumi-fukaya:20180417212334p:plain

「request 1 ether from faucet」ボタンをクリックしましょう。

トランザクションを発行され、MetaMaskから1.000ETH取得できたことが確認できます。

f:id:akifumi-fukaya:20180417212727p:plain

Infuraへの登録

Infura - Scalable Blockchain Infrastructure

Infuraは、Gethなどのイーサリアムクライアントを利用しなくとも、テストネットやメインネットにコントラクトをデプロイできる仕組みを提供しています。

Gethでデプロイすることはもちろん可能ですが、各ネットのブロックチェーンと同期する必要があるため、時間とディスク容量を大量に消費してしまいます。

https://infura.io/signup からアカウントを作成しましょう。

登録完了後、各ネットワークのURLが取得できます。

TruffleでのRopstenネットワークの設定

truffle-hdwallet-providerをインストールしましょう。

$ npm install truffle-hdwallet-provider

TruffleのプロジェクトにRopstenネットワークを設定します。

truffle.jsにネットワーク設定を追記しましょう。

$MNEMONICに、MertaMaskインストール時に保存したニーモニックを入力します。

$INFURA_ACCESS_TOKENは、Infuraにユーザー登録した際にメモしたURLの「https://ropsten.infura.io/」の後ろを入力します。

Gasを明示しないとデプロイに失敗するので、migrations/2_deploy_dapps_token.jsファイルでGasを明示しておきましょう。

Ropstenネットワークへのデプロイ

$ truffle migrate --network ropsten

上記のコマンドでRopstenネットワークへデプロイできます。

コントラクトのアドレスが出力されるので、メモしておきましょう。

デプロイ完了後、MetaMaskの画面を表示し、TOKENタブから「ADD TOKEN」ボタンをクリックします。

Token Contract Address, Token Symbol, Decimals of Precisionを入力して「Add」を押して登録しましょう。

MetaMaskのTOKENタブに1000DTKNが表示されて入れば、デプロイユーザーへの付与は完了しています。

Ropstenネットワークでトークンを送信してみましょう。

$ truffle console --network ropsten
truffle(ropsten)> d = DappsToken.at("0x7d20eaf8d2238eabec6fb98fb25f017e38b5d36f")
truffle(ropsten)> d.balanceOf("0x1297Cd103A77f87419a6bd68F56ecBD04d2978A2")
{ [String: '1e+21'] s: 1, e: 21, c: [ 10000000 ] }
truffle(ropsten)> d.balanceOf("0x1931Cb91567e1Ad51215A2a7364C1E263d7CCA85")
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
truffle(ropsten)> d.transfer("0x1931Cb91567e1Ad51215A2a7364C1E263d7CCA85", 1e18)
{ tx: '0x4824274b48c424332c1b5f868fea0f98f6434fa7e1997d9324afed8dca0551ba',
  receipt:
   { blockHash: '0x5314ef977950aa4623fa96ce257871350900406f9c1dfbdfeb88c64724baf2a8',
     blockNumber: 3062029,
     contractAddress: null,
     cumulativeGasUsed: 82408,
     from: '0x1297cd103a77f87419a6bd68f56ecbd04d2978a2',
     gasUsed: 51839,
     logs: [ [Object] ],
     logsBloom: '0x00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000020000001100010000000000000000000000000000000000000000000000000000400000000000000000000000010000000000000000000000000000000000000040000000000000000000000000002000000000000000000000000000000000000000800000000000000000000000000000008000000000000000000000000000000000000000000000000',
     status: '0x1',
     to: '0x7d20eaf8d2238eabec6fb98fb25f017e38b5d36f',
     transactionHash: '0x4824274b48c424332c1b5f868fea0f98f6434fa7e1997d9324afed8dca0551ba',
     transactionIndex: 1 },
  logs:
   [ { address: '0x7d20eaf8d2238eabec6fb98fb25f017e38b5d36f',
       blockNumber: 3062029,
       transactionHash: '0x4824274b48c424332c1b5f868fea0f98f6434fa7e1997d9324afed8dca0551ba',
       transactionIndex: 1,
       blockHash: '0x5314ef977950aa4623fa96ce257871350900406f9c1dfbdfeb88c64724baf2a8',
       logIndex: 1,
       removed: false,
       event: 'Transfer',
       args: [Object] } ] }
truffle(ropsten)> d.balanceOf("0x1297Cd103A77f87419a6bd68F56ecBD04d2978A2")
{ [String: '999000000000000000000'] s: 1, e: 20, c: [ 9990000 ] }
truffle(ropsten)> d.balanceOf("0x1931Cb91567e1Ad51215A2a7364C1E263d7CCA85")
{ [String: '1000000000000000000'] s: 1, e: 18, c: [ 10000 ] }
truffle(ropsten)>

MetaMask上でも、トークンの残高が変更されています。

Chapter 8-2: ERC20準拠のトークン作成

ERC20準拠のトーク

ERC20とは、イーサリアム上のトークンを標準化する仕様のことです。

ERC20に準拠するトークンをERC20準拠のトークンと呼びます。

ERC20に準拠することで、異なるトークン同士でのやり取りが簡単になり、ERC20対応のウォレットでの取り扱いが可能となります。

詳しくはこちらを参照してください。

ERC20 Token Standard - The Ethereum Wiki

プロジェクト作成

$ mkdir dapps-token
$ cd dapps-token
$ truffle init

OpenZeppelinのインストール

OpenZeppelinは、Solidity言語でセキュアにスマートコントラクトを開発できるオープンソースフレームワークです。

$ npm init -f
$ npm install zeppelin-solidity

トークコントラクトの作成

contracts/DappsToken.solファイルを作成し、トークコントラクトの実装を行います。

pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";


contract DappsToken is StandardToken {
  string public name = "DappsToken";
  string public symbol = "DTKN";
  uint public decimals = 18;

  function DappsToken(uint initialSupply) public {
    totalSupply_ = initialSupply;
    balances[msg.sender] = initialSupply;
  }
}

dapps-token/DappsToken.sol at master · akifumi/dapps-token · GitHub

デプロイ時に動作するスクリプトを記述します。

migrations/2_deploy_dapps_token.jsファイルを作成します。

var DappsToken = artifacts.require("./DappsToken.sol");

module.exports = function(deployer) {
    var initialSupply = 1000;
    deployer.deploy(DappsToken, initialSupply);
};

dapps-token/2_deploy_dapps_token.js at master · akifumi/dapps-token · GitHub

テストコードの作成

tests/DappsToken.jsファイルを作成します。

var DappsToken = artifacts.require("./DappsToken.sol");

contract('DappsToken', function(accounts) {

  it("should put 1000 DappsToken in the first account", function() {
    return DappsToken.deployed().then(function(instance) {
      return instance.balanceOf.call(accounts[0]);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), 1000, "1000 wasn't in the first account");
    });
  });
});

dapps-token/DappsToken.js at master · akifumi/dapps-token · GitHub

テストを実行します。

$ truffle develop
truffle(develop)> test

migrateコマンドでdevelopネットワークにデプロイし、設定した名前などを確認しましょう。

truffle(develop)> migrate
truffle(develop)> dappsToken = DappsToken.at(DappsToken.address)
truffle(develop)> dappsToken.name()
'DappsToken'
truffle(develop)> dappsToken.symbol()
'DTKN'
truffle(develop)> dappsToken.totalSupply()
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }

アカウント別の発行量を確認します。

アカウントの1番目は発行者なので、トークンを全額保持しています。

アカウントの2番目は保持量が0です。

truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[0])
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }
truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[1])
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }

送金してみましょう。

送金完了後に各アカウントが所持するトークン数を確認すると、トークンが正常に動作していることがわかります。

truffle(develop)> dappsToken.transfer(web3.eth.accounts[1], 100)
{ tx: '0xf001aa4460728b5b75b96e7afdc72e739d5a53cf71dffc4cb6323b83d1d5b2d0',
  receipt:
   { transactionHash: '0xf001aa4460728b5b75b96e7afdc72e739d5a53cf71dffc4cb6323b83d1d5b2d0',
     transactionIndex: 0,
     blockHash: '0x933600dadc8888729d6d538a27944088e37859b2d931af5f5e1a19a9f15e780f',
     blockNumber: 13,
     gasUsed: 51519,
     cumulativeGasUsed: 51519,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000010000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0xf001aa4460728b5b75b96e7afdc72e739d5a53cf71dffc4cb6323b83d1d5b2d0',
       blockHash: '0x933600dadc8888729d6d538a27944088e37859b2d931af5f5e1a19a9f15e780f',
       blockNumber: 13,
       address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
       type: 'mined',
       event: 'Transfer',
       args: [Object] } ] }
truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[0])
{ [String: '900'] s: 1, e: 2, c: [ 900 ] }
truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[1])
{ [String: '100'] s: 1, e: 2, c: [ 100 ] }

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コマンドでテストを実行することができます。

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

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

Truffleについて

Truffle

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

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

Solidityを使用したスマートコントラクト開発のデファクトスタンダートになりつつあります。

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の設定ファイルの雛形

ちなみに、こんな感じのプロジェクトができました。

GitHub - akifumi/truffle-first

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

最後に

Truffleを使って、早速アプリケーションを作成してみましょう!!

Chapter 1 - ブロックチェーンとは?

ブロックチェーンとは?

ブロックチェーン"インターネット依頼の発明"と言われるくらい注目されています。 暗号通貨システムとしてブロックチェーンの技術は発明されました。しかし、暗号通貨システム以外の様々な分野で応用される可能性が高まっています(ブロックチェーン2.0と呼ぶこともある)。

P2P方式

サービスを提供する「サーバ」とサービスを受ける「クライアント」が明確にその役割を分けている方式のことを、クライアントサーバ方式と言います。 世の中で動作している多くのサービスは、クライアントサーバ方式で動いています。

P2P方式は、すべての参加者がサーバにもクライアントにもなり、中央がいない方式です。 P2P方式は管理者がいないため、サーバ障害などサービスが止まることはありません。

DApps

DAppsとは、Decentralized Applications の略称です。 ブロックチェーン技術では、従来の中央集権型ではなく、自律分散型(非中央集約型)アプリケーション(DApps: Decentralized Applications)なシステムを実現できます。 ビットコインは世界で初めて登場したDAppsと言われています。

イーサリアム

イーサリアムは、誰でも自由にブロックチェーンにプログラムをデプロイし、新しいブロックチェーンアプリケーションを実装できるプラットフォームです。 イーサリアムによって、DAppsを開発する敷居はとても低くなりました。

Hello World!!

ブロックチェーンの勉強を始めることにしました。

ひとまず「ブロックチェーンアプリケーション開発の教科書」を読み進めながら、ブログとしてまとめていこうと思います!!