目录
在以太坊中,若需要合约与合约之间的调用,则可以使用call、callcode和delegatecall方法,它们之间的联系如下:
图1:三种调用方式
这里以合约EthAlice调用合约EthBob为例,进行说明,其执行流程如下:
图2:合约间的调用流程(Alice调用Bob)
1、调用者EthAlice
pragma solidity ^0.4.18;
contract EthAlice {
uint public num;
address public addr;
function callSetNum(address ads, uint value) public returns(uint) {
require(ads.call(bytes4(keccak256("SetNum(uint256)")), value));
return value;
}
function callcodeSetNum(address ads, uint value) public returns(uint) {
require(ads.callcode(bytes4(keccak256("SetNum(uint256)")), value));
return value;
}
function delegatecallSetNum(address ads, uint value) public returns(uint) {
require(ads.delegatecall(bytes4(keccak256("SetNum(uint256)")), value));
return value;
}
}
2、被调用者EthBob
pragma solidity ^0.4.18;
contract EthBob {
uint public num;
address public addr;
event sendAddr(address);
function SetNum(uint _num) public {
num = _num;
addr = msg.sender;
emit sendAddr(msg.sender);
}
}
3、部署合约
在MetaMask里选择一个Rinkeby测试网账户:0x6026DfB9816D22F65F1011639B207B1c3A2C2e84
然后在Remix上部署EthAlice和EthBob合约,得到如下:
EthAlice合约地址:0xeb0282Dcd268afCFeAFA84ea2260edC2c7747381
EthBob合约地址: 0xe981880Ac36360A1bF4F8F2a369877dbE29Aa8d4
3.1 测试call()调用方式
在Remix里的部署页面里,点开ETHALICE --> callSetNum 输入如下2个参数:
ads:(Bob)0xe981880Ac36360A1bF4F8F2a369877dbE29Aa8d4
value:32
图3:call()调用方式
Alice通过call()方式,修改的是Bob的num:0–>32,而不是自身的num:0–>0;即call()方式,修改的是被调用者的storage。
Alice的msg.sender = 交易的发起者地址
Bob的msg.sender = 调用者地址(Alice合约地址)
3.2 测试callcode()调用方式
在Remix里的部署页面里,点开ETHALICE --> callcodeSetNum 输入如下2个参数:
ads:(Bob)0xe981880Ac36360A1bF4F8F2a369877dbE29Aa8d4
value:34
图4:callcode()调用方式
Alice通过callcode()方式,修改的是自身num:32–>34,
它不会修改Bob的num:32–>32;
即callcode()方式,修改的是调用者自身的storage。
Alice的msg.sender = 调用者地址(Alice合约地址)
Bob的msg.sender = 调用者地址(Alice合约地址)
3.3 测试delegatecall()调用方式
在Remix里的部署页面里,点开ETHALICE --> delegatecallSetNum 输入如下2个参数:
ads:(Bob)0xe981880Ac36360A1bF4F8F2a369877dbE29Aa8d4
value:36
图5:delegatecode()调用方式
Alice通过delegatecall()方式,修改的是自身num:34–>36,
它不会修改Bob的num:32–>32;
即delegatecall()方式,修改的是调用者自身的storage。
Alice的msg.sender = 交易的发起者地址
Bob的msg.sender = 调用者地址(Alice合约地址)