# 面向资产互换的原子性保障应用使用指南 ## 概述 ### 跨链原子性协议概述 本应用支持基于哈希时间锁合约`HTLC`、哈希时间锁优化合约`Lilac`实现具有事务原子性保障的跨链资产互换。应用用户客户端实现了提案筛选、事件监听、自动取款、自动退款等操作。 了解跨链原子性协议设计方案,请看该链接: [跨链原子性协议设计方案](../tech/面向资产互换的原子性保障应用.md) ## 部署流程 ### 源码下载 * 下载源码到本地 ```bash git clone https://git.chainmaker.org.cn/ibpc/atomic_assets_swap.git ``` ## 应用代码整体目录结构 ```bash . ├── bin # 区块链必要的可执行文件 ├── chainclient # 链SDK接口 ├── chainmaker_contract_test.sh # 长安链合约测试脚本 ├── chainmaker_restart.sh # 长安链重启脚本 ├── client # 用户客户端接口 ├── client_test.md # 用户客户端测试示例文档 ├── commod.md # 用户客户端测试命令文档 ├── config # 链用户私钥、证书接口 ├── config_files # 链配置文件、测试用户私钥、证书 ├── contracts # 链上合约 ├── deploy # 合约部署脚本 ├── fabric_restart.sh # Fabric重启脚本 ├── go.mod ├── go.sum ├── install-deploy-contract.sh # 启动合约部署脚本 ├── keystore ├── main.go # 用户连接客户端 ├── Makefile ├── presentation # 性能测试 ├── projectinterface # 链接入的标准接口 ├── README.md ├── restart.sh # 系统重启脚本 ├── scripts # 其它脚本 ├── stop.sh # 关闭链脚本 ├── test # Fabric合约测试 ├── test.sh # 覆盖率测试脚本 ├── ut_cover.sh # ut测试脚本 ├── utils ├── 设计方案.md └── 部署和使用文档.md ``` ### 部署本地链环境,安装并启动区块链 * 进入应用文件夹,部署链环境 ```bash cd atomic-assets-swap/ make && ./restart.sh ``` ### 安装必要的合约 * 执行`install-deploy-contract.sh`脚本,编译并安装合约 ```bash bash install-deploy-contract.sh ``` ### 启动客户端 * 在应用根目录下, 打开两个`terminal`,模拟`用户1`和`用户2` * `用户1`终端执行 ```bash go run main.go client1 ``` * `用户2`终端执行 ```bash go run main.go client2 ``` * 在两个终端会看到类似的输出 ```bash tips: [当前工作空间: /home/.../atomic-assets-swap] info: [chain1_user1 address: 99fecbbd54840df106f652f571c05384b4bafba8] info: [chain2_user1 address: e70f6e47003083409c43392665c72a37115dc07f] info: [配置文件: ./config_files/fabric/user.yaml] info: [call assets getAddress] info: [call assets reset] info: [fabric_user1 address: 63642b1ad5a7f5dcb03372bee094b0851bef668dc5a04e8033388d4184b1f424] Please input command line :info: [订阅lilac的withdraw] info: [订阅lilac的newProposal] info: [订阅htlc的newProposal] info: [订阅htlc的withdraw] ``` * 通过输入对应的命令执行对应的操作 * 输入`exit`或者`break`退出客户端 ## 使用方法 * 通过在控制台输入相应的交互命令执行对应的操作 * 当输入命令错误的时候会提示命令 ```bash tips: [###### usage ######] newHtlcProposal chainName userName toAddr amount Preimage hashlock timelock chain2 amount newLilacProposal chainName userName toAddr amount Preimage hashlock timelock chain2 amount refund chainName userName contractName proposalID withdraw chainName userName contractName proposalID preimage getProposal chainName userName proposalType proposalID getBalance chainName userName getAddress chainName userName break exit tips: [###### end ######] ``` ### 退出 * 在终端输入命令进行退出 ```bash exit/break # 输出如下: info: [login out client.] ``` ### 获取用户的地址 * 获取链`chainName`上用户`userName`的地址 * 比如在链`chain1`上获取用户`user1`的地址 ```bash # getAddress chainName userName getAddress chain1 user1 # 输出如下: info: [address:18bea55343220196ce02038b147c149e275b38cc] ``` ### 获取用户余额 * 获取链`chainName`上用户`userName`的余额 * 比如在链`chain1`上获取用户`user2`的余额 ```bash # getBalance chainName userName getBalance chain1 user2 # 输出如下: info: [chain1 user2 balance: 1000] ``` ### 发起一个新的htlc proposal * 发起一个新的`htlc proposal`,是从`chainName`的用户`userName`,发送给目的地址`toAddr`为`4d8bae757deae72905c6cbc6bc688dc74f634c77`的用户`amount`个token,并以`preimage`为原像,锁定`timelock`秒的时间,兑换`chain2`的`amount`个token * 如果`preimage`设置不为`nil`则会自动计算哈希锁`hashlock`,此时`hashlock`的输入没有作用 * 如果`preimage`字段设置为`nil`,则将会使用`hashlock`字段作为哈希锁 * 比如链`chain1`上的用户`user1`,发起一个`htlc proposal`, 发给链`chain1`的`4d8bae757deae72905c6cbc6bc688dc74f634c77`地址用户`10`个币,并从链`chain2`获得`1`个币,设置原像为`preimage`, 时间锁`timelock`设置为`600`秒, 命令为 ```bash # newHtlcProposal chainName userName toAddr amount Preimage hashlock timelock chain2 amount newHtlcProposal chain1 user1 4d8bae757deae72905c6cbc6bc688dc74f634c77 10 preimage nil 600 chain2 1 # 输出如下: info: [preimage preimage] info: [hashlock 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f] info: [timelock 600] tips: [发起时的hashlock 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f] info: [newProposal:705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4] tips: [proposal加入完成 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4] info: [{18bea55343220196ce02038b147c149e275b38cc 4d8bae757deae72905c6cbc6bc688dc74f634c77 10 1682062662 600 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f preimage false false false 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4 chain1 user1 htlc htlc chain2 1}] ``` * 同时在客户端2看到输出 ```bash info: [===== chain1 监听到proposal ===== 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4] info: [{18bea55343220196ce02038b147c149e275b38cc 4d8bae757deae72905c6cbc6bc688dc74f634c77 10 1682062661 600 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f null true false false 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4 chain1 user2 htlc htlc 0}] ``` * 表示客户端2收到一个关于自己用户的proposal * 客户端2上的链2用户2发起一个对应的proposal, 发给链`chain2`上的用户`user1`地址 `d9053ab1c1088feaab4f727eeeac69aa327eb28c` 1个token,并以同样的哈希锁 `107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f` ,设置时间锁`hashlock`为`300`秒, 期望获得链`chain1`的`10`个token ```bash newHtlcProposal chain2 user2 d9053ab1c1088feaab4f727eeeac69aa327eb28c 1 nil 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f 300 chain1 10 # 输出如下: info: [preimage ] info: [hashlock 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f] info: [timelock 300] tips: [发起时的hashlock 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f] info: [newProposal:8caefc5171998eafd5ff7d19116c795be5435c50ffce9e57517a8f1d24d80863] tips: [proposal加入完成 8caefc5171998eafd5ff7d19116c795be5435c50ffce9e57517a8f1d24d80863] info: [{e525a7ff7b740539b9bb36c3fd081acb3a0d20c2 d9053ab1c1088feaab4f727eeeac69aa327eb28c 1 1682062882 300 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f false false false 8caefc5171998eafd5ff7d19116c795be5435c50ffce9e57517a8f1d24d80863 chain2 user2 htlc htlc chain1 10}] ``` * 同时会在客户端1看到输出, 表示进入了自动取款程序 ```bash info: [===== chain2 监听到proposal ===== 8caefc5171998eafd5ff7d19116c795be5435c50ffce9e57517a8f1d24d80863] info: [{e525a7ff7b740539b9bb36c3fd081acb3a0d20c2 d9053ab1c1088feaab4f727eeeac69aa327eb28c 1 1682062881 300 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f null true false false 8caefc5171998eafd5ff7d19116c795be5435c50ffce9e57517a8f1d24d80863 chain2 user1 htlc htlc 0}] tips: [等待1秒] info: [===== new proposal切换到对端链取钱 =====] info: [{"sender":"e525a7ff7b740539b9bb36c3fd081acb3a0d20c2","receiver":"d9053ab1c1088feaab4f727eeeac69aa327eb28c","amount":0,"posaltime":1682062881,"timelock":300,"hashlock":"107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f","preimage":"preimage","locked":false,"unlocked":true,"rolledback":false}] info: [====== 取钱成功 ======: 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4] info: [======= chain1 =======] info: [自己的proposal被取钱了] info: [{18bea55343220196ce02038b147c149e275b38cc 4d8bae757deae72905c6cbc6bc688dc74f634c77 0 1682062661 600 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f preimage false true false 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4 chain1 user1 htlc htlc 0}] warning: [监听到属于自己的Propsal, 但是没在本地找到匹配的proposal异常] ``` * 随后在客户端2看到输出, 表示看到了 ```bash info: [======= chain2 =======] info: [自己的proposal被取钱了] info: [{e525a7ff7b740539b9bb36c3fd081acb3a0d20c2 d9053ab1c1088feaab4f727eeeac69aa327eb28c 0 1682062881 300 107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f preimage false true false 8caefc5171998eafd5ff7d19116c795be5435c50ffce9e57517a8f1d24d80863 chain2 user2 htlc htlc 0}] info: [withdraw切换到对端链取钱] info: [{"sender":"18bea55343220196ce02038b147c149e275b38cc","receiver":"4d8bae757deae72905c6cbc6bc688dc74f634c77","amount":0,"posaltime":1682062661,"timelock":600,"hashlock":"107661134f21fc7c02223d50ab9eb3600bc3ffc3712423a1e47bb1f9a9dbf55f","preimage":"preimage","locked":false,"unlocked":true,"rolledback":false}] ``` * 链1用户1和链2用户1查看余额 ```bash getBalance chain1 user1 getBalance chain2 user1 # 输出如下: info: [chain1 user1 balance: 990] info: [chain2 user1 balance: 1001] ``` * 客户端2同理 ### 发起一个新的lilac proposal * 和`htlc proposal`一样,唯一的不同是`preimage`字段需要写入多个原像,并以`,`隔开 * 发起一个新的`lilac proposal`,是从`chainName`的用户`userName`,发送给目的地址`toAddr`为`4d8bae757deae72905c6cbc6bc688dc74f634c77`的用户 `amount`个token,并以`preimage1`和`preimage2`为原像,锁定`timelock`秒的时间,兑换`chain2`的`amount`个token,其中`preimage`字段有多个用户,以英文逗号`,`分割 * 如果`preimage`设置不为`nil`则会自动计算哈希锁`hashlock`,此时`hashlock`的输入没有作用 * 如果`preimage`字段设置为`nil`,则将会使用`hashlock`字段作为哈希锁 * 比如链`chain1`上的用户`user1`,发起一个`lilac proposal`, 发给链`chain1`的 `4d8bae757deae72905c6cbc6bc688dc74f634c77` 地址用户`10`个币,并期望从链`chain2`兑换`1`个币,设置原像为 `preimage1,preimage2`, 时间锁`hashlock`设置为`10`, 等待10秒会自动退款, 命令为 ```bash # newLilacProposal chainName userName toAddr amount Preimage hashlock timelock chain2 amount newLilacProposal chain1 user1 4d8bae757deae72905c6cbc6bc688dc74f634c77 10 preimage1,preimage2 nil 10 chain2 1 ``` * 有如下输出, 其中 `04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854`为`proposal id` ```bash info: [vPreimage: [preimage1 preimage2]] info: [vHashlock: [5144f34d1b8edc707120dc254bf56e00bd9f5a6f5e6892f72103408f43ee9ded 7a869987c84cbd23568dab928f0229581c2658e61a1ee37214c83ea16ba9cba7]] info: [timelock 10] tips: [发起时的hashlock [5144f34d1b8edc707120dc254bf56e00bd9f5a6f5e6892f72103408f43ee9ded 7a869987c84cbd23568dab928f0229581c2658e61a1ee37214c83ea16ba9cba7]] info: [newProposal:04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854] tips: [proposal加入完成 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854] info: [{18bea55343220196ce02038b147c149e275b38cc 4d8bae757deae72905c6cbc6bc688dc74f634c77 10 1682063920 10 [5144f34d1b8edc707120dc254bf56e00bd9f5a6f5e6892f72103408f43ee9ded 7a869987c84cbd23568dab928f0229581c2658e61a1ee37214c83ea16ba9cba7] [preimage1 preimage2] false false false 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854 chain1 user1 lilac lilac chain2 1}] ``` * 等待10秒会自动退款,有如下输出 ```bash info: [proposa超时,进入退款程序:{18bea55343220196ce02038b147c149e275b38cc 4d8bae757deae72905c6cbc6bc688dc74f634c77 10 1682063920 10 [5144f34d1b8edc707120dc254bf56e00bd9f5a6f5e6892f72103408f43ee9ded 7a869987c84cbd23568dab928f0229581c2658e61a1ee37214c83ea16ba9cba7] [preimage1 preimage2] false false false 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854 chain1 user1 lilac lilac chain2 1}] info: [{"sender":"18bea55343220196ce02038b147c149e275b38cc","receiver":"4d8bae757deae72905c6cbc6bc688dc74f634c77","amount":0,"posaltime":1682063920,"timelock":10,"hashlock":["5144f34d1b8edc707120dc254bf56e00bd9f5a6f5e6892f72103408f43ee9ded","7a869987c84cbd23568dab928f0229581c2658e61a1ee37214c83ea16ba9cba7"],"preimage":[],"locked":false,"unlocked":true,"rolledback":true}] ``` ### 手动退款 * 用户`userName`在链`chainName`上发起一个`contractName`的退款请求 * 比如用户`user1`对在链`chain1`上`proposalid`为`04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854`的`lilac proposal`退款,命令如下 ```bash # refund chainName userName contractName proposalID refund chain1 user1 lilac 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854 ``` * 由于这个`proposal id`已经被取款了,所以会失败, 报锁定状态错误 ```bash info: [run commond: [refund chain1 user1 lilac 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854]] funcName->run commond error->funcName->c.refund error->c.Refund error: funcName->contractinvoke.RefundLilac error->=== IncokeContract === resp.Message-> resp.ContractsResult->code:1 result:"proposal \"locked\" state error" message:"Fail" gas_used:11625 error->=== client.InvokeContract === resp.Message-> resp.ContractsResult->code:1 result:"proposal \"locked\" state error" message:"Fail" gas_used:11625 ``` * 比如用户`user1`对在链`chain1`上`proposalid`为`04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854`的`htlc proposal`退款,命令如下 ```bash # refund chainName userName contractName proposalID refund chain1 user1 htlc 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854 ``` ### 对某个proposal id取款 * 用户`userName`在链`chainName`上对id为`propsalID`的`contractName`类型的proposal取款`withdraw`, 同时提供原像`preimage` * 比如链`chain1`用户`user1`,对`proposal id`为`04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854`的`lilac`类型proposal取款,使用`withdraw`命令,需要提前知道`preimage`,命令如下 ```bash # withdraw chainName userName contractName proposalID preimage withdraw chain1 user1 lilac 04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854 preimage1,preimage2 ``` * 取款`htlc`类型的proposal,和`lilac`一样,示例命令如下 * 比如链`chain1`用户`user1`,对`proposal id`为`04dac20d774781d9a0814cbbb84a8634e24b684d100f32203068d9228700a854`的`htlc`类型proposal取款,使用`withdraw`命令,需要提前知道`preimage`,命令如下 ```bash # withdraw chainName userName contractName proposalID preimage withdraw chain1 user1 htlc 705b7fb6cd2c28ad848a00abda4708856d6f20706ba93021a5fc4d44c8eb45a4 preimage ```