ブロックチェーンアプリ開発の基礎：Solidityの基礎、スマートコントラクト

#はじめに
[前回(ブロックチェーンアプリ開発基礎の基礎)](https://qiita.com/KazukiKawamura/items/8d4b9a05c70f687f1370)Gethの基本的な使い方が分かったと思うので、今回は実際にコントラクト指向言語である**Solidity**を用いて**スマートコントラクト**の開発を行ってみたいと思います。

基本的には[前回](https://qiita.com/KazukiKawamura/items/8d4b9a05c70f687f1370)の続きになります。今回必要な部分は以下にまとめておきますが、分からない部分があれば適宜[前回記事](https://qiita.com/KazukiKawamura/items/8d4b9a05c70f687f1370)を参照してください。

<details><summary>最低限必要な準備</summary><div>

```
$ brew tap ethereum/ethereum
$ brew install ethereum
```

```
$ mkdir ~/private_net
```

```json:genesis.json
{
  "config": {
    "chainId": 42,
    "homesteadBlock": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "gasLimit": "0x8000000",
  "difficulty": "0x100",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}
```

※ genesis.jsonは~/private_netに置いておいてください。

```
$ geth --datadir ~/private_net/ init ~/private_net/genesis.json
```

```
$ geth --networkid "10" --nodiscover --datadir ~/private_net --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth,net,web3,personal"  console 2>> ~/private_net/err.log
```

```
> personal.newAccount("sender")
"0xfb814cf6d7deae6d68d9dea8f8cef23b9ce63e5f"
```

```
> personal.newAccount("receiver")
"0x9e495cc88b7d99c28918efb641f564f896eec6f5"
```

```
> exit
```

</div></details>

開発に入る前に、スマートコントラクトの基本的な事項を確認しておきます。


#スマートコントラクトとは

スマートコントラクトとは、本来、**「自動的に契約を履行する仕組み」**を指します。

よく例に挙げられるのが**自動販売機**で、ユーザーが欲しいジュースの代金を自動販売機に投入し、購入したいジュースのボタンを押すと自動的にジュースが出てくるという仕組みになっています。

このような仕組みをさらに応用し**ブロックチェーン上**でプログラムによって自動で契約を履行しようという取り組みが現在非常に注目されています。ブロックチェーンとスマートコントラクトを組み合わせるとブロックチェーンの特性により、次のようなメリットがあります。

- 契約に関する不正が減る
- 契約で発生する手数料が減る
- 契約が安全に履行される

**契約に関する不正が減る**というのは、契約の改ざんが不可能であることからきています。また、仮想通貨などと同様に、仲介者が不在なため**契約で発生する手数料も低く**抑えられます。さらに、本来、契約は契約相手を信頼することで成立しています。現実にはお金を払ったが品物が届かないというようなことがあり得るわけです。しかし、ブロックチェーン上では**自動で契約が履行されるので安全**です。

それでは、さっそくスマートコントラクトの開発をおこなっていきましょう。


#Solidityのインストール

まずは、Solidityのコンパイラsolcをインストールします。

```
$ brew tap ethereum/ethereum
$ brew install solidity
$ brew linkapps solidity
```

インストールが無事終わったかどうかは、

```
$ solc --version
```

などで確認することができます。


#コントラクトの作成

まずは、スマートコントラクトの内容、すなわち、契約の中身であるコントラクト・コードを書いていきます。

```javascript:Consum.sol
pragma solidity ^0.4.0;

contract Consume {
    int money = 100;

    function subtract(int i) {
        money -= i;
    }

    function get() returns(int) {
        return money;
    }
}
```

今回のコントラクトは、**最初の所持金が100でsubtractを呼び出す度に指定の額を減額する**というシンプルなものにしておきます。


#コントラクトのコンパイル

続いて、ソースコードをコンパイルします。

```
$ solc --abi --bin Consume.sol
======= Consume.sol:Consume =======
Binary: 
60606040526064600055341561001457600080fd5b60db806100226000396000f3006060604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14604e578063ae0f6166146074575b600080fd5b3415605857600080fd5b605e6094565b6040518082815260200191505060405180910390f35b3415607e57600080fd5b60926004808035906020019091905050609d565b005b60008054905090565b806000808282540392505081905550505600a165627a7a72305820315d8335a1d79518ac81b964a07822149e11dd39b780ae3e080d70bc06de6b6b0029
Contract JSON ABI 
[{"constant":false,"inputs":[],"name":"get","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"int256"}],"name":"subtract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
```

実行結果として**Binary**と**Contract JSON ABIが**得られますが、これらは次章で使います。

#コントラクトのデプロイ

デプロイというのは、コントラクトをEthereumネットワークに送信しブロックチェーンに登録するまでの一連の作業です。

まずは、Gethを起動します。Gethを起動するのに最初に作ったアカウントのパスフレーズを求められます。[前回]((https://qiita.com/KazukiKawamura/items/8d4b9a05c70f687f1370))に引き続きの方は"sender"です。

```
$ geth --networkid "10" --nodiscover --datadir ~/private_net --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth,net,web3,personal" --unlock 0 console 2>> ~/private_net/err.log
```

次に、コントラクトのアカウントを作成します。**bin**は、Binaryの先頭に**0x**を付けたもの、**abi**は、Contract JSON ABIをそのまま使います。

```
> var bin = "0x60606040526064600055341561001457600080fd5b60db806100226000396000f3006060604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636d4ce63c14604e578063ae0f6166146074575b600080fd5b3415605857600080fd5b605e6094565b6040518082815260200191505060405180910390f35b3415607e57600080fd5b60926004808035906020019091905050609d565b005b60008054905090565b806000808282540392505081905550505600a165627a7a72305820315d8335a1d79518ac81b964a07822149e11dd39b780ae3e080d70bc06de6b6b0029"
undefined
```

```
> var abi = [{"constant":false,"inputs":[],"name":"get","outputs":[{"name":"","type":"int256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"int256"}],"name":"subtract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
undefined
```

続いて、コントラクトのオブジェクトを生成し、オブジェクト情報を含んだトランザクションをEthereumネットワークに送信します。

```
> var contract = eth.contract(abi)
undefined
```
```
> var myContract = contract.new({ from: eth.accounts[0], data: bin, gas: 1000000})
undefined
```

少し、myContractの中身を見ておきましょう。

```
> myContract

{
  abi: [{
      constant: false,
      inputs: [],
      name: "get",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: false,
      inputs: [{...}],
      name: "subtract",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: undefined,
  transactionHash: "0x46ff4c60ed1c94f7461d7e7b07e772e91dd5016e24f803470ef3545a4bb39e12"
}
```

この状態では、addressが「undefined」となっており、ブロックチェーンに承認されていないことが分かります。そこで、マイニングをおこなって、ブロックチェーンに承認します。

```
> miner.start()
null
```

マイニングをしてしばらくして、myContractの中身を確認するとaddressが表示され、デプロイが成功したことが分かります。

```
> myContract
{
  abi: [{
      constant: false,
      inputs: [],
      name: "get",
      outputs: [{...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: false,
      inputs: [{...}],
      name: "subtract",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }],
  address: "0xdc9fdd0878e4c7fc0964755b4710fb69f880e2d6",
  transactionHash: "0x46ff4c60ed1c94f7461d7e7b07e772e91dd5016e24f803470ef3545a4bb39e12",
  allEvents: function(),
  get: function(),
  subtract: function()
}
```
デプロイに成功したので、マイニングは一旦中止しておきます。

```
> miner.stop()
true
```

#コントラクトのメソッド

コントラクトのデプロイが終わったので、このコントラクトにアクセスしていきます。まずは、このコントラクトへアクセスするためのオブジェクトを生成します。

```
> var cnt = eth.contract(myContract.abi).at(myContract.address);
undefined
```

Ethereumでは、メソッドの呼び出し方には、**「Transaction」**、**「Call」**の2種類があります。まずは、getメソッドでコントラクト内の変数money(所持金)を呼びだします。特に何の操作も行なってないので、初期値の100が返ってきます。

```
> cnt.get.call()
100
```

さきほどは説明しませんでしたが、**Call**は、ブロックチェーンの状態を変化させないような命令に使い、承認されることなく使用することができますが、**Transaction**は、ブロックチェーンの状態を変化させるような命令に使うので承認が必要になります。では、subtractを使って、所持金を20減額させてみます。

```
> cnt.subtract.sendTransaction(20, {from:eth.accounts[0], gas:1000000})
"0xc35bdd3767b4ba6d99dafa2ef52d07ee533a0aaffe1c2325341aeb8a71f15b53"
```

Transactionは承認が必要なので、マイニングを行います。

```
> miner.start()
null
```

しばらくして、getメソッドで所持金を確認してみます。

```
> cnt.get.call()
80
```

期待通り、所持金が100から20減額し80になっていることが分かります。Transactionが承認されたことが分かったのでマイニングを止めておきましょう。

```
> miner.stop()
true
```

これで、コントラクトのメソッドの基本的な使い方は理解できたと思います。