IOSTで簡単なスマートコントラクトを書いてみる。

最近話題（？）のIOSTでスマートコントラクトを書いてみたので、頭の整理がてら記事書いてみます。

まずスマートコントラクトを書く前に次のものが必要です。

Docker（18.06CEより新しいやつ）

iWallet：IOSTのコマンドラインツールです。これでIOSTブロックチェーンとやり取りします。
公式ドキュメントを見てインストールしてみてください。
https://developers.iost.io/docs/ja/4-running-iost-node/iWallet.html

今回の流れは

1. ローカルでテストノードを立てる。
2. スマートコントラクト書く
3. 実際にIOSTブロックチェーンとやり取りしてスマートコントラクトを試す。

という感じです。


#### 1.ローカルテストノードを立ててみよう。

IOSTのDockerイメージをもとにDockerコンテナを作ってその中でノードを立てます。
まずターミナルを開いて次のコマンドを打ちます。

```terminal 
docker run --rm -d -p 30000-30003:30000-30003 iostio/iost-node
```

これでコンテナが立ち上がり、その中でブロックチェーンが動いてます。

次に下のコマンドでコンテナIDを調べて、

```terminal
docker ps
```

それをコピーして下のコマンドの、ここだよ、に貼り付けます。<>は除いてください。

```terminal
docker exec -it <ここだよ> /bin/bash
```

するとworkdir#　が出てきてコンテナ内でシェルを開いた状態になります。
そこで下のようにコマンドを入力します。
adminはローカルテストネット用に公式が用意してくれているアカウントです。
終わったらexitと入力してコンテナ内を出ます。

```terminal
root@containerID:/workdir# iwallet account import admin 2yquS3ySrGWPEKywCPzX4RTJugqRh7kJSo5aehsLYPEWkUxBWA39oMrZ7ZxuM4fgyXYs2cPwh5n8aNNpH5x2VyK1
```

とりあえずこれで諸々の準備は終わりました。

次からはコントラクトを書いていきます。


####　２．スマートコントラクトを書く

では早速スマートコントラクトを書いてみましょう。

今回はユーザーインプットをブロックチェーンのストレージにID付きで保存。
それをIDで呼び出してみるよ、っていうコントラクトになっています。


まず前提として、IOSTのストレージにはJSON形式でデータが保存されます。
なので
ストレージに数値をしまいたければJSON.stringify（）
ストレージから取り出した値を数値として使いたい場合はJSON.parse()して使う必要があります。
毎回書くとめんどくさいので最初にまとめて書いてしまいます。
長いコントラクトになればなるほど役立つと思います。

```javascript

_get(k){
    const val = JSON.parse(storage.get(k));
    return val;
}

_put(k,v){
    const val = JSON.stringify(v);
    storage.put(k,val);
} 
```

storage.put：ストレージにKey-Valueペアを保存
storage.get：ストレージからKeyをもとにValueを取ってくる。
などはIOSTのAPIです。
詳しくは公式ドキュメントのAPIページを見てください。
https://developers.iost.io/docs/en/3-smart-contract/IOST-Blockchain-API.html

では本題。

```javascript:trecorder.js

class TextRecorder {
    init (){
　　　 //パブリッシュされたときに
      // {"count":"0"}
      // "text" っていう名前のmapに {"text_count_0":"GENESIS_TEXT"}って感じで保存。
        this._put("count", 0);
        storage.mapPut("text", "text_count_0" ,"GENESIS_TEXT");
    }

    
//これはアップデート関数のテンプレートです
    can_update(data) {
        return blockchain.requireAuth(blockchain.contractOwner(), "active");
    }


    putText(txt){
　　　　　//"count"のValueを持ってきて数値化。
        let textId = this._get("count");
　　　　　// それに１を足してそれが今回のテキストの番号になる
        textId = textId + 1;
　　　　　//テキストは”text"に{"text_count_#":"xxxx"}という感じのペアで保存される。
        storage.mapPut("text", "text_count_" + textId, txt);
　　　　　//最後にcountを再度JSON化してストレージに保存して今のテキストの数を記録する。
        this._put("count", textId);
    }

//今何個テキストが保存されてるかわかる。
    getTextCount(){
        return storage.get("text_count");
    }

//テキストの番号をもとにストレージから対応するValueを返す。
    getText(id){
        let textId = "text_count_" + id;
        let txt = storage.mapGet("text",textId);
        return txt; 
     }

    _get(k){
       const val = JSON.parse(storage.get(k));
       return val;
     }

    _put(k,v){
       const val = JSON.stringify(v);
       storage.put(k,val);
     } 
}

//abiファイルに出力する
module.exports = TextRecorder;
```

ざっくりまとめると、

テキストは"text_count_#":"xxxx"というのペアで保存される。
それとは別に"count":"xx"というペアがありputTextの度に”xx”の値が１ずつ増える。

こんな感じでストレージを使ってテキストに対してユニークな番号を割り当ててます。


#### スマートコントラクトを試す
 

ｊｓファイルをコンパイルしてabiファイルを生成します。
abiファイルは、IOSTネットワーク上のスマートコントラクトを呼び出すためのインターフェースです。
ここでトランザクションを受付して指定されたコントラクトを呼び出してくれるわけです。

```terminal
iwallet compile trecorder.js
```

jsファイル,abiファイルをブロックチェーン上にパブリッシュして乗っけます。最後の行のコントラクトIDは取っておいてください。

```terminal
iwallet publish -a admin trecorder.js trecorder.js.abi
```

![スクリーンショット 2019-04-24 9.05.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344683/60be7dd7-a843-2a05-f100-e232a206f637.png)


関数の呼び出しはiwallet callを使いますコントラクトID、関数名を指定して引数は配列の形で渡します。全部文字列です。

```terminal
iwallet call -a admin contractID "関数名" '["引数"]'
```

まずgetText関数でしっかりtext_count_0の”GENESIS_TEXT"がストレージに保存されているか見てみます。

```terminal
iwallet call -a admin Contract5YykenC3DqcgQbZt6m1Gis8vLuGK1p63mEwfVJSrFP1h "getText" '["0"]'
```

![スクリーンショット 2019-04-24 9.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344683/cf77eee9-58b4-73f2-346c-31e1f9280294.png)


しっかり保存されています。

じゃあ次はputTextで適当にテキストを保存してみます。

```teminal
iwallet call -a admin Contract5YykenC3DqcgQbZt6m1Gis8vLuGK1p63mEwfVJSrFP1h "putText" '["Hello IOST"]'
```

で、またgetTextで呼び出しますが、今度は引数に1を渡します。

すると

![スクリーンショット 2019-04-24 9.43.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344683/82c7239c-5d85-9715-3e88-3fdc6b81da12.png)

こんな感じでしっかりtextのtext_count_1にHello IOSTが保存されていますね。

ちなみにコントラクトのアップデートは、ｊｓファイルを再度コンパイルして次のコマンドを打ちます。

```terminal
iwallet publish -a admin trecorder.js trecorder.js.abi --update コントラクトID
```


####まとめ

IOSTの初歩的なスマートコントラクトをいじってみました。
まだまだ開発環境が整っていなかったり文献が少ないのでわからないこと多々です。


今度はUIとつなげてDApp的なもの作ってまた記事にしようと思います。


おしまい