Dapp开发教程三 Asch Dapp Mini DAO

Asch网友2017-11-03 13:49:19  阅读 -评论 0

如果说前面两篇文章是热身的话,那么从这里开始,我们要进入正题了。

这一次,我们要正式创建新的交易类型或者智能合约了。

1 创建合约

首先要进入dapp所在目录

cd dapps/<dapp id>/

然后执行asch-cli的contract子命令

asch-cli contract -a

接下来会提示我们输入合约的名字,这里我们输入的是"Project"

? Contract file name (without .js) Project

New contract created: ./contracts/Project.js

Updating contracts list

Done

这个命令会帮我们做三件事

  1. 新增了合约模板文件modules/contracts/Project.js
  2. 在modules/helper/transaction-types.js注册了交易类型
  3. 在modules.full.json中注册了新的模块
2 定义实体字段

在实现一个智能合约之前,我们需要定义好合约执行后生成的交易数据实体,即最终存储到区块链上的是哪些数据,也就是相当于创建关系数据的表格
一个合约类型对应一张表格
表格的schema在blockchain.json中进行配置

我们的project类型比较简单,只包含name和description字段
另外transactionId字段是每个实体表格都需要的,是作为基础交易transactions的外键。

{

"table": "asset_project",

"alias": "t_p",

"type": "table",

"tableFields": [

{

"name": "name",

"type": "String",

"length": 16,

"not_null": true

},

{

"name": "description",

"type": "Text",

"not_null": true

},

{

"name": "transactionId",

"type": "String",

"length": 21,

"not_null": true

}

],

"foreignKeys": [

{

"field": "transactionId",

"table": "transactions",

"table_field": "id",

"on_delete": "cascade"

}

]

}

然后我们需要在join字段种加入新的配置,还是为了联合查询以及序列化和反序列化时使用

{

"type": "left outer",

"table": "asset_project",

"alias": "t_p",

"on": {

"t.id": "t_p.transactionId"

}

}

将来,我们会把这些配置通过自动化的方式生成,开发者只需要输入实体字段的名称和类型即可。

3 实现合约接口

一个合约包含如下接口,有的必须要实现,有个则使用默认生成的代码即可

create # 创建一个交易的数据对象,主要是赋值操作

calculateFee # 设置交易费,即生成一次交易需要消耗的XAS数量

verify # 验证交易数据,比如字段是否合法,依赖条件是否满足等

getBytes # 返回交易的二进制数据,类型为Buffer

apply # 合约的执行逻辑,在区块打包时调用,主要是分配和转移交易涉及到的各个账户的资产,以及账户其他字段的设置等

undo # apply的相反操作,在区块回滚时会调用

applyUnconfirmed # 合约的预执行逻辑,与apply类似,但是这个会实时的调用,就是说区块打包前就会调用,因此涉及到的账户操作都是临时、未确认的

undoUnconfirmed # applyUnconfirmed的相反操作,回滚时使用

ready # 交易是否准备完毕,是否满足打包的条件,这是个高级功能,大部分情况都不需要,以后会单独讲解

save # 交易数据的序列化操作,就是将json字段映射到数据库表格字段

dbRead # 交易的反序列化操作,将数据库表格字段映射到json字段

normalize # 交易数据的格式化,把不相关的对象字段删除,相关的对象统一类型,一般情况不需要

上面的接口大部分情况下使用默认的就可以了
开发者需要注意的主要是apply和applyUnconfirmed两个接口,这是业务逻辑的主体部分。

4 实现Project合约

实现create

trs.recipientId = null;

// 创建项目只需要发起者,不需要接收者,所以设为null

trs.amount = 0;

// 也不需要金额,只需要手续费

trs.asset.project = {

name: data.name,

description: data.description

}

// project对象的两个数据字段

return trs;

设置交易费

这个项目我们不希望与XAS对接,那么就把交易费设置为0就行了

Project.prototype.calculateFee = function (trs) {

return 0;

}

数据检验

这个没啥可解释的

Project.prototype.verify = function (trs, sender, cb, scope) {

if (trs.recipientId) {

return cb("Recipient should not exist");

}

if (trs.amount != 0) {

return cb("Amount should be zero");

}

if (!trs.asset.project.name) {

return cb("Project must have a name");

}

if (trs.asset.project.name.length > 16) {

return cb("Project name must be 16 characters or less");

}

if (!trs.asset.project.description) {

return cb("Invalid project description");

}

if (trs.asset.project.description.length > 1024) {

return cb("Project description must be 1024 characters or less");

}

cb(null, trs);

}

获取二进制数据

二进制数据主要是为了生成签名数据,所以只需要把交易的实体数据组合起来打包成Buffer就可以了。
组合的方式可以随便,比如,可以通过bytebuffer,也可以通过简单的字符串连接。

Project.prototype.getBytes = function (trs) {

try {

var buf = new Buffer(trs.asset.project.name + trs.asset.project.description, "utf8");

} catch (e) {

throw Error(e.toString());

}

return buf;

}

合约执行逻辑

我们先看未确认合约的执行

Project.prototype.applyUnconfirmed = function (trs, sender, cb, scope) {

if (sender.u_balance["POINTS"] < BURN_POINTS) {

return setImmediate(cb, "Account does not have enough POINTS: " + trs.id);

}

if (private.uProjects[trs.asset.project.name]){

return setImmediate(cb, "Project already exists");

}

modules.blockchain.accounts.mergeAccountAndGet({

address: sender.address,

u_balance: { "POINTS": -BURN_POINTS }

}, function (err, accounts) {

if (!err) {

private.uProjects[trs.asset.project.name] = trs;

}

cb(err, accounts);

}, scope);

}

在这一步,我们检查用户的余额是否足够,否则拒绝执行,
接着判断是否已经存在相同的项目名称,
最后我们会看到一个dapp开发中最重要的api,即modules.blockchain.accounts.mergeAccountAndGet。

这个api的功能是对账户进行操作,这个操作包括对数字的加减法、数组的增删、字符串的设置等。
这里我们对账户余额执行了减法操作,即把u_balance中的POINTS资产,减去BURN_POINTS。
这里我们取名BURN_POINTS主要是为了表达这个合约的执行需要燃烧一定数量的资产,因为我们没有指定被消耗掉的资产的去向,那么这些被消耗的资产就只有消失了,也就是被燃烧了。
这里我们只是为了简单起见,如果你的业务逻辑不希望燃烧,可以把这些资产作为手续费,转给应用的开发者或者节点运营者,或者转移到一个基金账户中,用作将来的开发经费,完全由你自己决定。

接下来再看看确认合约的执行代码

Project.prototype.apply = function (trs, sender, cb, scope) {

modules.blockchain.accounts.mergeAccountAndGet({

address: sender.address,

balance: {"POINTS": -BURN_POINTS}

}, cb, scope);

}

非常简单,只有一个操作,仅仅是对账户资产进行一个减法操作。
大部分情况下, applyUnconfirmed是比apply要复杂的,特别是涉及到资产的减法操作时,因为前者要比后者执行的更早,后者就没必要做多余的条件检查了。
我们要注意到,apply修改的是balance字段,applyUnconfirmed修改的是u_balance字段,

所以如果u_balance满足条件(即有足够的剩余资产),那么balance一定也会满足条件,所以就没必要进行进一步检查了。

接下来的save, dbRead我想就没必要解释了,开发者可以自己发现其中的规律,直接套用即可。

5 实现http接口

在上一个步骤,我们已经定义了一个project合约的所有逻辑了。
在这一步,我们需要增加两个接口,都是为客户端或前端服务的,一个是用于创建交易,一个是用于查询交易历史。

几乎所有的交易创建都是类似的,一般可以分解成一下几步

  1. 使用客户端传过来的secret生成密钥对keypair
  2. 使用公钥查询或新建账户数据,通过api modules.blockchain.accounts.getAccount
  3. 然后使用客户端传过来的交易实体数据和账户数据以及密钥对,创建一个交易对象,通过api modules.logic.transaction.create
  4. 最后是调用api modules.blockchain.transactions.processUnconfirmedTransaction来处理这个交易

有一点需要注意的是library.sequence.add接口的使用,这个接口可以保证多个交易按先后顺序严格执行,如果你的合约逻辑中涉及到异步操作,应该要使用这个api。

我们再来看一下list这个查询接口,熟悉sql的同学一眼就看出,这只不过是个联表查询操作。

为什么要联表查询呢?

因为transactions和asset_xxx表示的是一个交易的不同部分,前者是数据的基础数据,所有交易都通用,比如交易的发起者,交易数据的签名,金额等等,
后者则属于交易数据的扩展部分,是用户自定义的数据,与具体的业务逻辑相关。

6 实现投票合约

这个就不逐行解释了,开发者可以自己研究asch-mini-dao的源码,有了上面的基础后,相信不难理解。

声明:链世界登载此文仅出于分享区块链知识,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担。此文如侵犯到您的合法权益,请联系我们100@7234.cn

    参与讨论 (0 人参与讨论)

    相关推荐

    比特币有什么缺点?

    1.交易平台的脆弱性。比特币网络很健壮,但比特币交易平台很脆弱。交易平台通常是一个网站,而网站会遭到黑客攻击,或者遭到主管部门的关闭。2.交易确认时间长。比特币钱包初次安装时,会消耗大量时间下载历史交易数据块。而比特币交易时,为了确认数据准确性,会消耗一些时间,与p2p网络进行交互,得到全网确认后,交易才算完成。3.价格波动极大。由于大量炒家介入,导致比特币兑换现金的价格如过山车一般起伏。使得比

    业务中使用区块链的四种方式

    业务中使用区块链的四种方式

    暴走时评:区块链是一种支持像比特币这样的数字货币的公共分类帐本,并且正改变着我们的业务方式。一旦那些对匿名交易,甚至是秘密交易感兴趣的人接纳了这样一种鲜为人知的工具,加密货币就会日趋成为主流。 区块链是一种支持像比特币这样的数字货币的公共分类帐本,并且正改变着我们的业务方式。一旦那些对匿名交易,甚至是秘密交易感兴趣的人接纳了这样一种鲜为人知的工具,加密货币就会日趋成为主流。越来越多的个人和企

    区块链:法定数字货币技术路线的必然选择

    区块链:法定数字货币技术路线的必然选择

    在人类发展史上,货币的进化从未停止。从物物交换,到金属铸币,再到纸质货币,以及当前正在发展的数字货币正在向着越来越便捷的方向进化。 比特币的出世起初并未带来轰动,但是最近几年其价格惊人的爬高创造出了一个个造富神话,引起各国政府及监管机构的关注。虽然金融专家普遍认为它只是一种资产,而非货币,但是,其背后的区块链(Blockchain)技术引起了包括各大金融机构、政府、企业及学术界的浓厚兴趣,未

    用区块链记录证书,证明真伪,墨尔本大学迈出了第一步

    用区块链记录证书,证明真伪,墨尔本大学迈出了第一步

    墨尔本大学宣布发起区块链认证和审核计划,允许通过一种隐私、安全且持久的方式验证学生的证书。 墨尔本大学正在试验一个区块链记录维护项目,允许接收者(即学生)存储他们的证书,出于核验目的,第三方也能访问这个系统。Learning Machine是这个发布系统的开发者,他们采用的是麻省理工媒体实验室(MIT Media Lab)在2016年提交的Blockcerts开源代码。 墨尔本大学副校长格雷

    日本IT巨头富士通联合日本“三大行”开发区块链p2p资金转移系统

    日本IT巨头富士通(Fujitsu)与三家大型银行已经宣布计划试点一项基于区块链创建的点对点资金转移系统。 通过与日本三大行——瑞穗金融集团,三井住友金融集团和三菱UFJ金融集团——的合作,富士通将现场试验一种基于云的区块链平台,用于在个体之间发送资金,并开发一款智能手机APP来提高这个系统的可用性。 从理论上讲,这个平台将把三大行的客户法定货币账户与这个区块链系统相连接。客户然后将能够使用这

    动画科普:什么是比特币?

    动画科普:什么是比特币?

    比特币(Bitcoin,简写BTC)概念由中本聪(化名)提出,是一种点对点、去中心化的数字资产;2009年,中本聪打包了第一个区块,并获得50枚比特币的挖矿奖励,挖矿奖励每4年减半一次,按此计算,比特币预计2140年发行完毕,总量为2100万枚。 随着比特币的发展,比特币逐渐受到认可:德国为全球首个接受比特币支付的国家;微软、戴尔等知名企业也纷纷接受比特币支付。 举个栗子,你能直接用比特币买到

    3分钟理解什么是公有链、私有链、联盟链、许可链

    不同的区块链有着不同的内涵和功能,在区块链领域经常出现的公有链、私有链、联盟链、许可链,这些又都代表什么意思呢? 公有链 公有链是指全世界任何人都可以随时进入系统中读取数据、发送可确认交易、竞争记账的区块链。公有链通常被认为是完全去中心化的,因为没有任何人或机构可以控制或篡改其中数据的读写。公有链一般会通过代币机制鼓励参与者竞争记账,来确保数据的安全性。比特币、以太坊都是典型的公有链。 私

    区块链是比特币的底层技术,但似乎两者已走上不同的道路

    区块链是比特币的底层技术,但似乎两者已走上不同的道路

    比特币的出现带来了一项新的技术——区块链,不过区块链和比特币似乎已走上了两条不一样道路,作为技术的区块链被越来越多的人所看好,而性质偏向于投资的比特币似乎被更多人看衰。 成也萧何败也萧何 比特币火爆的原因是其拥有去中心化、全世界流通、专属所有权、低交易费用、无隐藏成本、跨平台挖掘的特性,这些特性促使比特币成为了很多人关注的焦点。之后众多庄家的入局让比特币一瞬间成为了热门投资产业,但这几大特

    麦妖榜
    更新日期 2019-04-24
    排名用户贡献值
    1BitettFan23830
    2等待的宿命23697
    3六叶树20309
    4区块大康16762
    5天下无双16192
    6lizhen00214933
    7让时间淡忘14286
    8linjm122713830
    9冷风大q11188
    10momo11174
    返回顶部 ↑