【中編】Ethereum Pet Shop DAppの作成とテスト~コントラクト作成編~
IT技術
~中編~Ethereum Pet ShopでDApp作成とテスト
今回は、前回に引き続き、「Ethereum Pet Shopを使って DAppの作成からテスト」までを行ってみたいと思います!
前編では、環境構築を行っていきましたが、今回からは実際にコントラクトを作成していきたいと思います!
作成工程
- 環境設定
- Truffle Box を使って Truffle プロジェクトを作成
- コントラクト作成
- コントラクトをコンパイルしてデプロイ
- コントラクトのテスト
- UI 作成
- ブラウザ上の DApp でログインする
コントラクトの作成
それでは、実際にコントラクトを作成していきましょう!
contract フォルダー内にファイルを作成
Solidity のソースファイルである contract フォルダー内に、「Adoption.sol」ファイルを作成します。
そして、以下のコードを記入していきます。
1pragma solidity ^0.5.0;
2contract Adoption {
3address[16] public adopters;
4// adopter変数のIDの領域
5function adopt(uint petId) public returns (uint) {
6 require(petId >= 0 && petId <= 15);
7 adopters[petId] = msg.sender;
8 return petId;
9}
10// getAdopters( )関数で設定したadopters変数の戻り値
11function getAdopters() public view returns (address[16] memory) {
12 return adopters;
13}
14}
コード解説
PetShop のコントラクト作成は、web3 と連携するため、以下のような仕様になります。
- function で public の adopters 変数と petID (引数)を設定
- 引き渡しは address 型(戻り値を修正しない view で宣言)
- MetaMask と Ganache に設定したアドレスで開く
コントラクトのコンパイルとデプロイ
EVM の実行のため、コントラクトをコンパイルしてバイトコードに変換します。
DApp が含まれているディレクトリーで、ターミナルに以下のコマンドを入力します。
1truffle compile
マイグレーションファイルの作成
マイグレーションファイルが、コントラクトを EVM へデプロイしてくれます。
migration フォルダーの中に、「1_initial_migration.js」ファイルがあります。
これが「migration.sol」の操作ファイルで、コントラクトが二重にコンパイルされるのを防ぎます。
「2_deploy_contract.js」ファイルを作成
migration フォルダーに、「2_deploy_contract.js」というファイルを作成します。
そして、以下のコードを書き込みます。
1var Adoption = artifacts.require("Adoption");
2
3module.exports = function(deployer) {
4 deployer.deploy(Adoption);
5};
コントラクトのデプロイ
ターミナルで以下のコマンドを入力し、デプロイします。
1truffle develop
2truffle(develop)>migrate
コントラクトのテスト
それでは、コントラクトをテストしてみましょう!
Ganache アカウントの作成
Ganache の workspace に「truffle-config.js」をアップロードします。
Gas の設定
アカウント作成後は、全ての Blockchain に、テスト用として100Ether ずつ入っています。
この Ether は、デプロイする度に Gas(送金料)が消費されます。
Gas と RPC Server の設定は、以下のようになります。
コントラクトのテスト
PetShop 解凍時に、空のテスト用フォルダーが生成されています。
このフォルダーの中に「TestAdoption.sol」を作成し、以下のコードを記入します。
1 pragma solidity ^0.5.0;
2
3 //上記2つのコントラクトは外部のグローバルフォルダーからインポートします
4
5 import "truffle/Assert.sol";
6 import "truffle/DeployedAddresses.sol";
7 import "../contracts/Adoption.sol";
8
9 contract TestAdoption {
10 // TestAdoption関数にadoptiin変数でデプロイされたアドレスを読み込む
11 Adoption adoption = Adoption(DeployedAddresses.Adoption());
12
13 // テストに使われるペットのID
14 uint expectedPetId = 8;
15
16 //アドレス型のexpectedAdopter変数の戻り値
17 address expectedAdopter = address(this);
18
19 }
最初にインポートしている3つのファイルの内、「Assert.sol」と「DeployedAddresses.sol」はグローバルのTruffleファイルなので、プロジェクトフォルダーの中には有りません。
この2つのファイルの役割は、以下のようになります。
Assert.sol
テスト時の確認作業を行います。
テストから成功/失敗を返すために、「同等(EQ)」「不等(NE)」などをチェックします。
DeployedAddresses.sol
テストを実行すると、デプロイされたコントラクトのアドレスを取得します。
関数設定
このコードには、以下の3つの wide variables (変数)が含まれています。
- DeployedAddresses
- expectedPetID
- expectedAdopter
uint型「expectedPetID」の引数8の戻り値が、address型「expectedAdopter」に返されます。
adopt()関数のコード修正
テストのため、adopt()関数のコードを修正します。
仕様は以下のようになります。
- expectedPetID を事前に宣言
- テストが成功したら、Assert.equal()に ID を返す
- 失敗したら、コンソールに「Adoption of the expected pet should match what is returned.」を表示
「TestAdoption.sol」コントラクトの「Adoption」変数の後に、以下のコードを追加してください。
1pragma solidity ^0.5.0;
2
3import "truffle/Assert.sol";
4import "truffle/DeployedAddresses.sol";
5import "../contracts/Adoption.sol";
6
7contract TestAdoption {
8 // adoption変数のアドレスの戻り値をテスト
9 Adoption adoption = Adoption(DeployedAddresses.Adoption());
10
11// adopt() 関数のテスト
12function testUserCanAdoptPet() public {
13 uint returnedId = adoption.adopt(expectedPetId);
14
15 Assert.equal(returnedId, expectedPetId, "Adoption of the expected pet should match what is returned.");
16}</span>
17
18 // テストに使われるペットのID
19 uint expectedPetId = 8;
20
21 // アドレス型のexpectedAdopter変数の戻り値
22 address expectedAdopter = address(this);
23
24}
単一ペットオーナー受け入れ確認テスト
まず、単一ペットオーナー受け入れ確認テストをします。
public 変数は、自動ゲッターメソッドなので、上記の Adoption Test で格納したアドレスをそのまま取得できます。
また、保存されたデータはテスト中は存続するため、expectedPetID の値は他のテストでも取得可能です。
TestAdoption.sol をコード修正
「TestAdoption.sol」コントラクトを、以下のコードに修正します。
1ragma solidity ^0.5.0;
2
3import "truffle/Assert.sol";
4import "truffle/DeployedAddresses.sol";
5import "../contracts/Adoption.sol";
6
7contract TestAdoption {
8 // TestAdoption関数内でadoption変数で値を読み込む
9 Adoption adoption = Adoption(DeployedAddresses.Adoption());
10
11// testUserCanaAdoptPet()関数内でadopt()変数の値returnedID,expectedPetIdを検索して等価の場合は値を返し、不等価の場合はメッセージを返す。
12
13function testUserCanAdoptPet() public {
14 uint returnedId = adoption.adopt(expectedPetId);
15
16 Assert.equal(returnedId, expectedPetId, "Adoption of the expected pet should match what is returned.");
17}
18
19 <span style="color: #ff0000;" data-mce-style="color: #ff0000;">
20 // ペットオーナーが同一のデータ検索テスト
21 function testGetAdopterAddressByPetId() public {
22 address adopter = adoption.adopters(expectedPetId);
23
24 Assert.equal(adopter, expectedAdopter, "Owner of the expected pet should be this contract");
25 }
26</span>
27
28
29 // テストに使われるペットのID
30 uint expectedPetId = 8;
31
32 //アドレス型のexpectedAdopter変数の戻り値
33 address expectedAdopter = address(this);
34
35}
全てのペットオーナーの受け入れ確認テスト
続いて、すべてのペットオーナーの受け入れ確認テストをします。
配列は、単一キーを指定すると単一の値しか返せません。
そのため、配列全体に対して独自のゲッターを作成しましょう。
TestAdoption.sol をコード修正
以下のコードを「TestAdoption.sol」に追加し、修正します。
1pragma solidity ^0.5.0;
2
3import "truffle/Assert.sol";
4import "truffle/DeployedAddresses.sol";
5import "../contracts/Adoption.sol";
6
7contract TestAdoption {
8 // テストされる adoptionコントラクトのアドレス
9 Adoption adoption = Adoption(DeployedAddresses.Adoption());
10
11// adopt() 関数をテストする
12function testUserCanAdoptPet() public {
13 uint returnedId = adoption.adopt(expectedPetId);
14
15 Assert.equal(returnedId, expectedPetId, "Adoption of the expected pet should match what is returned.");
16}
17
18// ペットオーナーが同一のデータ検索のテスト
19function testGetAdopterAddressByPetId() public {
20 address adopter = adoption.adopters(expectedPetId);
21
22 Assert.equal(adopter, expectedAdopter, "Owner of the expected pet should be this contract");
23}
24
25//全てのペットオーナーの検索テスト
26function testGetAdopterAddressByPetIdInArray() public {
27 // メモリー内のadopter変数に値を格納する
28 address[16] memory adopters = adoption.getAdopters();
29
30 Assert.equal(adopters[expectedPetId], expectedAdopter, "Owner of the expected pet should be this contract");
31}
32</span>
33 // テストに使われるペットのID
34 uint expectedPetId = 8;
35
36 //アドレス型のexpectedAdopter変数の戻り値
37 address expectedAdopter = address(this);
38
39}
メモリー属性に注意!
ここで、「adopter 変数のメモリー属性」に注意してください。
メモリー属性は、値をコントラクトのストレージに保存するのではなく、メモリーに一時保存するよう Solidity に指示します。
adopter 変数は配列であり、最初の adoption test から、「expectedPetID」が存続しています。
そのため、「testGetAdopterAddressByPetIdInArray()」関数で、配列内の「expectedPetID」と「expectedAdopter」の戻り値を比較して検索します。
テストを実行
以下のコードを、ターミナルで入力します。
1truffle test
テスト終了後の画面
以上で、ローカルのブロックチェーンにコントラクトを作成・展開し、コンソールで操作できるようになりました!
おすすめの本
後編へ続く
後編では、UI を作成していきたいと思います!
お楽しみに!
こちらの記事もオススメ!
2020.08.14ブロックチェーン特集知識編ブロックチェーンとコンセンサスアルゴリズム実装編【Blockchain Data Managerを使ってみたEt...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
後編はこちら
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
「好きを仕事にするエンジニア集団」の(株)ライトコードです! ライトコードは、福岡、東京、大阪、名古屋の4拠点で事業展開するIT企業です。 現在は、国内を代表する大手IT企業を取引先にもち、ITシステムの受託事業が中心。 いずれも直取引で、月間PV数1億を超えるWebサービスのシステム開発・運営、インフラの構築・運用に携わっています。 システム開発依頼・お見積もり大歓迎! また、現在「WEBエンジニア」「モバイルエンジニア」「営業」「WEBデザイナー」を積極採用中です! インターンや新卒採用も行っております。 以下よりご応募をお待ちしております! https://rightcode.co.jp/recruit
おすすめ記事
immichを知ってほしい
2024.10.31