[図解] delegatecall callcode call の違い

# はじめに

Solidity には contract が別の contract を呼び出す仕組みがあるが、関数がいくつかあるためどれを使えば良いのか多少混乱しました。Remix で動かしつつ挙動を確認したのでそれぞれの特徴を整理してみました。

実際に動かして挙動を試したい方は、こちらの gist を remix に貼り付けて動きを見てみる事をオススメします。
https://gist.github.com/critesjosh/68593429fd2f84f8f55d4ff7b74f0323

# 関数と特徴

上記 gist のコントラクトを例として各関数の挙動を解説します。

```
pragma solidity ^0.4.15;

contract C1 {
  uint public num;
  address public sender;

  // 直接呼び出し
  function c2setNum(address _c2, uint _num) public{
      C2 c2 = C2(_c2);
      c2.setNum(_num);
  }

  // call 呼び出し
  function callSetNum(address c2, uint _num) public {
    if(!c2.call(bytes4(sha3("setNum(uint256)")), _num)) revert(); // C2's num is set 
  }

  // callcode 呼び出し
  function callcodeSetNum(address c2, uint _num) public {
    if(!c2.callcode(bytes4(sha3("setNum(uint256)")), _num)) revert(); // C1's num is set
  }

  // delegatecall 呼び出し
  function delegatecallSetNum(address c2, uint _num) public {
    if(!c2.delegatecall(bytes4(sha3("setNum(uint256)")), _num)) revert(); // C1's num is set 
  }
}

contract C2 {
  uint public num;
  address public sender;

  function setNum(uint _num) public {
    num = _num;
    sender = msg.sender;
    // msg.sender is C1 if invoked by C1.callcodeSetNum
    // msg.sender is C3 if invoked by C3.foo()

  }
}
```

## 関数の直接呼び出し

上記の `c2setNum` による呼び出し。

<img width="1279" alt="スクリーンショット 2018-07-04 11.16.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/28899/120e0e19-8adb-85f1-c9cf-3aa42a7849eb.png">

一番オーソドックスな呼びだし方で、C2 側の `msg.sender` には `C1` のアドレスが入る。
C2 が参照する storage 領域は C2 のものなので、C2 の `num` と `sender` が更新される。

## Call による呼び出し

上記の `callSetNum` による呼び出し。
具体的に呼び出しは関数名の sha3 の上位 4 バイトを使って呼び出す。

```
c2.call(bytes4(sha3("setNum(uint256)")), _num)
```

<img width="1272" alt="スクリーンショット 2018-07-04 11.16.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/28899/4d2b2e2b-339a-be7d-9c7b-5bf7abfbd72e.png">

挙動としては直接呼び出しと同じ。

## callcode による呼び出し

上記の `callcodeSetNum` による呼び出し。

<img width="1289" alt="スクリーンショット 2018-07-04 11.16.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/28899/4df44a58-bbae-58c0-acea-1a94e4e3e528.png">

この呼び出し方では、C2 が指す Storage 領域は C1 のものになる。また `msg.sender` は直接の呼び出し元である C1 のアドレスになる。
この関数が実行され終わったあとで、C1 の `num` と `storage` が更新されていて、C2 の`num` と `storage` は更新されない。
現在は非推奨の method なので基本的には使わない方が良い。

## delegatecall による　呼び出し

上記の `delegatecallSetNum` による呼び出し。

<img width="1266" alt="スクリーンショット 2018-07-04 11.16.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/28899/88b5f8b4-233d-8dac-9b78-2df7ac150500.png">

この呼び出し方では、C2 が指す Storage 領域は C1 のものになる。また `msg.sender` は元々の呼び出し元である EOA のアドレスになる。
EOA からみるとあたかも C1 コントラクトが全ての処理を行い結果を格納しているように見えるので、ライブラリなどを利用する際にはこの呼び出し方を使うと良い。

# まとめ

それぞれの関数はの特徴をまとめるよ以下のようになります。

| 関数の呼び出し方 | msg.sender       | storage                                    | 用途                                                      |
|------------------|------------------|---------------------------------------------|-----------------------------------------------------------|
| 直接呼び出し     | 直接の呼び出し元 | 呼び出された contract の storage を指す     | Crowdsale contract が token contract の関数を呼び出すなど |
| call             | 直接の呼び出し元 | 呼び出された contract の storage を指す     | Crowdsale contract が token contract の関数を呼び出すなど |
| callcode         | 直接の呼び出し元 | 直接の呼び出し元 contract の storage を指す | 非推奨                                                    |
| delegatecall     | EOA              | 直接の呼び出し元 contract の storage を指す | ライブラリなど                                            |