Help us understand the problem. What is going on with this article?

call() vs delegatecall() vs callcode()

More than 1 year has passed since last update.

call()とdelegatecall()(およびcallcode())の違い

いずれも別のコントラクトの関数の処理を実行するための関数

  • <コントラクトアドレス>.call(): 呼び出し先コントラクトのコンテキストで関数の処理を実行する。関数内の状態参照や状態変更は呼び出し先コントラクトの状態を参照したり更新したりする。
  • <コントラクトアドレス>.delegatecall()および<コントラクトアドレス>.callcode(): 呼び出し元コントラクトのコンテキストで関数の処理を実行する。関数内の状態参照や状態変更は呼び出し元コントラクトの状態を参照したり更新したりする。

delegatecall()とcallcode()の違い

関数内のmsg.senderとmsg.valueが違う。

delegatecall()で実行される関数内のmsg.senderはdelegatecall()が含まれる関数の呼び出し元コントラクトであるのに対し、callcode()で実行される関数内のmsg.senderは、callcode()が含まれる関数のコントラクトである。

わかりづらいので例示

以下のようにCallerCaller -> Caller -> Calleeと呼び出すパターンで、CallerからCalleeの呼び出しでcall()とdelegatecall()とcallcode()を使い分けてみる。

contract CallerCaller {
    Caller caller;
    function CallerCaller(address _caller) public {
        caller = Caller(_caller);
    }
    function setByCall(uint256 _v) public {
        caller.setByCall(_v);
    }
    function setByCallcode(uint256 _v) public {
        caller.setByCallcode(_v);
    }
    function setByDelegateCall(uint256 _v) public {
        caller.setByDelegateCall(_v);
    }
}

contract Caller {
    uint256 public v;
    address callee;
    function Caller(address _callee) public {
        callee = _callee;
    }

    function setByCall(uint256 _v) public {
        require(callee.call(bytes4(keccak256("set(uint256)")), _v));
    }
    function setByCallcode(uint256 _v) public {
        require(callee.callcode(bytes4(keccak256("set(uint256)")), _v));
    }
    function setByDelegateCall(uint256 _v) public {
        require(callee.delegatecall(bytes4(keccak256("set(uint256)")), _v));
    }
}

contract Callee {
    uint256 public v;
    event SenderIs(address);
    function set(uint256 _v) public {
        v = _v;
        SenderIs(msg.sender);
    }
}
  • setByCall(42) -> Calleeのvが42にセットされ、SenderIsイベントに含まれるアドレスはCallerのもの。
  • setByDelegateCall(43) -> Callerのvが43にセットされ、SendierIsイベントに含まれるアドレスはCallerCallerのもの
  • setByCallCode(44) -> Callerのvが44にセットされ、SendierIsイベントに含まれるアドレスはCallerのもの

delegatecallはなんのためにあるのか

delegatecallはライブラリを実現するためにある。コントラクトとしてインストールされたライブラリを使う際にライブラリ利用側の状態を参照・変更するため。

callcode

msg.senderの問題があり非推奨。

参考ページ

https://ethereum.stackexchange.com/questions/3667/difference-between-call-callcode-and-delegatecall

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away