文章转载来源: HashKey Capital

作者:HashKey Capital Head of Investment Research Jeffrey HU、HashKey Capital Investment Manager Harper LI

近期比特币社区里掀起来一波关于重新启用 OP_CAT 等操作码的讨论。Taproot Wizard 也通过推出 Quantum Cats 的 NFT、声称已经获得 BIP-420 的编号等,吸引了不少人的注意力。支持者宣称,启用了 OP_CAT 可以实现‘限制条款’(covenants)、实现比特币的智能合约或可编程性。

如果你注意到‘限制条款’这个词并稍作搜索,就会发现这是另一个很大的兔子洞。开发人员已经讨论了多年,除了 OP_CAT 之外,还有 OP_CTV、APO、OP_VAULT 等等实现限制条款的技术。

那么,究竟什么是比特币的‘限制条款’?为什么能吸引到如此多的开发人员持续数年的关注和讨论?能实现比特币的哪些可编程性?背后的设计原理是什么样的?本文试做一个概览性的介绍和讨论。

什么是‘限制条款’

Covenants,中文译作‘限制条款’,有时也翻译为‘契约’,是一种能够给未来的比特币交易设置条件的机制。

当前的比特币脚本也包含了限制的条件,例如花费的时候要输入合法的签名、送入符合的脚本等。但是只要用户能解锁,就可以将该 UTXO 花到任意他希望的地方。

而限制条款是,在此限制如何解锁的基础之上,做出更多限制,例如限制 UTXO 之后的花费,也就是实现类似‘专款专用’的效果;或一笔交易中送入的其他输入条件等。

更为严谨地说,目前的比特币脚本也具备一定的限制条款,例如基于操作码的时间锁,就是通过内省交易的 nLock 或者 nSequence 字段来实现交易花费前的时间限制,但也基本仅限于时间方面的限制。

那么,开发和研究人员为什么要设计这些限制检查?因为限制条款不只是为了限制而限制,更是设置了交易执行的规则。这样,用户只能按照预先设定的规则来执行交易,从而完成预定的业务流程。

所以比较反直觉的是,这可以解锁更多应用场景。

应用场景

确保 Staking 的惩罚

限制条款的一个最直观的例子是 Babylon 在 Bitcoin staking 流程中的 slash 交易。

  • Babylon 的 Bitcoin staking 过程是用户将自己的 BTC 资产在主链上发送到一个特殊的脚本中,花费条件包括两种:
  • Happy ending:经过一定的时间后,用户用自己的签名即可解锁,即完成 unstake 的过程

Bad ending:如果用户在某个被 Babylon 租借安全性的 PoS 链上有双签等作恶行为,那么通过 EOTS(extractable one-time signatures,一次性可提取签名),可以解锁出这部分资产,并由网络中的执行角色将一部分资产强制发送到燃烧地址(slash)

图片[1] - 详解Covenants:如何实现比特币的可编程性?

来源:Bitcoin Staking: Unlocking 21M Bitcoins to Secure the Proof-of-Stake Economy

注意这里的‘强制发送’,这意味着即便是可以解锁这笔 UTXO,但该资产不能任意地发送到其他任何地方,只能燃烧掉。这样才能保证作恶的用户无法抢先用自己已知的签名把资产转回给自己,以逃脱惩罚。

这个功能如果在 OP_CTV 等限制条款实现后,可以在 staking 脚本的‘bad ending’分支中增加 OP_CTV 等 opcode 以实现限制。

而在 OP_CTV 启用前,Babylon 就需要通过变通的方法,由用户 + 委员会共同执行的方式来模拟实现限制条款强制执行的效果。

拥堵控制

一般而言,拥堵是指当比特币网络上手续费率很高,交易池中积攒了比较多的交易等待打包,所以如果用户想要快速确认交易,就需要提高手续费。

而此时如果一个用户必须发送多笔交易给多个收款方,就不得不提高手续费,承担比较高的成本。同时也相应的会进一步推高整个网络的手续费率。

如果有了限制条款,一个解决方法是发送方,可以先承诺到一笔批量发送的交易上。这个承诺可以让所有的接收方相信,最终的交易都会进行,可以等到手续费率低的时候再发送具体的交易即可。

如下图所示,当对区块空间的需求很高时,进行交易变得非常昂贵。通过使用 OP_CHECKTEMPLATEVERIFY,大批量支付处理商可以将其所有付款聚合到单个 O(1) 事务中以进行确认。然后,一段时间后,当对区块空间的需求减少时,付款可以从该 UTXO 中扩展出来。

图片[2] - 详解Covenants:如何实现比特币的可编程性?

这个场景是 OP_CTV 这个限制条款提出的比较典型的一个应用案例。还有更多的应用案例可从 https://utxos.org/uses/ 找到,除了上述拥堵控制,该网页列举了 Soft Fork Bets、Decentralized options、Drivechains、Batch Channels、Non Interactive Channels、Trustless Coordination-Free Mining Pools、Vaults、Safer Hashed Time Locked Contracts (HTLCS) Limits 等。

保管库

保管库(vault)是比特币应用中一类比较广泛讨论的应用场景,特别是在限制条款领域内。因为日常操作不可避免的要在资金保管与资金使用需求之间进行平衡,所以人们希望能有一类保管金库的应用:可以保证资金安全,甚至即使账户被黑(泄露了私钥),也能限制资金的使用。

基于实现限制条款的技术,保管库类的应用可以比较容易的构建出来。

以 OP_VAULT 的设计方案为例:在花费保管库中的资金时,需要先发送一笔交易上链。这笔交易表明了希望花费保管库的意图,即‘trigger’,并在其中设置了条件:

  • 如果一切正常,那么第二笔交易是最终取款的交易。等待 N 个区块后,可以将资金进一步花费到任意地方
  • 如果发现是这笔交易被窃取的(或者是被‘扳手攻击’时候胁迫的),在 N 个区块的取款交易发送前,可以立即发送到另一个安全地址(用户更安全的保管)

图片[3] - 详解Covenants:如何实现比特币的可编程性?

需要注意的是,在没有限制条款的情况下,也可以构建出来一个保管库应用,一个可行的办法是用私钥来准备好以后花费的签名,然后销毁掉这个私钥。但限制仍然比较多,例如需要确保这个私钥已经销毁掉(类似于零知识证明中的 trusted setup 过程)、金额和手续费提前确定(因为要预签名)因而缺乏灵活性等。

图片[4] - 详解Covenants:如何实现比特币的可编程性?

更健壮和灵活的状态通道

一般可以认为,包括闪电网络在内的状态通道拥有和主链近乎等同的安全性(在保证节点可观察最新状态、能够正常发布最新状态上链的情况下)。然而在有了限制条款之后,一些新的状态通道的设计想法可以在闪电网络的之上更加健壮或灵活。这其中比较知名的包括 Eltoo、 Ark 等。

Eltoo (也称为 LN-Symmetry)就是其中一个比较典型的例子。这个技术方案取‘L2’的谐音,为闪电网络提出了一种执行层,允许任何后来的通道状态取代之前的状态,而不需要惩罚机制,因此也可以同时避免类似闪电网络节点那种必须保存多个之前状态以防止对手作恶。为了实现上述效果, Eltoo 提出了 SIGHASH_NOINPUT 的签名方式,即 APO(BIP-118)。

而 Ark 旨在降低闪电网络的入站流动性和通道管理等难度。它是一种 joinpool 形式的协议,多个用户都可以在一定时间内接受一个服务提供商作为交易对手,在链外进行虚拟 UTXO(vUTXO)的交易,但在链上共享一个 UTXO 从而降低成本。和保管库类似,Ark 也可以在当前的比特币网络上实现;但引入了限制条款之后,Ark 可以基于交易模板降低所需要的交互量,实现更去信任化的单边退出。

限制条款技术概览

从上述应用可以看到,限制条款更像一个效果而非某种技术,因此有许多种实现的技术方式。如果进行分类,可以包括:

  • 类型:通用型、专用型
  • 实现方式:基于 Opcode、基于签名
  • 递归:递归、非递归

图片[5] - 详解Covenants:如何实现比特币的可编程性?

而其中,递归是指:有一些限制条款的实现,也可以通过限制下一笔输出来限制再下一笔的输出,可以实现添加的限制可以超越一笔交易,达到更高的交易深度。

一些主流的限制条款设计包括:

图片[6] - 详解Covenants:如何实现比特币的可编程性?

* 递归:如果结合 OP_CAT

限制条款的设计

从前面的介绍可以看出来,目前的比特币脚本主要限制了解锁的条件,没有限制该 UTXO 如何进一步被花费。要实现限制条款,我们就要反过来思考:为什么目前的比特币脚本无法实现限制条款?

原因主要在于目前的比特币脚本无法读取交易自身的内容,即交易的‘内省’(introspection)。

如果我们可以实现交易的内省——检查交易的任何内容(包括输出),那么就可以实现限制条款了。

因此限制条款的设计思路也主要围绕在如何实现内省上。

基于操作码 vs 基于签名

最简单粗暴的想法是,增加一个或多个操作码(即一个操作码 + 多种参数,或多个不同功能的操作码),直接读取交易的内容。这个也就是基于操作码的思路。

而另外一种思路是,可以不在脚本中直接读取和检查交易自身的内容,而是可以利用交易内容的哈希——如果已经对这个哈希进行了签名,那么只要在脚本里改造例如 OP_CHECKSIG 等来实现对这个签名的检查,就可以间接的实现交易内省及限制条款了。这个思路就是基于签名的设计方式。主要包括 APO 及 OP_CSFS 等。

APO

SIGHASH_ANYPREVOUT(APO)是提议中的一种比特币签名方式。签名的最简单的方式是对交易的输入输出都承诺,但比特币还有更为灵活的方式,即 SIGHASH,选择性地对一笔交易中的输入或输出进行承诺。

图片[7] - 详解Covenants:如何实现比特币的可编程性?

如上图所示,除了适用到全部数据的 ALL 之外,NONE 的签名方式是只适用到所有输入,而不用于输出;SINGLE 是在此基础上,只对适用到相同输入序号的输出。另外,SIGHASH 还可以组合,叠加了 ANYONECANPAY 修饰符后,只适用于一笔输入。

而 APO 的 SIGHASH 则是只对输出签名,而不对输入部分签名。这也就意味着,用 APO 方式签名之后的交易,可以在之后附加到任何一个满足条件的 UTXO 上。

图片[8] - 详解Covenants:如何实现比特币的可编程性?

这种灵活性是 APO 实现限制条款的理论基础:

  • 可以预先创建一笔或多笔交易
  • 通过这些交易的信息构建出一个只能求出一个签名的公钥
  • 这样任何发送到该公钥地址上的资产都只能通过预先创建的交易来花费

值得注意的是,因为这个公钥没有对应的私钥,所以可以确保这些资产只能通过预先创建的交易来花费。那么,我们就可以在预先创建的这些交易中规定资产的去向,从而实现限制条款。

我们可以进一步通过对比以太坊的智能合约来理解:通过智能合约我们可以实现的也是只有通过一定的条件,才能从合约地址中取款,而非靠一个 EOA 签名就任意花费。从这一点来讲,比特币通过签名机制的改进就可以实现这种效果。

但上述过程中的问题在于计算时存在循环依赖,因为需要知道输入的内容来预签并创建交易。

APO 以及 SIGHASH_NOINPUT实现这种签名方式的意义在于可以解决这种循环依赖问题,在计算时只需要知道(指定)交易的全部输出即可。

OP_CTV

OP_CHECKTEMPLATEVERIFY (CTV) ,即 BIP-119 ,采用了改进 Opcode 的方式。它将 commitment hash 作为参数,并要求任何执行操作码的交易都包含一组与该承诺匹配的输出。通过 CTV,将允许比特币用户限制他们使用比特币的方式。

该提案最初以 OP_CHECKOUTPUTSHASHVERIFY (COSHV) 的名义推出,并且早期侧重于创建拥塞控制交易的能力,因此对该提案的批评也集中在该方案不够通用、过于具体地针对拥塞控制用例。

在上文提到的拥堵控制用例中,发送者 Alice 可以创建 10 个输出并对这 10 个输出进行哈希,并使用生成的摘要来创建一个包含 COSHV 的 tapleaf 脚本。Alice 还可以使用参与者的公钥来形成 Taproot 内部密钥,以允许他们在不泄露 Taproot 脚本路径的情况下合作支出。

然后,Alice 会给每个接收者一份所有 10 个输出的副本,以便他们每个人都验证 Alice 的设置交易。当他们以后想要花费这笔付款时,他们中的任何一个都可以创建一个包含承诺输出的交易。

在整个过程中,在 Alice 创建并发送设置交易时,Alice 可以通过现有的异步通信方法(如电子邮件或云驱动器)发送这 10 个输出副本。这意味着,接收者不需要在线,也不需要相互交互。

图片[9] - 详解Covenants:如何实现比特币的可编程性?

来源:https://bitcoinops.org/en/newsletters/2019/05/29/#proposed-transaction-output-commitments

和 APO 类似,地址也可根据支出条件来构建,可以用不同的方式来制作‘锁’,包括:增加其他的 key、时间锁、可组合逻辑。

图片[10] - 详解Covenants:如何实现比特币的可编程性?

来源:https://twitter.com/OwenKemeys/status/1741575353716326835

CTV 在此基础上提出了可以检查经过 hash 后的花费交易是否与定义的匹配,即将交易数据作为开‘锁’的密钥。

我们可以将上面 10 个接收者的例子继续延伸,接收方可进一步将其地址密钥设置为已签名但未广播的 tx 发送给下一批接收方地址,以此类推,形成一个如下图所示的树状结构。Alice 在链上只用 1 utxo 的区块空间就可以构造一个涉及多个用户的账户余额变更。

图片[11] - 详解Covenants:如何实现比特币的可编程性?

来源:https://twitter.com/OwenKemeys/status/1741575353716326835

而如果其中一个叶子是闪电通道、是 cold storage、是其他支付路径呢?那么这棵树将从单维多层的支出树扩展至多维多层次的支出树,能支持的场景将更为丰富和灵活。

图片[12] - 详解Covenants:如何实现比特币的可编程性?

来源:https://twitter.com/OwenKemeys/status/1744181234417140076

CTV 自提出以来,经历了 2019 年从 COSHV 更名、在 2020 年被分配了 BIP-119,并出现用于创建支持 CTV 合约的编程语言 Sapio,在 22、23 年得到了社区很多讨论、更新,以及对其激活方案的争论,目前仍是社区讨论比较多的一个软分叉升级提案之一。

OP_CAT

OP_CAT 如开篇所介绍的,也是一个目前非常受关注的升级提案,实现的功能对堆栈中的两个元素进行拼接(concatenante)。虽然看上去很简单,但 OP_CAT 可以很灵活的在脚本中实现很多功能。

最直接的例子就是对于 merkle 树相关的操作。Merkle 树可以理解为两个元素先拼接,再进行 hash。目前比特币脚本里有 OP_SHA256 等 hash 的操作码,所以如果能用 OP_CAT 实现对两个元素拼接,就可以在脚本中实现 merkle 树的验证功能,也就在一定程度上具备了轻客户端验证的能力。

另外的实现基础还包括对于 Schnorr 签名的增强:可以对脚本的花费签名条件设置为用户的公钥和公开 nonce 的拼接;之后如果签名者如果想要另签一个交易将这笔资金花费到其他地方,就不得不使用同样的 nonce 而导致私钥泄露。也就是通过 OP_CAT 实现了对 nonce 的承诺,进而确保已签名交易的有效性。

OP_CAT 的其他的应用场景还包括:Bistream、树形签名、抗量子的 Lamport 签名、保管库等等。

OP_CAT 本身并不是一个新的功能,它曾在比特币最早期版本中存在过,不过由于可能导致被攻击所利用而在 2010 年开始被禁用。例如,重复使用 OP_DUP 和 OP_CAT 就可以很容易的让全节点在处理此类脚本时堆栈爆炸,参考这个 demo。

但现在重新启用 OP_CAT 不会发生前面提到的堆栈爆炸问题么?因为当前的 OP_CAT 提案只涉及到在 tapscript 中启用,而 tapscript 限定了每个堆栈元素不超过 520 字节,所以不会产生以前的堆栈爆炸问题。还有一些开发者认为中本聪直接禁用 OP_CAT 可能过于严苛。但由于 OP_CAT 的灵活性,可能确实一些会导致漏洞的应用场景在当前无法穷尽。

所以综合了应用场景和潜在风险等,OP_CAT 最近受到很多关注,也有过 PR review,是当前最热门的升级提议之一。

结语

‘自律带来自由’,从上面的介绍可以看到,限制条款可以直接在比特币脚本中实现对交易进一步花费的限定,从而实现类似智能合约效果的交易规则。相比于 BitVM 等链外方式,这种编程方式可以更为原生的在比特币上验证,同时也可以改进主链上的应用(拥堵控制)、链外应用(状态通道)以及其他的新的应用方向(staking 惩罚等)。

限制条款的实现技术如果能再结合一些底层的升级,会进一步释放可编程性的潜力。例如,最近在 review 中的 64 位运算符的提案,就可以进一步与提议的 OP_TLUV 或其他的限制条款结合,可以基于交易输出的聪的数量来进行编程。

但限制条款也可能会导致一些计划外的滥用或漏洞,因此社区对此也比较谨慎。另外,限制条款的升级也需要涉及到共识规则的软分叉升级。鉴于 taproot 升级时的情形,限制条款相关的升级可能也需要假以时日来完成。

感谢阿剑、Fisher、Ben 对本文的审阅和建议!