精华 深入解析调用合约的三种方法
发布于 2 年前 作者 路人-戊 4386 次浏览 来自 分享

当获取合约实例之后(比如 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"

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

8 回复

@路人-戊 厉害了,之前只是知道他们有区别,不知道实质。你这个是在哪里参考的资料哦

@路人-戊 我测试了,可以通过,在变量前面加上public就可以把testMem当作一个方法可以调用吗? uint public testMem; 调用testFunc1为什么不返回resMes字符串呢?

@sunnyFrank 没有constant关键字,它是一笔交易,那需要广播到网络中,最后这个执行的过程是在矿工的机器上进行的,所以不返回字符串很正常啊

楼主说的没错,但是对于第一种方法的返回值有点疑问,我自己试了一下,不管你函数的返回值你写的是什么,只要以发送交易的方式来调用函数,它的返回值都是一串交易hash,那这样就没法确认我的函数是否执行成功,比如我的函数本意是返回一个bool量,现在返回的是交易hash值,那么我如何通过检查我函数本意返回的那个bool值来确认我的调用是否成功呢?

@cq696925 可以通过回调函数来获取执行的结果

@路人-戊 如果我现在有一个方法,生成一条类似数据库的记录(比如注册用户),我需要把该数据保存在哪里,因为会经常生成数据。如果保存在关系型数据库,怎么和区块链上的hash进行对应?

回到顶部