Ethereum中涉及各种类型的方法调用。一个编程中常用的call概念,可能为Ethereum Vitrual Machine(EVM)内的call,又可能为EVM外的call,又涉及诸如Message/Transaction等基本概念;同时还包括call/delegatecall/callcode/send/transfer/sendTransaction等等方法。
对这些调用机制及基本概念的说明散落在 solidity文档 、黄皮书、白皮书 中,初学者容易搞晕。这里对这些基本概念、调用机制及用法做一下整体梳理。
PDF版本:Ethereum调用机制总结
PNG版本:Ethereum调用机制总结
示例代码:测试代码下载
pragma solidity ^ 0.4.18;
contract A {
uint public var2;
uint public var1;
B b1;
address addrB;
function A() public {
b1 = new B();
addrB=address(b1);
}
function callSet(address addr, uint param) public returns(uint) {
//addr.call(bytes4(keccak256(“set(uint)”)), param); //使用了uint,调用不生效。应当使用uint256; uint是uint256的昵称,但在ABI调用时候,只能使用长类型。
//使用address.call
addr.call(bytes4(keccak256(“set(uint256)”)), param); //call 使用的是被调用者的存储,因此改变的是B.var1值
//使用实例方式,可以直接采用callee.method形式调用,从而直接获取函数返回值
/*
B b2 = B(addr);
uint result = b2.set(param);
return result;
*/
//使用 new B()方式方式调用
// uint b1=b1.set(param);
// addrB.call(bytes4(keccak256(“set(uint256)”)), param);
return 1;
}
function delegatecallSet(address addr, uint param) {
//addr.delegatecall(bytes4(keccak256(“set(uint)”)), param); //使用了uint,调用不生效。应当使用uint256; uint是uint256的昵称,但在ABI调用时候,只能使用长类型。
addr.delegatecall(bytes4(keccak256(“set(uint256)”)), param); //delegatecall和callcode都是使用调用者的存储,特别要注意调用者和被调用者合约变量定义顺序,目前改变的是A.var2的值。
B b2 = B(addr); //使用实例方式,可以直接采用callee.method形式调用,从而直接获取函数返回值
uint result = b2.set(param);
// uint b1=b1.set(param);
// addrB.call(bytes4(keccak256(“set(uint256)”)), param);
}
function callcodeSet(address addr, uint param) {
addr.callcode(bytes4(keccak256(“set(uint256)”)), param);
}
function getVar1() public view returns(uint) {
return var1;
}
function getVar2() public view returns(uint) {
return var2;
}
function getAddr() public view returns(address) {
return addrB;
}
}
contract B {
uint public var1;
event MyEvent(uint param, uint result);
function set(uint param) public returns(uint) {
var1 = param;
MyEvent(param, 1);
return param;
}
}
转载请注明:出家如初,成佛有余 » Ethereum调用机制总结call/delegatecall/callcode/send/transfer