# 从BTC到Sui、ADA与Nervos：UTXO模型及其相关扩展

By [极客 Web3](https://paragraph.com/@web3-12) · 2023-07-13

---

**作者：0xAyA**

作为比特币的核心设计原则之一，UTXO模型在诞生之日起就成为了区块链领域中一种重要的技术范式。它在保障交易安全性和可追溯性方面发挥了重要作用，同时提供了传统账户余额模型以外的另一条道路。随着近些年区块链技术不断经历更新迭代，UTXO模型本身也在不断地演化与扩展（如eUTXO、cell、Strict access list等）。

本文以学习和了解UTXO模型为目的，用浅显易懂的方式，**_简单梳理从BTC到Sui、Cardano和Nervos、Fuel各自的UTXO模型及实现方式，使其更好理解。_**

**首先，什么是UTXO？**

可以通过一个例子理解UTXO模型：

假设有两个人，Alice和Bob，他们原本各有5块钱。之后，双方发生了冲突，Alice被Bob抢走了2块钱。二人最终持有的金钱数额如下图所示：

![](https://storage.googleapis.com/papyrus_images/bb2f315f2eb0e73de76517d45f4c6aef621af2845fb16337e3b350a2f840ca84.png)

不难看出，Alice最终剩下3块钱，Bob最终持有7块钱。这种小学加减法一样的记账方式频繁出现在银行系统中，_被称为_**“账户/余额模型”**。其中，账户的余额作为单一的数值而存在。

如果用不同于账户模型的方式，比如UTXO表示Alice和Bob之间发生的财富转移，示意图则会变成不同的样子：

![](https://storage.googleapis.com/papyrus_images/ea12a7aa386805def7f5ce0e5432058a5489060055754e09fbebde20fef3705e.png)

此时，Alice还是剩3块钱，Bob还是剩7块钱，但这7块钱并不是用一个单一数值表示的，而是被拆成了“5块钱”和“2块钱”。这种反常规的方法是不是让人感到不太习惯？这就是特殊的记账方式——UTXO 。

在这种记账方式下，每笔链上交易会表现为UTXO的变化与转移。比如，在上文提到的交易事件中，**_Alice最初拥有的“5块钱”作为输入参数，被标记为UXTO\_0，之后会被销毁；同时，程序会生成“2块钱”（UTXO\_1）和“3块钱”（UTXO\_2）作为输出参数，UTXO\_1将被转给Bob，UTXO\_2将转回给Alice，ALice和Bob之间的财富转移以此完成。_**

![](https://storage.googleapis.com/papyrus_images/9ce7e5548c1a755b43544769c816f8c99bc5de567ca5d01ea4bbab1891547746.png)

实际上，在UTXO模型中，不存在“账户”和“余额”这两个明确的概念，\*\*\*UTXO只是帮助交易执行的数据结构，它会记录自身代表的金额、与其相关的交易索引等信息。\*\*\*每个UTXO都代表一个可以被使用但未被使用的交易输入，具有确定的所有者。当一笔交易发生时，可以将某些UTXO作为输入，将其销毁后会产生新的UTXO作为交易输出结果。

![](https://storage.googleapis.com/papyrus_images/5acd16d28b08f8a9188d0c1a4f74d7662f76da9f4674e591d31084270073b285.png)

这就是Bitcoin的记账方式：每次交易都会有旧的UTXO被销毁，新的UTXO被产生。被销毁的UTXO总金额等于新造的UTXO金额（其中某部分是给矿工的手续费）。这样一来，没有人可以凭空增发资金。

**UTXO模型和账户/余额模型的比较**

假设有一批用户同时发起了大量交易请求，如果分别使用UTXO模型和账户/余额模型处理交易，情况会是怎样？

在账户/余额模型中，每个用户都拥有一个账户，其中记录着余额信息。有交易发生时，相应账户的余额要被更新，这涉及对其“读”和“写”的操作。可如果某两笔交易涉及同一个账户，往往会产生读写上的冲突，即状态争用，这是必须要避免的情况。

![](https://storage.googleapis.com/papyrus_images/5223fbec832ab3048f94abbab842dc879636eca81bbdae3361c3ef57dbafb572.png)

传统的数据库系统往往通过“锁”机制，解决对某部分数据的读写争用。在这种场景下，构成数据争用关系的多笔交易往往要排队，无法同时执行，这会使交易的处理效率下降。当有大量交易待处理时，上述情况可能会导致严重的性能瓶颈，彼此有数据争用关系的交易可能长时间处于等待状态，无法被快速处理。

**_相比于账户余额模型，比特币的UTXO模型可以更好的解决数据争用问题。因为在这种方式下，每笔交易的直接处理对象不再是某个“账户”，而是各个独立的UTXO。由于不同的UTXO互不干扰，比特币网络中每笔交易都是互不干扰的。因此，比特币网络节点在处理大量的待处理交易时，可以同时处理多笔交易，无需使用“锁”，这样可以大大提高系统的_**吞吐量和**_并发性能_。**

![](https://storage.googleapis.com/papyrus_images/7722ff1a028a9e1f34f05929106273979fd2eb58be6193fedcceff2de5ec528f.png)

此外，UTXO模型的加密钱包通常会在用户发起一笔交易后，生成一个新地址，这样可以实现隐私保护——要将交易和某个具体的人关联起来变得更为困难——相比之下，账户/余额模型由于使用固定的地址，更容易被关联性分析。

但UTXO也存在局限性，其设计初衷是实现简单的货币转移，不是处理复杂的业务逻辑，尽管可以用脚本语言进行一些简单的功能实现，如多签、时间锁等，但由于比特币的UTXO能记录的状态信息太简陋，使其在进行一些复杂操作时有心无力。

比特币UTXO的局限性间接推动了“以太坊”的诞生——Vitalik作为Bitcoin Magazine最早的撰稿人之一，对比特币的缺点十分了解。而账户/余额模型不仅更容易为大多数人所理解，还可以解决UXTO难以处理富状态应用的困境，正如他在“以太坊白皮书”中所说的：

**_UTXO 可以是已使用或未使用；用于保存任何其他内部状态的多阶段合约或脚本是没有机会出现的。这使得多阶段期权合约、去中心化交易报价或两阶段加密承诺协议（这是安全计算赏金所必需的）难以创建。这也意味着 UTXO 只能用于构建简单的一次性合约，而不是去中心化组织等更复杂的“有状态”合约，使得元协议难以实现。二进制状态加之价值盲点也意味着另一个重要应用 — 提款限制 — 是不可能实现的。_**

**UXTO模型的应用、优化和扩展**

在介绍各种对UXTO的应用和优化之前，首先要分析UTXO在保持其优势的同时有哪些提升点，简单总结为如下几点：

1.  **_对UTXO所存储状态的意义进行抽象；_**
    
2.  **_对状态的所有权进行抽象。_**
    
3.  **_解决共享UTXO的状态争用问题。_**
    

在BTC中，状态唯一的意义就是代币数量，而所有权通常用公钥来定义，至于状态争用，BTC并不是为dapp而设计，所以也没有过多涉及。

**Sui**

**_Sui为开发人员提供了两种对象类型：OwnedObject和SharedObject，前者相当于UTXO（更具体来说是UTXO的增强版）_**，后者相当于账户/余额模型，两者可以同时使用，此处引用Sui技术文档的解释：

**_一个Object可以被共享，这意味着任何人都可以读取或写入该Object。与可变的OwnedObject（只能有一个写入者）相比，SharedObject需要共识来对读取和写入进行排序。_**

**_在其他区块链中，每个Object都是共享的。然而，Sui编程人员通常可以选择使用OwnedObject、SharedObject或两者的组合来实现特定的用例。这个选择可能对性能、安全性和实现复杂性产生影响。_**

在Sui中，Owned Objects就类似于UTXO，只有它的所有者Owner能对其进行操作，且Object都有版本号，“一个object的某个版本只能被它的 owner 花销一次”，所以，**_“一个object的某个版本” 实质就相当于 UTXO。_**

至于状态争用的问题，则可以通过特殊处理（局部排序，和Fuel类似）SharedObject来实现。

**Cardano**

Cardano使用extended UTXO模型，缩写为eUTXO。eUTXO支持更高的可编程性，同时兼有比特币UTXO模型的优点。

在Cardano中，状态的意义通过脚本进一步得到扩展，而其状态的所有权则通过更一般化的方式进行定义，同时使用UTXO集来尽量避免出现状态争用问题。具体概括，eUTXO在两个方面有所加强：

1.  **_eUTXO模型中存在更一般化的地址，这些地址不仅仅可以基于公钥的哈希，还能基于任意逻辑定义在何种条件下可以花费eUTXO，即可以对状态的所属权进行编程。_**
    
2.  **_除了地址和值之外，输出还可以携带（几乎）任意数据，即可以通过脚本对状态的意义进行编程。_**
    

![](https://storage.googleapis.com/papyrus_images/2795d3c319d7e0695a6486b6f5c469ccc612d4dcdb6aaa79f1c1ce4bb828c9a2.png)

具体而言，eUTXO允许用户将类似JSON格式的任意数据添加到UTXO中，该数据称为Datum。Datum 允许开发人员为脚本提供类似状态的功能，它与特定的 UTXO 相关联。

![](https://storage.googleapis.com/papyrus_images/00f2ac90e9a93758deab2389b9b6444d611a90e3c5865a08c758dc6682d8ee0e.png)

同时，Cardano上的交易可以携带与特定用户相关的参数，称为Redeemer。Redeemer允许交易发起者定义UTXO的使用方式，可以被dapp开发人员用于各种目的。

当一笔交易被验证时，验证脚本会使用Datum、Redeemer和包含交易数据的上下文进行操作，该脚本中会包含在满足条件时使用UTXO的逻辑。

需要注意的是，eUTXO仍然是通过脚本来完成拓展任务的，和传统意义上的“智能合约”有着很大的差别（创始人Charles Hoskinson认为实际的名字应该叫“可编程验证器”，但“智能合约”这个说法更容易被市场所接受）。

**Nervos**

在Nervos（即CKB）中，状态的意义由typescript抽象，而其状态的所有权由lockscript抽象，一个简单的UTXO优化模型——cell代码如下：

**_pub struct CellOutput {_**

**_pub capacity: Capacity,_**

**_pub data: Vec,_** **_pub lock: Script,_** **_pub type\_: Option_** **_}_** 而对于状态争用问题，目前CKB推进研究的是Open Transaction，用户可以提出一个部分UTXO指明交易目的，然后由撮合者撮合成完整的交易。 Nervos的cell模型是UTXO的“一般化”版本，对其详细的科普Jan在Nervos论坛上如此解释： Layer1的关注点在状态，以Layer1为设计目标的CKB设计的关注点很自然就是状态。Ethereum将交易历史和状态历史分为两个维度，区块和交易表达的是触发状态迁移的事件而不是状态本身，而Bitcoin协议中的交易和状态融合成了一个维度，交易即状态，状态即交易，正是一个以状态为核心的架构。 同时，CKB想要验证和长久保存的状态，不仅仅是简单的数字（nValue)，而是任何人们认为有价值的、经过共识的数据。显然Bitcoin的交易输出结构满足不了这个需求，但是它已经给了我们足够的启发：只需要将nValue一般化，把它从一个存放整数的空间变成一个可以存放任意数据的空间，我们就得到了一个更加一般化的”CTxOut"，或者叫Cell。 在Cell里面，nValue变成了capacity和data两个字段，这两个字段共同表示一块存储空间，capacity是一个整数，表示这块空间有多大（以字节数为单位），data则是保存状态的地方，可以写入任意的一段字节；scriptPubKey变成了lock，只是换了一个名字而已，表达的是这块共识空间的所有者是谁 - 只有能提供参数（例如签名）使得lock脚本成功执行的人，才能“更新”这个Cell中的状态。整个CellOutput占用的字节数必须小于等于capacity。CKB中存在着许许多多的Cells，所有这些Cell的集合形成了CKB完整的当前状态，在CKB的当前状态中存储的是任意的共同知识，不再仅仅是某一种数字货币。 交易依然表示状态的变化/迁移。状态的变化，或者说Cell内容的“更新”实际上也是通过销毁和创建来完成的（并不是真的去修改原有Cell中的内容）。每一笔交易实际上都会销毁一批Cells，同时创建一批新的Cells；新创造的Cells会有新的所有者，也会存放新的数据，但是被销毁的capacity总和，总是大于等于新创建的capacity总和，由此保证没有人可以随便增发capacity。因为capacity可以转让，无法增发，拥有capacity等于拥有相应数量的共识状态空间，capacity是CKB网络中的原生资产。Cell的销毁只是把它标记为“已销毁”，类似Bitcoin的UTXO从未花费变为已花费，并不是从区块链上删掉。每一个Cell只能被销毁一次，就像每一个UTXO只能被花费一次。 这样一个模型的特点是： **_状态是第一性的；_** **_所有者是状态的属性，每一份状态只有一个所有者；_** **_状态不断的被销毁和创建；_** 所以说，Cell是UTXO的一般化(generalized)版本。 **Fuel** Fuel采用了基于UTXO优化的Strict access list模型，这种模型定义了一种新的UTXO——合约UTXO。 正如上文所介绍过的，BTC中的UTXO只有两个属性：币的数量和所有者，而合约UTXO则提供了更多的基础属性，包括：币的数量、合约ID、合约代码哈希和存储根。 如果使用无状态执行模型，只有在合约UTXO中才需要合约代码哈希和存储根。在有状态执行模型中，合约UTXO可以省略这些字段，但需要单独的存储元素UTXO类型。UTXO ID（每个UTXO的唯一标识符，可以用作键值存储数据库中的键）是产生UTXO的输出点，或者其变体（例如，输出点及其字段的哈希）。 在这种模型中，合约UTXO和智能合约一样是任何人都可以调用的。 需要注意的是Fuel提供的是更为贴近智能合约的功能，而非脚本，而UTXO本身模型的限制使得基于VM去做应用时会有数不清的麻烦，最典型的就是UTXO的争用问题，一般来说有三种解决办法：一是在链下处理如Rollup；二是先提前做好额外的排序工作，Fuel采用的就是后者；三是刚刚在CKB部分提到的Open Transaction，即每个用户可以提部分交易，然后由撮合者（类似定序器），撮合成完整的交易，BTC与之相对应的解决方案为PBST。 **结尾** 通过梳理，了解了UTXO的基本原理，知道了其模型与ETH的账户/余额模型的优劣之处，并对UTXO概念及其相关扩展有了更加清晰的了解。 作为比特币的核心设计原则之一，UTXO模型在保障交易的安全性和可追溯性方面发挥了重要作用，随着区块链技术的不断发展，UTXO模型也在不断演化和扩展（如EUTXO、cell、Strict access list等），为数字资产的交易和管理提供了更多可能性，通过深入研究和理解UTXO概念及其相关扩展，可以更好地把握区块链技术的本质，并为未来的创新和应用打下更加坚实的基石。

---

*Originally published on [极客 Web3](https://paragraph.com/@web3-12/btc-sui-ada-nervos-utxo)*
