====== Truffleを使ったスマートコントラクト開発 ======
Truffle は ethereum スマートコントラクトのコンパイル、マイグレーション、テストを行うためのフレームワークです。
====== 必要なソフトウエア ======
Truffle は [[https://github.com/npm/cli|npm]] を使ってインストールしますので、事前に npm をインストールしてください。
[[https://nodejs.org/en/download/|npm パッケージ配布サイト]]
また、ethereum ブロックチェーンも使用しますので [[blockchain:ethereum構築ハンズオン_ganache編|ethereumブロックチェーンの構築(Ganache編)]] を参考に Ganache をインストールしてください。
====== インストール ======
> npm install -g truffle
====== 初期化 ======
> mkdir my_project
> cd my_project
> truffle init
Starting init...
================
> Copying project files to C:\Users\shinobu\NoNameSeminer\ethereum\my_project
Init successful, sweet!
Try our scaffold commands to get started:
$ truffle create contract YourContractName # scaffold a contract
$ truffle create test YourTestName # scaffold a test
http://trufflesuite.com/docs
生成されたファイルを確認してみます。
> tree /f
ボリューム シリアル番号は EEAF-D230 です
C:.
│ truffle-config.js
│
├─contracts
│ Migrations.sol
│
├─migrations
│ 1_initial_migration.js
│
└─test
.gitkeep
各ファイルとディレクトリの説明。
* truffle-config.js: truffle の設定ファイル。ethereum ブロックチェーンのアドレス等を設定する。
* contracts: スマートコントラクトのソースコードを格納するディレクトリ。最初からマイグレーションの現在のバージョンを管理するための「Migrations.sol」が作られています。
* migrations: マイグレーションの設定ファイルを格納するディレクトリ。最初からマイグレーションの現在のバージョンを管理するための「1_initial_migration.js」が作られています。
* test: テストコードを格納するディレクトリ。
====== 設定 ======
truffle-config.js を開いて、コメントを削除し以下のように変更してください。
* *Ganache に接続する場合の設定です。
* *__**port番号は 8545 から 7545 に変更しています。**__
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
====== Ganacheとの連携 ======
Ganache を起動し「NEW WORKSPACE」をクリックします。
{{:blockchain:ganache_truffle01.png?800|}}
「ADD PROJECT」をクリックし、先ほど作成した「truffle-config.js」を選択します。
{{:blockchain:ganache_truffle02.png?800|}}
{{:blockchain:ganache_truffle03.png?800|}}
これで Ganache と Truffle の連携設定は完了です。「SAVE WORKSPACE」をクリックしてください。
{{:blockchain:ganache_truffle04.png?800|}}
====== Truffle コンソール ======
> truffle console
truffle(development)>
====== スマートコントラクト ======
===== 生成 =====
truffle(development)> truffle create contract Counter
truffle(development)>
上記のコマンドで constracts ディレクトリの中に Counter.sol ファイルが生成されます。
===== 実装 =====
エディタで Counter.sol を開き、以下のように編集してください。
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract Counter {
uint public count;
// Function to get the current count
function get() public view returns (uint) {
return count;
}
// Function to increment count by 1
function inc() public {
count += 1;
}
// Function to decrement count by 1
function dec() public {
count -= 1;
}
}
===== コンパイル =====
truffle(development)> truffle compile
Compiling your contracts...
===========================
> Compiling .\contracts\Counter.sol
> Compiling .\contracts\Counter.sol
> Compiling .\contracts\Migrations.sol
> Artifacts written to C:\Users\shinobu\NoNameSeminer\ethereum\my_project\build\contracts
> Compiled successfully using:
- solc: 0.8.13+commit.abaa5c0e.Emscripten.clang
truffle(development)>
===== マイグレーションファイルの作成 =====
Counter コントラクトをデプロイするためのマイグレーションファイルを作成します。
truffle(development)> truffle create migration Counter
truffle(development)>
上記のコマンドで migrations ディレクトリの中に nnnnnnnn_counter.js ファイルが生成されます。
ファイルの以下のように書き換えて、Counter コントラクトをデプロイするように設定します。
const Counter = artifacts.require("Counter");
module.exports = function(_deployer) {
// Use deployer to state migration tasks.
_deployer.deploy(Counter)
};
===== デプロイ =====
truffle(development)> truffle migrate
Compiling your contracts...
===========================
> Compiling .\contracts\Counter.sol
> Compiling .\contracts\Migrations.sol
> Artifacts written to C:\Users\shinobu\NoNameSeminer\ethereum\my_project\build\contracts
> Compiled successfully using:
- solc: 0.8.13+commit.abaa5c0e.Emscripten.clang
Starting migrations...
======================
> Network name: 'development'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Replacing 'Migrations'
----------------------
> transaction hash: 0x09353f6ea3c2ce57acf8de3a9c2c1110fb2abfeea6d51d896477509d6e6edc6a
> Blocks: 0 Seconds: 0
> contract address: 0x9864601fA497E29d85720c336b15267Ff0a89386
> block number: 1
> block timestamp: 1651037552
> account: 0x12C1B9B5152b14CE5af7A83947971108Dc89e54D
> balance: 99.99502292
> gas used: 248854 (0x3cc16)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00497708 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00497708 ETH
1651036112_counter.js
=====================
Replacing 'Counter'
-------------------
> transaction hash: 0x45b148c06609f587e5636a17a088f6685fc2e05603aed75a54bfcf01ba881129
> Blocks: 0 Seconds: 0
> contract address: 0x852560406282C788aeF29AbD5A9313588d86c3dB
> block number: 3
> block timestamp: 1651037554
> account: 0x12C1B9B5152b14CE5af7A83947971108Dc89e54D
> balance: 99.99086736
> gas used: 165265 (0x28591)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0033053 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0033053 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.00828238 ETH
truffle(development)>
===== 実行 =====
Counter コントラクトを呼び出すためのインスタンスを取得する。
truffle(development)> let counter = await Counter.deployed()
undefined
truffle(development)>
Counter コントラクトの get を呼び出す。
truffle(development)> counter.get()
BN { negative: 0, words: [ 0, <1 empty item> ], length: 1, red: null }
truffle(development)>
:!: 「BN」は「BigNumber」という意味です。後々、テスト等で値の比較をするときに int とは扱いが変わってきますので、覚えておいてください。
Counter コントラクトの inc を呼び出す。
truffle(development)> counter.inc()
{
tx: '0x10e87f126ce0934123624a8bd0d9c70a7d2d492fd1ade783646e828ccad6ad42',
receipt: {
transactionHash: '0x10e87f126ce0934123624a8bd0d9c70a7d2d492fd1ade783646e828ccad6ad42',
transactionIndex: 0,
blockHash: '0xc95665ead9fae2045cff12ba600d778a99454fbcdfcafe257f6c5dee61f76917',
blockNumber: 5,
from: '0x12c1b9b5152b14ce5af7a83947971108dc89e54d',
to: '0x852560406282c788aef29abd5a9313588d86c3db',
gasUsed: 42229,
cumulativeGasUsed: 42229,
contractAddress: null,
logs: [],
status: true,
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
rawLogs: []
},
logs: []
}
truffle(development)>
もう一度、Counter コントラクトの get を呼び出す。(値が0から1になっている)
truffle(development)> counter.get()
BN { negative: 0, words: [ 1, <1 empty item> ], length: 1, red: null }
truffle(development)>
====== テスト ======
===== 生成 =====
truffle(development)> truffle create test SimpleCounterTest
truffle(development)>
上記のコマンドで test ディレクトリの中に simple_counter_test.js ファイルが生成されます。
===== 実装 =====
エディタで simple_counter_test.js を開き、以下のように編集してください。
const Counter = artifacts.require("Counter");
/*
* uncomment accounts to access the test accounts made available by the
* Ethereum client
* See docs: https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript
*/
contract("SimpleCounterTest", function (/* accounts */) {
it("should assert true", async function () {
await Counter.deployed();
return assert.isTrue(true);
});
it("Counter inc", async function () {
let counter = await Counter.deployed();
let before = await counter.get();
await counter.inc();
let after = await counter.get();
// before and after is BN(BigNumber)
return assert.equal(after.toNumber(), before.toNumber() + 1);
});
it("Counter dec", async function () {
let counter = await Counter.deployed();
let before = await counter.get();
await counter.dec();
let after = await counter.get();
// before and after is BN(BigNumber)
return assert.equal(after.toNumber(), before.toNumber() - 1);
});
});
===== 実行 =====
truffle(development)> truffle test
Using network 'development'.
Compiling your contracts...
===========================
> Compiling .\contracts\Counter.sol
> Compiling .\contracts\Migrations.sol
> Artifacts written to C:\Users\shinobu\AppData\Local\Temp\test--15628-Lt5184Kc9NTX
> Compiled successfully using:
- solc: 0.8.13+commit.abaa5c0e.Emscripten.clang
Contract: SimpleCounterTest
√ should assert true (55ms)
√ Counter inc (1361ms)
√ Counter dec (1419ms)
3 passing (3s)
truffle(development)>