來源:極客 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<u8>,
pub lock: Script,
pub type_: Option<Script>, }
而對於狀態爭用問題,目前 CKB 推進研究的是 Open Transaction,用戶可以提出一個部分 UTXO 指明交易目的,然後由撮合者撮合成完整的交易。
Nervos 的 cell 模型是 UTXO 的“一般化”版本,對其詳細的科普 Jan 在 Nervos 論壇上如此解釋:
Layer 1 的關注點在狀態,以 Layer 1 爲設計目標的 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 只能被花費一次。
這樣一個模型的特點是:
1. 狀態是第一性的。
2. 所有者是狀態的屬性,每一份狀態只有一個所有者。
3. 狀態不斷地被銷毀和創建。
所以說,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 概念及其相關擴展,可以更好地把握區塊鏈技術的本質,並爲未來的創新和應用打下更加堅實的基石。
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。