solidity的call跟delegatecall
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相关推荐
- 智能合约语言Solidity Solidity API
链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 智能合约语言Solidity Solidity API Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对 ...
- 已知bug列表——Solidity中文文档(12)
写在前面:HiBlock区块链社区成立了翻译小组,翻译区块链相关的技术文档及资料,本文为Solidity文档翻译的第十二部分<已知bug列表>,特发布出来邀请solidity爱好者.开发者 ...
- 智能合约语言 Solidity 教程系列9 - 错误处理
这是Solidity教程系列文章第9篇介绍Solidity 错误处理. Solidity系列完整的文章列表请查看分类-Solidity. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文 ...
- 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 ...
- 智能合约语言 Solidity 教程系列8 - Solidity API
这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里. <!-- more --> 写在前面 Solidity 是 ...
- 从 Demo 中学习 Solidity
从 Demo 中学习 Solidity [注解译文] 前 (全文参考) Solidity官方文档 以太坊白皮书_ZH 以太坊白皮书_EN 发现网上的资料太过琐碎, 惊奇的发现官方有详细的教程, 和例子 ...
- 【Solidity】3.类型 - 深入理解Solidity
索引 [Solidity]1.一个Solidity源文件的布局 [Solidity]2.合约的结构体 [Solidity]3.类型 [Solidity]4.单位和全局可变量 [Solidity]5.表 ...
- 深入理解Solidity
Solidity源文件布局 pragma(版本杂注) 用于指定源文件的版本,表明编译器的版本,例如 pragma solidity ^0.4.0 ^用于指代版本号需要大于0.4.0但是不可以超过大的层 ...
- 区块链教程(三):Solidity编程基础
注:本教程为技术教程,不谈论且不涉及炒作任何数字货币 区块连教程(一):前置知识-linux补充 区块链教程(二):基础概念介绍 区块链教程(三):Solidity编程基础 区块链教程(四):搭建私链 ...
最新文章
- Java-NIO(九):管道 (Pipe)
- window 删除顽固 node_modules
- ASP.NET MVC 学习网站
- 官方消息:微软再次提醒IE浏览器将于6月15日停止支持
- vue怎么截取时间年月_Vue + Element 获取标准时间、时间戳进行转换与操作(年月日)...
- linux php安装memcached扩展
- idea 创建多模块依赖Maven项目
- 【bzoj2806】 Ctsc2012—Cheat
- 如何快速精确的和leader沟通
- 讨论一个比较有意思的业务需求
- 《Linux 鸟哥私房菜》 第一部分 Linux文件、目录与磁盘格式
- Android ActionBar的Overlay模式如何不遮盖顶部内容的问题
- JavaScript中||(或)逻辑运算符注意点
- VS2017 CUDA编程学习12:CUDA流
- 创业文档: 软件定制开发合同
- 兼容移动端的 Web 档案馆可视化管理系统
- Windows下使用命令修改文件权限和所有者
- 名校申博有多难?印度小哥申请CMU一路被拒,最终拿到马普研究所offer
- PS:动图加文字(二)
- 中国云计算行业研究报告