区块链跨链互操作技术 (上篇)

Chain Interoperability

翻译:CoinEx链开发团队/kui | 原作者:Vitalik Buterin | 原文PDF | 下篇

Chain Interoperability

在区块链行业发展的开始几年,如果有人认为将有唯一的“一条链来统治一切”,那么还算是有情可原,如今,这种可能性已经距离现实越来越远了。在公链领域,不同的项目在安全、隐私性、高效性、灵活性、复杂度、易用性、甚至政治价值等方面做出了不同的折衷权衡。在私有链和联盟链领域,在不同的行业会有不同的链,甚至同一行业内也会有多条链——这一点也基本上是大家的共识了。在这样的一个世界里,自然会出现一个问题:这些链相互之间如何互操作?目前的区块链实现中,密码学的认证(即签名)被包含在每个交易中,这带来了一个好处:相对于业已存在的平台间耦合和互动的机制,区块链之间的耦合和互动,能够更加紧密和安全。目前中心化平台之间的连接,往往就是彼此开放一个API,而在区块链之间的互操作,可以走得更远:某些场景下,一条链上的智能合约代码可以直接验证另外一条链上是否对某事件达成了最终共识,而这种验证是在完全不需要信任任何中间人的情况下做到的。

可互操作的链,打开了新世界的大门:将资产从一条链转移到另外一条,支付对支付的组合,支付对交付的组合,在一条链上访问另一条链的信息(例如支付链需要访问“身份链”的信息)——所有这些都将变得非常容易,甚至可以由第三方在不修改底层区块链的协议的情况下完成。目前链间互操作的概念,在很大程度上还是理论上的,很少有实践,重要的原因在于成功的链间互联实例,需要建立在两条现存的、稳定的、足够强大的链之上,但是这一现状已经开始在改变了。

到目前为止,对链间互操作的研究,主要是在公链的场景下进行的,本文在很大程度上,是已有研究的“文献回顾”,因此也集中在公链上。虽然这些技术中有很多也能应用于私有链和联盟链,但应用中会遇到一些特殊的挑战,这些挑战就不在本文所讨论的范围内了。例如,目前还没有一条“有许可”的链被大规模应用,所以我们也不知道在共识算法在何种程度上可以适配于它。此外,很多“互操作”需要牵涉到同传统系统及协议的互动(例如SWIFT,SEPA,FIX),但本文并不会讨论这些,因为公链在近期或中期的未来,同这些系统相连接的可能性非常低。

Types of Interoperability

从技术的角度讲,链间互操作有三大类策略:

  • 中心化或者多签的公证人机制:一方或者多方同意在链B上采取某行动,如果在链A上发生了某事件。
  • 侧链/中继:一条链的内部系统可以验证和读取其它链上的事件或状态。
  • 哈希锁:在链A和链B各自设置一个操作,这两个操作有相同的触发条件,通常这个条件是揭示某个哈希值的原像(即由怎样的原始数据可以哈希得到此哈希值)

互操作可以实现如下几种潜在的用例:

  • 链间转移资产:例如可以把若干Fedcoin(这是一个假设的、由政府发行的数字资产)从它的“家链”(这条链对于Fedcoin资产拥有最终的权威)被安全地转移到另外一条链X上。在链X上,这些Fedcoin可以用来做交易、做抵押或者别的用处,然后还可以随时把它们转回到“家链”上来。
  • 支付对支付”或“支付对交付”:在技术文献里,这个概念一般被成为“原子交换”。“原子”一词,在它所发源的希腊文里是“不可分”的意思,即,确保两个交易要么同时发生,要么都不发生。本质上,我们的目的是允许用户X把数字资产组合A传输给Y,以换取Y把数字资产组合B传输给X(A和B在两条不同的链上,X和Y在这两条链上都有自己的账户),这两笔传输必须是原子的和安全的。
  • 跨链预言机:例如某人希望通过一条链上的智能合约对某个地址执行某项操作,其前提是另外一条链上的身份预言机确认此地址对应于某个唯一的实体。注意,被读取的这条链,在这一互操作事件发生的过程中,自身并没有发生改变。
  • 资产留置:在链X上锁定资产组合A,锁定的条件依赖于链Y上发生的某事件。用于:扣押,金融衍生品中的抵押物,破产回收物,法院指令,以及涉及到保证金的一些用例。
  • 通用的跨链智能合约:例如在链X上给链Y上某资产的拥有者派发红利。

在上述的用例中,有两个获得了最广泛的关注:跨链资产转移和跨链资产交换。接下来的章节,我们首先用通用的术语来描述互操作的问题,这些描述适用于所有的应用场景;之后,我们会聚焦于跨链资产转移和跨链资产交换的安全性和其它一些考量。然而,值得注意的是,跨链资产转移只是一种达成它所期待之目标的方法——对于无发行者背书的资产(例如BTC、ETC),它的确是唯一的方法;但对于有发行者背书的资产,还有其他的方法,例如:在多条链上发行资产,同时在法律层面约定这些资产有互换性(而不是在区块链协议层面)。

“侧链”一词,经常用来指代可跨链转移的资产,然后这种提法在很多方面都是误导和令人困惑的。首先,Blockstream对于“侧链”的正式定义是:侧链是一条验证来自其他链的数据的区块链。然而,这个定义的范围太宽了。如果按照这个定义的话,由于BTCRelay的存在(下文会详细描述它),以太坊已经是Bitcoin的侧链了。在一般的讨论中,“侧链”更多地是用来指代Blockstream所说的“楔入的侧链”,它意味着一条区块链从另一条链读取信息是用来实现跨链的资产转移。这个概念相对于一般的“侧链”有更多的内涵:它要求两条链是彼此的侧链,或者存在一个可信的联盟(下文中的见证人机制会详细描述这一点),同时,在跨链通讯的机制之上,有一个机制真实实现了跨链资产转移的逻辑。

其次,“链A是链B的侧链”这一提法,隐含着一种“从属关系”,在很多实例中,很难有理由说存在这种“从属关系”。还是刚才的那个例子,以太坊从技术上讲是Bitcoin的侧链,但是以太坊从任何角度讲,都不“从属”于Bitcoin。“侧链”和“楔入的侧链”,当时是在这样的语境中被提出的:有一条链(即Bitcoin)拥有唯一的占有统治地位的资产(即BTC),因此,如果有一条链上包含着“楔入的BTC”,那么它就很自然地被视为Bitcoin的侧链了。然后,事实上,“楔入的”这一属性,应该用于描述链上的资产,而不是描述链本身。

例如以太坊上包含有Ether(以太坊的原生代币),但是,如果其它区块链实现了必要的协议更新(或者存在一个可信的联盟),那么以太坊上就能包含“e-BTC”,它可以同Bitcoin链上的BTC一比一兑换,能包含“e-DOGE”,它可以同Dogecoin链上的DOGE一比一兑换,等等。这样,以太坊就成为了所有这些链的侧链。但是,以太坊本身并没有“楔入”到任何其它链上。因此,讨论某链是不是“侧链”并不妥当,更好的提法是:“链B可以读取链A”,“链B上有链A的中继”,“D是一种可跨链移动的资产,它的家在链A上,也可以在链B上使用”。

Notary Schemes

从技术上讲,最简单的实现跨链操作的方法,是“见证人机制”。在见证人机制中,一个可信的实体,或者多个可信的实体所组成的团体,被用来向链X声明链Y上发生了某事件,或者声明关于链Y上的某个断言为真。这些实体可以是活动的,不断监听链Y上的事件,当发生某事件之后,自动地做出响应;也可以是响应式的,只有当收到请求的时候,才会对某些消息进行签名。在这个方向上走得最远的,是由Ripple公司开发的Interledger项目。Interledger,至少在它所说的“自动模式”下,使用了一种拜占庭容错的共识算法,以便在一组公证人中,就某事件是否发生取得共识,从而签发一则消息,此消息用来最终化某笔支付。

Interledger还展望了这样一种组合式的跨链转账。如果X和Y希望交换数字资产组合,但这两个资产分布位于链A和链F上,A和F并没有直接的连接。那么,我们可以找到中间人,他们位于链B、C、D、E上,而相邻的两个链具有直接的连接(即在AB、BC、CD、DE、EF之间,两两存在着公证人和交换资产的可行性),这时,就可以通过一系列的资产互换来实现A和F之间的交换,同时,中间人也能从中获得一点点套利的收益。在整个交换的过程中,使用单一的共识过程,确保所有的互换要么同时完成,要么都不完成。

注意:上述方法并非获得原子性的唯一方法,哈希锁(下面的章节会详细描述)也能达到此目的,在闪电网络中,就使用了哈希锁来实现跨链转移的原子性。然而,公证人机制在技术上讲相对简单,而且在它所依赖的信任模型(只有一小部分被选择的公证人是拜占庭的,即有恶意的)之下,它的确很好地实现了目标。每一种资产互换可以单独地选择它的公证人集合。我们可以设想这样一种协商机制:所有的参与者都提交自己所能相信的公证人列表,这些列表的交集就作为公证人集合。我们还可以把公证人机制和下文所描述的机制相结合,形成这样一种链间资产交换协议:努力为资产交换争取尽可能高的安全等级,当底层的区块链还不支持无信任(Trustless)的中继协议时,回退到公证人机制上。

另一个相关的机制是所谓的“楔入的联盟链”,其目的是实现跨链资产转移,而单向或双向的楔入,是通过多签的机制完成的。这一机制在Liquid中实现了,Liquid是一条Bitcoin的侧链,由Blockstream所创造。你可以把一个BTC打入一个由参与者联盟所控制的多签地址,然后等Liquid链上对Bitcoin链上的这笔转帐交易达成共识之后,你就可以在Liquid链上获得一个“L-BTC”。L-BTC可以在Liquid上自由交易。你也可以销毁L-BTC,控制多签地址的联盟会把等额的BTC从这个多签地址上转给你发出销毁交易的地址(即一对一兑换)。

注意,两条公链之间,可以实现“联盟式的楔入”,一条公链和一条联盟链之间也可以。对后一种情况而言,可以简单地让构成联盟链的成员们集体控制那个多签地址。对于前一种情况而言,除非“侧链”上还跑着其它同这个被楔入的资产无关的应用,否则在公链上应用“联盟式的楔入”只是增加了开销,而没有对安全性有任何提升,因为它本质上还是依赖于联盟成员的诚实性。

Relays

中继是实现互操作的更加直接的方法。它不再依赖可信的中间人来提供关于其他链的信息,而是让链本身接管了这一任务。大体的方法是这样:假定链B上的智能合约希望了解链A上是否发生了特定的事件,或者在链A的某个状态上,某个对象拥有某个特定的值;假定链A被设计得像Bitcoin或者以太坊那样有“区块”和“区块头”的概念,而且在区块头是一个区块(以及当前状态)的压缩的表示(此压缩的表示基于密码学的一些构造,例如Merkle树)。

这时,我们就能在链B上创建一个智能合约,它以链A的区块头为输入,使用链A上的共识算法所确定的标准验证流程来验证这个区块头:如果是PoW,要验证这个区块头相对于任何与之冲突的区块头拥有更大的累积算力;如果是传统的拜占庭容错共识算法,要验证大于2/3的Validator都对这个区块头签名了。一旦中继合约确认此区块头已经最终化了,它就可以进一步验证任何交易,或者任何账户/状态项,是不是有效的(通过以Blocker Header为终点的Merkle Proof)。

用这种所谓的“轻客户端验证”的技术来做中继是非常理想的,因为区块链在本质上都是资源紧张的。事实上,想要在链A里完全验证链B,同时在链B里完全验证链A,这是完全不可能的。试想:你怎么可能让两个盒子同时包含对方呢?使用“轻客户端验证”,让A包含B的一些片段,让B包含A的一些片段,这些片段都是按需拉取来的,这样才具有可行性。 一个链B上的智能合约希望验证链A上的某个特定的交易、事件或状态,它就会以一种非常类似轻客户端的方式,通过Merkle Proof的方式来验证(注意,区块链是“自包含”的环境,并没有自然的访问接口可以感知外部世界,链A上的数据其实是被某个用户提交到链B上来的;然而,由于这些数据在密码学意义上是可以自验证,我们无需相信这个提交数据的用户。)

中继是非常强大的,它可以用来实现资产转移,原子交换,或者其他更加复杂的用例,而没有任何本质性的限制。一个基于中继来实现的资产转移的系统大体是这样的:

注意,一般而言,在中继机制背后的复杂密码学验证,可以轻易地被抽象掉,开发者不必关心这些。对事件的验证本身,能够被包在一个智能合约里面,其它智能合约调用它就如同调用一个预言机。事件的读取可以被抽象为一个异步操作:设想一种跨链的智能合约编程语言,它包含一个原语createEvent(destinationChain, params),此原语注册一个事件,并且给它分配一个唯一的ID;还包含一个函数onRecieveEvent(senderChain,params),此函数在如下条件满足时才被调用:一、一个密码学的证据表明,某事件被传入了;二、一条记录被加入了持久存储以防止这个函数因为同样的事件被第二次调用。

您可能注意到了,这样一个异步事件读取模型可以被看作是两种风格的混合体:以太坊式的“具有状态的”区块链,以及类似比特币的UTXO模型。没有被消费掉的事件记录就像是一条UTXO。上面的异步事件架构假定事件都会被立即消费掉。但编程语言也可以设计成这样:直到被需要的时候,事件才会被消费掉,而那些没有被消费掉的时间,就成为了长时间存在的状态的一部分。

跨链移动Fedcoin的代码,大致如下所示:

function sendCrossChain(destChain, to, value) {
	if (balances[msg.sender] < value) throw;
	createEvent(destChain, {name: SEND, to: to, value: value});
	balances[msg.sender] -= value;
	crossChainBalances[destChain] += value;
}
function onReceiveEvent(senderChain, params) {
	if (params.name == SEND) {
		if (crossChainBalances[senderChain] < params.value) throw;
		balances[params.to] += params.value;
		crossChainBalances[senderChain] -= params.value;
	}
	...
}

这一合约在Fedcoin的主链和附属链上都存在。这段代码的逻辑非常简单。函数sendCrossChain函数首先检查发送者是否有足够的Fedcoin;如果没有就退出并且返回error。如果发送者的确有足够的Fedcoin,它就创建一个事件,担保说这些Fedcoin应该在目标链上被创建出来,同时在发送链上从发送者的余额中减去发送的金额,同时给目标链的余额中加上发送的金额。这些管理目标链余额的代码,提供了一种安全保障:即使目标链的共识机制由于某种原因被破坏了,目标链向主链发送回的Fedcoin的金额也不会超过主链曾经向它发送的,这样就防止了不可被信任的目标链被攻击之后,向主链不受限制地发送回任意数量的Fedcoin。

函数onRecieveEvent在确信发送链可以发送给定金额的Fedcoin之后,会增加接收者的余额,减少发送链的余额。注意:在每一条附属链上,crossChainBalances[mainChain]都被初始化为无穷大(变量mainChain保存Fedcoin主链的ID),这表明附属链都认可主链是Fedcoin权威的发行者。

在Bitcoin和以太坊之间,已经有一个中继合约被成功地实现了,它就是BTCRelay,一个能读取Bitcoin链上状态的以太坊智能合约。但请注意,这里的“互操作”其实是单向的:Bitcoin链并不能读取以太坊链,因为它的脚本语言还不足够强大。BTCRelay已经得到少量的应用。在撰写本文时,有一个叫做EthereumLottery.io的应用,它本身是以太坊上的智能合约,但它使用比特币的区块头作为随机数源头,因为比特币的区块头包含一大笔奖励,要操控它需要付出高昂的代价。作为一个“跨链预言机”应用,这是一个有些原始但在技术上很出色的例子。 中继在这个例子中为增强应用的安全性做出了重要贡献。

Relays for Cross-Chain Atomic Swaps

除了跨链资产转移和跨链预言机,跨链中继的另外一个自然的用途是跨链的原子交换,即,用链A上的资产M交换链B上的资产N。基于BTCRelay和以太坊,MakerDAO团队正在实现这一功能。然而,很不幸地,这样系统不可避免地会有一个弱点,这个弱点是Bitcoin协议自身的根本性限制所带来的。一个典型的例子是竞态条件攻击:如果A希望用50个ETH换一个BTC,他把50个ETH存在了一个智能合约中,此合约的逻辑是:如果任何人可以提供一个证明,说在Bitcoin链上他把1个BTC发送给地址X了,那么他就能拿到这50个ETH。这时候B发送了1个BTC给地址X,希望得到这50个ETH。A看到这笔交易之后,自己也给地址X发送了1个BTC,然后抢在B之先,从智能合约中提走了50个ETH。最后的结果是A有2个BTC和50个ETH,B什么也没有了。

如果Bitcoin链拥有类似以太坊这样的智能合约,上面的问题就不存在了:目标地址X可以是一个合约地址,它只接受第一笔打款,后面的打款都会原路退回。如果没有这种能力,那么我们只能在以太坊上使用信号量(semaphores) 机制:允许买这50个ETH的人先预定下来在一段时间内做这笔交易的权力,然后就可以安全地在这个时间窗口内打款BTC了。MakerDAO团队目前使用的其实就是这种机制。但是,用信号量做预定的机制,有可能招致拒绝服务攻击:某人可以持续地做预定但从不打款。把预定操作的开销设计得很高,可以解决这一问题,但又会影响用户体验:你需要拥有相当数量的ETH才能用BTC换更多数量的ETH。的确还有一些方法,通过引入毋须信任的第三方来解决这一问题,但那些方法都太复杂了,需要2-of-2的第三方代管以及Bitcoin链上的时间锁。抛开这些表述中的细节不论,从更深远的意义来讲,“竞态条件”是基于中继的应用所不得不考虑的一种常见的安全隐患,它就像以太坊智能合约中的“可重入”问题,或者网络应用中的SQL注入问题,必须引起开发者时时刻刻的关注。

中继的另一个相关的弱点是它们自身的异步特性,尤其是当跨链的一方或者双方使用的共识算法不具备快速最终化之一特性的时候。一条链要想确信另一条链对某操作达成共识,必须等待很长的时间,这限制了跨链操作的速度。对于跨链的原子交换而言,这是一个特别不幸的缺点,因为市场的汇率会在原子交换的过程中发生显著的改变。因此,中继可以在具有快速最终化能力的两条链之间良好地工作,否则它就会遇到问题。在出块间隔非常短的第三条链上预付保证金,可能是克服这一问题的方法之一。

Hash Locking

还有一种著名的技术可以实现跨链的原子交换:哈希锁,它并不需要两条链深入地“了解”对方。哈希锁技术是由Bitcoin论坛上名为TierNolan的用户所提出的,近来,Interledger协议对它进行了积极的探索,希望利用它来去掉对第三方公证人的信任要求。在跨链原子交换的场景下,哈希锁的机制可以简单地描述如下:

  1. A生成一个秘密的随机数s,然后计算其哈希值hash(s)=h,之后A把h送给B。
  2. A和B都将自己的资产锁定在一个智能合约中,A先进行锁定,B看到A的锁定操作成功之后,再进行锁定。智能合约的逻辑是:在A一侧,如果在2X秒之内,秘密的随机数s被提供了出来,那么资产就转移给B,超时则资产传回给A;在B一侧,如果在X秒之内s被提供了出来,那么这笔资产就转移给A,超时则资产传回给B。
  3. A为了获得B的合约中锁定的资产,会在X秒之内揭示s;同时,这也保证了B可以在链上观察到s,从而获得A的合约中锁定的资产。

注意,这里的原子性是可证明的,如果A在X秒之内揭示了s,这保证了B至少有X秒的时间窗口来拿到属于他的资产。A如果犯了一个错误,在X秒之后揭示了s,那么B可以获得资产而A就无法获得了,但这是A自己的错误,而且是可以轻易地避免掉的错误。如果A在2X秒之后揭示s,或者永远不揭示,那么双方都将拿回自己待交易的资产。如果A从不锁定自己的资产,那么B也不会锁定。如果B没有锁定自己的资产(或者锁定得不恰当,例如时间窗口太小了),A只需要永不揭示s,让双方给自拿回自己待交易的资产。

注意,在真实世界中,存在着汇率的波动,因此金融上的安全,没有得到完美的保证。一个恶意的A,会先等待X/2秒,观察市场汇率,如果汇率朝着有利于他的方向变化,他才揭示s;参与这场原子交换,意味着B给了A一个自由选择的机会。您可能会说,为了均衡,B在意料到A有这种自由选择的机会的情况下,会在交换的价格上要求一些优惠,但这一场景仍然是不完美的:这等于是说,如果某人希望交换自己的资产,那么他要么需要反复重试好几次,或者在价格上给出足够的优惠,才能激励它的对手方一次完成交换,这就减弱了市场参与者有效地对冲风险的能力。

跨链的哈希锁,还可以同状态通道(state channel) 结合起来,以实现更快速的交换,即用状态通道相对于主链所具备的更高的速度来缓解上面提到的问题。这个领域仍然处于积极的研究和开发中。注意,哈希锁只适用于原子交换,它不适用于跨链资产转移和跨链预言机。它不能适用于跨链预言机的原因很简单:访问跨链预言机对于被读取的链而言,是一个被动的操作,而哈希锁对双方而言,都是主动的操作。它不能适用于跨链资产转移的原因,有一些微妙:哈希锁所实现的原子交换保证了两条链上的资产总额各自保持不变,因此它不能把资产从一条链转移到另外一条链。但是,哈希锁可以同中继相结合:基于中继的跨链资产转移可以使同一资产在不同链上的Token的汇率非常贴近1:1,因为任何其他的汇率都会造成套利的机会;在汇率是固定不变的情况下,普通的用户就可以通过哈希锁的方法,安全地把资产从A链上转到B链上,只要他能找到一个想把资产从B转到A的对手方。

1 Like