Plasma Cashを動かす

この記事は [Ethereum Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ethereum) の17日目の記事です。

## Plasmaとは

とても簡単に言うと、親チェーン（基本的にはEthereumのブロックチェーン）に接続する子チェーンを作成して処理を小チェーンで行い、最終的な状態のみを親チェーンに書き込むことで処理性能を向上させるブロックチェーンのスケーラビリティを解決するためのフレームワークです。
いろいろな解説記事とかあるのですが、ちょっとピンと来てないところがあったのでこれを機に実際に触ってみようということでPlasmaを動かしてみたいと思います。
実際この界隈の発展が早すぎて、Plasmaなんちゃらがいっぱい出てきて何が何やらわからないので笑
Plasmaの中でも代表的なPlasma Cashを触りたかったので、OmisegoのPlasma Cashを触ります。言語はpythonです。Omisegoは実際にPlasma DogというPlasmaを利用してゲームも作っているので気になりました。他にもLoom Networkのjsの実装とかもあるんですが、今回はこちらを触ってみます。

https://github.com/omisego/plasma-cash
https://github.com/loomnetwork/plasma-cash
https://sadyba-plasmadog.hoard.exchange/


## 開発環境

Ubuntu 18.04
Python 3.7
Nodejs 11.4.0
Ganache-Cli v6.2.3
Solidity 0.4.24+commit.e67f0147.Linux.g++ (0.5以降はエラーになるようなので注意)

## Plasma-Cashとは

実際に動かすのが目的なので詳細は省きます。
こちらの記事がわかりやすかったです。
https://zoom-blc.com/what-is-plasma-cash
https://medium.com/@tomoyaishida/plasma%E3%81%AE%E8%AA%B2%E9%A1%8C%E3%82%92%E8%A7%A3%E6%B1%BA%E3%81%99%E3%82%8Bplasma-cash%E3%81%A8%E4%BB%8A%E5%BE%8C%E3%81%AE%E7%99%BA%E5%B1%95-plasma-xt-plasma-debit-more-viable-plasma-3e7bee73f21f

Plasma Cashの特徴としてはトークンに固有のIDが振り分けられていることです。
Plasma Cash以前のPlasmaでは自分の資産を管理するため全てのデータをダウンロードして検証する必要がありましたが、Plasma Cashの場合は自分の保有しているトークンIDに関連したデータのみ検証するだけで十分となるため、検証の効率化に繋がります。

## インストール

基本的にはREADME通りです。いくつかハマり点があったので書いておきます。
まずはGitHubからクローン。

```
git clone https://github.com/omisego/plasma-cash.git
```

Solidityとganacheもそのままいけました。
Solidityは自分は最新の0.5.1でデプロイしたらエラーになったので指定されたバージョンを入れましょう。

```
$ npm install -g ganache-cli
$ wget https://github.com/ethereum/solidity/releases/download/v0.4.24/solc-static-linux
$ chmod +x ./solc-static-linux
$ sudo mv solc-static-linux /usr/bin/solc
```

ちなみにですがエラーはこういう内容でした。
constantというmodifierを削除したみたいですね。

```
solc.exceptions.SolcError: RLP.sol:33:55: ParserError: The state mutability modifier "constant" was removed in version 0.5.0. Use "view" or "pure" instead.
```

leveldbを使うのでpythonのライブラリを入れるのにエラーになるので入れておきます。
Ubuntuの場合はこれでいけます。
Macの場合はhomebrewでいけるようです。

```
$ sudo apt-get install libleveldb-dev
```

pythonの仮想環境を使ってインストール。

```
$ python -m venv venv
$ source venv/bin/acrivate
$ pip install -r requirements.txt
```

これで準備OKです。

## ganache, child_chain起動

デプロイはganache上で行います。このganacheのブロックチェーンがRootChainになります。
plasma_cashをつけないとChildChainの起動時に読み込めなくなるのでつけましょう。

```
$ ganache-cli -m=plasma_cash
```

ChildChainはこちらのコマンドで起動できます。
起動したら8546のポートが開放されます。(ganacheは8545)
flaskで書かれていて普通のAPIサーバーという感じです。

```
$ python -m plasma_cash.child_chain
```

ChildChainのデータは指定したDBに保持されます。
levledbかmemory(PCのメモリ？)を指定できて、デフォルトがmemoryになってます。これけっこうハマりました。
memoryにすると、トランザクションのデータが保持されていないことがあるのか、こういうエラーが出たりします。

```
plasma_cash.child_chain.exceptions.PreviousTxNotFoundException: failed to apply transaction
```

leveldbを指定するようにします。

plasma-cash/plasma_cash/config.py

```
db_config = {
    'type': 'leveldb'
}
```

これでトランザクションのデータは実行ディレクトリの.dbに保存されるようになります。


# デプロイ

```
$ python deployment.py 
Successfully deployed RootChain contract with tx hash 0xebb7920cd2c6f9fc69c6b24a313a8370f76987d3922e090827cb77ba8defe4df in contract address 0xda52B0A0a040BFeAb711065cB69321ebAE9bB96f!
```

ganacheでコントラクトがデプロイされました。
logを見るとこんな感じになってると思います。

```
Listening on 127.0.0.1:8545
web3_clientVersion
eth_getTransactionCount
eth_estimateGas
eth_gasPrice
eth_sendRawTransaction

  Transaction: 0xebb7920cd2c6f9fc69c6b24a313a8370f76987d3922e090827cb77ba8defe4df
  Contract created: 0xda52b0a0a040bfeab711065cb69321ebae9bb96f
  Gas usage: 3725250
  Block Number: 1
  Block Time: Sun Dec 16 2018 21:51:23 GMT+0900 (GMT+09:00)

eth_getTransactionReceipt
```

## READEMEよりのサンプル

せっかくなのでもう少し色々動かしたいなということで、READMEに書かれているサンプルも実行してみます。

```
python
>>> from web3.auto import w3
>>> from plasma_cash.client.client import Client
>>> from plasma_cash.dependency_config import container
>>> operator_key = '0xa18969817c2cefadf52b93eb20f917dce760ce13b2ac9025e0361ad1e7a1d448'
>>> userA_key = '0xe4807cf08191b310fe1821e6e5397727ee6bc694e92e25115eca40114e3a4e6b'
>>> userB_key = '0xee092298d0c0db61969cc4466d57571cf3ca36ca62db94273d5c1513312aeb30'
>>> operator = Client(container.get_root_chain(), container.get_child_chain_client(), operator_key)
>>> userA = Client(container.get_root_chain(), container.get_child_chain_client(), userA_key)
>>> userB = Client(container.get_root_chain(), container.get_child_chain_client(), userB_key)
>>> userA.deposit(10, '0x0000000000000000000000000000000000000000')
>>> operator.submit_block()
>>> userA.send_transaction(1, 1693390459388381052156419331572168595237271043726428428352746834777341368960, 10, '0x08d92dca9038ea9433254996a2d4f08d43be8227')
>>> operator.submit_block()
>>> userB.start_exit(1693390459388381052156419331572168595237271043726428428352746834777341368960, 1, 2)
>>> w3.providers[0].make_request('evm_increaseTime', 60 * 60 * 24 * 14)  # force ganache to increase time for two week
>>> userB.finalize_exit(1693390459388381052156419331572168595237271043726428428352746834777341368960)
```

こちらのoperator_key、userA_key、userB_keyをganache起動時に出てきたprivate keyに変更したら実行できます。
operator.submit_block()といちいちsubmit_blockしてブロックを掘ってるように見えますが、operator_cron_jobを起動すると勝手にsubmit_blockしてくれます。
このサンプルでは手動でやったほうがわかりやすいので手動でやるのが良いかと思います。
ちなみにcron_jobなんて名前がついてますが、常時起動するタイプのものなので、cronで定期的に実行するように変更するようです。

```
$ python -m plasma_cash.operator_cron_job
```

サンプルコードのこちらの数字の羅列がどうやらPlasma Cashの固有のトークンIDです。
1693390459388381052156419331572168595237271043726428428352746834777341368960
コード内ではuidという変数で保持されています。

正直ganacheとChildChainとoperator_cron_jobと3つ起動させておく必要があるので、
開発環境とはいえどなかなか面倒だなと思いました。
インストールも手間なのでdockerとかdocker-composeとか使った方が楽だよなあとか思ったり。
てかdocker作ろうかな。。。

## 感想

とりあえず触ってみるぞということでOmisegoのPlasma Cashを使ってみました。
実際に触ってみてコードを見ていくほうが自分にはわかりやすいので、なんとなくPlasmaのやってることがイメージできました。他にもいろいろなPlasma実装があるみたいなので触っていきたいと思います。