Solidityで「お薬手帳」を作る -Contract編- Block 2

# はじめに
- 本記事では Smart Contract を書き始める
- いきなりお薬手帳完全版を作るのは厳しいのでまずはざっと思いつく変数を書いてみる
- いったんコンパイルが通るか確認してみる

solidity 関連で気になる用語や困ったことがあったら以下のサイトを読むとよい
https://docs.soliditylang.org/en/v0.8.16/

# Smart Contract を書いてみる
### ソースコードの License について
世界中の人が自分の書いたコードを使用できるよう、基本的には以下の文言をファイル先頭に記載する。
商用利用禁止のコードは別の文言がファイル先頭に記載されているはず？なので、注意するべし。
```solidity:medicineNotebook.sol
// SPDX-Licence-Identifier: MIT
```

### Contract の記述開始！！
まず、どの solidity version で動作するかを記載する必要がある。

```solidity: medicineNotebook.sol
// SPDX-Licence-Identifier: MIT
pragma solidity ^0.8.16;
```

これはこのコードが solidity version 0.8.16 未満でコンパイルできないことを意味している。
また、version情報の前に `^` がついているので solidity version 0.9.0 以上でも動かせないことを意味している。

次に contract を記述する部分を作成する。
```solidity: medicineNotebook.sol
// SPDX-Licence-Identifier: MIT
pragma solidity ^0.8.16;

contract medicineNotebook {

}

```

`contract コントラクト名 {}`で `{}` の中にコントラクトを記述することができる。

ここで、処方された薬をどのように記録するか検討する。
まず、薬の標準コードについて調べてみたところ、以下のサイトを発見。
GIN-13という薬品コード規格というものがあるらしい。文字列ではなく数値で表されるらしい。今回はこれを使ってみる。
https://www.data-index.co.jp/knowledge/146/

病気や病院についても何かしらコードがあるはず...なので、
とりあえず数値で表されると考える。

※Solidity は文字列の記録に多めのガス代がかかる場合があるらしい？が
私もまだ理解しきれていないため、いったん先へ進む。（どこかでしっかり調べようと思う）

- ガス代とは？
取引を実行する際にかかる手数料のこと。
\
Ethereum は世界中に分散したマイナー達がトランザクションを監視、記録することで
不正なく取引を実行できる仕組みを提供している。
このマイナー達もボランティアでそのようなことをしているのではなく、
記録の際にある条件を満たすと報酬+手数料（ガス代）が得られる仕組みになっている。
マイナー達に報酬+手数料（ガス代）を得られるというインセンティブを与え、
電気代やハードウェア代を投入してでも Ethereum のトランザクションを記録しようとするモチベーションが生まれている。
\
また Ethereum ネットワークに高負荷をかけるような攻撃への抑止力としても機能している。
ガス代が存在することでトランザクションの実行回数に上限ができ、
保有資金以上のガス代を必要とするような大量のトランザクションを実行することができない。
攻撃が失敗したときに自分の資産が無くなるので、そんな攻撃する人いないよね？ということである。

とりあえず処方された薬の他に、一緒に記録したほうが良いと思われる情報を
記録するための変数や構造体を書いてみた。

```solidity:medicineNotebook.sol
/ SPDX-Licence-Identifier: MIT
pragma solidity ^0.8.16;

contract medicineNotebook {
    // globaly recorded items on this contract
    // - medicine code（GTIN-13)
    // - disease code
    // - hospital code
    // - population
    uint256[] public medicineCodesList;
    uint64[] public diseaseCodesList;
    uint256[] public hospitalcodesList;
    uint256 public population;

    // struct for record list
    struct RecordItem {
        uint256 recordTime; // Unit: second, epoch unix time
        uint8 age; // Unit: years oldnode --v
        uint8 weight; // Unit: kg
        uint8 height; // Unit: cm
        uint8 sex; // 0: men, 1: women
        uint256[] medicineCurrentTaking; // medicine currently taking
        mapping(uint256 => uint8) medicineToTakingQuantity; // medicine quantity when you take at once
        uint64[] diseaseCodes; // disease code you have
        uint256[] hospitalCodes; // hospital code you go to
    }

    // struct for each person
    struct Person {
        uint256 humanId; // ID number for each person
        uint8 lifeAndDeath; // life and death
        RecordItem[] records; // recorded items
    }
}

```

- `//` ：コメント行
`//`と書いてそのあとに文章が書かれているが、これはコメント行である。自分や他人がこのコードを見たときに役立つ情報を記載するものである。記載ルールもあるようなので、私の書き方を信用しないよう注意。

- `uint` ：unsigned integer type
0 と整数のみを表すことのできる型。ほかにも`int` 型や`bytes`型などがある。

- `struct` ：構造体
複数の変数をひとまとまりにすることのできるカスタマブルな型である。今回、RecordItem という構造体に診察時の情報をまとめることができ、さらにその情報をPerson という構造体にまとめることができるようにしている。

### compile してみる
compileは簡単。ターミナルに以下のコマンドを打てばコンパイルできる。
`brownie compile`

実施したところ、以下のエラーが出た...。簡単じゃないやん...
```powershell:エラー
PS C:\Users\taken\Documents\demos\medicineNotebook> brownie compile                     ineNotebook\build\contracts
情報: 与えられたパターンのファイルが見つかりませんでした。
Brownie v1.19.1 - Python development framework for Ethereum

  File "C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\_cli\__main__.py", line 64, in main
    importlib.import_module(f"brownie._cli.{cmd}").main()
  File "C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\_cli\compile.py", line 50, in main
    proj = project.load()
  File "C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\project\main.py", line 780, in load
    return Project(name, project_path)
  File "C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\project\main.py", line 188, in __init__
    self.load()
  File "C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\project\main.py", line 198, in load
    contract_sources = _load_sources(self._path, self._structure["contracts"], False)   
  File "C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\project\main.py", line 1029, in _load_sources
    source = fp.read()
UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 160: illegal multibyte sequence

```
最後の一文に`cp932`というコーデック（暗号化したり複合したりするソフト）で何かを複合できないと書いてあるようだ。
調べると`cp932` はShift_JIS規格でありWindowsのデフォルトの標準出力がこの規格になっているのに対し、pythonは`utf-8`というものを使用している模様。
ここでファイルの文字コードと読み込む際に指定された文字コードが異なることでエラーが発生しているようだ。（まだ理解しきれていない）
ひとまず`source = fp.read()`という部分が問題なようなのでそこを見てみる。この記載は1行上の`C:\Users\taken\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\brownie\project\main.py`にあるようだ。

```python: main.py
    for path in project_path.glob(f"{subfolder}/**/*"):
        if path.suffix not in suffixes:
            continue
        if next((i for i in path.relative_to(project_path).parts if i.startswith("_")), False):
            continue
        with path.open() as fp:
            source = fp.read()
```
`source = fp.read()`を検索すると上記の記載があった。
この下から２行目の`with path.open() as fp:`のカッコ内に`encoding="utf-8"`というオプションを追記してみる。

```python: main.py
    for path in project_path.glob(f"{subfolder}/**/*"):
        if path.suffix not in suffixes:
            continue
        if next((i for i in path.relative_to(project_path).parts if i.startswith("_")), False):
            continue
        with path.open(encoding="utf-8") as fp:
            source = fp.read()
```
修正後に main.py を上書き保存し、再度`brownie compile`を実行してみる。

```powershell: brownie compile の実行結果
PS C:\Users\taken\Documents\demos\medicineNotebook> brownie compile
情報: 与えられたパターンのファイルが見つかりませんでした。
Brownie v1.19.1 - Python development framework for Ethereum

Project has been compiled. Build artifacts saved at C:\Users\taken\Documents\demos\medicineNotebook\build\contracts
```
エラー解消し、無事compileできた模様！

ざっと思いつく変数を記録し、コンパイルすることができた。
今回はここまでとする。