如何基于超级链开放网络快速部署一款DApp

自建链,开发部署太麻烦?

缺钱少人成本高?

一个超级链开放网络统统解决你的问题。

 

在上期线上公开课中,工程师详细介绍了“开放网络快速上手秘籍”。

本期超级链学院线上公开课教你如何基于超级链开放网络快速部署一款DApp。

明星讲师超哥主要围绕以下几点展开:

1. 智能合约如何与业务结合,使业务变为DApp

2. 链上智能合约与业务结合的例子

3. 例子中智能合约扮演的角色

4. 怎么开发公益基金公示智能合约

5. 如何使用迭代器查询

6. 智能合约总体功能图中的权限管理是什么

7. 如何部署和调用DApp

干货多多,继续往下看吧!

 

Q1:上期我们讲了如何部署一个智能合约,很多人会关心,智能合约如何跟自己的业务结合使业务变成一个DApp,超哥能给大家介绍下吗?

好的,一般来说,DApp的核心在于业务逻辑和数据不再托管在一个中心化服务上,而是通过智能合约运行在区块链网络这样的去中心化操作系统上,从而保证了数据安全、可信。

在实际实现过程中,开发者大多采用智能合约+用户界面的形式实现DApp,用户界面可以是Web页面或移动应用,实现用户交互对接。

 

Q2:能用举一个例子介绍下链上的智能合约如何和业务结合吗?

嗯,最近新冠肺炎疫情让大家都非常揪心,大家在保护好自己的同时也都积极的为湖北贡献自己的爱心,例如捐款捐物等。

现在有很多公益基金会接受捐款,对于捐赠者而言,自己的捐款是否用在合适的地方是大家都关心的,而对于公益基金会,构建更公开透明的运行机制才能赢得大家的信任。

而区块链在建立信任上有天生优势,特别是建立在更具有公信力的开放网络上。因此,我们可以公益捐款为例,介绍一个基金会利用开放网络智能合约构建的公益捐款公示DApp。

这个样例中,主要实现捐赠基金汇总、捐赠资金来源和去向的逐条公示,并对于每个捐款者可以查到自己的所有捐款记录,从而做到有据可查、公开透明。

 

Q3:那在这个例子中,智能合约扮演什么样的角色呢?

智能合约是慈善基金公示的核心,负责存储所有捐赠记录、支出记录,并提供对捐赠记录、支出记录的查询以及基金会资金总额的查询,也就是说最核心的业务逻辑都通过智能合约实现,数据完全存储在链上。

如上图所示的公益基金公示DApp,智能合约运行在超级链开放网络上,并对外提供数据查询和写入接口。数据写入接口主要包括新增支出、新增捐款、数据初始化等,数据查询接口主要包括查询所有支出和捐款明细,按照捐款人查询等。

同时,写入接口需要进行权限控制,只有基金会的管理账户才有权限写入数据,保证链上数据不被随意更改,而基金会每次对数据的修改都会记录在开放网络的账本上,因此保证了数据的公开透明。

而建立在智能合约之上的用户交互层则非常简单,通过开放网络SDK,可以实现对智能合约访问的RESTful API,并通过Web或移动程序的方式展现。

 

Q4:那么下面应该是实际开发智能合约了,超哥跟大家详细介绍下怎么开发这个公益基金公示智能合约吧。

嗯,又到了令人开心的编码环节。智能合约开发首先是设计好合约接口和参数。前面我们已经明确了合约需求,因此在接口设计上也比较清楚,写入接口主要包含下面三个,实现数据初始化、新增捐赠记录、新增支出记录功能: 

读接口主要包括下面4个,分别提供基金会当前概览数据,按照捐款人查询,查询所有捐款明细,查询所有拨款支出明细等:

确定所有接口和参数后,我们开始设计数据结构。目前C++合约支持KV存储和Table存储模型,在本例中,我们选用KV存储保存数据。为了方便遍历查询,我们给“所有捐款明细”、“所有支出明细”、“捐款人捐款列表”指定不同的Key前缀,方便通过合约SDK中的迭代器进行遍历查询。以所有捐款明细为例,数据组织方式如下图所示:

这里的“AllDonate_”是所有捐款明细列表的Key前缀,后面的“0000000001”是捐款记录的自增ID编号。而Value则是一个半结构化数据,包括捐款者的用户ID、捐款数额、时间、其他备注信息等。

对于按照捐款人维度查询的接口,则组织Key结构上稍微复杂一点,大致上以“Key前缀+捐款人ID+捐款记录ID”拼成一个key,本例中Key前缀是“UserDonate_”,这样在确定要查询的捐款人ID后,拼接为“UserDonate_UserID”的key前缀进行遍历。

同时,考虑到要进行基金会运行概览的统计,因此需要几个全局变量记录总得金额数据,分别是:TotalDonates表示总捐款金额,TotalCosts表示总拨付支出金额,Balance表示基金会目前账面余额。为了维护自增ID,也需要记录总捐款记录数和总支出记录数两个统计值。

数据接口确定后,就进入了具体的编码实现阶段了,实际代码编写不详细介绍了,这个公益基金公示智能合约样例我们开源在了

https://github.com/xuperchain/xuperchain/blob/v3.6/core/contractsdk/cpp/example/charity_demo.cc,大家可以查看完整的合约代码了解细节信息。

 

Q5:那么如何使用迭代器查询呢,能举一个查询接口的具体例子吗?

好的,我们以按照捐款人查询所有捐款记录为例介绍下迭代器如何使用。

上面是迭代器查询的代码片段,可以看到使用迭代器主要分为几个步骤:

1. 首先要确定迭代器遍历的Key前缀和终止位置,并创建迭代器对象iter。本例中Key前缀就是“UserDonate_UserID%”,而“~”字符这是ASCII表中最后一个可见字符,所以作为遍历终止位置。

2. 然后,开始进入循环迭代,“iter->next()”函数返回迭代器是否还有下一行符合条件的结果,如果没有则循环结束。

3. 如果迭代器找到下一行结果,则通过“iter->get()”获取到一个key-value对,Key中除去前缀部分就是捐款记录ID,value中这是捐款记录详情。

通过上述步骤可以遍历出捐款人的所有捐款记录。需要注意的是,迭代器默认的一次循环返回的最大结果是100行,因此如果记录数比较多的情况下,最好是每次传入一个起始ID进行分页查询。在我们的示例代码中,queryDonates和queryCosts两个接口都是传入一个查询起始ID和每页查询数量做分页查询,大家可以参照这两个接口了解具体实现。

 

Q6:之前的智能合约总体功能图中,还有一个权限管理的部分,能详细介绍下吗?

权限管理主要是对于写接口进行权限限制,因为捐款数据和支出数据不是任何人都能随便写入的,而是基金会的管理者才有权限将捐款信息和支出信息写入智能合约对外公示,因此需要对写入者的身份进行验证。在超级链开放网络中,我们有两种方式可以控制哪些人有权限访问相应的合约接口:

1. 一种是在智能合约的接口实现代码中,获取到合约上下文参数中的initiator,这个initiator是本次合约调用的发起人,开发者可以判断调用者是否是某个具有管理权限的address。而具有管理权限的address则可以在合约部署时通过initialize函数参数写入智能合约。

2. 另一种是使用超级链本身的ACL权限控制,这种方式支持合约接口级别的ACL权限配置,可以指定那些address具有访问某个接口的权限,并且ACL配置可以随时修改。相对而言,这种方式设置权限更为灵活。

而在本例中,我们采用了第一种方法设置管理权限,在初始化函数中通过“admin”参数写入一个管理员账户address,后面的写接口对会对比initiator是否是admin账号。这种硬编码的方式相对而言更具公信力,但不够灵活。

 

Q7:上面我们已经完成了DApp中智能合约的设计和开发,那么如何部署和调用呢?

部署的话,智能合约首先需要本地编译成wasm字节码,然后可以通过Go SDK进行部署,也可以通过xchain.baidu.com的开放网络平台上传字节码部署。

首先介绍下使用Go SDK部署合约,上一期我们介绍了通过Go SDK如何导入一个加密的账户私钥,我们进一步介绍下如何部署一个智能合约。在Go SDK中,部署合约已经封装成了很方便的接口,具体的代码实现可以参照SDK的样例代码:

https://github.com/xuperchain/xuper-sdk-go/blob/master/example/main.go#L124

通过平台图形化界面进行部署更为简单方便,可以参考开放网络文档

https://xuperos.readthedocs.io/zh_CN/latest/operation_manuals.html#create

这里也跟大家预告一个好消息,超级链开放网络很快会支持开发者在线编辑合约代码、编译并直接部署,整体易用性进一步提升。

 

合约调用目前可以通过Go SDK实现,具体的样例代码可以参考上一期的开放网络快速上手教程:

https://xchain.baidu.com/n/news/03b09bfde5edadcb20e9e67145af4b8b