Solidityによるコントラクトの作成(1) - 基礎

今回はSolidityを用いたコントラクトの作り方について説明致します。

開発環境
OS : OSX 10.11.4

## Ethereumインストール
Ethereumをインストールしていない方は、インストールしてください。
Consoleで以下のコマンドを叩けばインストールされます。

````
bash <(curl https://install-geth.ethereum.org -L)
```
その他のインストール方法については[こちら](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum)を参考にしてください。

## Ethereum立ち上げ
続いてEthereumをを立ち上げましょう。今回はテスト用に使うため、Private_netを立ち上げます。

```
geth --networkid "11"  --datadir "path_to_directory" --genesis "path_to_genesisjson" console
```

`--networkid`：networkIDを指定します。1,2,3以外の数字を使いましょう。
`--genesis`　：genesis blockを指定します。
`--datadir`　：databaseのあるディレクトリを指定します。
`console`　　：consoleを開くために必要です。

[geth command line options](https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options)

## コントラクト作成
早速コントラクトを記述してみましょう。言語はSolidityを使います。
(事前にsolidityコンパイラ(solc)がインストールされているか確認してください。されてない場合は[こちらの記事](http://book.ethereum-jp.net/first_use/contract.html)に沿ってインストールしてください。)

エディタで次のようなコントラクトを記述しましょう。これはEthereum上に独自のコインを作るためのコントラクトです。

```token.sol
contract token { 
    mapping (address => uint) public coinBalanceOf;
    event CoinTransfer(address sender, address receiver, uint amount);

  /* Contract初期化のための関数。contract名と同じにする */
  function token(uint supply) {
        coinBalanceOf[msg.sender] = supply;
    }

  /* コインを送るための関数 */
    function sendCoin(address receiver, uint amount) returns(bool sufficient) {
        if (coinBalanceOf[msg.sender] < amount) return false;
        coinBalanceOf[msg.sender] -= amount;
        coinBalanceOf[receiver] += amount;
        CoinTransfer(msg.sender, receiver, amount);
        return true;
    }
}
```

このコントラクトから改行を削除します。テキストから改行を削除する方法については[こちらの記事](http://linux.just4fun.biz/%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E6%94%B9%E8%A1%8C%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B.html)を参考にしてください。

```token_one_line.sol
contract token {    mapping (address => uint) public coinBalanceOf;    event CoinTransfer(address sender, address receiver, uint amount);  /* Contract初期化のための関数。contract名と同じにする */  function token(uint supply) {        coinBalanceOf[msg.sender] = supply;    }  /* コインを送るための関数 */    function sendCoin(address receiver, uint amount) returns(bool sufficient) {        if (coinBalanceOf[msg.sender] < amount) return false;        coinBalanceOf[msg.sender] -= amount;        coinBalanceOf[receiver] += amount;        CoinTransfer(msg.sender, receiver, amount);        return true;    }}
```

### コンパイル
続いて、`solc`を用いてコントラクトをコンパイルします。

```
> var source = "contract token {    mapping (address => uint) public coinBalanceOf;    event CoinTransfer(address sender, address receiver, uint amount);  /* Contract初期化のための関数。contract名と同じにする */  function token(uint supply) {        coinBalanceOf[msg.sender] = supply;    }  /* コインを送るための関数 */    function sendCoin(address receiver, uint amount) returns(bool sufficient) {        if (coinBalanceOf[msg.sender] < amount) return false;        coinBalanceOf[msg.sender] -= amount;        coinBalanceOf[receiver] += amount;        CoinTransfer(msg.sender, receiver, amount);        return true;    }}"
> var compiledSource = eth.compile.solidity(source)
```

これでコンパイルは完了しました。続いてコンパイルしたコードをEthereumのネットワークに送信します。

```
> var abiDefinition = compiledSource.token.info.abiDefinition
> var compiledContract = eth.contract(abiDefinition)
> var supply = 10000
> var contract = compiledContract.new(supply, {from:eth.accounts[0], data: compiledSource.token.code, gas:1000000})
```

これでネットワークへの送信は完了しました。しかしまだマイニングは行われていないので、このコントラクトは承認されていません。そのためaddressもまだ未定です。

```
> contract
{
  address: undefined,
  transactionHash: "0x09b7b27e8d948b601ef1dd0548c7d33604c2fc7b8ee31d7d8e637f66da302a69"
}
```

マイニングが完了すると以下のようにaddressが付与されます。

```
> contract
{
  address: "0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6",
  transactionHash: "0x09b7b27e8d948b601ef1dd0548c7d33604c2fc7b8ee31d7d8e637f66da302a69",
  CoinTransfer: function(),
  allEvents: function(),
  coinBalanceOf: function(),
  sendCoin: function()
}
```

### コントラクトのメソッドを用いる

コントラクトで定義されているメソッドを呼び出してみましょう。
以下のsendCoinメソッドは引数を2つとります。1つ目は受取主、2つ目は送金額です。

```
> contract.sendCoin.sendTransaction(eth.accounts[1], 1000, {from: eth.accounts[0]})
I0511 22:09:00.939817    8397 xeth.go:1028] Tx(0xcd1003befe323aa1cdaee4e81e032b07cfe70fffc33400f46d033dc86cf4c4a1) to: 0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6
"0xcd1003befe323aa1cdaee4e81e032b07cfe70fffc33400f46d033dc86cf4c4a1"
```

メソッドがネットワークに送信されました。しかしまだマイニングされていないので、eth.accounts[0]の残高は10,000、eth.accounts[1]の残高は0のままです。

```
> contract.coinBalanceOf(eth.accounts[0])
10000
> contract.coinBalanceOf(eth.accounts[1])
0
```

マイニングを行います。すると残高が以下のように変化します。

```
> contract.coinBalanceOf(eth.accounts[0])
9000
> contract.coinBalanceOf(eth.accounts[1])
1000
```

以上がコントラクト内のメソッドの呼び出し方です。

### 外部からコントラクトにアクセスする

第三者がコントラクトにアクセスするには`AbiDefinition`と`address`が必要です。今回の場合は以下になります。

```
> abiDefinition 
[{
    constant: false,
    inputs: [{
        name: "receiver",
        type: "address"
    }, {
        name: "amount",
        type: "uint256"
    }],
    name: "sendCoin",
    outputs: [{
        name: "sufficient",
        type: "bool"
    }],
    type: "function"
}, {
    constant: true,
    inputs: [{
        name: "",
        type: "address"
    }],
    name: "coinBalanceOf",
    outputs: [{
        name: "",
        type: "uint256"
    }],
    type: "function"
}, {
    inputs: [{
        name: "supply",
        type: "uint256"
    }],
    type: "constructor"
}, {
    anonymous: false,
    inputs: [{
        indexed: false,
        name: "sender",
        type: "address"
    }, {
        indexed: false,
        name: "receiver",
        type: "address"
    }, {
        indexed: false,
        name: "amount",
        type: "uint256"
    }],
    name: "CoinTransfer",
    type: "event"
}]
```

```
> contract.address
"0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6"
```

上記のデータを用いて、コントラクトにアクセスする変数を作成します。


```
> var theContract = eth.contract(abiDefinition).at(contract.address)
> theContract
{
  address: "0xb4ffc81cb032941a6cfd29f1f1817dc76413fae6",
  CoinTransfer: function(),
  allEvents: function(),
  coinBalanceOf: function(),
  sendCoin: function()
}
```

これで第三者がコントラクトにアクセス出来るようになりました。


### まとめ
以上Solidityを使ったコントラクトの作成方法でした。次回はSolidityを用いたデリバティブの実装方法についてご説明致します。


### 参考記事
https://ethereum.gitbooks.io/frontier-guide/content/ether_transfer.html
http://book.ethereum-jp.net/first_use/contract.html
https://solidity.readthedocs.io/en/latest/index.html
http://linux.just4fun.biz/%E9%80%86%E5%BC%95%E3%81%8DUNIX%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89/%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%8B%E3%82%89%E6%94%B9%E8%A1%8C%E3%82%92%E5%89%8A%E9%99%A4%E3%81%99%E3%82%8B.html