以太坊在调用智能合约中的函数时,即使交易成功发布到区块链上,但是如果合约参数检查出错,交易执行会失败,这个时候调用端仍然能够查询到交易被打包,但是交易执行结果跟期望的会不相符。
假设一个智能合约中有一个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,则可以调用正式的合约函数调用去向区块链发起合约调用的交易。
1万+

被折叠的 条评论
为什么被折叠?



