以太坊智慧合約中函式呼叫三種方法(很重要!!!)
阿新 • • 發佈:2018-12-29
外部呼叫: sendTransaction/call
函式呼叫一般分外部呼叫和內部呼叫兩種, 外部呼叫是通過JSON-RPC介面實現對合約函式的呼叫, 有3種呼叫方式:
testInstance.testFunc.sendTransaction();
testInstance.testFunc();
testInstance.testFunc.call();
區別如下:
testInstance.testFunc.sendTransaction()
; 會建立一個交易,呼叫之後會返回一個交易hash值,它會廣播到網路,等待礦工打包, 它會消耗gas。testInstance.testFunc.call()
testInstance.testFunc()
; 它會比較特殊,由於有constant標識的方法不會修改狀態變數,所以它不會被編譯器執行。所以,如果testFunc() 有constant標識,它並不會被編譯器執行,web3.js會執行call()的本地操作。相反如果沒有constant標識,會執行sendTransaction()操作。
測試程式碼如下:
pragma solidity ^0.4.12; contract Test { uint public testMem; function testFunc1() returns (string resMes){ testMem++; resMes = "try to modify testMem,but has no constant label"; } function testFunc2() constant returns (string resMes){ testMem--; resMes = "try to modify testMem and has constant label"; } }
內部呼叫: call,callcode,delegatecall
內部呼叫是指合約內呼叫其他合約的函式. 除了直接呼叫函式,還可以通過call,callcode,delegatecall的方式呼叫其他合約的函式,區別如下:
- CALL:是在 被呼叫者 的上下文中執行,只能修改被呼叫者的storage;
- CALLCODE和DELEGATECALL: 是在 呼叫者 的上下文中執行, 可以修改呼叫者的storage;
- CALLCODE 阻止msg.sender和msg.value傳遞; 而DELEGATECALL不阻止;
- 在A的函式中,B.callcode(c的函式): c看到msg.sender是B;
- 在A的函式中,B.delegatecall(c的函式): c看到msg.sender是A;
合約示例如下:
contract D {
uint public n;
address public sender;
function callSetN(address _e, uint _n) {
// E的 storage被修改,D未修改
_e.call(bytes4(sha3("setN(uint256)")), _n);
}
function callcodeSetN(address _e, uint _n) {
// D的 storage被修改, E未修改
_e.callcode(bytes4(sha3("setN(uint256)")), _n);
}
function delegatecallSetN(address _e, uint _n) {
// D的storage被修改, E未修改
_e.delegatecall(bytes4(sha3("setN(uint256)")), _n);
}
}
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不會更新
}
}
contract C {
function foo(D _d, E _e, uint _n) {
_d.delegatecallSetN(_e, _n);
}
}
轉載連結:https://www.jianshu.com/p/f33df6fb3ce4
來源:簡書