來源:Starknet 中文社區
精選速覽
-
深入探討在比特幣上建構demo 橋契約,為Starknet 的生產級橋奠定基礎
-
實作存取款聚合器、橋接器和提款擴充器四種智慧合約
-
利用遞歸契約和梅克爾樹有效地批量處理存款和提款請求,同時保持用戶帳戶的完整性和安全性
引言
本文,我們深入探討了sCrypt 如何在比特幣上建立一個demo 橋契約。此概念驗證實作旨在為Starknet 二層(L2)網路的生產級橋奠定基礎。該橋的設計允許將多個存款或提款請求交易合併為一個根交易,並將其併入主橋契約中,更新其狀態,該狀態由一組以默克爾樹組織的帳戶組成。
由於橋契約腳本非常複雜,我們在sCrypt 利用了sCrypt 專屬領域語言(DSL)來編寫其實作方式。
概覽
該橋由一個遞歸契約比特幣腳本構成。在這裡,「契約」意味著鎖定腳本能夠對支出交易施加條件,而「遞歸」則意味著上述規則足夠強大,可以在鏈上實現持久的邏輯和狀態(這是任何鏈上智能合約的基本要求)。
該腳本存在於一系列交易中,每筆交易都對後續交易結構施加約束,而後續交易解鎖當前交易的輸出。每當一筆新交易加入這條鏈時,就代表了橋狀態的更新。因此,這條鏈的末端保存著目前的橋狀態。
契約狀態— 具體來說,就是其雜湊值— 儲存在一個不可消耗的OP_RETURN 輸出中。雖然我們不會花費這個UTXO,但在執行契約腳本時可以檢查其資料。具體來說,狀態保存了包含帳戶資料的默克爾樹的根雜湊值,如下所示:
該默克爾樹保存了一組固定帳戶槽的資料。葉節點包含各自帳戶資料的雜湊值,其中包括地址和餘額。為了表示空的帳戶槽,這些槽被標記為零位元組。
每次橋的更新都會導致帳戶樹發生變化。為了方便這種更新,我們依賴默克爾證明,其驗證在比特幣腳本中非常有效率。更新主要包含兩個步驟。首先,我們驗證一個梅克爾證明,以證明證明梅克爾樹包含了特定帳戶的當前狀態。然後,在計算該帳戶的新狀態後,我們使用前述默克爾證明中的相同輔助節點來推導出新的根雜湊值。
更新可以是存款,也可以是提款。橋可在單筆交易中執行這些更新的批次操作。
存款
我們的目標是讓用戶能夠獨立提交存款或提款請求。為此,使用者分別建立交易,分別支付給存款或提款聚合契約。該契約將這些請求匯總成一棵梅克爾樹。該樹的根哈希值可以合併到主橋契約中,主橋契約隨後處理每筆存款或提款。
在存款交易中,除了對存款資料進行哈希並建立默克爾樹之外,契約還確保鎖定在契約輸出中的存款satoshis 按正確的方式累積至樹的根節點。聚合契約確保只有正確的鏈上智能合約才能使用這些資金。 (當然,在生產環境中,我們也會允許用戶取消其存款交易)。
這種樹狀結構的設計源自於契約腳本建構的限制,即不允許包含過多輸入和輸出的交易。樹形結構使我們能夠擴展到潛在的任意吞吐量。
提款請求
提款請求的聚合與存款類似,但有幾處不同。首先,我們需要一種認證方法,以便用戶可以從自己的帳戶提款。這與存款不同,存款是任何人可以向任何帳戶存款,這與比特幣地址的使用方式類似。認證在聚合樹的葉節點層完成。提款請求聚合契約會檢查提款位址是否與葉交易中第一個輸入的P2WPKH 位址相符。
這確保了地址的所有者批准提款,因為他們已經簽署了請求提款的交易。與存款聚合相比,另一個細微的不同之處在於,我們也會將中間的累積金額哈希,向上傳遞到樹結構中。這是因為在擴充提款時,我們需要這些數據,稍後會詳細說明。
敏銳的讀者可能會注意到這種提款請求認證模型的潛在問題。假如操作員決定作弊,創建一個聚合樹的根交易,而聚合樹的資料是透過未經認證的虛假取款請求在本地偽造的,那該怎麼辦?我們需要一種有效的方法來驗證根交易是否來自有效的葉交易。
為了解決這個問題,我們執行了所謂的「創世檢查(genesis check)」。本質上,我們讓聚合契約檢查其前一筆交易以及前兩筆交易,即其「祖先交易」。契約驗證這些交易是否包含相同的契約腳本,並執行相同的檢查。透過這種方式,我們實現了一個歸納式的交易歷史檢查。由於前兩筆交易與目前契約一樣,執行了相同的檢查,我們可以確認這些交易的「祖先」也執行了相同的檢查,一直追溯到葉節點(即創世交易)。
當然,我們對樹的兩個分支都執行了驗證。因此,每個聚合節點交易總共檢查最多六筆交易。
提款擴展
現在讓我們進入解決方案的最後部分:提款擴充。在處理一批提款請求後,主橋契約會強制執行一個輸出,將總提款金額支付給擴充契約。我們可以將這個契約視為執行提款請求聚合契約所做操作的逆向過程。其從取款樹的根節點開始,將其擴展為兩個分支,每個分支包含應支付到該分支的相應取款金額。這個過程一直延續到提款樹的葉節點。葉交易強制執行一個簡單的支付輸出,向帳戶所有者的地址支付他們要求提取的金額。
實現方式
為了實現我們的橋契約,我們開發了四個sCrypt 智能合約,分別處理系統的不同面向。本節,我們將簡要概述每個合約的功能。
存款聚合器合約
存款聚合器(DepositAggregator)合約將單一存款聚合成一棵默克爾樹,然後將其合併到主橋契約中。這種聚合可實現批量存款處理,減少需要由橋樑單獨處理的交易數量。此外,它還允許用戶獨立提交存款,稍後由操作員進行處理。
合約建構函數有兩個參數:
-
operator:橋操作員的公鑰,該操作員有權聚合存款。
-
bridgeSPK:主橋契約的腳本公鑰(SPK),確保聚合存款正確合併。
存款聚合器的核心功能封裝在「聚合(aggregate)」方法中。此方法執行以下步驟:
驗證Sighash 原像和操作員簽名:確保交易經過橋樑操作員授權,並且sighash 原像格式正確且屬於正在執行的交易。透過這篇文章了解更多關於sighash 原像驗證的資訊。
建立和驗證前置交易ID:檢查已聚合的前置交易是否有效並正確引用。
梅克爾樹聚合:驗證作為見證雜湊值傳遞的存款資料是否與前置交易中儲存的狀態相符。
金額驗證:確認前置輸出中的金額與指定的存款金額匹配,確保資金在聚合中正確計算。
狀態更新:透過連接前交易的雜湊值計算新的雜湊值,並更新OP_RETURN 輸出中的狀態。
重入攻擊防範:強制執行嚴格的輸出腳本和金額,以防止未經授權的修改或雙花。
一旦存款被聚合,它們必須合併到主橋契約中。這一過程由「最終確認(finalize)」方法處理,其步驟包括:
驗證前置交易:與「聚合(aggregate)」方法類似,驗證前置交易,以確保合併資料的完整性。
與橋契約的整合:透過引用橋的交易ID 和腳本公鑰,檢查聚合後的存款是否正確地合併至主橋契約。
存款聚合合約的完整原始碼可查看GitHub。
取款聚合器合約
提款聚合器(WithdrawalAggregator)合約旨在將單一提款請求聚合成一棵默克爾樹,與存款聚合器處理存款的方式類似。不過,提款操作需要額外的認證,以確保只有合法的帳戶所有者才能從其帳戶中提取資金。
提款聚合器的核心功能封裝在「聚合(aggregate)」方法中,該方法執行下列步驟:
建立和驗證前置交易ID:該過程驗證已聚合的前置交易是否有效並正確引用。
所有權證明驗證:驗證所有權證明交易確保只有合法的所有者才能從帳戶中提取資金。
-
所有權證明交易:一種證明控制提款地址的交易。合約檢查提款請求中的地址是否與所有權證明交易中的地址相符。
透過「祖先交易」進行創世檢查:與存款聚合器類似,合約透過驗證祖先交易執行歸納檢查。這確保了交易歷史的完整性,並防止操作員插入未經授權的提款請求。
金額驗證和總金額計算:此方法透過將提款請求或先前的聚合進行金額相加,計算出要提取的總金額。
狀態更新:計算一個新的雜湊值,其中包含前置交易的雜湊值和提款金額的總和。這個哈希值儲存在OP_RETURN 輸出中,以更新狀態。
重入攻擊防範和輸出強制:確保嚴格定義輸出,以防止未經授權的修改或重入攻擊。
提款聚合合約的完整原始碼可查看GitHub。
橋合約
橋(Bridge)合約是我們系統的核心組件,是維護橋狀態的主要契約,包括以默克爾樹組織的帳戶及其餘額。其透過與我們之前討論的聚合器合約集成,處理存款和提款操作。
合約建構函數有兩個參數:
-
operator:橋操作員的公鑰,該操作員有權更新橋狀態。
-
expanderSPK:提款擴充器(WithdrawalExpander)合約的腳本公鑰(SPK),在提款過程中使用。
存款方法負責處理聚合的存款交易,並相應更新帳戶餘額。
存款方法執行的步驟包括:
處理存款並更新帳戶:
-
遍歷存款,並使用「應用存款(applyDeposit)」方法將每筆存款應用到相應的帳戶。
更新橋狀態和輸出:
-
處理存款後,計算新的帳戶默克爾根。
-
建立新的狀態雜湊值,表示更新後的橋狀態。
-
建構合約輸出,將總存款金額加至橋餘額。
-
保證輸出符合預期格式,以維護資料完整性。
提款方法處理聚合的提款交易,更新帳戶餘額,並透過提款擴充器準備分配的資金。
提款方法執行的步驟包括:
處理提款請求並更新帳戶:
-
遍歷提款請求,並使用「套用存款(applyDeposit)」方法將每筆提款套用到對應的帳戶。
更新橋狀態和輸出:
-
處理提款後,計算新的帳戶梅克爾根。
-
建立新的狀態雜湊值,表示更新後的橋狀態。
-
建造合約輸出,將總取款金額從橋餘額中扣除。
-
為取款擴展器合約建立一個擴充輸出,其中包含總取款金額。
-
保證輸出符合預期格式,以維護資料完整性。
完整原始碼可查看GitHub。
取款擴充器合約
取款擴展器(WithdrawalExpander)是我們橋系統的最終組件,負責根據用戶的取款請求將聚合的取款金額分發回各個用戶。它逆轉了取款聚合器執行的聚合過程,將聚合的取款資料擴展回單一用戶的支付。
提款擴展器的核心功能封裝在「擴充(expand)」方法中。此方法接受聚合的提款數據,並透過遞歸的方式將其擴展為單獨的提款交易,向使用者支付相應的金額。
擴展到葉節點:如果方法擴展到葉節點(單一提款),它會驗證提款數據,並建立直接支付到使用者地址的輸出。
進一步擴展: 如果該方法尚未達到葉節點層,則會繼續擴展,將聚合資料分成兩個分支,並建立輸出,以供進一步擴展的交易消費。
結語
在這個概念驗證實作中,我們使用sCrypt 嵌入式領域專屬語言(DSL)開發了一個基於OP_CAT 支援的比特幣的橋契約。該橋利用遞歸契約和梅克爾樹有效地批量處理存款和提款請求,同時保持用戶帳戶的完整性和安全性。透過設計和實作存款聚合器(DepositAggregator)、提款聚合器(WithdrawalAggregator)、橋接器(Bridge)和提款擴充器(WithdrawalExpander)這四種智慧合約,我們提供了一種在比特幣上管理有狀態互動的方法,促進了與像Starknet 這樣的二層網路的互通性。這項工作為建造生產級橋提供了技術基礎,可能增強比特幣生態系統中的可擴展性和功能性。
所有程式碼實作以及端對端測試均可在GitHub 上取得。
[全文完]
原文連結:https://starkware.co/blog/implementing-a-bridge-covenant-on-op-cat-bitcoin/
Mirror: https://mirror.xyz/starknet-zh.eth/zFbhQB7gfmSTV4CcTv5MRqJBUnKuwMLTNOgZ6jUgDK8