
結果預確認:無需完整區塊即可驗證區塊承諾
本文提議利用 EIP-7928 的區塊存取清單(BAL)讓提議者在不洩露區塊內容的情況下驗證預確認約束,解決了默克爾證明在延遲與表達力上的限制。
內容摘要(tl;dr)
可信的預確認(preconf)協議要求提議者(proposer)在簽署區塊之前,必須驗證其承諾是否得到履行。一種天真的做法是檢查完整的區塊體,但這會洩露建構者(builder)的區塊內容,因此是行不通的。中繼器(Relays)可以填補這一空白,但在 ePBS 之後則不再是必需的。去信任化的解決方案是讓建構者在投標時提交約束滿足證明(proofs of constraint satisfaction)。缺點是證明生成會增加關鍵路徑的延遲,特別是當約束條件演變到超越簡單的交易包含(transaction inclusions)時。
EIP-7928 的區塊訪問列表(BALs)提供了一種結構化的替代方案。BAL 是區塊中每一次狀態寫入的完整記錄,作為執行的副產品產生,並承諾在區塊標頭中。由於每個 BAL 條目都具有相同的結構,任何預確認類型都可以簡化為對同一個對象的「真/假」查詢。單一的驗證語言可以涵蓋任何預確認類型(包含、執行、排序、排除等),且單一的驗證器函數無需重新部署即可處理所有類型。新的預確認類型將變成新的公式,並可透過相同的基礎設施進行驗證。這在減少延遲和複雜性的同時,嚴格改進了透過 Merkle 證明所能提供的保證。
背景
預確認允許提議者在區塊建構之前承諾其下一個區塊將具備某些屬性。用戶可能會收到預確認,保證其交易將被包含、某個值被寫入特定的存儲插槽,或者超過特定閾值的支付會進入該區塊。
提議者所做的承諾限制了區塊必須如何建構。在今天沒有約束的情況下,建構者可以自由地向提議者展示任何區塊。例如,有了包含預確認,建構者就受到約束,必須展示包含指定交易的區塊。
在承諾一個區塊之前,提議者需要一種手段來驗證該區塊是否滿足了所有約束,以確保他們的承諾將得到履行。請注意,這裡的區別在於:承諾(commitment)是面向用戶的,而約束(constraint)是面向建構者的。
驗證問題
顯而易見的方法是讓提議者直接檢查完整的區塊體。如果區塊滿足約束,提議者就簽名。但這是行不通的,因為這會允許提議者在不支付建構者費用的情況下竊取區塊。
中繼器今天已經解決了這個公平交換問題。在悲觀中繼(pessimistic relaying)模式下,中繼器在分享標頭給提議者簽名前會完整執行區塊,並可以將其擴展為驗證預確認約束的受信服務。另一種是樂觀中繼(optimistic relaying),中繼器在不完整執行區塊的情況下轉發標頭,而是依賴追溯性的錯誤歸因:如果建構者的區塊後來被發現無效或違反約束,他們將受到處罰。這兩種模式目前都在生產環境中存在。但在 ePBS 中,兩者都無法存續,因為 ePBS 將中繼器完全從關鍵路徑中移除。
去信任化的替代方案是讓建構者在投標的同時生成約束滿足證明。最簡單的形式是針對區塊標頭中承諾的 Trie 根進行 Merkle 包含證明。建構者可以證明某個特定交易已被包含,或者某個特定存儲插槽在區塊結束時為設定值,而無需洩露完整的區塊體。
一個問題是延遲。證明生成發生在區塊完全建構之後。隨著預確認約束數量的增加,證明生成變成了區塊建構與投標提交之間關鍵路徑上不可忽視的一步。每一毫秒都會消耗寶貴的建構時間,從而損害提議者的收入。
另一個問題是表達能力。Merkle 證明是區塊級別的:它們可以證明交易被包含或狀態插槽持有特定值,但它們無法證明交易級別的狀態差異(state diffs)。沒有 Merkle 證明能證明某個特定交易導致了某個特定狀態的改變。驗證具備狀態性的預確認需要完整重新執行或 ZK 證明,出於隱私或延遲原因,這些都是行不通的。
區塊訪問列表(BAL)提供了什麼
EIP-7928 將區塊級別訪問列表(BAL)定義為區塊執行期間訪問的所有帳戶和存儲位置的完整記錄。每個 BAL 透過 block_access_list_hash 與特定的投標/區塊綁定,透過重放 BAL,任何人都可以重新計算區塊的最終狀態,而無需執行實際交易。
在預確認的背景下,這主要有兩個用途:
1. BAL 是執行的直接副產品。 沒有單獨的證明生成步驟。建構者在區塊建構完成時就已經擁有它。BAL 記錄了區塊期間發生的每一次狀態寫入:存儲插槽值、餘額變更、nonce 增加和代碼更新,每個都標有捕捉全局寫入順序的 block_access_index。這足以讓提議者直接驗證關於狀態結果的任何屬性:某個插槽被寫入了什麼值、帳戶餘額是否跨越了閾值、nonce 是否增加、兩次寫入是否按特定順序發生,或者合約是否被觸及。這些檢查都不需要檢查交易。
2. BAL 可以在不洩露區塊內容的情況下進行驗證。 重構區塊需要實際的簽名交易及其輸入,而 BAL 省略了這些。僅檢查 BAL 的提議者無法學到任何能讓他們在不支付建構者的情況下重構並重新提交區塊的信息。然而,如果每筆交易都來自公共內存池(mempool),理論上一個堅定的提議者可以僅憑公共信息重構它(但在這種情況下,他們本可以自己建構相同的區塊,而根本不需要建構者的 BAL)。具有私有訂單流(private order flow)的區塊則無法被重構。
從交易承諾到結果預確認
目前的預確認方法是對特定的簽名交易做出承諾。結果預確認則從交易轉向僅關注關於狀態的承諾。
在今天的意圖(intents)模型中,你規定一個特定的結果,例如「將 X 兌換為至少 Y」,求解器(solvers)競爭尋找自定義解決方案,最後由智能合約驗證意圖是否得到滿足。結果預確認在提議者層應用了相同的模型。當提議者承諾「對插槽 S 的第一次寫入將是值 V」時,他們承諾的是狀態結果,而不是執行路徑。建構者可以透過任何有效的交易序列來滿足此約束,因為約束並未說明是哪筆交易產生了寫入、誰發送了它、消耗了多少 gas 等。
簡單來說,提議者表達其區塊期望的結果,建構者競爭尋找任何能實現這些結果的有效執行路徑,而提議者在承諾區塊之前(且不洩露區塊內容的情況下)驗證結果是否已實現(透過 BAL)。
統一的約束語言
BAL 是一個單一結構,任何結果預確認類型都可以針對它進行驗證。這與今天的預確認運作方式有顯著不同,目前每種類型都是其自身的設計問題:包含預確認需要一種證明格式,排序約束需要另一種,執行預確認則需要再一種。每一種新類型都需要提議者新的驗證邏輯和新的鏈上罰沒(slashing)基礎設施。增加一種新的預確認類型意味著整個堆棧每一層的協調升級。
因為每個 BAL 條目都共享相同的四個欄位(地址、欄位類型、寫入值和排序索引),驗證任何結果預確認都可以簡化為同樣的「真/假」問題:是否存在具有這些屬性的寫入?這個地址是否不存在?寫入 A 是否發生在寫入 B 之前?
一階邏輯(First-order logic, FOL)是一種正式語言,專門用於對一組固定對象做出這類「真/假」陳述。它已被充分理解,並已知在有限結構上是完備的:任何你可以用平實英語表達的關於固定模式 BAL 的布林屬性,都可以用 FOL 公式表達。
實際的結果是,永遠只需要一個驗證器。它將 FOL 公式和 BAL 作為輸入,並返回真或假。驗證器函數只需構建一次(在提議者的 sidecar 中用於正常投標流程,在罰沒合約中用於爭議),且永遠不需要更改。新的預確認類型意味著編寫新的 FOL 公式,而不是部署新的基礎設施。
該語言有兩類原語。比較(Comparisons)是葉子節點:應用於匹配條目中值的欄位相等、不等和排序檢查(==, >=, < 等)。邏輯連接詞(Logical connectives)是結構:「存在一個滿足...的條目」、「兩個條件都成立」以及「此條件不成立」。這與從單一門類型構建任何邏輯電路的原理相同,只需極少的原語即可獲得無限的表達能力。
Dapps 預計將代表其用戶計算公式。這涉及確定哪些存儲位置受用戶交易影響且與 BAL 檢查相關。對於算術約束(「餘額增加 Y」、「價格在 5% 以內」、「nonce 增加」),Dapp 直接將這些提示提供給公式,這意味著語言本身不需要支持算術。具體來說,如果 Alice 的 nonce 是 5,她的 USDC 餘額是 500,且她希望收到至少 2000 USDC,Dapp 會讀取前置狀態,計算出 6 和 2500,並構建一個僅檢查 nonce == 6 且 balance >= 2500 的公式。
結果預確認模式與 L1 用戶體驗
以下每個模式都是 BAL 上的公式。同一個驗證器可以處理所有模式。請注意,這些僅具演示性質,可能並不完整。在下面的公式中,(A, Nonce) 和 (A, Balance) 指的是帳戶 A 的 nonce 和 ETH 餘額欄位;(C, S) 指的是合約 C 中的存儲插槽 S;V 是預期存在的值。這些直接對應於 BAL 條目中的欄位類型。
保證包含(Guaranteed inclusion)。 Alice 希望她給 Bob 的 ETH 轉帳被包含在下一個區塊中。Alice 的 nonce 增加確認了她的交易已運行,Bob 的餘額增加確認了支付已到賬。這兩次寫入必須共享相同的 block_access_index,以確認它們來自同一筆交易。Dapp 在構建公式之前從父區塊狀態根計算絕對的後置狀態值。
存在一個對 (Alice, Nonce) 的寫入,其值 == n+1 [稱此為 e1]
且 存在一個對 (Bob, Balance) 的寫入,其值 >= bob_pre_balance + amount 且 index == e1.index
區塊頂端(Top-of-block)。 用戶的交易應該是區塊中的第一筆用戶交易。block_access_index 是按交易分配的,其中索引 0 保留給預執行系統合約寫入(例如 EIP-4788 信標根更新),用戶交易從索引 1 開始分配。這是目前最強的排序保證,應相應定價。
存在一個對 (Alice, Nonce) 的寫入,其值 == n+1 且 index == 1
且 存在一個對 (C, S) 的寫入,其值 == V 且 index == 1
首次合約訪問(First contract access)。 用戶希望成為第一個與特定合約交互的人,但不願支付區塊頂端的費用。經典例子是鑄造 NFT:第一個調用鑄造函數的人,對其他一切無所謂。檢查範圍完全限定在合約 C 的條目內,讓建構者有充分自由來排序其他所有內容。
存在一個對 (C, S) 的寫入,其值 == V
且 其 index 小於或等於對 C 的所有其他寫入
同插槽意圖結算(Same-slot intent settlement)。 用戶簽署一個意圖,「將我的 X ETH 兌換為至少 Y USDC」,而不指定如何完成。建構者同時包含用戶的意圖交易和求解器的履行交易。公式中的排序約束確保意圖在求解器支付之前運行。至關重要的是,健康的建構者競爭對於改善用戶的結果非常重要。
存在一個對 (A, Nonce) 的寫入,其值 == n+1 [稱此為 e1]
且 存在一個對 (A, ETH_Balance) 的寫入,其值 <= eth_pre_balance - X 且 index == e1.index
且 存在一個對 (A, USDC_Balance) 的寫入,其值 >= Y [稱此為 e2]
且 e1.index < e2.index
執行結果預確認(Execution outcome preconf)。 歷史上,保證特定的後置狀態需要對 EVM 執行進行 ZK 證明。有了 BAL,nonce 增加確認了用戶交易已運行;存儲插槽檢查確認了預期的狀態變更。兩次寫入必須共享相同的索引以確認它們來自同一筆交易。不需要重新執行。
存在一個對 (A, Nonce) 的寫入,其值 == n+1 [稱此為 e1]
且 存在一個對 (C, S) 的寫入,其值 == V 且 index == e1.index
上述模式可以自由組合。透過在 nonce 檢查中加入 index == 1,可以將區塊頂端保證疊加到同插槽意圖結算上。執行結果可以與排序約束結合。上述任何合取(conjunction)都是有效公式,並使用相同的驗證器函數進行驗證。
ePBS 下的結果預確認
由於結果預確認的範圍限定在結果而非特定交易,滿足它們就變成了一個市場。多個搜索者(searchers)可以獨立競爭完成任何給定的預確認。建構者選擇最佳組合。任何一方都無需看到另一方的執行策略。下面的序列展示了這如何融入 ePBS 後的投標流程。
請注意,建構者簽署的約束承諾在鏈上流程中不發揮作用。其目的是協議外的:簽署了約束但隨後提交違反約束的 BAL 的建構者,等於產生了其自身過錯的加密證明,外部罰沒或聲譽系統可以據此採取行動。
約束驗證步驟在提議者的 sidecar 中運行,這是部署在罰沒合約中相同驗證器邏輯的離線實現。兩者在構造上是等價的,因此提議者確認的是罰沒合約稍後在爭議中會運行的相同檢查。
另外請注意,在 ePBS 規範中,建構者的投標包含的是 block_hash 承諾,而不是標頭本身。因此,提議者需要建立從 BAL → block_access_list_hash → header → block_hash → bid 的信任鏈。
局限性
BAL 並不證明底層交易具有有效的簽名。建構者可以構建一個滿足所有結果預確認檢查但對應於無效或虛假交易的 BAL。當有效載荷(payload)被揭示時,它將無法通過驗證,提議者會錯過他們的插槽。幸運的是,在 ePBS 後,提議者仍會無條件獲得投標金額。
如果沒有協議外的罰沒機制來抑制這種建構者行為,如果打破預確認承諾是可以獲利的,結果預確認可能會進一步激勵建構者行使其免費期權(free option)。讓建構者甚至多方對約束做出承諾,是邁向此類機制的一步。
BAL 作為爭議證據
如果結果預確認爭議進入鏈上裁決,每個約束都是可以獨立爭議的。爭議方提供被違反的約束、提議者對其的簽名、建構者簽署的承諾、BAL 以及區塊標頭。罰沒合約針對 block_access_list_hash 認證 BAL,並運行提議者 sidecar 在正常驗證期間運行的相同驗證器。如果返回假,則證明違規。
FOL 公式結構非常適合 ZK 證明。對固定模式 BAL 的查詢證明起來比任意 EVM 執行要便宜得多,因此針對承諾的 BAL 根進行 ZK 證明是一個合理的未來優化方向。
邁向協議內置(Enshrining)之路
本文描述的設計完全是協議外的。提議者和建構者的承諾透過經濟激勵和協議外罰沒來執行。從網絡的角度來看,違反結果預確認的區塊仍然是有效區塊。
有一條合理的道路可以將其納入協議內。PEPC 確定了對協議強制提議者承諾的需求,但將承諾表示方式留作開放問題(是使用 EVM 執行、SNARKs 還是其他結構),並指出了數據可用性問題:第三方如何以證明者(attesters)可以驗證的方式交付承諾證明?BAL 潛在地解決了這兩個問題,因為它已經是區塊標頭中承諾的一等對象,因此不需要單獨的證明交付機制。FOL 約束語言是極簡且定義明確的,驗證器是可在共識層部署的單一函數。協議可以直接針對認證的 BAL 驗證 FOL 公式,而不是讓證明者重新執行承諾代碼。
為了讓這在協議內運作,還需要幾個額外的部分:
綁定承諾廣播。 提議者的約束需要在投標過程之前發布,且必須是不可篡改且可追溯的。類似於 PTC 但針對約束。
隨投標交付 BAL 和標頭。 為了讓提議者在簽名前驗證約束,建構者必須在投標的同時包含 BAL 和標頭,這目前不屬於 ePBS 規範的一部分。
對無效 BAL 的建構者處罰。 如果隨投標提交的 BAL 與最終揭示的區塊不匹配,或者揭示的區塊驗證失敗,建構者應受到處罰。在 ePBS 後,建構者已被要求繳納抵押品,因此大部分繁重的工作已經完成。
總結
在 ePBS 下不再需要中繼器,因此重新引入它們作為受信的預確認驗證器並不理想。Merkle 證明提供了一種去信任的替代方案,但會增加關鍵路徑的延遲,且無法表達狀態性或排除性約束。BAL 解決了這兩個問題:它們作為區塊執行的副產品產生,沒有額外延遲;透過從交易級別轉向意圖級別的承諾,任何預確認類型都可以簡化為對同一 BAL 結構的公式。這種表達能力不需要在關鍵路徑上進行 ZK 證明,且增加新的預確認類型不需要對驗證器或罰沒基礎設施進行任何更改。
1 則貼文 - 1 位參與者
[閱讀完整主題](https://ethresear.ch/t/outcome-preconfs-verifying-block-commitments-without-the-block/24466)