这章的内容详细分析一下涉及智能合约Dapp的整个开发流程,注意是涉及只能合约,若是你只要一些基本转BTM功能没有太大意义,本内容补充一下官方提供的 比原链DAPP开发流程,详细实践过好踩到的一些坑,还有一些真正具体的技巧还有经验,我的认为很是有用,起码让开发者能够更快速地去操做。html
资料说的储蓄分成合约太复杂了,简单说说逻辑,银行发了一笔股份资产,用合约锁定,用户去触发这个合约的方法,付出了钱兑换了对应份额的股份资产,当达到必定的高度,就能够经过用股份资产兑换回本金与分成(钱+利息)。 里面包含了两个合约~~前端
总体流程git
开发流程分为,1)编写智能合约;2)发合约交易;3)测试解锁合约方法;4)基于插件钱包开发Dapp前端;5)开发后端;github
流程貌似很是简单,本人在1,2,3 步浪费了不少时间。其中有些坑踩过接下来介绍一下;后端
1)编写智能合约,上面提供的 比原链DAPP开发流程,写得很清楚,使用的是equity很是简单,直接下载最新版 用命令 【./equity TradeOffer --instance 】 就能获得一串编译后的合约程序代码,简称智能合约程序。api
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 } }
看看智能合约的交易图,方便小白理解:app
因此储蓄分成合约一开始确定要锁定一部分资产,因此必须部署合约交易。那么如何触发呢?高并发
本人经过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/'
核心用到的接口有:
/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基础上根据官方的方案改一下,必定程度解决并发问题,你们期待一下。
参考资料:
做者:天才的饭桶