11. 面向资产互换的原子性保障应用

11.1. 概述

面向资产互换的原子性保障应用包含两种事务原子性保障协议,哈希时间锁合约协议(hash time lock contract, HTLC)哈希时间锁合约优化协议Lilac。该应用在长安链(ChainMaker)上实现支持具有跨链事务原子性保障的跨链资产互换功能,支持长安链与长安链ChainMaker(v2.3.0 && v2.3.1)同构跨链、长安链ChainMakerFabric(release1.4)异构跨链。 在同构跨链与异构跨链基础上,该应用实现了基于哈希时间锁协议HTLC优化协议Lilac的跨链用户客户端,以支持用户自动取款和时间锁超时失效后自动退款等操作。

客户端具备如下功能:

  • 查询用户账户相关跨链资产信息

  • 发起HTLC事务原子性保障跨链资产互换提案

  • 发起Lilac事务原子性保障跨链资产互换提案

  • 自动对发给用户的跨链资产互换提案取款

  • 自动对发给用户的超时跨链资产互换提案退款

快速部署和使用实例,请按如下链接内容进行: 部署和使用文档

11.2. 设计

11.2.1. 整体设计逻辑

  • 整体设计逻辑如下图所示
    整体设计逻辑

  • 应用整体分为两部分,链上部分和链下部分。

  • 链上部分主要包括三个合约:跨链资产合约Assets、哈希时间锁合约Htlc、哈希时间锁优化合约Lilac

  • 链下用户客户端主要包括,长安链SDK、Fabric SDK、用户可用的功能模块,如查询用户账户地址、查询用户账户资产情况、发起跨链资产互换提案、对提案发起取款、对超时提案发起退款等

11.2.1.1. 链上合约设计

  • 链上合约主要实现三个合约,分别是跨链资产Assets合约,哈希时间锁HTLC合约,哈希时间锁优化Lilac合约 Assets合约主要包括以下功能:

  • approve授权其他账户能够从当前账户中花费一定金额的token

  • allowance获取当前账户能够从指定账户中花费的token数量

  • transfer转移一定数量的token给指定用户

  • balanceOf获取当前账户剩余token数量

  • transferFrom转移被授权人的token给指定用户

  • getAddress获取当前用户的地址

HTLC合约主要包括以下功能:

  • newProposal发起一个新的哈希时间锁提案

  • getProposal根据proposal id获取完整的提案信息

  • withdraw根据proposal id获取转给自己的token

  • refund对一个超时的提案,取回自己锁定的token

Lilac合约主要包括以下功能:

  • newProposal发起一个新的Lilac提案

  • getProposal根据proposal id获取完整的提案信息

  • withdraw根据proposal id获取转给自己的token

  • refund对一个超时的提案,取回自己锁定的token

11.2.1.2. 链下用户客户端

  • 链下用户客户端为用户开放部分可操作方法。用户通过连接客户端,输入命令的方式与系统交互。用户输入命令交由客户端后台解析命令,调用对应链的SDK接口,由对应区块链方法完成上链等相关工作。 用户客户端主要包括以下功能

  • newHtlcProposal发起一个新的哈希时间锁提案

  • newLilacProposal发起一个新的Lilac提案

  • refund对一个属于自己的提案进行退款

  • withdraw对一个属于自己的提案取款

  • getProposal根据proposal id查询提案具体信息

  • getBalance查询自己的token余额

  • getAddress获取自己的地址

  • break退出用户客户端

  • exit退出用户客户端

11.3. 接口及结构说明

  • 为了屏蔽不同链之间的区别并适配更多的链,提高应用的扩展性并减少未来的适配成本,应用设计了链SDK接口本地提案结构

11.3.1. 链SDK接口说明

  • 为了更好的进行多链适配与模块化,设计了链SDK接口抽象接口,任何想要接入该系统客户端的区块链,只要实现响应的接口即可。

// ChainClientInterface 客户端实现这个接口, 定义功能
type ChainClientInterface interface {
	// 在链chainName发起一个proposalType的proposal, 参数为params
	// @param proposalType 发起的proposal类型
	// @param toAddr 接收者地址
	// @param amount 发送的数量
	// @param hashlock 哈希锁
	// @param timelock 时间锁, 单位秒
	// @return string proposalID
	// @return error 错误信息
	NewProposal(propsalType, toAddr, amount string, hashlock, timelock any) (string, error)

	// 撤销一个proposal
	// @param proposalType proposal类型"htlc","lilac"
	// @param proposalID 被撤销的id
	Refund(proposalType, proposalID string) error

	// 取钱
	// @param proposalType proposal类型"htlc","lilac"
	// @param proposalID 取这个proposal的钱
	// @param preimage 原像
	Withdraw(proposalType, proposlID string, preimage any) error

	// 监听一个链的事件
	// @param contractName 被监听的合约名
	// @param eventName 被监听的事件名称
	// @param resultChain 获取监听结果的通道
	SubscribeEvent(contractName, eventName string, resultChan chan<- any)

	// 解析订阅事件为一个proposal结构体
	// @param eventInfo 每个链对应的事件信息
	// @return proposal 解析出来的proposal
	// @return error 解析失败
	ParseEventToProposal(eventInfo any) (proposalstruct.Proposal, error)

	// 获取余额
	// @param address 地址,如果为""则返回自己的余额
	// @return string 余额
	// @return error err
	GetBalance(address string) (string, error)

	// 获取proposal
	// @param proposalID proposalID
	// @return proposal 这个proposalID对应的proposal
	// @return error err
	GetProposal(proposalType, proposalID string) (proposalstruct.Proposal, error)

	// 获取地址
	// @return string 地址
	// @return error err
	GetAddress() (string, error)

	// 获取chainID
	// @return string id
	// @return error err
	GetChainID() (string, error)

	// 关闭客户端
	// 最后 defer
	Close()
}

11.3.2. 本地提案结构

  • 为了屏蔽不同区块链信息解析的障碍,应用设计了本地提案结构,实现链SDK接口的链,在与用户客户端进行通信时,需要将链上信息解析为指定结构,便于客户端对信息的管理

// Proposal 提案结构, 用于本地存储
type Proposal struct {
	Sender    string `json:"sender"`    // sender account Address
	Receiver  string `json:"receiver"`  // receiver account Address
	Amount    int64  `json:"amount"`    // transfer/lock token amounts
	PosalTime int64  `json:"posaltime"` // proposal generation time
	TimeLock  int64  `json:"timelock"`  // timelock
	// hashlock, 在htlc中是string, 在lilac中是[]string, 需要先转换成any/[]any
	HashLock any `json:"hashlock"`
	// 原像, 在htlc中是string, 在Lilac中是[]string, 需要先转换成any/[]any
	Preimage any `json:"preimage"`
	// BlockDepth int64  `json:"blockdepth"`
	Locked     bool `json:"locked"`     // proposal locked status
	Unlocked   bool `json:"unlocked"`   // proposal unlocked status
	Rolledback bool `json:"rolledback"` // propsoal rolledback status

	// 以下是为了实现proposal匹配而额外增加的属性
	ProposalID             string `json:"proposalID"`     // proposal id
	ChainName              string `json:"chainName"`      // proposal chain name
	UserName               string `json:"userName"`       // proposal user name
	ContractName           string `json:"contractName"`   // 这个proposal合约名
	ProposalType           string `json:"proposalType"`   //proposal type such as 'htlc' 'lilac'
	CorrespondingChainName string `json:"correChainName"` // 对端的名字
	CorrespondingAmount    int64  `json:"correAmount"`    // 对端应该转给我多少钱
}