來源:極客web3
作為比特幣的核心設計原則之一,UTXO 模型在誕生之日起就成為了區塊鏈領域中重要的技術範式。它在保障交易安全性和可追溯性方面發揮了重要作用,同時提供了傳統帳戶餘額模型以外的另一條道路。隨著近年來區塊鏈技術不斷經歷更新迭代,UTXO 模型本身也在不斷演化與擴展(如eUTXO、cell、Strict access list 等)。
本文以學習和了解UTXO 模型為目的,以淺顯易懂的方式,簡單梳理從BTC 到Sui、Cardano 和Nervos、Fuel 各自的UTXO 模型及實作方式,使其更能理解。
什麼是UTXO?
可以透過一個例子來理解UTXO 模型:
假設有兩個人,Alice 和Bob,他們原本各有5 塊。之後,雙方發生了衝突,Alice 被Bob 搶走了2 塊錢。兩人最終持有的金錢金額如下圖所示:
不難看出,Alice 最終剩下3 塊錢,Bob 最終持有7 塊錢。這種小學加減法一樣的記帳方式經常出現在銀行系統中,被稱為「帳戶/餘額模型」。其中,帳戶的餘額作為單一的數值而存在。
如果用不同於帳戶模型的方式,例如UTXO 表示Alice 和Bob 之間發生的財富轉移,示意圖會變成不同的樣子:
此時,Alice 還是剩3 塊錢,Bob 還是剩7 塊錢,但這7 塊錢並不是用一個單一數值表示的,而是被拆成了「5 塊錢」 和「2 塊錢」。這種反常規的方法是不是讓人感到不太習慣?這就是特殊的記帳方式- UTXO 。
UTXO 英文全名為Unspent Transaction Output,指 「未花費的輸出」。在這種記帳方式下,每筆鏈上交易都會表現為UTXO 的變化與轉移。例如,在上文提到的交易事件中,Alice 最初擁有的“5 塊錢” 作為輸入參數,被標記為UXTO_0,之後會被銷毀;同時,程式會產生“2 塊錢”(UTXO_1)和“ 3 塊錢」(UTXO_2)作為輸出參數,UTXO_1 將轉給Bob,UTXO_2 將轉回給Alice,ALice 和Bob 之間的財富轉移以此完成。
實際上,在UTXO 模型中,不存在「帳戶」 和「餘額」 這兩個明確的概念,UTXO 只是幫助交易執行的資料結構,它會記錄自身代表的金額、與其相關的交易索引等資訊。每個UTXO 都代表一個可以被使用但未被使用的交易輸入,具有確定的所有者。當一筆交易發生時,可以將某些UTXO 作為輸入,銷毀後會產生新的UTXO 作為交易輸出結果。
這就是Bitcoin 的記帳方式:每次交易都會有舊的UTXO 被銷毀,新的UTXO 被產生。被銷毀的UTXO 總金額等於新造的UTXO 金額(其中某部分是給礦工的手續費)。這樣一來,沒有人可以憑空增發資金。
UTXO 模型和帳戶/餘額模型的比較
假設有一批使用者同時發起了大量交易請求,如果分別使用UTXO 模型和帳戶/餘額模型處理交易,情況會是如何?
在帳戶/餘額模型中,每個使用者都擁有一個帳戶,其中記錄著餘額資訊。當有交易發生時,相應帳戶的餘額要被更新,這涉及對其「讀取」 和「寫」 的操作。但如果某兩筆交易涉及同一個帳戶,往往會產生讀寫上的衝突,即狀態爭用,這是必須要避免的情況。
傳統的資料庫系統往往透過「鎖」 機制,解決某部分資料的讀寫爭用。在這種場景下,構成資料爭用關係的多筆交易往往要排隊,無法同時執行,這會使交易的處理效率下降。當有大量交易待處理時,上述情況可能會導致嚴重的效能瓶頸,彼此有資料爭用關係的交易可能長時間處於等待狀態,無法被快速處理。
相較於帳戶餘額模型,比特幣的UTXO 模型可以更好的解決資料爭用問題。因為在這種方式下,每筆交易的直接處理對像不再是某個“帳戶”,而是各個獨立的UTXO。由於不同的UTXO 互不干擾,比特幣網路中每筆交易都是互不干擾的。因此,比特幣網路節點在處理大量的待處理交易時,可以同時處理多筆交易,無需使用“鎖”,這樣可以大大提高系統的吞吐量和並發性能。
此外,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. 除了位址和值之外,輸出還可以攜帶(幾乎)任意數據,即可以透過腳本對狀態的意義進行程式設計。
具體而言,eUTXO 允許使用者將類似JSON格式的任意資料加入UTXO中,該資料稱為Datum。 Datum 允許開發人員為腳本提供類似狀態的功能,它與特定的UTXO 相關聯。
同時,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