几个月之前,我们发布了雷霆网络(Thunder Network)的alpha测试版本。我们当时已经解释过了,雷霆网络中大部分交易都不在比特币区块链上进行,并且,只有小部分需要记录在区块链上的交易处理得当,雷霆网络才能正常运作。通俗一点讲:不能在法庭上执行的合约是无效的。同样的道理在雷霆支付(thunder payments)中也适用——用户要有信心,发送到“法庭”(比特币区块链)的支付是有效的。
一开始,我们推出了layer-2支付协议——dual-tx。dual-tx能带来很多优势,但要实现更新升级却比我们想象的要困难的多。
dual-tx如何让雷霆网络使用更方便
在目前的协议层中,退款(refund)需要花费1个多月的时间,前提是在这段时间里你的下线时间不能超过1天。要是你想要出门玩两个星期,那退款时间很可能就会延长到1年左右。我们希望能尽量缩短退款时间,让收款方不再继续拖延。
Dual-tx在广播结算和申请支付之间添加了第二个协议层,这样就能申请支付的过程和等待延迟撤销的过程分离开来。如果收款方想要取消交易,他必须在延迟撤销到期之后才能申请second-tx输出,同时广播这第二笔交易。如果交易参与任意一方存在欺诈行为,其他参与方甚至可以在第二个协议层中取回这笔资金。这种第二个协议层中的交易的功能就像一个安全网。注意:只有当你想广播通道交易的输出申请时,才需要使用第二个协议层。交易任意参与方随时有权直接从你的交易通道中进行退款操作。
这种方式使支付时间缩短到1天,退款延迟撤销时间缩短到两个星期,大大提高了协议性能。
以下是我们的工程师Mats Jerratsch所述有关这一更新的细节。
处理交易结算
为了使这一过程更加通俗易懂,我分成3点来讲。
首先,我们会跟踪监控通道锚点的交易区块,一旦发现类似交易,我们会调用ChainSettlementHelper.onChannelTransaction(..)进行分析,确认其来源以及具体的交易信息是否和我们的记录吻合(如果不吻合就存在欺诈嫌疑)。然后再为每笔支付创建对应的ChannelSettlement对象,为了正常输出,我们会跟踪每笔支付的状态。这一过程全部完成之后,所有的ChannelSettlement就会储存在数据库中。
其次,ChannelSettlements会随着每个区块信息的更新而变化。交易方资金、支付请求及更新等信息都会被储存下来,以便用户再次发起支付。用ChainSettlementHelper.onBlockSave(..)可以查到。
第三,比特币交易是用ChainSettlementHelper.onBlockAction(..)创建的,用户需基于以下标记进行广播:
- ourTx——是我们在区块链上广播通道还是另一方希望进行链上结算?
- Cheated——该通道交易是最新的一笔还是有人欺诈?
- Sending——我们是支付发起方还是接收方?
- secondTx——我们是否已经在区块中看到第二笔交易支付了?
典型的案例
一个典型的例子是这样的:我给Bob发起了一笔支付,可是想要退回来,但Bob却不在线。由于我和Bob先前商量好的退款时间快到了,所以我必须自己做决定。我是要直接忽略这笔支付还是保持支付通道的开启?从这个案例的状况来看,还是关闭支付通道比较好。
我们只会广播最后一笔通道交易。一旦我们发现它在区块中,onChannelTransaction(..)会将ChannelSettlement对象在数据库中储存相应的。onBlockAction(..)函数会让dual-tx中包含一些支付机密,这是十分必要的,这样一来,支付就不会超时。
然后,该交易会到达下一区块,这样一来onBlockSave(..)就可以更新ChannelSettlement对象。但必须在延迟撤销时间之后才能储存信息,大概需要一个星期。要等上1008个区块。ChainSettlementHelper.onBlockAction(..)函数创建的交易会最终让退款到达我们的钱包中。
当交易其中一方有欺诈嫌疑,通常我们是可以申请所有通道交易输出的。为了实现这一目标,我们需要重新取回交易中撤销的哈希。除非数据丢失了,不然我们是可以从数据库中取回哈希的,或者用一些更先进的机制比如shachain的计算也是可以达到目的的。不过,如果交易参与方决定广播second-tx支付,他可能会损失一部分资金(手续费)。
对于那些已经遭遇欺诈的案例,这项新功能暂不适用。它的使用率肯定不大,我也不想鼓励欺诈行为。欢迎提出任何改进方案。
完美的代码,但希望永远不要执行
但愿我们不用再担心交易欺诈问题,所以我希望这个代码永远不要执行。但还是要说一句,这个代码已经经过了多种案例的严格测试,该代码执行时比特币脚本可以照常工作。但是,没有经过重重考验的代码是不完美的,所以任何的改进和意见我们都无任欢迎。