DockerでTruffleを動かせるようにする方法

## 背景
https://www.oreilly.co.jp/books/9784873119342/  
↑こちらの書籍でスマートコントラクトの[勉強会](https://nkutomi.educ.kyoto-u.ac.jp/)を進めていましたが、
第３章で環境構築を行う際にバージョンが古くなっていたため,本の通りには作業を進められず対応に苦慮しました。  
具体的にはParityというイーサリアムクライアント(HTTPクラインアントのイーサリアムネットワーク版みたいなもの)がすでにgithubでアーカイブされており、今後の開発も行われないとのことで、我々には使うことができなくなっていました。  
![スクリーンショット 2023-07-17 15.37.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2708192/55747773-3612-7bbf-7f9f-afa5837a0db7.png)

ここでは代替案としてDockerを使って環境構築を行いましたので、ここで備忘録的にまとめます([参考にしたサイト](https://qiita.com/kane-hiro/items/81db353b5b1e50b6aae5))。

## Truffleとは
Truffleは、イーサリアムを用いるアプリケーション開発をするために必要になるフレームワークです。  
詳しくは[こちら](https://baasinfo.net/?p=3331)。

## 解決手順(CUI)
### 環境構築
まずはubuntu環境を作るところから。
```
docker run -it --name truffle -v ${PWD}/app:/app ubuntu:22.04
apt update && apt upgrade -y && apt install -y curl
apt install software-properties-common # Python関係のプロパティを入れる必要があってインストールするが、余計なものもたくさん入ってきてしまうため、もっとスマートにしたい
```

次にnode.jsのバージョン管理に便利なnvmを入れる。
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash # 最新バージョンをここで確認(url)
```
nvmを使用するために必要な環境変数を設定
```
export NVM_DIR="$HOME/.nvm"   
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # nvm.shファイルが存在し、サイズが0でない場合
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # bash_completionファイルが存在し、サイズが0でない場合
```
node.jsを入れていく。
```
nvm install 18
npm i -g npm
apt install make
apt install g++
npm install -g node-gyp
```
node.jsのおかげでtruffleが簡単にインストールできる。
```
npm install -g truffle
```
truffleがちゃんと入ったか確認。
```
truffle version
```
ここまでで環境構築は完了です。
### truffleのサンプルを作ったテスト  
ここまでで環境が構築できたかどうか確認するため、書籍の第４章の序盤にあるテストを行います。  
(著作権の心配がありましたが、サンプルコードの使用については特別に許可を取る必要はない旨が書籍に明記されていましたので、安心して載せています)[^1]  
まずは下準備。
```
mkdir greeter
cd greeter
```
truffleが提供するサンプルをローカルに展開。
```
truffle init
```

ファイルを編集する必要があるためvimをインストール。
```
apt install vim
```
空のコントラクトを正しくデプロイできるかどうかをテストするためのスクリプトを作成する。
```
touch test/greeter_test.js
vi test/greeter_test.js
```

以下のように編集する。
```javascript:test/metacoin_test.js

const GreeterContract = artifacts.require("Greeter");

contract("Greeter", () => {
  it("has been deployed successfully", async () => {
    const greeter = await GreeterContract.deployed();
    assert(greeter, "contract was not deployed");
  });
});
```
空のGreeterコントラクトを作成する。
```
touch contracts/Greeter.sol
vi contracts/Greeter.sol
``````
以下のように編集する。

```javascript:contracts/Greeter.sol

pragma solidity = 0.8.20;

contract Greeter {
}
```
Greeterコントラクトをネットワークに追加するためにスクリプトを作成する。
```
touch migrations/2_deploy_greeter.js
vi migrations/2_deploy_greeter.js
```
以下のように編集する。
```javascript:migrations/2_deploy_greeter.js

const GreeterContract = artifacts.require("Greeter");

module.exports = function(deployer) {
  deployer.deploy(GreeterContract);
}
```
最後にテストを実行する。
```
truffle test
```
以下のように「1 passing」となれば成功です。
![スクリーンショット 2023-07-17 21.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2708192/7d647cc5-c5b1-b4bf-601c-0200973aedf4.png)

### 作業の終了と再開方法
ついでに、毎回dockerコマンドを忘れて調べ直しているので書き記しておきます。  
上で作った仮想環境を停止する時は
```
exit # ubuntu環境の終了
docker stop truffle # ubuntuコンテナの停止
```
上記で作った仮想環境で作業を再開する時は
```
docker start truffle
docker exec -it truffle /bin/bash
```
[^1]: Kevin Solorio、 Randall Kanna、 David H. Hoover 著『SolidityとEthereumによる実践スマートコントラクト開発』(オライリー・ジャパン刊、ISBN978-4-87311-934-2)