web3j采用call方式查询智能合约执行结果

 

 

以太坊在调用智能合约中的函数时,即使交易成功发布到区块链上,但是如果合约参数检查出错,交易执行会失败,这个时候调用端仍然能够查询到交易被打包,但是交易执行结果跟期望的会不相符。

假设一个智能合约中有一个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. 引入web3.js库 需要先在HTML文件中引入web3.js库,可以从官方网站下载或者使用CDN链接。 ```html <script src="https://cdn.jsdelivr.net/npm/web3@1.3.0/dist/web3.min.js"></script> ``` 2. 连接到以太坊网络 在JavaScript代码中,创建一个`Web3`对象并连接到以太坊网络。 ```js // 连接到以太坊网络 const web3 = new Web3(Web3.givenProvider || "http://localhost:8545"); ``` 其中,`Web3.givenProvider`是指网页已经连接了以太坊网络,可以直接使用当前提供商,否则指定一个本地的以太坊节点地址。 3. 加载智能合约ABI和地址 需要加载智能合约的ABI和地址,以便使用web3.js调用智能合约的方法。 ```js // 加载合约ABI和地址 const contractABI = [...]; const contractAddress = '0x...'; const myContract = new web3.eth.Contract(contractABI, contractAddress); ``` 4. 调用智能合约方法 调用智能合约的方法可以使用`myContract.methods`属性,该属性包含了智能合约的所有方法。以调用`get()`方法为例: ```js // 调用合约get()方法 myContract.methods.get().call((error, result) => { if (!error) { console.log(result); } else { console.error(error); } }); ``` 其中,`call()`方法表示调用智能合约的读取方法(不改变区块链数据),如果是写入方法需要使用`send()`方法。回调函数返回结果或错误信息。 5. 监听智能合约事件 智能合约的事件可以通过`myContract.events`属性进行监听。以监听`Transfer`事件为例: ```js // 监听Transfer事件 const transferEvents = myContract.events.Transfer(); transferEvents.on('data', (event) => { console.log(event.returnValues); }); transferEvents.on('error', console.error); ``` 以上就是使用web3.js调用智能合约的基本流程。涉及到的概念比较复杂,需要深入学习区块链和以太坊相关知识。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值