Help us understand the problem. What is going on with this article?

Ethereumのフレームワーク「Truffle」とローカル開発環境「Ganache」入門ログ

More than 1 year has passed since last update.

概要

Ethereumを使ったスマートコントラクトの開発をしていて、ローカルの開発環境としてGanacheが便利だよ、と聴いたのでその入門ログを残します。

リアルタイムで導入しながら記事を書いています。たまにはこういう記事の書き方もいいですね。

前提

当方、メインネットへのスマートコントラクトのデプロイ(という言い方が正しいかどうかすらわからない)とかやったことないですし、入門書を読んで一通りやったくらいです。
これくらいのレベルの人間でも環境構築して動作させるくらいは訳ない、という意味でのGanache解説記事だと思っていてくださいm(_ _)m

導入手順

Google検索

「Ethereum Ganache」でGoogle検索すると

Ethereum のローカル開発環境 Ganache を使ってみる
Truffle Suite | Ganache - Truffle Framework
Ganache で始める Ðapp 開発
あたりが出てきました。

まあ公式を見るのが最善でしょう。ブロックチェーン領域はメジャーバージョンアップで過去のドキュメントが参考にならなくなることもしばしば。

公式のクイックスタートを見ながらやってみます。

Ganacheのダウンロード

GitHub ReleasesからDMGファイルを落とします。

次に、CLIをインストールします。と思ったのですがこれはデスクトップ版とCLI版がある、ということなんですね。せっかくなのでこちらも入れてみます。

npm install -g ganache-cli
+ ganache-cli@6.1.8
added 4 packages from 36 contributors in 32.249s

READMEによると、Dockerバージョンもあるみたいですね。

docker run -d -p 8545:8545 trufflesuite/ganache-cli:latest

CLIバージョンでスマートコントラクトの実行を試す

デスクトップ版を使っている解説記事が多いですが、ここではあえてCLIで。
ganache-cliコマンドを叩くと、それだけでGanacheが起動するようです。

$ ganache-cli
Ganache CLI v6.1.8 (ganache-core: 2.2.1)

Available Accounts
==================
(0) 0x6c96ae5a0710680aaa4c57b5683b2bf89343HOGE (~100 ETH)
(1) 0x85aa9d90973598ef2cf8f08a37a16421034aHOGE (~100 ETH)
・・・
Gas Price
==================
20000000000

Gas Limit
==================
6721975

Listening on 127.0.0.1:8545

本当かな?ということで試してみましょう。

まずは適当なスマートコントラクトを記述します。

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

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

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

次に、マイグレーションファイルを書きます。

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

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

これらをそれぞれcontracts、migrationsディレクトリに入れて、

npm install -g truffle
truffle compile
truffle migrate

を叩きます。このあたりはTruffleの公式ドキュメントにも書かれているので、そちらを参照しながら進めてください。

Ganacheによってすでにローカル開発環境としてブロックチェーンが起動しているので、スマートコントラクトがデプロイされます。(デプロイって単語は合っているのかな)

Running migration: 2_deploy_dapps_token.js
  Deploying DappsToken...
  ... 0xcab58c136b6bafe5c7eb7fa4aaHOGE42cb6589d93cd9fc62cfa99ae3598aHOGE
  DappsToken: 0xd4f045b7615084aHOGE9441357203dd4e079HOGE
Saving successful migration to network...
  ... 0xd58206d125c10cb5f457a2de854bc2HOGE1d5819177f902c38c8b7b1396eHOGE
Saving artifacts...

次に、スマートコントラクトを実行できるプログラムを書きます。Node.jsを採用しました。余談ですがasync awaitはやっぱり便利ですね・・・。やっていることは、2者で送受金やっているだけです。

execContract.js
var Web3 = require('web3');
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));

class web3Client {
  constructor() {
    this.ERC20_TOKEN = '0xd4f045b7615084aHOGE9441357203dd4e079HOGE';
  }
  get contract() {
    return new web3.eth.Contract(this.minAbi, this.ERC20_TOKEN);
  }
  get minAbi() {
    return [
      // balanceOf
      {
        "constant": true,
        "inputs": [{
          "name": "_owner",
          "type": "address"
        }],
        "name": "balanceOf",
        "outputs": [{
          "name": "balance",
          "type": "uint256"
        }],
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [{
            "name": "_to",
            "type": "address"
          },
          {
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "transfer",
        "outputs": [{
          "name": "",
          "type": "bool"
        }],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      // decimals
      {
        "constant": true,
        "inputs": [],
        "name": "decimals",
        "outputs": [{
          "name": "",
          "type": "uint8"
        }],
        "type": "function"
      }
    ];
  }
  async getBalance(account) {
    return new Promise((resolve, reject) => {
      this.contract.methods.balanceOf(account).call({
        from: account
      }, (error, balance) => {
        resolve(balance);
      });
    });
  }
  async transfer(from, to, value = 1) {
    return new Promise((resolve, reject) => {
      this.contract.methods.transfer(to, value).send({
        from
      }, (error, transactionHash) => {
        resolve(transactionHash);
      });
    })
  }
}

const _main_ = async () => {
  let balance = await new web3Client().getBalance('0x6c96ae5a0710680aaa4c57b5683b2bf89343HOGE');
  console.log('送信者の残高', balance);
  balance = await new web3Client().getBalance('0x85aa9d90973598ef2cf8f08a37a16421034aHOGE');
  console.log('受信者の残高', balance);
  const transferResult = await new web3Client().transfer('0x6c96ae5a0710680aaa4c57b5683b2bf89343HOGE', '0x85aa9d90973598ef2cf8f08a37a16421034aHOGE', 1);
  console.log('送信に成功しました。トランザクション:', transferResult);
  balance = await new web3Client().getBalance('0x6c96ae5a0710680aaa4c57b5683b2bf89343HOGE');
  console.log('送信者の残高', balance);
  balance = await new web3Client().getBalance('0x85aa9d90973598ef2cf8f08a37a16421034aHOGE');
  console.log('受信者の残高', balance);
}

_main_();

ソースコード中のポイントを書いておきます。

Ganacheを起動したときに、8545ポートで起動したというコンソールへのログが出ていたので、それをそのまま書きます。

const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545'));

スマートコントラクトをデプロイしたときに、DappsToken: hogehogehoge...というログが出ていたと思うのですが、それをコピーして定数に入れます。
この辺はどう考えても環境変数に持たせたほうがいいので、実際に開発するときはそのあたりも考えてください。

    this.ERC20_TOKEN = '0xd4f045b7615084aHOGE9441357203dd4e079HOGE';

あとはGanacheを起動したときに「Available Accounts」として出てきたアカウントから任意の2アカウントを選んで、getBalanceとtransfer関数の引数に渡すようにしています。

以上のソースコードを実行すると

$ node execContract.js
送信者の残高 1
受信者の残高 999
送信に成功しました。トランザクション: 0xcdcded20fa32c4e6754db630c05b25697a9b1309f58a012b6f7228fe546e7f0f
送信者の残高 0
受信者の残高 1000

このように、送金に成功していることがわかります。1000イーサ持っている方から送らせたほうが見栄えが良かったですがもう気にしない・・・

CLIに戻ってみると、ログが出ています。

eth_gasPrice
eth_sendTransaction

  Transaction: 0xcdcded20fa32c4e6754db630c05b25697a9b1309f58a012b6f7228fe546e7f0f
  Gas usage: 21547
  Block Number: 9
  Block Time: Wed Oct 24 2018 14:53:29 GMT+0900 (JST)

eth_getTransactionReceipt

まとめ

特にまとまりのない記事でしたが、見よう見まねで自分のPCでブロックチェーンを動かすことに成功しました。
以前Gethを使ってEthereumを動かしたことがあったのですが、コマンドは長いしマイニングも自分で実行しないといけないしで、かなり面倒だったところが、今回はコマンド一発でそちら側の構築が終わるというのはなかなかお手軽です。

Truffle側のドキュメントも目を通してみてますが、サンプルも豊富なので勉強が捗りそうです。

mejileben
オンライン家庭教師マナリンク(https://manalink.jp/)のCTOです。好きなプログラミング言語はTypeScript。好きなCSSプロパティはtransform。好きなAWSのサービスはLambdaです。 経歴は奈良高専卒→LIFULLでHOME'SのWebエンジニアを3年→2019年現職に転職。 技術スキルはWebフルスタックで、SEOやUIデザインもよしなにカバーします。
https://meijin.me
noschool
中高生向けのオンライン家庭教師サービス”マナリンク”を開発・運営しています。2018年創立のベンチャー企業です。
https://manalink.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away