之前,我们介绍了一种通用技术来维护比特币智能合约中的状态。它直接将状态存储在单个 UTXO 中。例如,我们将该技术用于1层 Token 解决方案,其中状态是全局 Token 余额表。当用户数量增加时,它很快变得非常昂贵,因为每个 UTXO 也即每个交易都携带整个状态。
现在有一个更具突破性的想法,可以在有效地保持状态的同时避免交易体积快速膨胀。具体来说,是将状态的 Merkle 根而不是其本身存储在 UTXO 中,同时仍然在1层强制执行所有状态转换规则。它将 UTXO 大小从 O(n)减小为 O(log n),其中 n 是状态大小,使得存储大型状态在经济上可行。
分片和默克尔树
状态被分割为多个块,这些块被组织成一个 Merkle 树。比特币中使用了相同的技术将交易提交到块头中的根哈希。
上图为 Token 表作为 Merkle 树1
合约的 UTXO 中仅存储 Merkle 树的根哈希。验证状态转换时,仅需要涉及的块及其 Merkle 路径,而无需整个状态。这将合约的空间复杂性大大降低到 Merkle 树的深度,即O(log n)。
实现
Token 的参考实现在这里。可以看出合约中仅存储状态的 Merkle 根(32字节),而不是原始 Token 合约中的状态本身。传输时,仅需要发送者和接收者的节点及其 Merkle 路径。即使整个状态在任何给定的转移中都不为合约所知,合约中仍然可以强制执行所有转移规则。
状态变换
在旧模型中,状态本身存储在链上,并且可以通过追踪状态链上最近的交易来获取最新状态。在新模型中,只有状态的 Merkle 根存储在链上。状态本身是链下存储的。通过遵循状态链并依次执行每个交易直到叶节点,可以重建最新状态。这可以由用户自己完成,也可以外包给第三方。在后一种情况下,用户仍然可以使用 Merkle 证明独立进行验证,只要他可以检索最新的 Merkle 根即可。这与比特币中的简化付款验证(SPV)非常相似。
时间可扩展性
该提案解决了有状态合约的空间可扩展性。乍看起来,此类有状态合同的所有交易似乎都需要顺序处理,因为在任何给定时间只有一个全局链端点。但是,在链下拼接在一起后,它们从矿工的角度来看是独立的。因此,可以像其他任何链式交易一样在1层并行处理它们2。链下部分主要是用于计算 txid 的 sha256 哈希值,这在商用硬件上可以非常快地完成。
总结
我们发现了一种在比特币合约中存储状态的极为有效的方法,从而使存储大型状态成为现实,并通过实现高效的1层 Token 来证明其能力。
致谢
有关该想法的提出和代码实现均来自于 @zhangweis ,再次感谢分享。
[1] 感谢 lilong 提供的图示说明。
[2] 目前受到未确认链式交易限额的约束,该限额后续将提高并最终被取消。