call
原型
<address>.call(...) returns (bool)
简介
调用后内置变量 msg .sender的值会修改为调用者合约地址,涉及存储修改,修改的是被调用者合约的内存(<address>的)。默认情况下将所有可用的gas传输过去,gas传输量可调。执行失败时返回false。
如果调用的函数不存在,则调用fallback函数;

实例
//call的函数调用
nameReg.call("register", "MyName");
nameReg.call(bytes4(keccak256("fun(uint256)")), a);
//设置调用时的gas和传输的钱
nameReg.call.gas(1000000).value(1 ether)("register", "MyName");

delegatecall
原型
<address>.delegatecall(...) returns (bool)

简介
调用后内置变量 msg .sender的值不会修改为调用者合约地址,
涉及存储修改,修改的是调用者合约的内存(当前合约的),默认情况下将所有可用的gas传输过去,gas传输量可调。执行失败时返回false。
本函数目的在于让合约能够在不传输自身状态(如balance、storage)的情况下使用其他合约的代码。

实例
nameReg.delagatecall.gas(1000000)("register", "MyName");
//delegatecall不支持.value

call与delegatecall对比简析
相同之处
(1)调用时会将本合约所有可用的gas传输过去
(2)执行失败均返回false

不同之处
(1)call可以使用.value传ETH给被调用合约
(2)假设在contract_test合约中分别有nameReg.call("somefunction")以及nameReg.delegatecall("somefunction")
    nameReg.call以nameReg合约的身份在nameReg中执行somefunction
    nameReg.delegatecall以contract_test合约的身份在nameReg中执行somefunction
(3)delegatecall的目的就是让合约在不用传输自身状态(如balance、storage)的情况下可以使用其他合约的代码

测试如下:

pragma solidity ^0.4.0;

contract Proxy {
  /**
  * @dev Tells the address of the implementation where every call will be delegated.
  * @return address of the implementation to which it will be delegated
  */
  function implementation() public view returns (address);

/**
  * @dev Fallback function allowing to perform a delegatecall to the given implementation.
  * This function will return whatever the implementation call returns
  */
  function () payable public {
    address _impl = implementation();
    require(_impl != address(0));

assembly {
      let ptr := mload(0x40)
      calldatacopy(ptr, 0, calldatasize)
      let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
      let size := returndatasize
      returndatacopy(ptr, 0, size)

switch result
      case 0 { revert(ptr, size) }
      default { return(ptr, size) }
    }
  }
}

library SomeLib {
    event CalledSomeLib(address _from);
    function calledSomeLibFun() public {
        emit CalledSomeLib(this);
    }
}

contract TestContract {
    uint num = 10;
    event callMeMaybeEvent(address sender, address _from);
    function callMeMaybe() payable public {
        num = num + 1;
        emit callMeMaybeEvent(msg.sender,this);
    }
    function getNum() public view returns(uint256){
        return num;
    }
}

contract CallsTestContract is Proxy {
    uint num;
    address smart;
    
    function set(address _addr) public {
        smart = _addr;
    }
    
    function implementation() public view returns (address){
        return smart;
    }
    
    function callTheOtherContract(address _contractAddress) public {
        require(_contractAddress.call(bytes4(keccak256("callMeMaybe()"))));
        require(_contractAddress.delegatecall(bytes4(keccak256("callMeMaybe()"))));
        require(address(this).call(bytes4(keccak256("callMeMaybe()"))));
        require(address(this).delegatecall(bytes4(keccak256("callMeMaybe()"))));
        SomeLib.calledSomeLibFun();
    }
    
    function getNum() public view returns(uint256){
        return num;
    }
}

部署合约 (账户地址:0xca35b7d915458ef540ade6068dfe2f44e8fa733c)
1、先部署TestContract; (合约地址:0xcbbe6ec46746218a5bed5b336ab86a0a22804d39)
2、再部署CallsTestContract;    (合约地址:0x100eee74459cb95583212869f9c0304e7ce11eaa)
3、以TestContract合约地址为参数,调用CallsTestContract的set方法;
4、以TestContract合约地址为参数,调用CallsTestContract的callTheOtherContract方法;

生成logs如下:

[
    {
        "from": "0xcbbe6ec46746218a5bed5b336ab86a0a22804d39",
        "topic": "0x6f047d87ead77bed598fcd7848a13aaf5af905a842213507a0ebc158d568351b",
        "event": "callMeMaybeEvent",
        "args": {
            "0": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "1": "0xCBbe6ec46746218A5beD5b336AB86a0A22804d39",
            "sender": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "_from": "0xCBbe6ec46746218A5beD5b336AB86a0A22804d39",
            "length": 2
        }
    },
    {
        "from": "0x100eee74459cb95583212869f9c0304e7ce11eaa",
        "topic": "0x6f047d87ead77bed598fcd7848a13aaf5af905a842213507a0ebc158d568351b",
        "event": "callMeMaybeEvent",
        "args": {
            "0": "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c",
            "1": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "sender": "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c",
            "_from": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "length": 2
        }
    },
    {
        "from": "0x100eee74459cb95583212869f9c0304e7ce11eaa",
        "topic": "0x6f047d87ead77bed598fcd7848a13aaf5af905a842213507a0ebc158d568351b",
        "event": "callMeMaybeEvent",
        "args": {
            "0": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "1": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "sender": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "_from": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "length": 2
        }
    },
    {
        "from": "0x100eee74459cb95583212869f9c0304e7ce11eaa",
        "topic": "0x6f047d87ead77bed598fcd7848a13aaf5af905a842213507a0ebc158d568351b",
        "event": "callMeMaybeEvent",
        "args": {
            "0": "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c",
            "1": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "sender": "0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c",
            "_from": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "length": 2
        }
    },
    {
        "from": "0x100eee74459cb95583212869f9c0304e7ce11eaa",
        "topic": "0x5e7091f10fdcc639a86214a4a72e1b3d6e058d14be100fbe52d22ca354ef18ec",
        "event": "CalledSomeLib",
        "args": {
            "0": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "_from": "0x100eeE74459CB95583212869f9c0304e7cE11EAA",
            "length": 1
        }
    }
]

分析logs得到的msg.sender顺序为 :
    0x100eee74459cb95583212869f9c0304e7ce11eaa ---> CallsTestContract(当前合约地址)
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c ---> 执行函数的账户地址
    0x100eee74459cb95583212869f9c0304e7ce11eaa ---> CallsTestContract(当前合约地址)
    0xca35b7d915458ef540ade6068dfe2f44e8fa733c ---> 执行函数的账户地址
    
CallsTestContract的callTheOtherContract方法里有四种调用:(logs的_from字段)
    第一种是以TestContract身份去调用TestContract的代码,如果涉及修改内存,修改的是TestContract的内存;
    第三种是以CallsTestContract身份去调用TestContract的代码;如果涉及修改内存,修改的是CallsTestContract的内存;
    第二、四个也是以CallsTestContract身份去调用TestContract的代码,如果涉及修改内存,修改的是CallsTestContract的内存;
    
所以,运行结束后,TestContract的num值为11(仅修改一次), CallsTestContract的值为13(修改三次);

callcode: 调用后内置变量 msg.sender 的值会修改为调用者合约地址,涉及存储修改,修改的是调用者合约的内存(当前合约的)。

参考:
 https://www.jianshu.com/p/fd5075ff0ab9
 https://zhuanlan.zhihu.com/p/35292014

https://www.anquanke.com/post/id/145458
https://paper.seebug.org/633/

solidity的call跟delegatecall相关推荐

  1. 智能合约语言Solidity Solidity API

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 智能合约语言Solidity Solidity API Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对 ...

  2. 已知bug列表——Solidity中文文档(12)

    写在前面:HiBlock区块链社区成立了翻译小组,翻译区块链相关的技术文档及资料,本文为Solidity文档翻译的第十二部分<已知bug列表>,特发布出来邀请solidity爱好者.开发者 ...

  3. 智能合约语言 Solidity 教程系列9 - 错误处理

    这是Solidity教程系列文章第9篇介绍Solidity 错误处理. Solidity系列完整的文章列表请查看分类-Solidity. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文 ...

  4. How to Secure Your Smart Contracts: 6 Solidity Vulnerabilities and how to avoid them (Part 1)

    In a previous post we discussed the future of Ethereum's scalability by analyzing the concepts prese ...

  5. 智能合约语言 Solidity 教程系列8 - Solidity API

    这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里. <!-- more --> 写在前面 Solidity 是 ...

  6. 从 Demo 中学习 Solidity

    从 Demo 中学习 Solidity [注解译文] 前 (全文参考) Solidity官方文档 以太坊白皮书_ZH 以太坊白皮书_EN 发现网上的资料太过琐碎, 惊奇的发现官方有详细的教程, 和例子 ...

  7. 【Solidity】3.类型 - 深入理解Solidity

    索引 [Solidity]1.一个Solidity源文件的布局 [Solidity]2.合约的结构体 [Solidity]3.类型 [Solidity]4.单位和全局可变量 [Solidity]5.表 ...

  8. 深入理解Solidity

    Solidity源文件布局 pragma(版本杂注) 用于指定源文件的版本,表明编译器的版本,例如 pragma solidity ^0.4.0 ^用于指代版本号需要大于0.4.0但是不可以超过大的层 ...

  9. 区块链教程(三):Solidity编程基础

    注:本教程为技术教程,不谈论且不涉及炒作任何数字货币 区块连教程(一):前置知识-linux补充 区块链教程(二):基础概念介绍 区块链教程(三):Solidity编程基础 区块链教程(四):搭建私链 ...

最新文章

  1. Java-NIO(九):管道 (Pipe)
  2. window 删除顽固 node_modules
  3. ASP.NET MVC 学习网站
  4. 官方消息:微软再次提醒IE浏览器将于6月15日停止支持
  5. vue怎么截取时间年月_Vue + Element 获取标准时间、时间戳进行转换与操作(年月日)...
  6. linux php安装memcached扩展
  7. idea 创建多模块依赖Maven项目
  8. 【bzoj2806】 Ctsc2012—Cheat
  9. 如何快速精确的和leader沟通
  10. 讨论一个比较有意思的业务需求
  11. 《Linux 鸟哥私房菜》 第一部分 Linux文件、目录与磁盘格式
  12. Android ActionBar的Overlay模式如何不遮盖顶部内容的问题
  13. JavaScript中||(或)逻辑运算符注意点
  14. VS2017 CUDA编程学习12:CUDA流
  15. 创业文档: 软件定制开发合同
  16. 兼容移动端的 Web 档案馆可视化管理系统
  17. Windows下使用命令修改文件权限和所有者
  18. 名校申博有多难?印度小哥申请CMU一路被拒,最终拿到马普研究所offer
  19. PS:动图加文字(二)
  20. 中国云计算行业研究报告

热门文章

  1. 在EDIUS中使用调音台的方法
  2. JPEG压缩原理与DCT离散余弦变换
  3. 电力电子技术(第二章)
  4. 杰理之带T卡(装有升级文件)上电死机问题以及T卡【篇】
  5. 基于蓝牙串口通信,实现实时脉象采集(项目总结与思路梳理)
  6. 正则化-最通俗的解释
  7. 微信/支付宝/银联依据收款码区分
  8. 君正x2000开发板usb口读取文件
  9. Activiti工作流引擎进阶【收藏可做笔记系列】
  10. 用计算机把老式的织布机,电脑织布机的操作怎样操作电脑织布机