Dockerで構築するEthereum PET-SHOP TRUFFLE BOXES(その2)


その1からの続きでで、ETHEREUM PET SHOP チュートリアルをやっていきます。

Writing the smart contract

バックエンドとして動作するスマートコントラクト、Adoption.sol を作成していきます。

記述結果はこのようになります。

Adoption.sol
pragma solidity ^0.5.0;

contract Adoption {
    address[16] public adopters;

    // Adopting a pet
    function adopt(uint petId) public returns (uint) {
        require(petId >= 0 && petId <= 15);

        adopters[petId] = msg.sender;

        return petId;
    }

    // Retrieving the adopters
    function getAdopters() public view returns (address[16] memory) {
        return adopters;
    }

Compiling and migrating the smart contract

コンパイルは、

$ truffle compile

を叩きます。Docker環境の中で。これがポイント。

普通にやるのであれば、docker-compose up で起動中の環境を、Ctrl+Cで終了。
改めて、

$ docker-compose up -d

でバックグラウンド起動。
この状態で、Docker内のshellに入ります。
下記の、「truffle」は、docker-compose.yml で、services:の下で指定している名前。

$ docker-compose run truffle sh
/usr/src/app # 

こんな感じで表示されますので、truffle compile を実行します。

/usr/src/app # truffle compile
You can improve web3's performance when running Node.js versions older than 10.5.0 by installing the (deprecated) scrypt package in your project

Compiling your contracts...
===========================
> Compiling ./contracts/Adoption.sol
> Artifacts written to /usr/src/app/build/contracts
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang

成功です。

続いてマイグレーション。マイグレーションファイルを使って、ネットワークにデプロイします。

元々準備されている、migrations/1_initial_migration.js は、trrfle プロジェクトを作成した際に作られるもので、Migrations.sol をデプロイするということだけを書いているのですね。
そこで、Adoption.sol をデプロイするための、2_deploy_contracts.js を作ります。

やっている内容は、対象が違うだけで、1_initial_migration.js と同じです。

2_deploy_contracts.js
var Adoption = artifacts.require("Adoption");

module.exports = function(deployer) {
  deployer.deploy(Adoption);
};

マイグレートする前には、ganache が起動していることを確認しておきます。
RPC SERVER
HTTP://10.200.10.1:7545
です。

そして、コンパイル時に、Docker環境に入っていると思いますので、実行します。

/usr/src/app # truffle migrate
You can improve web3's performance when running Node.js versions older than 10.5.0 by installing the (deprecated) scrypt package in your project

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Starting migrations...
======================
> Network name:    'development'
> Network id:      5777
> Block gas limit: 0x6691b7


2_deploy_contracts.js
=====================

   Deploying 'Adoption'
   --------------------
   > transaction hash:    0x60f8967bc9aff355dac281fe96576362ea57bcc8b461466ee6eb19e7df645b76
   > Blocks: 0            Seconds: 0
   > contract address:    0xb25D78Fc89CE462816Aa4596e93b9a31CAfC176E
   > block number:        7
   > block timestamp:     1585479243
   > account:             0xc55F3d6C444ca88f529F3413EDEd85a39e38609C
   > balance:             99.98329494
   > gas used:            239915
   > gas price:           20 gwei
   > value sent:          0 ETH
   > total cost:          0.0047983 ETH


   > Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:           0.0047983 ETH


Summary
=======
> Total deployments:   1
> Final cost:          0.0047983 ETH

成功です。ganacheの画面でも、current block が増加し、最初のアカウントのetherが減少しています。

Testing the smart contract

次は、テストを書いていきます。テストは、JavaScript でも、Solidity でも書けるそうです。チュートリアルでは、Solidity で書いていきます。

Adoption.sol は、
- address[16] public adopters
- function adopt(uint petId) public returns (uint)
- function getAdopters() public view returns (address[16] memory)
のPublic 変数、Functionがありますので、それらをテストします。

チュートリアルに従って記述していくと、下記のようになります。

TestAdoption.sol
pragma solidity ^0.5.0;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Adoption.sol";

contract TestAdoption {
    // The address of the adoption contract to be tested
    Adoption adoption = Adoption(DeployedAddresses.Adoption());

    // Testing the adopt() function
    function testUserCanAdoptPet() public {
        uint returnedId = adoption.adopt(expectedPetId);

        Assert.equal(returnedId, expectedPetId, "Adoption of the expected pet should match what is returned.");
    }

    // Testing retrieval of a single pet's owner
    function testGetAdopterAddressByPetId() public {
        address adopter = adoption.adopters(expectedPetId);

        Assert.equal(adopter, expectedAdopter, "Owner of the expected pet should be this contract");
    }

    // Testing retrieval of all pet owners
    function testGetAdopterAddressByPetIdInArray() public {
        // Store adopters in memory rather than contract's storage
        address[16] memory adopters = adoption.getAdopters();

        Assert.equal(adopters[expectedPetId], expectedAdopter, "Owner of the expected pet should be this contract");
    }

    // The id of the pet that will be used for testing
    uint expectedPetId = 8;

    //The expected owner of adopted pet is this contract
    address expectedAdopter = address(this);

}

コンソールはDocker環境に入っていると思いますので、そこでテストを実行します。

/usr/src/app # truffle test
You can improve web3's performance when running Node.js versions older than 10.5.0 by installing the (deprecated) scrypt package in your project
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./test/TestAdoption.sol
> Artifacts written to /tmp/test-2020229-61-u4mbmv.pjgpm
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang



  TestAdoption
    ✓ testUserCanAdoptPet (140ms)
    ✓ testGetAdopterAddressByPetId (147ms)
    ✓ testGetAdopterAddressByPetIdInArray (164ms)


  3 passing (10s)

成功しました。

Creating a user interface to interact with the smart contract

では、UIの作成に入っていきます。

(いったん公開して、その3に続けていきます。)