#はじめに
Truffleのチュートリアルをひたすらやっていくだけです。
ETHEREUM PET SHOP
事前に用意しておくもの
Node.js(6以上)
#Truffleのインストールとプロジェクトの作成
Truffle=トリュフ です。
絵柄的にきのこのトリュフじゃなくて、チョコだと思います。
npmを使ってインストールします。
$ npm install-g truffle
今回はwork
フォルダの下にpet-shop
フォルダを作ってプロジェクトとします。
通常はtruffle init
でプロジェクトを作成するのですが、Truffle Boxという、テンプレみたいなのがあるらしく、その中にチュートリアルのペットショップ用のものがあるようなので今回はこれにします。
Truffle Boxes
$ cd work
$ mkdir pet-shop
$ cd pet-shop
$ truffle unbox pet-shop
pet-shop
フォルダの中にいろんなものができました。
#Ganacheのインストール
開発環境用のチェーンを作ったりGUIで見えるようにするやつだそうです。
ガナッシュがなんなのかわかりませんが、きっとお菓子なのでしょう。
gethだけでやってるときはターミナル画面にひたすらマトリックスみたいなのが流れて、アカウントなどはひたすらeth.accounts
とかを打ってましたがそれが見えるようになるなんて楽ですね。
こちらからダウンロードします。
Ganache
インストールしたら起動しておきます。
ポートはデフォルトで7545
が開放されているかと思うのでこれはこのままで。
#コントラクトの記述
コントラクトはcontracts
フォルダの中に入れていきます。
adoption.sol
を作成して、記述していきます。
$ touch contracts/Adoption.sol
pragma solidity ^0.4.2;
contract Adoption{
// 変数宣言
address[16] public adopters;
}
pragma~
はMigration.sol
にあわせて^0.4.2
にしてみました。
Solidity?スマートコントラクト?Ethereum?の「お作法」に則り、コントラクトに関わるものは大文字で記述します。
ちなみにadopt
は「採用する」というイメージが強いですが、ペットを飼うという意味もあるみたいです。
今回は「16匹が売り場に並んでおり、それぞれに飼い主がつく」という想定らしく、アドレス型で16個のarrayが宣言されています。
adopters[0]
からadopters[15]
まで作成されました。
public
なのでどこからでも呼び出せます。
このコントラクトの中に関数を書いていきます。
// 整数型のpetIdを入れると結果が整数型で返ってくる関数
function adopt(uint petId) public returns (uint){
// ペットは16匹しかいないので、範囲外のリクエストが来たら終わりとする
require(petId>=0 && petId<=15);
adopters[petId] = msg.sender; //トランザクション実行者のアドレスを入れ込む
return petId; // petIdを返す
}
msg.sender
はトランザクション実行者のアドレスを呼び出すメソッドですね。
ペットが買われていくとそれに応じて販売状況を更新しないといけないので現在の状況を取得するための関数を作ります。
// adoptersの状況を取得する関数
function getAdopters() public view returns (address[16]){
return adopters;
}
view
によって読み取り専用にしています。以前はconstant
を使用していたようで、時々constant
を使用したものを見ることがありますが、現在はview
でいいそうで。
#コンパイル
ここまでは人間が読めるコードで書いて来ましたが、Ethereumに載せるにはバイトコードにしないといけないのでコンパイルします。
アプリケーションが入ったフォルダでTruffleのコンパイルを実行します。
$ truffle compile
完了すると最後にWriting artifacts to ./build/contracts
と出てきますが、その通り、build
というディレクトリにJSON形式でのコントラクトが生成されました。
以下のような感じでコンパイルされました。
"bytecode": "0x6060604052341561000f57600080fd5b6102dd8061001e6000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633de4eb171461005c57806343ae80d3146100ad5780638588b2c514610110575b600080fd5b341561006757600080fd5b61006f610147565b6040518082601060200280838360005b8381101561009a57808201518184015260208101905061007f565b5050505090500191505060405180910390f35b34156100b857600080fd5b6100ce60048080359060200190919050506101c8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561011b57600080fd5b61013160048080359060200190919050506101fd565b6040518082815260200191505060405180910390f35b61014f610272565b60006010806020026040519081016040528092919082601080156101be576020028201915b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610174575b5050505050905090565b6000816010811015156101d757fe5b016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008082101580156102105750600f8211155b151561021b57600080fd5b3360008360108110151561022b57fe5b0160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550819050919050565b610200604051908101604052806010905b600073ffffffffffffffffffffffffffffffffffffffff1681526020019060019003908161028357905050905600a165627a7a7230582006abed684f9643fae8cd0377c8f2066f8c3226711091ba957fb093580ac96dd00029",
"deployedBytecode": "0x606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633de4eb171461005c57806343ae80d3146100ad5780638588b2c514610110575b600080fd5b341561006757600080fd5b61006f610147565b6040518082601060200280838360005b8381101561009a57808201518184015260208101905061007f565b5050505090500191505060405180910390f35b34156100b857600080fd5b6100ce60048080359060200190919050506101c8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561011b57600080fd5b61013160048080359060200190919050506101fd565b6040518082815260200191505060405180910390f35b61014f610272565b60006010806020026040519081016040528092919082601080156101be576020028201915b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610174575b5050505050905090565b6000816010811015156101d757fe5b016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008082101580156102105750600f8211155b151561021b57600080fd5b3360008360108110151561022b57fe5b0160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550819050919050565b610200604051908101604052806010905b600073ffffffffffffffffffffffffffffffffffffffff1681526020019060019003908161028357905050905600a165627a7a7230582006abed684f9643fae8cd0377c8f2066f8c3226711091ba957fb093580ac96dd00029",
"sourceMap": "25:635:0:-;;;;;;;;;;;;;;;;;",
"deployedSourceMap": "25:635:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;567:90;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;567:90:0;;;;;;;;;;;;;;;;48:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;164:351;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;567:90;611:11;;:::i;:::-;642:8;635:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;567:90;:::o;48:27::-;;;;;;;;;;;;;;;;;;;;;;;;;:::o;164:351::-;207:4;348:1;341:5;:8;;:21;;;;;360:2;353:5;:9;;341:21;333:30;;;;;;;;391:10;373:8;382:5;373:15;;;;;;;;;;;:28;;;;;;;;;;;;;;;;;;485:5;478:12;;164:351;;;:::o;25:635::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o",
"source": "pragma solidity ^0.4.2;\n\ncontract Adoption{\n address[16] public adopters;\n\n // 整数型のpetIdを入れると結果が整数型で返ってくる関数\n function adopt(uint petId) public returns (uint){\n\n // ペットは16匹しかいないので、範囲外のリクエストが来たら終わりとする\n require(petId>=0 && petId<=15);\n adopters[petId] = msg.sender; //トランザクション実行者のアドレスを入れ込む\n\n return petId; // petIdを返す\n }\n\n // adoptersの状況を取得する関数\n function getAdopters() public view returns (address[16]){\n \n return adopters;\n }\n\n}",
メインチェーンにデプロイするとバイトコードは誰でも見ようとすれば見れる状態になってしまいます。
したがって、コード上に直接秘密鍵を書いてしまうと読み取られてしまうらしいので要注意
#マイグレーション
migrations
の中に2_deploy_contracts.js
を作成してマイグレーションに必要なコードを記述します。
シンプルなのでささっとvimで作成&記述。
$ vi migrations/2_deploy_contracts.js
var Adoption = artifacts.require("Adoption");
module.exports = function(deployer){
deployer.deploy(Adoption);
};
意味はさっぱりわかりません。
そしてmigrateします。
$ truffle migrate
マイグレートされ、コントラクトがチェーン(今回はプライベートネット)の中にデプロイされました。
Ganacheを確認すると、index0のアドレスのetherが減り、BLOCKS
のメニューを見るとなにやらブロックができ、GASが使用されていることがわかります。
#スマートコントラクトのテスト
ちゃんと出来てるかチェックします。
性質上、デプロイするともう未来永劫そのままで修正不可能なのでテストは必須だからなのか、Truffleにはご丁寧に、テスト用のあれこれが用意されています。
test
フォルダができていると思うのでここにあれこれテスト用のものを作っていきます。
$ touch test/TestAdoption.sol
pragma solidity ^0.4.2;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol"; //デプロイしたアドレスを取得
import "../contracts/Adoption.sol"; //テスト対象のコントラクト
contract TestAdoption {
Adoption adoption = Adoption(DeployedAddresses.Adoption());
}
Assert.sol
ですが、Truffleに用意されてる変数の型などをチェックしてくれる関数が詰まったやつだそうです。
フルコードはこちら
8番のものを試しに買ってみて、想定する数値が返されるかのテストをコンストラクトの中に追記。
全文はこんな感じ。
pragma solidity ^0.4.2;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Adoption.sol";
contract TestAdoption {
Adoption adoption = Adoption(DeployedAddresses.Adoption());
// petIdの投入テスト
function testUserCanAdoptPet() public {
uint returnedId = adoption.adopt(8); //adopt関数は入れた数が返ってくるはず
uint expected = 8; // 8を入れたら8が返ってくるはず
// 結果が想定と正しくなかったらエラーメッセージを出す
Assert.equal(returnedId, expected, "Adoption of pet ID 8 should be recorded.");
}
// 8番にきちんと飼い主のアドレスが記録されているかのテスト
function testGetAdopterAddressByPetId() public {
address expected = this;
address adopter = adoption.adopters(8);
Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
}
// 配列の8番目にきちんと入っているかのテスト
function testGetAdopterAddressByPetIdInArray() public {
address expected = this;
address[16] memory adopters = adoption.getAdopters();
Assert.equal(adopters[8], expected, "Owner of pet ID 8 should be recorded.");
}
}
テストを実行
$ truffle test
なんだかんだあって、こんな感じのが出てればテスト合格です。
TestAdoption
✓ testUserCanAdoptPet (77ms)
✓ testGetAdopterAddressByPetId (64ms)
✓ testGetAdopterAddressByPetIdInArray (76ms)
3 passing (999ms)
コントラクト部分はこれでOKなので続いてWeb UIの部分を作っていきます。
後半へ続く