深入解析以太坊中调用合约的三种方法

当获取合约实例之后(比如 testInstance),在geth console中可以通过三种方法调用合约方法(比如testFunc)

  • 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.2;
    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";
      }
    }
    

    将合约部署到私有链,并获取合约实例testInstance
    调用testFunc1

    > testInstance.testFunc1({from:eth.accounts[0]})
    I0117 19:38:21.348763 internal/ethapi/api.go:1047] Tx(0x157d429be29953ea451ea95cf468a3a67c4a86e9b49d1b6b97cc15c579a27003) to: 0xc9bc867a613381f35b4430a6cb712eff8bb50310
    "0x157d429be29953ea451ea95cf468a3a67c4a86e9b49d1b6b97cc15c579a27
    

    可见,确实创建了一笔交易,开启挖矿,等待打包…再查看下

    > testInstance.testMem()
    1
    > eth.getTransaction('0x157d429be29953ea451ea95cf468a3a67c4a86e9b49d1b6b97cc15c579a27003')
    {
    blockHash: "0x9fa0c7d071e1d2e772de3f6f326595b9d9159b0056213416018c75f2d5c04ad2",
    blockNumber: 118,
    from: "0xcb1f9cd557b5dd81955a4df89e9b4c8a33023c12",
    gas: 90000,
    gasPrice: 20000000000,
    hash: "0x157d429be29953ea451ea95cf468a3a67c4a86e9b49d1b6b97cc15c579a27003",
    input: "0x561f5f89",
    nonce: 45,
    r: "0xb77558d48ab4efcaa24309b1003a7c4efabfdda26c3844c6aa18c58c6a08181a",
    s: "0x57fe6dde27fa7cfd2fb422e2adc9465125750b3271127b68bb65d496d99be531",
    to: "0xc9bc867a613381f35b4430a6cb712eff8bb50310",
    transactionIndex: 0,
    v: "0x1c",
    value: 0
    }
    

    可见,它确实是一笔交易,修改了合约的状态变量,并且有90000的gas消耗。
    再来试下testFunc2

    > testInstance.testFunc2({from:eth.accounts[0]})
    "try to modify testMem and has constant label"
    

确实只是在本地执行,并没有创建交易,所以更不会修改合约的状态变量。


编辑于 2017-03-30

文章被以下专栏收录