编辑 | kou
如何基于以太坊来编写去中心化应用?超全开发教程,手把手带你学起来!
福利福利!本文节选自《精通以太坊·智能合约开发》,文末免费送书,5本哟!
听听技术大咖们关于这本书的评价吧!
“本书完完全全是一本面向开发者的技术书籍,建议所有想加入区块链领域的开发者阅读。”
——西祠胡同创始人、FIBOS创始人 响马
“本书延续了《深入浅出区块链》的风格,并且对以太坊智能合约及DApp开发进行了极为系统、全面的介绍,强烈推荐初学者学习!”
——工信部区块链应用研究院副院长 赖一城
“希望这本书可以成为区块链世界的燎原火种。”
——PHP ConChina 联合创始人 锅巴GG
还等什么,这么好的书,赶紧读一读!
在去中心化应用中,发送给节点的请求通常被称为“交易”。交易和普通的请求有很大不同,即交易的数据经过用户个人签名之后发送到节点。
另外,普通的请求大多是同步的,而交易大多数都是异步的;交易不是使用普通的HTTP JSON请求,而是使用JSON RPC请求。所以,接下来,先谈一下,什么是JSON RPC?
JSON RPC
JSON RPC 介绍
JSON RPC(Remote Protocol Call)是一种以JSON为格式的远程调用协议,其请求和返回都是JSON格式,常见的请求格式如下:
jsonrpc定义了JSON RPC版本。method为调用方法名。params为传入的参数,若无参数则为null。id为调用标识符,可以为字符串。
返回也是JSON格式:
jsonrpc:定义JSON RPC版本。
result:方法返回值。error调用时错误,无错误时返回null,有错误时则返回一个错误对象。
id:调用标识符,与调用方传入的标识一致,当请求中的id检查发生错误时(转换错误/无效请求),则必须返回null。
关于 JSON RPC 的详细规范可以查阅说明文档(http://www.jsonrpc.org/ specification)。
如何与以太坊节点进行通信
以太坊使用JSON RPC 2.0规范来和节点进行通信,我们来看看这个步骤是怎样实现的:
首先要求我们在启动节点时,加入--rpc选项,如下所示。
geth 会默认使用8545进行监听JSON RPC请求,如果要更改端口,使用 --rpcport
在返回的结果中,可以从result里拿到余额,需要注意的是JSON里的数字是十六进制编码。
除 eth_getBalance 方法之外,常用的如发送交易(用于和合约互动或创建合约)的方法为 eth_sendTransaction,获取账号的方法为 eth_accounts,所有方法的使用可以通过 https://github.com/ethereum/wiki/wiki/JSON-RPC 查看。
Web3.js
通过使用JSON RPC虽然可以完成和节点的通信,但是这个过程需要和原始的底层数据交互,比较容易出错。Web3.js是以太坊官方的JavaScript SDK,可以帮助智能合约开发者使用HTTP或者IPC与本地的或者远程的以太坊节点进行交互。
当然Web3.js同样是使用JSON RPC和节点进行通信的。不过Web3.js提供了更友好的接口,实际上Web3.js就是一个库的集合,主要包括下面几个库:
web3-eth用来与以太坊区块链和智能合约交互。
web3-shh用来控制whisper协议与p2p通信,以及广播。
web3-bzz用来与swarm协议交互。
web3-utils包含了一些DApp开发应用的功能。
在geth中使用Web3.js
geth启动的时候会加载Web3.js库,因此可以在geth交互控制台里直接使用Web3.js。这在第9章介绍合约部署的时候已经使用过,之前使用的Web3.js提供的接口如下。
Web3.js API具体提供了哪些接口可以在文档
(http://web3js.readthedocs.io/ en/1.0/index.html)中查询到。
在应用中使用Web3.js
另一种方式是,在我们开发的应用中引入Web3.js库来和智能合约交互。
项目引入Web3.js
首先你需要将Web3引入到工程中,根据项目的不同,使用不同的方式。
npm,npm install Web3。
bower,bower install Web3。
meteor,meteor add ethereum:Web3。
vanilla,dist./Web3.min.js。
创建Web3实例
然后提供一个Provider来创建一个Web3的实例,为了不覆盖一个已有的Provider,需要先检查Web3实例是否已存在。因为在Mist中,在有MetaMask插件的浏览器中使用时会提供Provider。
创建实例的方法如下:
创建好Web3对象后,就可以使用Web3.js 提供的API了。Web3.js所有的API可以在网站(http://web3js.readthedocs.io/en/1.0/index.html)上查询。
使用回调
由于Web3.js API被设计用来与本地的RPC结点交互,所以所有函数默认使用同步的HTTP请求。
如果想发起一个异步的请求,那么大多数函数允许传一个跟在参数列表后的可选的回调函数来支持异步。回调函数支持错误优先的回调模式(Error First Callback)。例如:
批量请求
可以允许将多个请求放入队列并一起执行,方法如下所示。
注意:批量请求并不会更快,批量请求的主要目的是用来保证请求的串行执行。实际上同时发起多个请求会更快,因为请求是异步处理的。
处理大数据
数据类型的返回结果,得到一个BigNumber对象,因为JavaScript不能正确地处理BigNumber,如下所示。
所以Web3.js依赖BigNumber 库,并且会自动进行引入,如下所示。
再看下面一个例子,即使有20位以上的浮点值,也会出错。所以,尽量让账户余额以wei为单位,仅仅在需要向用户展示时,才转换为其他单位。
去中心化应用案例
我们结合一个完整的案例来说明Web3.js在去中心化应用中的使用。下面是一个Web应用,其开发完成之后的界面,如下所示。
这个应用的名字(Name)和年龄(Age)数据是存贮在区块链上的。我们来看看是如何实现的。
搭建测试环境
在开发初期,我们没有必要使用真实的公链。为了开发效率,一般选择在本地搭建环境。
这里使用Ganache(http://truffleframework.com/ganache/),它可以提供一个模拟的以太坊节点环境(Ganache CLI是它的命令行版本),安装之后,打开的界面如下所示。
从图中可以看到Ganache会默认创建10个账户,监听地址是http://127. 0.0.1:7545,可以实时看到Current Block、Gas Price、Gas Limit等信息。
创建智能合约
打开Remix IDE(https://remix.ethereum.org),
在代码区域编写智能合约代码:
合约代码很简单,name和age是存在区块链中的状态变量,函数setInfo和getInfo用来进行变量赋值与读取。
接下来把Remix IDE右侧功能区域切换到run的tab下,将Environment切换成Web3 Provider,并输入Ganache 提供的RPC地址http://127.0.0.1:7545。下面对这三个选项进行一下说明:
JavaScript VM:提供JavaScript虚拟机环境。
Injected Web3:连接到嵌入页面的Web3,比如连接到MetaMask。
Web3 Provider:连接到自定义的节点。
连接成功后,下面的Account选项会默认选择Ganache创建的第一个账户地址,如下图所示。
点击Create,就会将智能合约部署到我们的测试环境中,如下图所示。
智能合约部署之后,接下来要编写应用UI及跟合约交互的部分。
创建项目,安装Web3
先创建应用的项目目录,使用以下命令。
使用node.js(安装Node)的包管理工具 npm 初始化项目。
在命令运行期间,输入项目名称、版本等信息。项目创建完成后,生成一个package.json文件,保存项目信息及相关依赖。
然后运行命令,安装Web3.js。
注意:在实际安装过程中,我发现Web3在安装完成后并没有/node_modules/ web3/dist/web3.min.js文件。这个问题在issue#1041(https://github.com/ethereum/ web3.js/issues/1041)有提到,但官方好像一直没解决。不过我们可以在这里下载所需的文件,解压后将dist文件夹的内容拷贝到/node_modules/web3路径下。
创建UI
在项目目录下创建index.html文件,在这里编写基础的UI。UI包括name和age的输入框,以及一个按钮。这里也会引入jQuery进行一些交互,index.html代码如下:
接下来需要编写main.css文件,设定基本的样式。
使用Web3与智能合约交互
UI 创建好之后,在