摘要:前邊兩篇教程可以稱之為熱身,從這里開始,進入正題。這一次,我們要正式創(chuàng)建新的交易類型或者智能合約了。這個的功能是對賬戶進行操作,這個操作包括對數(shù)字的加減法數(shù)組的增刪字符串的設置等。
前邊兩篇教程可以稱之為熱身,從這里開始,進入正題。 這一次,我們要正式創(chuàng)建新的交易類型或者智能合約了。
1 創(chuàng)建合約
首先要進入dapp所在目錄
cd dapps//
然后執(zhí)行asch-cli的contract子命令
asch-cli contract -a
接下來會提示輸入合約的名字,這里輸入的是"Project"
? Contract file name (without .js) Project New contract created: ./contracts/Project.js Updating contracts list Done
這個命令會幫我們做三件事
新增了合約模板文件modules/contracts/Project.js
在modules/helper/transaction-types.js注冊了交易類型
在modules.full.json中注冊了新的模塊
2 定義實體字段
在實現(xiàn)一個智能合約之前,需要定義好合約執(zhí)行后生成的交易數(shù)據(jù)實體,即最終存儲到區(qū)塊鏈上的是哪些數(shù)據(jù),也就是相當于創(chuàng)建關系數(shù)據(jù)的表格 一個合約類型對應一張表格 表格的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字段種加入新的配置,還是為了聯(lián)合查詢以及序列化和反序列化時使用
{ "type": "left outer", "table": "asset_project", "alias": "t_p", "on": { "t.id": "t_p.transactionId" } }
將來,asch會把這些配置通過自動化的方式生成,開發(fā)者只需要輸入實體字段的名稱和類型即可。
3 實現(xiàn)合約接口
一個合約包含如下接口,有的必須要實現(xiàn),有個則使用默認生成的代碼即可
create # 創(chuàng)建一個交易的數(shù)據(jù)對象,主要是賦值操作 calculateFee # 設置交易費,即生成一次交易需要消耗的XAS數(shù)量 verify # 驗證交易數(shù)據(jù),比如字段是否合法,依賴條件是否滿足等 getBytes # 返回交易的二進制數(shù)據(jù),類型為Buffer apply # 合約的執(zhí)行邏輯,在區(qū)塊打包時調(diào)用,主要是分配和轉移交易涉及到的各個賬戶的資產(chǎn),以及賬戶其他字段的設置等 undo # apply的相反操作,在區(qū)塊回滾時會調(diào)用 applyUnconfirmed # 合約的預執(zhí)行邏輯,與apply類似,但是這個會實時的調(diào)用,就是說區(qū)塊打包前就會調(diào)用,因此涉及到的賬戶操作都是臨時、未確認的 undoUnconfirmed # applyUnconfirmed的相反操作,回滾時使用 ready # 交易是否準備完畢,是否滿足打包的條件,這是個高級功能,大部分情況都不需要,以后會多帶帶講解 save # 交易數(shù)據(jù)的序列化操作,就是將json字段映射到數(shù)據(jù)庫表格字段 dbRead # 交易的反序列化操作,將數(shù)據(jù)庫表格字段映射到json字段 normalize # 交易數(shù)據(jù)的格式化,把不相關的對象字段刪除,相關的對象統(tǒng)一類型,一般情況不需要
上面的接口大部分情況下使用默認的就可以了 開發(fā)者需要注意的主要是apply和applyUnconfirmed兩個接口,這是業(yè)務邏輯的主體部分。
4 實現(xiàn)Project合約
實現(xiàn)create
trs.recipientId = null; // 創(chuàng)建項目只需要發(fā)起者,不需要接收者,所以設為null trs.amount = 0; // 也不需要金額,只需要手續(xù)費 trs.asset.project = { name: data.name, description: data.description } // project對象的兩個數(shù)據(jù)字段 return trs;
設置交易費
這個項目不希望與XAS對接,那么就把交易費設置為0就行了
Project.prototype.calculateFee = function (trs) { return 0; }
數(shù)據(jù)檢驗
這個沒啥可解釋的
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); }
獲取二進制數(shù)據(jù)
二進制數(shù)據(jù)主要是為了生成簽名數(shù)據(jù),所以只需要把交易的實體數(shù)據(jù)組合起來打包成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; }
合約執(zhí)行邏輯
先看未確認合約的執(zhí)行
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); }
在這一步,檢查用戶的余額是否足夠,否則拒絕執(zhí)行, 接著判斷是否已經(jīng)存在相同的項目名稱, 最后會看到一個dapp開發(fā)中最重要的api,即modules.blockchain.accounts.mergeAccountAndGet。
這個api的功能是對賬戶進行操作,這個操作包括對數(shù)字的加減法、數(shù)組的增刪、字符串的設置等。 這里對賬戶余額執(zhí)行了減法操作,即把u_balance中的POINTS資產(chǎn),減去BURN_POINTS。 這里取名BURN_POINTS主要是為了表達這個合約的執(zhí)行需要燃燒一定數(shù)量的資產(chǎn),因為沒有指定被消耗掉的資產(chǎn)的去向,那么這些被消耗的資產(chǎn)就只有消失了,也就是被燃燒了。 這里只是為了簡單起見,如果業(yè)務邏輯不希望燃燒,可以把這些資產(chǎn)作為手續(xù)費,轉給應用的開發(fā)者或者節(jié)點運營者,或者轉移到一個基金賬戶中,用作將來的開發(fā)經(jīng)費,完全由你自己決定。
接下來再看看確認合約的執(zhí)行代碼
Project.prototype.apply = function (trs, sender, cb, scope) { modules.blockchain.accounts.mergeAccountAndGet({ address: sender.address, balance: {"POINTS": -BURN_POINTS} }, cb, scope); }
非常簡單,只有一個操作,僅僅是對賬戶資產(chǎn)進行一個減法操作。 大部分情況下, applyUnconfirmed是比apply要復雜的,特別是涉及到資產(chǎn)的減法操作時,因為前者要比后者執(zhí)行的更早,后者就沒必要做多余的條件檢查了。 我們要注意到,apply修改的是balance字段,applyUnconfirmed修改的是u_balance字段,
所以如果u_balance滿足條件(即有足夠的剩余資產(chǎn)),那么balance一定也會滿足條件,所以就沒必要進行進一步檢查了。
接下來的save, dbRead就沒必要解釋了,開發(fā)者可以自己發(fā)現(xiàn)其中的規(guī)律,直接套用即可。
5 實現(xiàn)http接口
在上一個步驟,已經(jīng)定義了一個project合約的所有邏輯了。 在這一步,我們需要增加兩個接口,都是為客戶端或前端服務的,一個是用于創(chuàng)建交易,一個是用于查詢交易歷史。
幾乎所有的交易創(chuàng)建都是類似的,一般可以分解成一下幾步
使用客戶端傳過來的secret生成密鑰對keypair
使用公鑰查詢或新建賬戶數(shù)據(jù),通過api modules.blockchain.accounts.getAccount
然后使用客戶端傳過來的交易實體數(shù)據(jù)和賬戶數(shù)據(jù)以及密鑰對,創(chuàng)建一個交易對象,通過api modules.logic.transaction.create
最后是調(diào)用api modules.blockchain.transactions.processUnconfirmedTransaction來處理這個交易
有一點需要注意的是library.sequence.add接口的使用,這個接口可以保證多個交易按先后順序嚴格執(zhí)行,如果你的合約邏輯中涉及到異步操作,應該要使用這個api。
再來看一下list這個查詢接口,熟悉sql的同學一眼就看出,這只不過是個聯(lián)表查詢操作。
為什么要聯(lián)表查詢呢?
因為transactions和asset_xxx表示的是一個交易的不同部分,前者是數(shù)據(jù)的基礎數(shù)據(jù),所有交易都通用,比如交易的發(fā)起者,交易數(shù)據(jù)的簽名,金額等等, 后者則屬于交易數(shù)據(jù)的擴展部分,是用戶自定義的數(shù)據(jù),與具體的業(yè)務邏輯相關。
6 實現(xiàn)投票合約
這個就不逐行解釋了,開發(fā)者可以自己研究asch-mini-dao的源碼,有了上面的基礎后,不難理解。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/23925.html
摘要:前邊兩篇教程可以稱之為熱身,從這里開始,進入正題。這一次,我們要正式創(chuàng)建新的交易類型或者智能合約了。這個的功能是對賬戶進行操作,這個操作包括對數(shù)字的加減法數(shù)組的增刪字符串的設置等。 前邊兩篇教程可以稱之為熱身,從這里開始,進入正題。 這一次,我們要正式創(chuàng)建新的交易類型或者智能合約了。 1 創(chuàng)建合約 首先要進入dapp所在目錄 cd dapps// 然后執(zhí)行asch-cli的contr...
摘要:但是我覺得在原理上與上一個項目相比,并沒有什么不同。源碼是最好的老師。 這個dice game與上一個mini dao相比,代碼規(guī)模大了許多,功能也復雜了很多,創(chuàng)建了三個合約類型,彼此之間有依賴關系,合約的執(zhí)行還要依賴歷史交易數(shù)據(jù)。 但是我覺得在原理上與上一個項目相比,并沒有什么不同。 源碼是最好的老師。
摘要:但是我覺得在原理上與上一個項目相比,并沒有什么不同。源碼是最好的老師。 這個dice game與上一個mini dao相比,代碼規(guī)模大了許多,功能也復雜了很多,創(chuàng)建了三個合約類型,彼此之間有依賴關系,合約的執(zhí)行還要依賴歷史交易數(shù)據(jù)。 但是我覺得在原理上與上一個項目相比,并沒有什么不同。 源碼是最好的老師。
摘要:基本流程有三種,,,,后兩種是發(fā)布到線上的,可通過公網(wǎng)訪問。第一種是運行在本地的只有一個節(jié)點的私鏈,主要是為了方便本地測試和開發(fā)。 1 基本流程 Asch有三種net,localnet,testnet,mainnet,后兩種是發(fā)布到線上的,可通過公網(wǎng)訪問。 第一種localnet是運行在本地的、只有一個節(jié)點的私鏈,主要是為了方便本地測試和開發(fā)。 Dapp的開發(fā)同樣要涉及到這三種網(wǎng)絡,即...
摘要:前一篇文章介紹了開發(fā)的基本流程,這一次打算創(chuàng)建一個擁有內(nèi)置資產(chǎn)的,并順便介紹下前后端通訊的協(xié)議和常用接口。我們的程序目前只能創(chuàng)建一種內(nèi)置資產(chǎn),如果有創(chuàng)建多種資產(chǎn)的需求,我們可以考慮開發(fā)。 前一篇文章介紹了asch dapp開發(fā)的基本流程,這一次打算創(chuàng)建一個擁有內(nèi)置資產(chǎn)的dapp,并順便介紹下前后端通訊的協(xié)議和常用接口。 1 創(chuàng)建一個帶內(nèi)置資產(chǎn)的dapp 其實這篇文章有些標題黨,因為創(chuàng)建...
閱讀 2130·2021-11-18 10:07
閱讀 3507·2021-09-04 16:48
閱讀 3214·2019-08-30 15:53
閱讀 1235·2019-08-30 12:55
閱讀 2453·2019-08-29 15:08
閱讀 3149·2019-08-29 15:04
閱讀 2879·2019-08-29 14:21
閱讀 2906·2019-08-29 11:21