Solidity call vs delegatecall vs callcode
调用已部署合约的 function 就靠它们了。合约之间的交互,其中包括正常使用,也包括恶意使用(攻击)。
使用它们调用已部署合约的 function 需要知道两件事:
- 已部署合约的 address。
- 该合约的 ABI。
可以概括为:调哪里(address) 的合约去做什么(function)。
注意:DELEGATECALL 已经取代了 CALLCODE(在以太坊 Homestead 版本之后)
它们的不同
contract D {
uint public n;
address public sender;
function callSetN(address _e, uint _n) {
_e.call(bytes4(sha3("setN(uint256)")), _n); // E 的 storage 被修改, D 不变
}
function callcodeSetN(address _e, uint _n) {
_e.callcode(bytes4(sha3("setN(uint256)")), _n); // D 的 storage 被修改, E 不变
}
function delegatecallSetN(address _e, uint _n) {
_e.delegatecall(bytes4(sha3("setN(uint256)")), _n); // D 的 storage 被修改, E 不变
}
}
contract E {
uint public n;
address public sender;
function setN(uint _n) {
n = _n;
sender = msg.sender;
// 如果 D 调用 callcodeSetN , msg.sender 是 D . E 的 storage 不变
// 如果被 C.foo() 调用, msg.sender 是 C. E 的 storage 不变
// 当被 D 的 callcodeSetN 或 C.foo() 调用时,this 指代 D
}
}
contract C {
function foo(D _d, E _e, uint _n) {
_d.delegatecallSetN(_e, _n);
}
}
根据代码,可以总结出两个不同:
storage 和 context 的不同
- 当 D call E 时,context 是 E 的,操作的也是 E 的 storage
- 当 D callcode E 时,context 是 D 的,操作的也是 D 的 storage,同理 delegatecall
msg.sender 的不同
- 当 C 引用 D,D delegatecall E ,E 的 msg.sender 是 C,由此 D E 二者的,msg.send 和 msg.value 都是一样的。
- 当 D callcode E 时,E 的 msg.sender 是 D,同理 delegatecall
总结
call 理解为 调用一个实例的方法,delegatecall 是 import 另一个合约然后调用方法。
错误示范
contract NameReg {
bytes32 public nn;
bytes public calldata;
function register(bytes32 name) {
nn = name;
}
function() {
calldata = msg.data;
}
function doesNotCallRegister() {
this.call("register", "MyName");
}
}
doesNotCallRegister() 会失败,失败后触发一个匿名方法(fallback 方法)。因为 solidity 中查找方法名字不是简单的的字符串搜索,而是在 EVM 虚拟机层面,计算方法签名的 hash——MethodID,以它的高位 4 字节为 key 进行查找。
正确方法
watch_addr.call(bytes4(sha3("Bar(int256)")), 42);
调用了 watch_addr 的 Bar 方法,并传值 42。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Solidity Modifier
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论