赞
踩
以太坊在调用智能合约中的函数时,即使交易成功发布到区块链上,但是如果合约参数检查出错,交易执行会失败,这个时候调用端仍然能够查询到交易被打包,但是交易执行结果跟期望的会不相符。
假设一个智能合约中有一个transfer函数:
- function transfer(address to, uint256 val) public view returns(bool) {
- require (msg.sender==owner);//only contract owner can call this function
- assert (val>0 && this.balance>=val);
- to.transfer(val);
- Award(to,val);
- return true;
- }
transfer函数中用require检查了参数,如果调用者不是合约发布者owner,或者合约的账户余额小于转账额度,都会抛出异常,导致交易区块链上回滚。
现在我这测试链上contract合约是由账户1发布的。如果让账户0来调用该合约给账户2转账10 ether,看一下区块链会发生什么情况:
- > contract.transfer.sendTransaction(eth.accounts[2],web3.toWei(10,"ether"),{from:eth.coinbase})
- INFO [08-15|17:16:11.230] Submitted transaction fullhash=0x6b87baddbf25edd4bf0d08a47a6f30a7811aba80ec4b1be248369b61983aece4 recipient=0xC14E589990F7e6F7cD4beDdb073716f66bbd254b
- "0x6b87baddbf25edd4bf0d08a47a6f30a7811aba80ec4b1be248369b61983aece4"
- INFO [08-15|17:16:11.230] evm run error err="invalid opcode 0xfd"
- INFO [08-15|17:16:11.230] VM returned with error err="invalid opcode 0xfd"
- > miner.start()
- INFO [08-15|17:16:21.585] Updated mining threads threads=0
- INFO [08-15|17:16:21.585] Transaction pool price threshold updated price=12000000000000
- INFO [08-15|17:16:21.585] Starting mining operation
- INFO [08-15|17:16:23.732]
查询交易:
- > eth.getTransaction("0x6b87baddbf25edd4bf0d08a47a6f30a7811aba80ec4b1be248369b61983aece4")
- {
- blockHash: "0x6b0b9d2afc7a575d98cd9ba5a6f8573cb63a39dd5213c2b91fc6efb1ce5d42cb",
- blockNumber: 8,
- from: "0xe0d268886b753fd1778b3698956726c3dbf5d9a4",
- gas: 90000,
- gasPrice: 100000000000,
- hash: "0x6b87baddbf25edd4bf0d08a47a6f30a7811aba80ec4b1be248369b61983aece4",
- input: "0xa9059cbb00000000000000000000000041111c21df363759fa47fabf530508369c0463190000000000000000000000000000000000000000000000008ac7230489e80000",
- nonce: 4,
- r: "0x1c0b64699e19f83af21119c47aa553bfcd74d3bffbf59f6ac8c7bef351efab5f",
- s: "0x6b3dffc583e4a33ccf4edd6c0a766d8f0b29c8ee98ff8688e2722924a82569ec",
- to: "0xc14e589990f7e6f7cd4beddb073716f66bbd254b",
- transactionIndex: 0,
- v: "0x10a",
- value: 0
- }
- >

可以看到交易被打包到高度为8的区块中了,但是账户2收到10 ether了没有?查询账户2余额:
- > eth.getBalance(eth.accounts[2])
- 0
可以看到合约交易虽然被打包,但是合约函数执行结果没效果。这个时候程序端是很难监控到合约执行效果的。由于合约函数调用时参数错误导致合约执行失败,区块链是不会返回错误给调用端的。可以采用call调用的方式来查询合约函数执行结果:
- > contract.transfer(eth.accounts[1],web3.toWei(10,"ether"),{from:eth.coinbase})
- INFO [08-16|11:06:50.363] evm run error err="invalid opcode 0xfd"
- INFO [08-16|11:06:50.363] VM returned with error err="invalid opcode 0xfd"
- false
- > contract.transfer(eth.accounts[1],web3.toWei(10,"ether"),{from:eth.accounts[1]})
- true
- >
采用call查询智能合约的transfer函数执行能不能成功,第一次使用eth.coinbase来调用合约,发现返回false。第二次使用合约的发布账户eth.accounts[1]来调用,这回返回true,说明这样能够调用成功。使用call方式只是查询区块链,但是并不会向区块链提交交易。
web3j里面实现call查询方式是:
- public boolean querryTransfer(String to, BigInteger val, String from, String contractAddress) throws Exception
- {
- List<Type> inputParameters = new ArrayList<>();
- inputParameters.add(new Address(to));
- inputParameters.add(new Uint256(val));
- Function function = new Function("transfer",
- inputParameters,
- Collections.<TypeReference<?>>emptyList());
- String encodedFunction = FunctionEncoder.encode(function);
- org.web3j.protocol.core.methods.response.EthCall response = ethClient.ethCall(
- Transaction.createEthCallTransaction(from, contractAddress, encodedFunction),
- DefaultBlockParameterName.LATEST)
- .sendAsync().get();
-
- if(response.getValue().equals("0x"))
- return false;
- return true;
- }

当函数返回false,说明合约函数调用会失败,这个时候需要检查相关参数。当函数返回true,则可以调用正式的合约函数调用去向区块链发起合约调用的交易。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。