【Blockchain】SmartContractを手動コンパイルして、ローカル環境(Ganache)にデプロイ&テスト


SmartContract を開発するためのフレームワーク Truffle.js などがありますが、今回は、仕組みを理解するために手動でコンパイルして BytecodeABI (Application Binary Interface) を取得します。
そして、ローカル環境の Blockchain ネットワークにデプロイ&テストをします。

Bytecode と ABI に関して

Bytecode (バイトコード)は、ブロックチェーンに上げるための SmartContract のバイナリコードです。EVM (Ethereum Virtual Machine) 仮想マシンによって実行されます。
ABI (Application Binary Interface) は、 Bytecode の機能や入力と出力などの情報が Json 形式で記載されています。ABI を見れば SmartContract にどういう機能を持っているのかがざっくり分かります。

コンパイルするファイルたち

MyProkject/
├─ .vscode
│  └─ settings.json
├─ contracts
│  └─ SampleContract.sol
└─ scripts
   └─ compile.js
  • /.vscode/settings.json に関しては、こちらの記事をご参照ください。
  • /contracts/ フォルダーには、開発する SmartContract プログラムを入れます。この例では、 SampleContract.sol を入れました。
  • /scripts/compile.js には、コンパイルするための Javascript で記載したスクリプトを入れます。
compile.js
// ライブラリのインポート
const path = require('path');   // ファイルパスを操作するためのライブラリ
const fs = require('fs');       // ファイルを読み書きするためのライブラリ
const solc = require('solc');   // Solidity言語のプログラムをコンパイルするためのライブラリ
const chalk = require('chalk'); // ログ出力に色をつけるためのライブラリ

// プログラムファイルのパスを設定
const contractPath = path.resolve(__dirname, "../contracts", "SampleContract.sol");

// プログラムファイルを読み込む
const source = fs.readFileSync(contractPath, 'utf8');

// プログラムをコンパイルし、Bytecode と ABI を取得する
const {abi, bytecode} = solc.compile(source, 1).contracts[':SampleContract'];

// Bytecode と ABI をログ出力する
console.log(chalk.green(bytecode));
console.log(chalk.cyan(abi));

コンパイル

ターミナルでプロジェクトのパスを開いて、次のコマンドを実行します。

node ./scripts/compile.js 

すると、コンパイルが行われ、結果としてログに緑色で Bytecode とシアン色で ABI が出力されます。
でも、これだと BytecodeABI をログ出力するだけなので、次は、ローカル環境に Blockchain の開発用のネットワーク環境を構築して、そこに開発した SmartContract をデプロイしたいと思います。

Ganache

Ganache は、 Blockchain の開発用のネットワーク環境です。

  • 次のアドレスからダウンロード、インストールします。

    https://truffleframework.com/ganache

  • 立ち上げると、次の画面が表示されるので、「QUICKSTART」をクリックします。

  • すると、ネットワークが構築され、100ETHを持つ10のアカウントが用意されます。

  • BLOCKS タブをクリックすると、ネットワークに保持される Blockchain が表示されます。最初は、開始ブロックである BLOCK 0 だけが存在します。このブロックは Block Genesys とも呼ばれています。

Deploy & Test

  • テスト用のライブラリをインストールします。
npm install --save-dev mocha@{バージョン}
  • /scripts/compile.js を次のように変更します。
compile.js
// ライブラリのインポート
const path = require('path');   // ファイルパスを操作するためのライブラリ
const fs = require('fs');       // ファイルを読み書きするためのライブラリ
const solc = require('solc');   // Solidity言語のプログラムをコンパイルするためのライブラリ

// プログラムファイルのパスを設定
const contractPath = path.resolve(__dirname, "../contracts", "SampleContract.sol");

// プログラムファイルを読み込む
const source = fs.readFileSync(contractPath, 'utf8');

// プログラムをコンパイルし、外部へ export する
module.exports = solc.compile(source, 1).contracts[':SampleContract'];
  • テスト用のスクリプト /test/SampleContract.test.js を作成します。
SampleContract.test.js
// ライブラリのインポート
const assert = require('assert');  // テスト assert をするためのライブラリ
const Web3 = require('web3');      // ローカル環境(Ganache)と接続するためのライブラリ

// ローカル環境(Ganache)と接続するためのオブジェクトを生成
const provider = new Web3.providers.HttpProvider("HTTP://127.0.0.1:7545");
const web3 = new Web3(provider);

// コンパイルスクリプトからBytecodeとABIを取得する
const {abi, bytecode} = require('../scripts/compile');

// 変数定義
let accounts;        // Ganacheで提供される10アカウントを保持する
let sampleContract;  // デプロイしたSmartContractを保持する

// 各テストを実行する前に実行する
beforeEach(async() => {
    // アカウントを取得する
    accounts = await web3.eth.getAccounts();
    // ABIとBytecodeを一番最初のアカウントを使ってデプロイ
    usersContract = await new web3.eth.Contract(JSON.parse(abi))  // ABI
        .deploy({data: bytecode})                                 // Bytecode
        .send({from: accounts[0], gas: '1000000'});               // 一番最初のアカウント、GAS=1000000
});

// テスト 'The UsersContract' 開始
describe('The UsersContract', async() => {
    // 1つ目のテスト: デプロイできたか?
    it('should deploy', () => {
        console.log(usersContract.options.address);
        assert.ok(usersContract.options.address);
    });
});
  • /package.json"test": "mocha" にする。
{
  "name": "myproject",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "mocha"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chalk": "^2.4.2",
    "mocha": "^5.2.0",
    "solc": "^0.4.24",
    "web3": "^1.0.0-beta.35"
  }
}
  • 次のコマンドでテストを実行して、Deployを確認します。
npm run test
  • 成功すると、ログに次のような出力を確認できます。
> [email protected] test /myproject
> mocha

  The UsersContract
0xdabBD1955e2873bB498A6F1f149A8A0d74f48170
    ✓ should deploy


  1 passing (72ms)
  • また、 GanacheTRANSACTIONS タブで SmartContract のデプロイができたことも確認できます。