簡介
這章的內容詳細分析一下涉及智能合約Dapp的整個開發流程,注意是涉及只能合約,如果你只要一些基本轉BTM功能沒有太大意義,本內容補充一下官方提供的 比原鏈DAPP開發流程,詳細實踐過好踩到的一些坑,還有一些真正具體的技巧還有經驗,個人認爲非常有用,起碼讓開發者可以更快速地去操作。
資料說的儲蓄分紅合約太複雜了,簡單說說邏輯,銀行發了一筆股份資產,用合約鎖定,用戶去觸發這個合約的方法,付出了錢兌換了對應份額的股份資產,當達到一定的高度,就可以通過用股份資產兌換回本金與分紅(錢+利息)。 裏面包含了兩個合約~~
整體流程
開發流程分爲,1)編寫智能合約;2)發合約交易;3)測試解鎖合約方法;4)基於插件錢包開發Dapp前端;5)開發後端;
流程貌似非常簡單,本人在1,2,3 步浪費了很多時間。其中有些坑踩過接下來介紹一下;
1)編寫智能合約,上面提供的 比原鏈DAPP開發流程,寫得很清楚,使用的是equity非常簡單,直接下載最新版 用命令 【./equity TradeOffer --instance 】 就能得到一串編譯後的合約程序代碼,簡稱智能合約程序。
E:\GoWorks\src\github.com\equity\equity>equity.exe jiedai_6.txt --instance ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 260374 260474 260574 260674 260774 260874 260874 00141ccef16d2ac1ab22baa8acfa1633fdc32df
d55aa b1f38553d95177c53755996baf523da006da977008f069792bb6a2c3b6a253fb
======= PartLoanCollateral =======
Instantiated program:
20b1f38553d95177c53755996baf523da006da977008f069792bb6a2c3b6a253fb1600141ccef16d2ac1ab22baa8acfa1633fdc32dfd55aa030afb03030afb0303a6fa030342fa0303def903037af9030316f90320ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ffffff4d2b015b7a76529c641d010000640c0100005c7900a0695c790500f2052a01947600a0695379cd9f5579cda09a916164380000005a95639a00000054798ccd9f5679cda09a916164500000005895639a00000055798ccd9f5779cda09a916164680000005695639a00000056798ccd
9f5879cda09a916164800000005495639a00000057798ccd9f5979cda09a916164980000005295639a0000005195c3787ca169c3787c9f916164f5000000005e795479515e79c1695178c2516079c16952c3527994c251006079895f79895e79895d79895c79895b79895a79895979895879
895779895679890274787e008901c07ec1696307010000005e795479515e79c16951c3c2516079c169632b010000587acd9f6900c3c2515c7ac1632b010000755b7aaa5b7a8800c3c2515d7ac1747800c0
2)發合約交易, 先解釋一下合約的邏輯,儲蓄分紅合約太複雜,所以我們用幣幣交易合約去舉例子,
contract TradeOffer(assetRequested: Asset,
amountRequested: Amount,
seller: Program,
cancelKey: PublicKey) locks valueAmount of valueAsset {
clause trade() {
lock amountRequested of assetRequested with seller
unlock valueAmount of valueAsset
}
clause cancel(sellerSig: Signature) {
verify checkTxSig(cancelKey, sellerSig)
unlock valueAmount of valueAsset
}
}
看看智能合約的交易圖,方便小白理解:
所以儲蓄分紅合約一開始肯定要鎖定一部分資產,所以必須部署合約交易。那麼如何觸發呢?
本人通過PC錢包的接口方式去部署合約,具體很多例子可以在智能合約學習文檔看到。
PC錢包方式,所有交易都必須三部,build-transaction,sign-transaction,submit-transaction,三個接口。
踩過的坑:
- 調試智能合約很慢,要等到交易確認才能知道是否成功,而且報錯不明顯,不知道哪裏出問題;
解決方案:
本地PC錢包solonet模式調試,更改源碼,快速出塊 difficulty/difficulty.go
func CheckProofOfWork(hash, seed *bc.Hash, bits uint64) bool {
compareHash := tensority.AIHash.Hash(hash, seed)
return HashToBig(compareHash).Cmp(CompactToBig(bits)) <= 0
}
裏面那句添加 ||true 如下
return HashToBig(compareHash).Cmp(CompactToBig(bits)) <= 0 || true
一開始沒想到這樣做,以爲很快調試好,搞了三天晚上10點才調試完。
2.智能合約對於除法的支持很不友好,儘量不要用除法,一開始寫了一個很複雜的合約,不知道錯誤,智能逐步改代碼快速調試去定位,最後發現 A/B,如果A=B沒問題,否則就直接報錯,問過官方沒有得到合適的回答,我嘗試過是存證這種問題,非常坑。
3.程序必須計算好對應結果utxo 流轉action的 input、ouput ;如下
{
"base_transaction": null,
"actions": [
{
"output_id": "13fbd1e5df196a1488e85e3b5983e51444c49ef3695df789c9473abb636e0f5c",
"arguments": [
{
"type": "integer",
"raw_data": {
"value": 5500000000
}
}, {
"type": "data",
"raw_data": {
"value": "00141ccef16d2ac1ab22baa8acfa1633fdc32dfd55aa"
}
},
{
"type": "integer",
"raw_data": {
"value": 0
}
}
],
"type": "spend_account_unspent_output"
},
{
"amount": 5500000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"control_program": "0014d470cdd1970b58b32c52ecc9e71d795b02c79a65",
"type": "control_program"
},
{
"amount": 5000000000,
"asset_id": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"control_program": "00141ccef16d2ac1ab22baa8acfa1633fdc32dfd55aa",
"type": "control_program"
},
{
"amount": 9999995000000000,
"asset_id": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"control_program": "20b1f38553d95177c53755996baf523da006da977008f069792bb6a2c3b6a253fb160014d470cdd1970b58b32c52ecc9e71d795b02c79a6503e1830403e1830403e256040322350403a21e0403e20e040307fb0320ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d2b015b7a76529c641d010000640c0100005c7900a0695c790500f2052a01947600a0695379cd9f5579cda09a916164380000005a95639a00000054798ccd9f5679cda09a916164500000005895639a00000055798ccd9f5779cda09a916164680000005695639a00000056798ccd9f5879cda09a916164800000005495639a00000057798ccd9f5979cda09a916164980000005295639a0000005195c3787ca169c3787c9f916164f5000000005e795479515e79c1695178c2516079c16952c3527994c251006079895f79895e79895d79895c79895b79895a79895979895879895779895679890274787e008901c07ec1696307010000005e795479515e79c16951c3c2516079c169632b010000587acd9f6900c3c2515c7ac1632b010000755b7aaa5b7a8800c3c2515d7ac1747800c0",
"type": "control_program"
},
{
"account_id": "0U374V0300A02",
"amount": 5500000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
},
{
"account_id": "0U374V0300A02",
"amount": 20000000,
"asset_id": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"type": "spend_account"
}
],
"ttl": 10000
}
一個解鎖合約交易要包含action類型有,
spend_account_unspent_output (合約的參數),
spend_account (輸入的資產描述),
control_program或者control_address (接收者資產描述),
可以理解成質量守恆。
如上面例子
spend_account_unspent_output 的action裏面有個output_id =13fbd1e5df196a1488e85e3b5983e51444c49ef3695df789c9473abb636e0f5c,這個資產的小數位爲8(這裏沒有體現),代表我要解鎖這個utxo,他的值爲 100000000.00000000 就是1億。
拆分成兩個action,一個 50.00000000,一個 99999950.00000000
只有btm = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 需要用來等手續費,所以允許不守恆,最後由曠工挖礦拿到手續費。
總結:那麼程序相當於要把合約裏面的邏輯整合進去,才能計算好真正的input、output~~我理解是交易確認的時候,解鎖合約的程序驗證現在的input、ouput是否跟合約一樣。
3)測試解鎖合約方法,2)裏面採坑已經說清楚這個問題了,補充一下就是最好一下子不要寫太複雜的合約,從簡單來開發調試。一定要注意質量守恆定律,只要懂了這個原理其實非常簡單。
4)基於插件錢包開發Dapp前端, 這塊具體可以看插件錢包API,儲蓄分紅合約前端源代碼,裏面說的非常清楚, 涉及到的接口,暫時他們API文檔還沒有整理出來,來自上一章說的blockcenter的接口
url地址 :testnet: 'http://app.bycoin.io:3020/', mainnet: 'https://api.bycoin.im:8000/'
核心用到的接口有:
根據合約與資產ID查詢UTXO接口
/api/v1/btm/q/list-utxos
參數:
{
"filter": { "script":"20b1f38553d95177c53755996baf523da006da977008f069792bb6a2c3b6a253fb160014d470cdd1970b58b32c52ecc9e71d795b02c79a6503e1830403e1830403e256040322350403a21e0403e20e040307fb0320ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d2b015b7a76529c641d010000640c0100005c7900a0695c790500f2052a01947600a0695379cd9f5579cda09a916164380000005a95639a00000054798ccd9f5679cda09a916164500000005895639a0000798ccd9f5779cda09a916164680000005695639a00000056798ccd9f5879cda09a916164800000005495639a00000057798ccd9f5979cda09a916164980000005295639a0000005195c3787ca169c3787c9f916164f5000000005e795479515e79c1695178c2516079c16952c3527994c251006079895f79895e79895d79895c79895b79895a79895979895879895779895679890274787e008901c07ec1696307010000005e795479515e79c16951c3c2516079c169632b010000587acd9f6900c3c2515c7ac1632b010000755b7aaa5b7a8800c3c2515d7ac1747800c0",
"asset":"80013f81a66cb99977879e31639bb4fe4b12b4c7058585d3f7f159d26a9" ,
"unconfirmed":false
},
"sort": {
"by":"amount",
"order":"desc"
}
}
unconfirmed ,代表是否確認的,這個對後期的併發問題非常有用,第三章我會詳細說明。
結果
{
"code": 200,
"msg": "",
"result": {
"_links": {},
"data": [
{
"hash": "16749b694a9f1bc6a7759cf66baefed4c864b65985e7488e8721184ecc4d6965",
"asset": "80013f81a66cb99977879e31639bb4fe4b12b4c7058585d3f7f159d26a9",
"amount": 3000000000
},
{
"hash": "e5f75036b6f662ff705378b55dd29dc1a43acb23d701dd44a068cdab2c43ad0c",
"asset": "80013f81a66cb99977879e31639bb4fe4b12b4c7058585d3f7f159d26a9",
"amount": 15000000000
}
],
"limit": 10,
"start": 0
}
}
(自己準備參數調用一下,以上是例子而已)
查詢用戶地址信息與餘額接口
/api/v1/btm/account/list-addresses
參數
{"guid":"b414005b-b501-4a0e-8b0f-e1cd762272f4"}
結果
{
"code": 200,
"msg": "",
"result": {
"_links": {},
"data": [{
"guid": "b414005b-b501-4a0e-8b0f-e1cd762272f4",
"address": "bm1qp4t6thlyktt6sh02scs8dqcpnk3ufk9e9pmq9s",
"label": "",
"balances": [{
"asset": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"balance": "68900000000",
"total_received": "69000000000",
"total_sent": "100000000",
"decimals": 8,
"alias": "",
"in_usd": "0.00",
"in_cny": "0.00",
"in_btc": "0.000000"
}, {
"asset": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"balance": "1329551000",
"total_received": "53790000000",
"total_sent": "52460449000",
"decimals": 8,
"alias": "btm",
"in_usd": "1.45",
"in_cny": "10.10",
"in_btc": "0.000142"
}]
}],
"limit": 10,
"start": 0
}
}
ps:
guid是專門插件錢包提供的,是唯一的,這個非常有用,第三章我會詳細說。
查詢交易信息
/api/v1/btm/account/list-transactions
參數
{"address":"bm1qp4t6thlyktt6sh02scs8dqcpnk3ufk9e9pmq9s","start":0,"limit":100}
結果
{
"code": 200,
"msg": "",
"result": {
"data": [{
"ID": 111,
"Hash": "471e5b267f646546be33505773186ee9d8dde2180a515df67a90d1a5f9d17bd2",
"AssetID": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"Amount": 7000000000,
"Address": "bm1qp4t6thlyktt6sh02scs8dqcpnk3ufk9e9pmq9s",
"BaseID": 5,
"Timestamp": "2019-07-08T09:23:12+08:00",
"Height": 263728,
"TransactionID": "471e5b267f646546be33505773186ee9d8dde2180a515df67a90d1a5f9d17bd2",
"InputAmount": 5700000000
}, {
"ID": 64,
"Hash": "e69631a8d6321d738793646399ffe022ac177a5732f562970e706ee76d49de82",
"AssetID": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"Amount": 5000000000,
"Address": "bm1qp4t6thlyktt6sh02scs8dqcpnk3ufk9e9pmq9s",
"BaseID": 5,
"Timestamp": "2019-07-05T16:37:07+08:00",
"Height": 262170,
"TransactionID": "e69631a8d6321d738793646399ffe022ac177a5732f562970e706ee76d49de82",
"InputAmount": 5500000000
}, {
"ID": 56,
"Hash": "cf74906808a1a6bc6a056c148510d542a10d2cbc350a4d830c670aa5ba973873",
"AssetID": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"Amount": 39000000000,
"Address": "bm1qp4t6thlyktt6sh02scs8dqcpnk3ufk9e9pmq9s",
"BaseID": 5,
"Timestamp": "2019-07-03T14:59:22+08:00",
"Height": 261006,
"TransactionID": "cf74906808a1a6bc6a056c148510d542a10d2cbc350a4d830c670aa5ba973873",
"InputAmount": 8900000000
}, {
"ID": 54,
"Hash": "6aedf609d47b3c06de2ce7dc9f2c99895124c80074573cd29407ac3b34ef8d40",
"AssetID": "80013f81a66cb99977879e31639bb4fe4b12b4c7050fe518585d3f7f159d26a9",
"Amount": 2000000000,
"Address": "bm1qp4t6thlyktt6sh02scs8dqcpnk3ufk9e9pmq9s",
"BaseID": 5,
"Timestamp": "2019-07-03T12:11:12+08:00",
"Height": 260936,
"TransactionID": "6aedf609d47b3c06de2ce7dc9f2c99895124c80074573cd29407ac3b34ef8d40",
"InputAmount": 5200000000
}]
}
}
5)開發後端,相當於bufferserver,第三章詳細說明順便我解析一下bufferserver的源碼內容,還有裏面踩過的坑。
總結:
這一章內容主要比較繁瑣強調是調試合約方面,就是最核心的問題,這裏拋出一個問題,就是UTXO問題,調試過程中非常繁瑣,本來區塊鏈不是做高併發,但是也存在併發問題,應該如何解決? 有使用過PC錢包的朋友肯定知道,裏面PC錢包的UTXO,在交易過程中鎖定了,沒辦法操作下一個,有些很多UTXO還好,如果只有一個,基本上調試跟實用都很麻煩~~~第三章我們基於原有bufferserver基礎上根據官方的方案改一下,一定程度解決併發問題,大家期待一下。
參考資料:
作者:天才的飯桶