EIP7——操作码DELEGATECALL

        EIP7(2015-11-15)引入了一个新的操作码DELEGATECALL。

提案内容

        以太坊改进提案EIP7在主网区块高度1150000(家园版本硬分叉)生效,该提案在0xf4处引入了一个新的操作码DELEGATECALL。DELEGATECALL和CALLCODE(已不被推荐使用)用法类似,可以调用其它合约的代码并来改变自身合约的状态,区别在于DELEGATECALL会将msg.sender的值传递给子调用,因此子调用会有和原始调用相同的msg.sender。

        msg.sender在子调用的传递使得合约更容易去调用另外一个合约的代码,因为子调用将在与父调用相同的环境下执行代码(除了会减少gas和增加栈堆深度外)。

        DELEGATECALL需要6个操作数如下:

        gas:代码在执行时可能使用的gas量;

        to:代码执行的目标地址;

        in_offset:输入在内存中的偏移量;

        in_size:输入的大小,单位是字节;

        out_offset:输出在内存中的偏移量;

        out_size:输出的大小。

        使用DELEGATECALL时,CALLER和VALUE在被调用者环境中的状态与他们在调用者环境中的状态完全相同。

用例(合约层面)

pragma solidity 0.8.10;
 ​
 // 被调用函数
 contract operator{
     uint public flag;
     bytes public word;
 ​
     function getValue() public view returns(uint,bytes memory){
         return (flag, word);
     }
 ​
     function changeValue(uint num,bytes memory something) public returns(uint,bytes memory,address){
         flag = num;
         word = something;
         return (flag, word, msg.sender);
     }
 } 
 ​
 // 进行delegatecall的函数
 contract Caller1{
     uint public flag;
     bytes public word;
     address public Op;
 ​
     constructor(address _addr){
         Op = _addr;
     }
 ​
     function getValue() public view returns(uint,bytes memory){
          return (flag, word);
     }
 ​
     //从delegatecall的返回值中看到msg.sender是自身账户,因此msg.sender传递给了子调用
     function changeValue(uint num,bytes memory something) public returns(bool, bytes memory){
         return Op.delegatecall(abi.encodeWithSignature("changeValue(uint256,bytes)",num,something));
     }
 }
 ​
 // 用delegatecall调用函数改变自身变量时,变量的存储布局必须和被调用合约一致,否则会写入脏数据。
 contract Caller2{
     address public Op;
     bytes public word;
     uint public flag;
 ​
     constructor(address _addr){
         Op = _addr;
     }
 ​
     function getValue() public view returns(uint,bytes memory){
          return (flag, word);
     }
 ​
     function changeValue(uint num,bytes memory something) public returns(bool, bytes memory){
        return Op.delegatecall(abi.encodeWithSignature("changeValue(uint256,bytes)",num,something));
     }
 }

资料来源

EIP-7: DELEGATECALL (ethereum.org)

猜你喜欢

转载自blog.csdn.net/llslinliansheng/article/details/129431382