1小时搞明白以太坊 DAPP 开发 - 熊丽兵 | Jeth 第
编者按:本文系 登链科技 CTO 的熊丽兵 讲师,在由掘金技术社区主办,以太坊社区基金会、以太坊爱好者与 ConsenSys 协办的 《开发者的以太坊入门指南 | Jeth 第三期 - 上海场》 活动上的分享整理。Jeth 围绕以太坊技术开发主题的系列线下活动。每期 Jeth 会邀请以太坊开发领域的优秀技术团队和工程师在线下分享技术干货。旨在为开发者提供线下技术交流互动机会,帮助开发者成长。
欢迎添加稀土君微信:xitujun,回复“以太坊”进群和讲师交流。
本场分享视频回放链接(B 站)
第三期的 Jeth上海站线下分享活动我们邀请到 登链科技 CTO 熊丽兵 ,来给开发者分享一下智能合约以及它存在的理由,然后再介绍 DAPP 与传统 APP 的区别, 以及智能合约担任什么角色,应用如何与智能合约进行交互,帮助有编程经验的开发者能够快速上手以太坊开发。
谢谢大家,很高兴能够和大家分享一些知识经验,今天主题就是《1小时搞明白以太坊 DAPP 开发》,我们直接进入主题,先介绍我自己,之前在创业工场、猎豹移动做工程师,然后现在区块链行业瞎折腾。
这是我分享的内容,第一个先介绍什么是区块链的应用,再简单的实现一个DAPP。
什么是去中心化的应用?
我们做一个对比,现在我们先来看一下APP的架构,就是我们平时接触到的。平时接触的是一个个前端,例如APP、H5、小程序等,这个前端后面一般都会有一个相关的服务器,不管是前端显示的内容或者一些动作,它其实都是会有一些对应的请求发送到服务器里面,然后服务器收到这个请求之后会有一些回应,再发到前端的应用,就是这样一个简单的架构。
作为一个去中心化的应用,它的前端表现都是一样的,其实有时候我们在跟客户做应用时,他说:“咦!你这个看上去好像和我们看到的应用完全一样,没什么区别啊。 ”其实实际也是如此,关键他的后端不一样。关于这个疑问,我们有时候会在界面上加一行字,“此数据经过全网同步”,然后他们表示这就是去中心化应用,但其实关键是连接前端的这个后端的节点,它不但是一个服务器,而是后端它连着的一个网络,不管你是连接到任何一个节点,它在理论上都是一样的。
实际上你的应用是在一个网络上面,当前端请求发送到后端的时候,后端连接的节点会把这个请求扩散到整个网络。所以只有当真正的请求达到了全网的一个共识之后,它这个请求才算是真正的生效。这就不像你只有一个服务器时的,只能它说了算。
去中心化的交易所和中心化的交易所有什么不一样?
在中心化的交易所中,你所有的钱都不是在你的钱包里面,而是在中心化交易所的钱包里面,理论上它是可以为所欲为的,但是去中心化它是不一样,你的钱是在你们自己的钱包里面的,而且你的所有交易都是经过全网共识的,并不是说它自己的节点,所以这个交易是受我们自己控制的,这就是去中心化的应用和中心化的应用的一个最大的不同。
在中心化应用里面,通常我们发送一个请求是可以直接拿到结果,而去中心化应用要经过全网的共识,通常当你前端有一个请求发到节点,节点告诉你,因为我收到这个请求,它并不能立马处理并拿到结果,这也是一个开发去中心化应用里比较大的不同点,所以如果我们要想拿到这一个请求的相关状态,一般是通过事件Event。还有一点在去中心化应用里面,通常这个请求叫交易,这个交易和我们开发普通应用的时候是不同的,它是经过用户私钥的签名,这些就是几个明显的不同点。
接下来涉及到具体开发的一个过程,下面图片中展示了 APP 和 DAPP 比较图。
前端部分和客户端部分其实基本上是一样的,
前端用户:一般通过在知道我们普通开发APP的时候,它是通过一个HTTP的请求发到服务器再清空某转发的话,最后它会调用到对应的后台的程序中;在对应的去中心化中的地位中智能合约大概相当于我们之前在写普通应用中一个后端的服务程序这样的角色。
不同点是通常在开发DAPP的时候这个发送请求不再是HTTP,而是RPC(远程调用)的一种方式,其中这个节点EVM就相当于我们平时在写DAPP中它的Nginx/Apache这样的一个角色。
智能合约,它其实是跑在一个节点上,或者说都跑到一个EVM上,当然这个EVM其实它就是在节点上的。
我们要开发一个去中心化应用最主要做的是三部分 :
-
前端部分的编写
-
智能合约部分的编写
-
前端和智能合约的交互
我要实现这样一个简单的DAPP,它是在区块链上,保存需要名字和年龄,通过这个更新它会把这个内容同步到区块链中。
如何实现简单的DAPP?
需要三个部分要写 :
-
编写智能合约部分,相当于我们在写后端的服务程序
-
编写前端的部分,这次展现的是Web形式,其实也有其他形式
-
实现前端与合约交互
什么是智能合约?
智能合约其实是以太坊的一个程序,它是代码和数据(状态)的集合。而编写智能合约的语言是Solidity,如果我们用图中举例,把contract变成一个class,这就和我们写其他的语言基本上是一样的,就用contract定义hello,用function定义hello这样的一个函数,这个只有一个简单功能,它可以把一个字符串返回出来,这就是一个最简单的合约。
你既然要编写一个合约或程序必然需要用到相关的工具 :
-
Remix它是编写Solidity的一个IDE,这是一个Web 形式的IDE.
-
MetaMask钱包,它可以负责帮你把发送的交易做一个签名
-
Ganache节点,在开发中我们需要连接到一个节点,如果我们每次都直接连接到以太坊的节点,这个过程是非常慢的。所以我们可以使用Ganache这样模拟的一个节点,可以方便我们进行开发
我定义了一个合约,刚刚在前面有提到两个部分,一是保持一个名字,二是保持一个年龄。那么这个合约就有两个变量,这两个变量在智能合约里面它叫做状态变量,它的内容就会存在区块链的网络上,然后由你定义的两个方法,一个叫set,一个叫get,set就是用来设置这两个变量的内容,get是用来获取。
(演示)我现在来教大家合约如何去编译部署
首先打开Remix里面(前面提及的工具中IDE Remix),地址:https://remix.ethereum.org/ ,
现在我们看到的就是IDE,然后中间是编辑代码的区域,右边这边有Compile它其实是我这边勾成的,所以它是会自动去部署。部署的时候有一个叫环境的选择,它其实就是关联到MetaMaskq提供的一个环境。
我们现在来部署一下,它其实也是提交交易的一个过程,所以它会弹出来提示让我们去付多少钱Gas,然后同时也会完成一个签名的过程。部署好了之后,我们就可以对合约相应的函数进行调用,而此时合约的编译和部署都已经完成了。然后我们这边可以设置一个内容,它其实会发起一个交易,所以每次发起一个交易的时候,因为这个交易是用户发起的,所以需要用户的确认,这也是一个签名的过程。现在智能合约部分就写完了,这相当于我们在写程序的时后端部分。
现在我们再来看看前端部分, 上图中这个info是由我来显示内容的,两个input是需要用户去输入内容,一个button去更新内容,当用户点击这个button更新的时候,我们就把数据提交到以太坊的网络中。
需要提及的是潜在部分,有几个关键地方就是引入了几个库,其中一个是web3,它是就是用来和节点进行交互的一个库。然后这部分是我们需要去编写的,就是和合约进行交互的部分,web3它就是和合约进行交互的。我们之前有一个RPC,就是从平时我们写应用的时候是用HTTP请求,但是在我们编写DAPP的时候,它是RPC的一个请求,其实web3它是对RPC的一个封装。
web3是和以太坊节点交互的一个库,它可以用来获取到节点的状态,还有账号的信息以及调用建立合约事件等等 。
它也是对RPC的一个封装,它其实有很多个语言的实现,我们现在要用到的是它的JavaScript版本的实现web3.js,我们在开发一些其他的,比如说你开发一个安卓的应用,可能就要需要用到web3j,或者是你开发其他的就是非web形式的话,可能就要用到其他版本的封装。
要实现前端和合约的交互,首先我们需要把这个web3导入进来,之后我们要对web3做一个初始化。
之后我们就需要用到合约的一些信息去初始化实例化合约,这有一个叫web3.eth.contract(ABI)就是智能合约提供的一些接口的描述。
在我们编译智能合约的时候,其实编译器会为我们生成ABI。我们编码的时候就可以把这个ABI的信息拷贝出来。我们在实例化合约的时候需要把这个ABI的信息填入进来,告诉我们的WEB3要连接的这个合约到底有哪些函数?ABI的大概作用就是这些。
我们需要连接到的这个合约的地址是什么?这个地址就是我们在部署之后,它会为我们生成一个地址,这就是它要关联的哪一个合约的地址。我们这个初始化合约部分就完成了,接着我们可以使用合约的实例去调用合约的相关函数。
我们可以拿到info,它对应的就是一个合约的实例,达到这个合约的实例之后,就可以用这个实例来调用合约对应的方法,前面提及我们合约里面有一个set一个get,现在可以通过这个实例来调用get,get它其实是一个info的过程,所以我们传播的一个函数,这个函数从这个result里面就可以拿到getinfo里面它返回的结果。
setinfo它有两个参数,一个name和一个get,这个get和set就是对应我们刚刚编写合约的两个方法。我可以再次打开合约来做一个比对,刚刚我们的代码里面有个set,一个get。
在web3里面使用实例的话,它就可以来调用到这两个方法,然后我在这个界面的这个app.js里面,我们在初始化合约之后就会调用这个getinfo,它其实就是通过合约的实例来调用的,因为getinfo返回的是两个内容,另外它在js里面这边就是一个数组了,然后通过 下标result[0] 拿到名字,下标result [1] 拿到年龄,之后就可以把它设置到这个页面上。
Setinfo是当我们去点击更新按钮之后,它会去调用setinfo。现在我们其通过这么以上的操作之后,这个最简单的DAPP就已经实现了。
接下来我们可以来运行一下。
(演示)现在保存之后,这个值就已经拿到了区块链上的信息,其实这个信息就是之前我在部署合约时设置的这两个内容。当我们的页面关联上对应的合约的地址以及连接到对应的节点,它就可以拿到这个数据。这就是一个最简单的DAPP。但其实这个开发的过程是有点复杂,因为我们还要去复制它的ABI、节点的信息等,因此有的时候这样的开发过程非常麻烦,但这可以让我们去了解DAPP开发的一个流程。所以实际上在开发的时候,我们可能需要借助一些其他的一些框架,就是常用的两框架是一个Truffle,一个叫Embark。
我这边可以使用这个Truffle框架来做个演示,刚刚我们是在Remix里面做了这样一个编译,其实我们可以使用Truffle来去简化这个过程,这样的话就不用说频繁的去切换这个环境,我们可以直接在这个里面(演示通过命令行 truffle compile 编译)去完成这个操作。我们可以直接在这边编译,之后它会在build文件夹下给我们生成一个对应合约名字的Json文件,这里面就是有ABI的信息。
我们使用truffle-contract来初始化合约的时候需要用到ABI的信息,然后我们也同样去再做一个部署,部署之后它也会为我们在这个编译好的个Json文件里面去生成对应的地址,原来我们在初始化合约的时候在app.js里面其实需要很多硬编码的一些内容,包括地址以及ABI的信息,但是我们使用Truffle提供这样的contract的一个抽象的话,就可以让我们免去这些过程。
我这边把index.html里面的这个APP.JS换成另外一个app_tf.js,也就是它使用Truffle框架的js在这里面的话,我们就可以不用硬编码的去去复制ABI或者地址,直接使用通过或获取到它生成的一个中间的文件,节省时间,很方便,通过这种方式来实例化合约。
我们接下来再来测试一下,因为刚刚我们在truffle里面重新的去部署了合约,所以现在这个合约的状态是0,因为它默认值是0,然后如果是一个字符串的话,它就是空的一个字符串,我们随便可以写一个来更新测试一下。因为要提交交易,所以要用户的一个确认。现在这样的一个DAPP就完成了。
代码的地址为: https://github.com/xilibi2003/DAppDemos
欢迎大家跟我交流,下面是我的微信,也可以关注登链学院,我们提供了很多区块链视频课程,谢谢大家!