实例
//call的函数调用
nameReg.call("register", "MyName");
nameReg.call(bytes4(keccak256("fun(uint256)")), a);
//设置调用时的gas和传输的钱
nameReg.call.gas(1000000).value(1 ether)("register", "MyName");
实例
nameReg.delagatecall.gas(1000000)("register", "MyName");
//delegatecall不支持.value
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方法;
[
{
"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(修改三次);
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/