🐣

ブロックチェーン開発メモ ~Truffle デプロイ編~

2023/11/23に公開

やりたいこと

Ethereum + Solidityでスマートコントラクトを実装したい。
前回: ブロックチェーン開発メモ ~Ethereum2.0 ネットワーク同期編~

Truffle サンプルプロジェクトを作る

主に https://trufflesuite.com/docs/truffle/quickstart/ に沿って行う。

まずはプロジェクトを作るところから始める。
Truffleにはサンプルプロジェクトが用意されているので、まずはそれを試してみる。

$ mkdir ./truffle-test1
$ cd ./truffle-test1
$ truffle unbox metacoin ./

コマンド実行後、指定したディレクトリにプロジェクトファイルが出力されるので、truffle-config.jsを開いてみる。

module.exports = {
// ~~
  compilers: {
    solc: {
      version: "0.8.13",      // Fetch exact version from solc-bin
    }
  }
};

solcjsのバージョンが0.8.13を示しているので、とりあえず自身の環境もそれに合わせておく。

$ npm uninstall -g solc
$ npm install -g solc@0.8.13
$ solcjs --version

テストを実行する

$ truffle test
Compiling your contracts...
===========================
✓ Fetching solc version list from solc-bin. Attempt #1
✓ Downloading compiler. Attempt #1.
> Compiling ./contracts/ConvertLib.sol
> Compiling ./contracts/MetaCoin.sol
> Compiling ./test/TestMetaCoin.sol
> Artifacts written to /tmp/test--4331-z5Y9Kzcsev39
> Compiled successfully using:
   - solc: 0.8.13+commit.abaa5c0e.Emscripten.clang

  TestMetaCoin
    ✔ testInitialBalanceUsingDeployedContract (78ms)
    ✔ testInitialBalanceWithNewMetaCoin (54ms)

  Contract: MetaCoin
    ✔ should put 10000 MetaCoin in the first account (49ms)
    ✔ should call a function that depends on a linked library (60ms)
    ✔ should send coin correctly (113ms)

  5 passing (4s)

コンパイルする

$ truffle compile
Compiling your contracts...
===========================
> Compiling ./contracts/ConvertLib.sol
> Compiling ./contracts/MetaCoin.sol
> Artifacts written to /home/vagrant/Desktop/projects/block-chain-test/build/contracts
> Compiled successfully using:
   - solc: 0.8.13+commit.abaa5c0e.Emscripten.clang

./build/contractsにJSONが出力される。

ローカルにデプロイする

スマートコントラクトをデプロイするには、メインネットやテストネットといったブロックチェーンにデプロイする必要があるが、Truffleにはテスト用にローカルで使用できるブロックチェーンが用意されている。
Truffleを使ってメインネットやテストネットにデプロイする方法は、またどこかで記載予定。

$ truffle develop
Truffle Develop started at http://127.0.0.1:9545/

Accounts:
(0) 0x2f8ecedd71ca2482c4a6466512095adb0e809720
(1) 0xddd0a152a9dba2d5d0141a37d31be8139739ac39
(2) 0xd23380e697c59f1d6bc37a8865218e385e769fe8
(3) 0x751c2b2c339c746d601e791fe0b17bef99962652
(4) 0x791be6829f14577f2a3b77ccf418a50aee88d89b
(5) 0x49b12ccbda7e6b57b6d48c490bd9d7af6ce30954
(6) 0xc837cffc2f940effb8418ea2b74fed21d59492ee
(7) 0xc44c095176f552b4cc0114d756b14dae5b67dc9d
(8) 0x064ce3aa53b87ba1b997c266066c626d699f7f2d
(9) 0xab2f5ca2b13d1804af7f29b87800ca0a5ad4d6a2

Private Keys:
(0) 99bb685fffdb298485b5c56e4c700c20341e7eda7af925a3bd132ba54f7afc98
(1) 96daf889b560e5c501da62d49a881140cd07c18c61372ebe851abde00a7c20ae
(2) 02a63d480401ed6defea76532a8673f59d550e7e0fab987f435c5e0754caf199
(3) 77ef7d76d40e11f90e8e85c4ed191da202155d2e5ed8f63c92a98cadad3ff525
(4) 4b627a7435bae4361e610ab40d41e237b17a375864b0671df6e467821b85fc8d
(5) da26caa0d051cf96f23de7f909eadca04e285d81fc1081094a9dec5adcc5e096
(6) 1a559ff31dfe7a4e7134682278f57c0485e47502c2adc04571f7bfc95e72c66c
(7) 0f1abdca38dfacd82bf0799eaac57d1215292a9269e64b0ace0289f1321d196d
(8) b9211d133ff2358af6c40b3a7fcc6711772fb4dc50de3e3112f79b6febda77ac
(9) 10116829a9e32ed98ad054fcbd846bc90d5cf3388c3f95f2fbcf0499dc68686f

Mnemonic: diagram naive such open soldier spice sound regret exact enter impose leopard

⚠️  Important ⚠️  : This mnemonic was created for you by Truffle. It is not secure.
Ensure you do not use it on production blockchains, or else you risk losing funds.

truffle(develop)>

migrateコマンドを実行するだけで、ローカルのブロックチェーンにコンパイル⇒デプロイが行われる。
デプロイは ./migrations/1_deploy_contracts.jsの内容に従って実行される。

truffle(develop)> migrate
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.

Starting migrations...
======================
> Network name:    'develop'
> Network id:      5777
> Block gas limit: 6721975 (0x6691b7)

1_deploy_contracts.js
=====================

   Deploying 'ConvertLib'
   ----------------------
   > transaction hash:    0xeb5782ec5f3136636152f79b2c81fe3fe8f820dd0d41329b1caf09fd19d8d432
   > Blocks: 0            Seconds: 0
   > contract address:    0x8f769C476B551033d784f0052f02C5BAecC4618C
   > block number:        1
   > block timestamp:     1700673166
   > account:             0x2f8eceDd71ca2482C4A6466512095AdB0E809720
   > balance:             99.9994680865
   > gas used:            157604 (0x267a4)
   > gas price:           3.375 gwei
   > value sent:          0 ETH
   > total cost:          0.0005319135 ETH

   Linking
   -------
   * Contract: MetaCoin <--> Library: ConvertLib (at address: 0x8f769C476B551033d784f0052f02C5BAecC4618C)

   Deploying 'MetaCoin'
   --------------------
   > transaction hash:    0xf5d98a825a322a59b4eeca87cf9e3627d8c09251b2a6a19d0abd353d047fa5da
   > Blocks: 0            Seconds: 0
   > contract address:    0xFFF84424a081Eb11991F9BbBb21DBbC91aCC4a70
   > block number:        2
   > block timestamp:     1700673166
   > account:             0x2f8eceDd71ca2482C4A6466512095AdB0E809720
   > balance:             99.9981051633782056
   > gas used:            416700 (0x65bbc)
   > gas price:           3.270753832 gwei
   > value sent:          0 ETH
   > total cost:          0.0013629231217944 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:     0.0018948366217944 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.0018948366217944 ETH

truffle(develop)>

ブロックチェーン上にデプロイ(トランザクション発行)するにはガス代がかかるが、ローカルのブロックチェーンなら開発用として無料で試せるのでぜひ活用していきたい。

Ganacheを使ってコントラクトを操作する

Ganacheで視覚的に情報を確認しながら、コントラクトを操作できる。

Truffleの設定を変更する

truffle-config.jsを開き、以下の様に変更する。

module.exports = {
~~~
  networks: {
~~~
    development: {
     host: "127.0.0.1",     // Localhost (default: none)
     port: 7545,            // Standard Ethereum port (default: none)
     network_id: "*",       // Any network (default: none)
    },
~~~
};

Ganacheを起動する

まずは起動する。

設定から ADD PROJECTを選択して、truffle-config.jsを指定。

再度デプロイする

改めてGanacheで確認できるようにデプロイする。

$ truffle migrate

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

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

1_deploy_contracts.js
=====================

   Replacing 'ConvertLib'
   ----------------------
   > transaction hash:    0x4052df8cc37e31b2b2d5f04b004dfbb159272f5191e6dbd14004007e455a702f
   > Blocks: 0            Seconds: 0
   > contract address:    0xEB5b97ca8DAd9D8d5EfD4534f2FF698D7B7Facce
   > block number:        1
   > block timestamp:     1700675871
   > account:             0xe8421bcd5E7092a51aA82900d001D5F86608bdCD
   > balance:             99.999468208
   > gas used:            157568 (0x26780)
   > gas price:           3.375 gwei
   > value sent:          0 ETH
   > total cost:          0.000531792 ETH

   Linking
   -------
   * Contract: MetaCoin <--> Library: ConvertLib (at address: 0xEB5b97ca8DAd9D8d5EfD4534f2FF698D7B7Facce)

   Replacing 'MetaCoin'
   --------------------
   > transaction hash:    0x16b84bda682d1b3b6855894360ea9ca344efc03dc250c88fb8e9699811454e62
   > Blocks: 0            Seconds: 0
   > contract address:    0x33D1e2e14474a050dEb6B653Fa7721Fb057C1103
   > block number:        2
   > block timestamp:     1700675871
   > account:             0xe8421bcd5E7092a51aA82900d001D5F86608bdCD
   > balance:             99.998105632065943366
   > gas used:            416594 (0x65b52)
   > gas price:           3.270752661 gwei
   > value sent:          0 ETH
   > total cost:          0.001362575934056634 ETH

   > Saving artifacts
   -------------------------------------
   > Total cost:     0.001894367934056634 ETH

Summary
=======
> Total deployments:   2
> Final cost:          0.001894367934056634 ETH

GanacheのTransactionsタブを確認すると、トランザクションの状況が確認できる。

コントラクトを操作する

Trrufleコンソールを開き、コントラクトを操作する。

$ truffle console

# MetaCoinコントラクトを保存
truffle(development)> let instance = await MetaCoin.deployed()
undefined
# アカウント一覧を保存
truffle(development)> let accounts = await web3.eth.getAccounts()
undefined
# コントラクトをデプロイしたアカウントのメタコイン残高を取得
truffle(development)> let balance = await instance.getBalance(accounts[0])
undefined
# 表示
truffle(development)> balance.toNumber()
10000
# イーサリアム換算でどれくらいかを取得
truffle(development)> let ether = await instance.getBalanceInEth(accounts[0])
undefined
# 表示(1メタコイン = 2イーサリアム)
truffle(development)> ether.toNumber()
20000
# 別アカウントに500メタコインを送信
truffle(development)> instance.sendCoin(accounts[1], 500)
{
  tx: '0xd2e62d332a87100e15f6d9b8ebdfbca94d90f4ee49c552926492c9f17c4a102b',
  receipt: {
    transactionHash: '0xd2e62d332a87100e15f6d9b8ebdfbca94d90f4ee49c552926492c9f17c4a102b',
    transactionIndex: 0,
    blockNumber: 3,
    blockHash: '0xee63b714688f82283256a4bc51584b4a86d4b3315749d9d7ff39c3f0704eda47',
    from: '0xe8421bcd5e7092a51aa82900d001d5f86608bdcd',
    to: '0x33d1e2e14474a050deb6b653fa7721fb057c1103',
    cumulativeGasUsed: 52297,
    gasUsed: 52297,
    contractAddress: null,
    logs: [ [Object] ],
    logsBloom: '0x00008000001000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000002000008000000000000000000000000000020000000000080000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000',
    status: true,
    effectiveGasPrice: 3186350418,
    type: '0x2',
    rawLogs: [ [Object] ]
  },
  logs: [
    {
      address: '0x33D1e2e14474a050dEb6B653Fa7721Fb057C1103',
      blockHash: '0xee63b714688f82283256a4bc51584b4a86d4b3315749d9d7ff39c3f0704eda47',
      blockNumber: 3,
      logIndex: 0,
      removed: false,
      transactionHash: '0xd2e62d332a87100e15f6d9b8ebdfbca94d90f4ee49c552926492c9f17c4a102b',
      transactionIndex: 0,
      id: 'log_fb3c9158',
      event: 'Transfer',
      args: [Result]
    }
  ]
}
# 別アカウントのメタコイン残高を確認
truffle(development)> let received = await instance.getBalance(accounts[1])
undefined
truffle(development)> received.toNumber()
500
# コントラクトをデプロイしたアカウントのメタコイン残高を確認
truffle(development)> let newBalance = await instance.getBalance(accounts[0])
undefined
truffle(development)> newBalance.toNumber()
9500

以上。

Discussion