哈希时间锁定

哈希时间锁合约(hash time lock contract,htlc)能够实现两条异构链之间资产的原子交换,即跨链转账。

如果你想快速体验跨链转账可以参考体验WeCross

WeCross提供了Solidity和Golang版本的htlc基类合约,基于htlc基类合约可以轻松开发适用于不同资产类型的htlc应用合约。

本章节以FISCO BCOS和Hyperledger Fabric的示例资产合约为例,演示如何实现两条异构链的资产互换。

准备工作

要完成资产互换,需要在各自链上部署资产合约以及哈希时间锁合约,然后通过WeCross控制台创建跨链转账提案,router会根据提案信息自动完成跨链转账。

部署WeCross和控制台

FISCO BCOS前期准备

部署合约

  • 拷贝合约

假设当前位于router的根目录,将conf/chains-sample/bcos/htlc目录下的LedgerSample.solHTLC.sol以及LedgerSampleHTLC.sol文件拷贝至BCOS控制台的contracts/solidity目录。

  • 部署LedgerSampleHTLC.sol
  1. [group:1]> deploy LedgerSampleHTLC
  2. # 合约地址需要记录下来
  3. contract address: 0xc25825d8c0c9819e1302b1cd0019d3228686b2b1

发行资产

FISCO BCOS提供的资产示例合约可借助ledger-tool完成资产的发行、转账和授权。

  1. git clone https://github.com/Shareong/ledger-tool.git
  2. cd ledger-tool
  3. gradle build
  4. # 工具包需要和节点通讯,将节点sdk目录下的证书文件ca.crt, sdk.crt, sdk.key拷贝到dist/conf目录,并根据实际情况配置conf目录下的application.xml,账户用默认的pem文件即可。
  5. # 根据金额发行资产,在dist目录下执行
  6. java -cp 'apps/*:lib/*:conf' Application init 100000000
  7. # 输出资产地址,以及资产的拥有者
  8. assetAddress: 0x1796f3f195697c38bedaaaa27e424d05f359ca0f
  9. owner: 0x55f934bcbe1e9aef8337f5551142a442fdde781c

资产授权

要完成跨链转账,资产拥有者需要将资产的转移权授权给哈希时间锁合约。

  1. # approve [资产地址],[被授权者地址](此处为自己的哈希时间锁合约地址),[授权金额]
  2. java -cp 'apps/*:lib/*:conf' Application approve 0x1796f3f195697c38bedaaaa27e424d05f359ca0f 0xc25825d8c0c9819e1302b1cd0019d3228686b2b1 1000000
  3. # 成功输出如下
  4. approve successfully
  5. amount: 1000000

哈希时间锁合约初始化

需要将资产合约的地址和对手方的哈希时间锁合约地址保存到自己的哈希时间锁合约。

  1. # 在FISCO BCOS控制台执行,此处约定Fabric的合约名为fabric_htlc,之后将以该名称安装和初始化链码
  2. call LedgerSampleHTLC 0xc25825d8c0c9819e1302b1cd0019d3228686b2b1 init ["0x1796f3f195697c38bedaaaa27e424d05f359ca0f","fabric_htlc"]
  3.  
  4. # 查看owner余额,检查是否初始化成功
  5. call LedgerSampleHTLC 0xc25825d8c0c9819e1302b1cd0019d3228686b2b1 balanceOf ["0x55f934bcbe1e9aef8337f5551142a442fdde781c"]
  6. [100000000]

重要

  • 初始化只能进行一次,所以在执行命令前务必确保相关参数都是正确的。
  • 如果初始化时传参有误,只能重新部署哈希时间锁合约,并重新做资产授权。

Fabric前期准备

拷贝链码

  1. # 获取docker容器id
  2. docker ps -a|grep cli
  3. 0523418f889d hyperledger/fabric-tools:latest
  4. # 假设当前位于router根目录, 将链码拷贝到Fabric的chaincode目录下
  5. docker cp conf/chains-sample/fabric/ledger 0523418f889d:/opt/gopath/src/github.com/chaincode/ledger
  6. docker cp conf/chains-sample/fabric/htlc 0523418f889d:/opt/gopath/src/github.com/chaincode/htlc

部署资产合约

  1. # 启动容器
  2. docker exec -it cli bash
  3. # 安装链码,-n指定名字,此处命名为ledgerSample
  4. peer chaincode install -n ledgerSample -v 1.0 -p github.com/chaincode/ledger/
  5. # 初始化
  6. peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n ledgerSample -l golang -v 1.0 -c '{"Args":["init","HTLCoin","htc","100000000"]}' -P 'OR ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'
  7. # 查看账户余额
  8. peer chaincode query -C mychannel -n ledgerSample -c '{"Args":["balanceOf","[email protected]"]}'
  9. # 输出应该为100000000

资产授权 ledgerSample合约通过创建一个托管账户实现资产的授权。

  1. # 该命令默认使用admin账户发交易,即admin账户完成了一次授权
  2. peer chaincode invoke -C mychannel -n ledgerSample -c '{"Args":["createEscrowAccount","1000000"]}' -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

部署哈希时间锁合约

  1. # 安装链码,命名为fabric_htlc
  2. peer chaincode install -n fabric_htlc -v 1.0 -p github.com/chaincode/htlc/
  3. # 初始化,需要指定己方资产合约名和对手方的哈希时间锁合约地址
  4. # init [己方资产合约名] [channel] [对手方哈希时间锁合约地址]
  5. peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabric_htlc -l golang -v 1.0 -c '{"Args":["init","ledgerSample","mychannel","0xc25825d8c0c9819e1302b1cd0019d3228686b2b1"]}'
  6.  
  7. # 查看admin余额,检查是否初始化成功
  8. peer chaincode query -C mychannel -n fabric_htlc -c '{"Args":["balanceOf","[email protected]"]}'
  9. # 输出应该为99000000,因为有一部资产已经转到了托管账户。

哈希时间锁合约配置

配置FISCO BCOS端router

在插件配置文件stub.toml中配置htlc资源。

  1. [[resources]]
  2. # name cannot be repeated
  3. name = 'htlc'
  4. type = 'BCOS_CONTRACT' # BCOS_CONTRACT or BCOS_SM_CONTRACT
  5. contractAddress = '0xc25825d8c0c9819e1302b1cd0019d3228686b2b1'

在主配置文件wecross.toml中配置htlc任务。

  1. [[htlc]]
  2. #本地配置的哈希时间锁资源路径
  3. selfPath = 'payment.bcos.htlc'
  4.  
  5. #确保已在router的accounts目录配置了bcos_default_account账户
  6. account1 = 'bcos_default_account'
  7.  
  8. #对手方的哈希时间锁资源路径
  9. counterpartyPath = 'payment.fabric.htlc'
  10.  
  11. #确保已在router的accounts目录配置了fabric_default_account账户
  12. account2 = 'fabric_default_account'

重要

  • 主配置中的htlc资源路径以及能访问这两个资源的账户请结合实际情况配置。

配置Fabric端router

在插件配置文件stub.toml中配置htlc资源。

  1. [[resources]]
  2. # name cannot be repeated
  3. name = 'htlc'
  4. type = 'FABRIC_CONTRACT'
  5. chainCodeName = 'fabric_htlc'
  6. chainLanguage = "go"
  7. peers=['org1']

在主配置文件wecross.toml中配置htlc任务。

  1. [[htlc]]
  2.  
  3. #本地配置的哈希时间锁资源路径
  4. selfPath = 'payment.fabric.htlc'
  5.  
  6. #确保已在router的accounts目录配置了fabric_default_account账户
  7. account1 = 'fabric_default_account'
  8.  
  9. #对手方的哈希时间锁资源路径
  10. counterpartyPath = 'payment.bcos.htlc'
  11.  
  12. #确保已在router的accounts目录配置了bcos_default_account账户
  13. account2 = 'bcos_default_account'

配置发送者账户

两个router需要在accounts目录下配置发送者的账户,因为跨链提案只能由资产的转出者创建。

FISCO BCOS用户需要将ledger-tool/dist/conf目录下的私钥文件配置到router端的accounts目录,并假设命名为bcos,配置方法详见BCOS账户配置

Fabric用户需要将admin账户配置到router端的accounts目录,并假设命名为fabric,配置方法详见Fabric账户配置

重启两个router

  1. bash stop.sh && bash start.sh

发起跨链转账

假设跨链转账发起方是FISCO BCOS的用户,发起方选择一个secret,计算 hash = sha256(secret) 得到hash,然后和Fabric的用户即参与方协商好各自转账的金额、账户以及时间戳。

协商内容

  • FISCO BCOS的两个账户:
    • 资产转出者:0x55f934bcbe1e9aef8337f5551142a442fdde781c(和ledger-tool初始化时返回的owner地址保持一致)
    • 资产接收者:0x2b5ad5c4795c026514f8317c7a215e218dccd6cf
  • FISCO BCOS转账金额:700
  • Fabric的两个账户:
    • 资产转出者:Admin@org1.example.com (admin账户)
    • 资产接收者:User1@org1.example.com
  • Fabric转账金额500
  • 哈希: 2afe76d15f32c37e9f219ffd0a8fcefc76d850fa9b0e0e603cbd64a2f4aa670d
  • 哈希原像: e7d5c31dcc6acae547bb0d84c2af05413994c92599bff89c4abd72866f6ac5c6(协商时只有发起方知道)
  • 时间戳t0:发起方的超时时间,单位s
  • 时间戳t1: 参与方的超时时间,单位s

注解

  • 哈希原像和哈希可通过控制台命令 genSecretAndHash 生成。
  • 两个时间戳可通过控制台命令 genTimelock 生成。
  • 时间戳需要满足条件:t0 > t1 + 300 > now + 300

创建跨链转账提案

两条链的资产转出者通过WeCross控制台创建跨链转账提案,将协商的转账信息写入各自的区块链。

  • 命令介绍
    • 命令:newHTLCTransferProposal
    • 参数:path, account(资产转出者账户名), hashsecretrolesender0receiver0amount0timelock0sender1receiver1amount1timelock1
  • 注意事项
    • 其中下标为0的参数是发起方信息。
    • 发起方secret传入哈希原像,role传入true;参与方secret传入null,role传入false。
  • 启动控制台
  1. # 进入控制台dist目录
  2. bash start.sh
  • 发起方创建转账提案

该步骤由发起方即BCOS链的资产转出者完成。

  1. newHTLCTransferProposal payment.bcos.htlc bcos edafd70a27887b361174ba5b831777c761eb34ef23ee7343106c0b545ec1052f 049db09dd9cf6fcf69486512c1498a1f6ea11d33b271aaad1893cd590c16542a true 0x55f934bcbe1e9aef8337f5551142a442fdde781c 0x2b5ad5c4795c026514f8317c7a215e218dccd6cf 700 2000010000 [email protected] [email protected] 500 2000000000
  • 参与方创建转账提案

该步骤由参与方即Fabric链的资产转出者完成。

  1. newHTLCTransferProposal payment.fabric.htlc fabric edafd70a27887b361174ba5b831777c761eb34ef23ee7343106c0b545ec1052f null false 0x55f934bcbe1e9aef8337f5551142a442fdde781c 0x2b5ad5c4795c026514f8317c7a215e218dccd6cf 700 2000010000 [email protected] [email protected] 500 2000000000

结果确认

哈希时间锁合约提供了查询余额的接口,可通过WeCross控制台调用,查看两方的接收者是否到账。

  • FISCO BCOS用户确认
  1. [WeCross]> call payment.bcos.htlc bcos balanceOf 0x2b5ad5c4795c026514f8317c7a215e218dccd6cf
  2. Result: [700]
  • Fabric用户确认
  1. [WeCross]> call payment.fabric.htlc fabric balanceOf [email protected]
  2. Result: [500]

:跨链转账存在交易时延,取决于两条链以及机器的性能,一般需要5~25s完成转账。