1. 程式人生 > >以太坊智慧合約中函式呼叫三種方法(很重要!!!)

以太坊智慧合約中函式呼叫三種方法(很重要!!!)

外部呼叫: sendTransaction/call

函式呼叫一般分外部呼叫和內部呼叫兩種, 外部呼叫是通過JSON-RPC介面實現對合約函式的呼叫, 有3種呼叫方式:

testInstance.testFunc.sendTransaction();
testInstance.testFunc();
testInstance.testFunc.call();

區別如下:

  • testInstance.testFunc.sendTransaction() ; 會建立一個交易,呼叫之後會返回一個交易hash值,它會廣播到網路,等待礦工打包, 它會消耗gas。
  • testInstance.testFunc.call()
    ; 它完全是一個本地呼叫,不會向區塊鏈網路廣播任何東西,它的返回值完全取決於 testFunc 方法的程式碼,不會消耗gas。
  • 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
來源:簡書