1.5 智能合约如何与其他IT系统交互

我们在这里介绍智能合约与其它IT系统的交互特指以太坊上的智能合约与其它IT系统的交互。

1.5.1 通过JSON—RPC接口调用智能合约

JSON-RPC是基于JSON的跨语言远程调用协议。在以太坊中每一个节点都提供了一个对JSON-RPC的支持。用户可以通过JSON-RPC来和以太坊智能合约进行交互。

在使用JSON-RPC界面和智能合约进行交互时操作相当繁琐而且容易出错,因此我们在这里对此种方式不做过多介绍,我们将详细介绍下面的通过Web3.js和智能合约交互的过程。

1.5.2 通过Web3.js接口调用智能合约

Web3.js是Javascript的库,提供了用于和以太坊节点geth通信的Javascript API,在它内部实际还是使用的JSON-RPC与geth通信。

Web3.js是以太坊官方的Javascript API,可以帮助智能合约开发者使用HTTP或者IPC与本地或者远程的以太坊节点进行交互。实际上就是一个库的集合,主要包括下面几个库。

  1. web3-eth用来与以太坊区块链和智能合约交互

  2. web3-shh用来控制whisper协议与p2p通信及广播

  3. web3-bzz用来与swarm协议交互

  4. web3-utils包含了一些DAPP开发会用到的功能

Web3与geth通信使用的是JSON-RPC,这是一种轻量级的RPC(Remote Procedure Call)协议,整个通信的模型可以抽象为下图。

Web3 Communication Model

下面我们介绍些web3和智能合约的交互。

第一步:搭建测试链。

在这里我们选择testrpc。testrpc会默认创建10个账户,监听地址是localhost:8545。

第二步:创建智能合约。

我们使用智能合约开发环境Remix。我们进入Remix的网站,在合约编辑页面编写如下代码:

pragma solidity ^0.4.0;

contract StoreData {

uint storedData;

function setData(uint inputData) public {

storedData = inputData;

}

function getData() public constant returns (uint retVal) {

return storedData;

}

}

代码很简单,就是给storeData变量赋值与读取,接下来切换到 run 的 tab 下,将Environment切换成Web3 Provider,并输入我们的测试链的地址http://localhost:8545。Environment下有三个选项,其含义分别如下:

- Javascript VM:简单的Javascript虚拟机环境,练习智能合约编写的时候可以选择。

- Injected Web3:连接到嵌入到页面的Web3,比如连接到MetaMask。

- Web3 Provider:连接到自定义的节点,如私有的测试网络。

如果连接成功,那么在下面的Account选项会默认选择 testrpc创建的第一个账户地址。然后在Remix的run页面点击Create按钮就会把这个合约部署到测试网中。Remix 的页面不要关闭,我们后面会继续用到。

第三步:安装Web3。

在这之前,先在终端创建我们的项目,运行下列命令:

mkdir info

cd info

接下来使用 node.js 的包管理工具 npm 初始化项目,创建package.json文件,其中保存了项目需要的相关依赖环境。

npm init

一路按回车,不用输入任何信息直到项目创建完成,会在info目录下创建一个package.json文件。最后,运行下面命令安装web.js:

npm install web3

注意:web3在安装的过程中有些文件没有自动安装,因此我们要在https://codeload.github.com/ethereum/web3.js/zip/develop这里下载web3.js-develop.zip文件,解压缩后将整个dist目录拷贝到./node_modules/web3路径下

第四步:创建交互界面UI。

在项目目录下创建index.html,在这里我们将创建基础的 UI,包括storeData的输入框,以及一个按钮,这些将通过 jQuery 实现:

注意:在界面中关于jquery的引用在编写本节时,其最新版本为:https://code.jquery.com/jquery-3.3.1.slim.min.js用户一定要根据实际情况查看写代码时jquery的最新版本,以最新版本为准。

接下来编写main.css文件设定基本的样式。

关于index.html以及main.css的编写属于界面设计与本节关系不大,故在此省略,读者可参考网上示例编写。这里特别要注意的是UI 创建好之后,在index.html页面源代码的<script></script>标签中间编写web3.js的代码与智能合约交互。首先创建web3实例,并与我们的测试环境连接,具体代码如下:

<script>

Web3 = require('web3');

if (typeof web3 !== 'undefined') {

web3 = new Web3(web3.currentProvider);

} else {

// set the provider you want from Web3.providers

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

}

</script>

在上面代码的基础上,接下来设置默认的以太坊账户:

web3.eth.defaultAccount = web3.eth.accounts[0];

我们也可以直接把Remix的run页面的account账户地址写进来使用,下例中地址即为本节编写时,本例在Remix中的账户地址。

web3.eth.defaultAccount = '0xcf810d28d3f54d8e68b3089552888f498046b1f8';

我们使用运行testrpc已经创建了 10 个账户了,这里我们选择第一个账户当作默认账户。

接下来我们给web3指定我们的合约,这里需要合约的ABI。ABI可以使我们调用合约的函数,并且从合约中获取数据。

重新回到我们打开的 Remix页面,在 Compile 的 tab 下我们点击Details出现的页面中我们可以拷贝合约的ABI,如下图所示。

将其ABI编码复制到下例代码中的“PASTE ABI HERE!”:

var infoContract = web3.eth.contract(PASTE ABI HERE!);

我们这个例子的ABI编码为:

[

{

"constant": true,

"inputs": [],

"name": "getData",

"outputs": [

{

"name": "",

"type": "uint256"

}

],

"payable": false,

"stateMutability": "view",

"type": "function"

},

{

"constant": false,

"inputs": [

{

"name": "_data",

"type": "uint256"

}

],

"name": "setData",

"outputs": [],

"payable": false,

"stateMutability": "nonpayable",

"type": "function"

}

]

接下来转到 run 的页面,拷贝合约的地址,将其复制到下面的代码中的“PASTE CONTRACT ADDRESS HERE”:

var info = infoContract.at('PASTE CONTRACT ADDRESS HERE');

此例中我们得到的地址为:0x85049d5ec4279b5bf90b3521a8181cd604ae84f6

接下来我们就可以在script脚本中调用info.setData()和info.getData()。

以上的代码就简单地实现了对合约中两个函数的调用,读取和显示storeData变量。

到此我们就完成了web3.js与智能合约的连接。至此我们在index.html中的<script></script>加入的完整代码为:

if (typeof web3 !== 'undefined') {

web3 = new Web3(web3.currentProvider);

} else {

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

}

web3.eth.defaultAccount = '0xcf810d28d3f54d8e68b3089552888f498046b1f8';

var mycontractContract = web3.eth.contract([{"constant": true,"inputs": [],"name": "getData","outputs": [{"name": "","type": "uint256"}],"payable": false,"stateMutability": "view","type": "function"},{"constant": false,"inputs": [{"name": "_data", "type": "uint256"}],"name": "setData","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function" }]);

var info = infoContract.at('0x85049d5ec4279b5bf90b3521a8181cd604ae84f6');

后续读者可自行调用info.setData()和info.getData()。

注意:这里我们仅展示了通过web3与部署在测试网testrpc上的智能合约的互动。用户若想测试与以太坊主网上智能合约的互动,则必须按照前面章节所展示的把智能合约部署在以太坊主网,然后再调用web3与合约互动。

1.5.3 区块链浏览器

区块链浏览器是一种区块链搜索工具,我们在区块链浏览器中输入区块及交易相关字段可以查到它们的详细信息。

比如我们在以太坊浏览器中通过输入某钱包地址可以查询到此钱包的余额,输入一笔交易的ID可以查到这笔交易的详细信息。我们还可以输入某区块的高度,块哈希值搜索这个区块的所有内容。

在以太坊中常用的浏览器有:etherscan.io和etherchain.org。

我们打开etherscan.io浏览器,然后在右上角空格中输入关键字就可以搜索。我们在上一节中通过MetaMask的一个地址向以太坊中部署了一个智能合约“StoreData”,我们把MetaMask的那个地址值输入到这个搜索框,然后点击其右边的“GO”就能搜索到这个合约创建的 交易,具体信息如下。