
從無狀態性視角審視 Frame 交易機制
本文分析在後 ZKEVM 時代的以太坊環境中,EIP-8141 Frame 交易與記憶體池策略如何與無狀態節點互動,並重點探討交易驗證所需的狀態需求。
在後 ZKEVM 世界中,AA 與 EIP-8141 內存池(mempool)策略如何與無狀態節點互動
後 ZKEVM 的基準
ZKEVM 以證明驗證取代了重新執行。一旦 SNARK 證明能在毫秒內驗證一個區塊,節點就不再需要完整狀態來參與共識。過去要求每個全節點持有約 280 GB 狀態的必要條件——重新執行——消失了。剩下的需求是經濟性的:建構者(builders)、RPC 提供商和搜尋者(searchers)持有狀態是因為其業務依賴於此。其他人則可以停止持有。
預期的應對方案是部分狀態化(partial statefulness):節點持有完整的帳戶樹(每個帳戶的 nonce、餘額、codeHash 和 storageRoot),加上針對其選擇追蹤的合約進行選擇性存儲。服務於 DeFi 協議的節點會追蹤該協議的存儲;專注於抗審查的節點則除了帳戶之外什麼都不追蹤。這個最低限度——僅驗證部分無狀態(Validity-Only Partial Statelessness, VOPS)——對於約 4 億個帳戶而言,成本約為 10 GB。部分狀態化(PS)位於 VOPS 之上:同樣擁有完整帳戶樹,加上所選合約的完整存儲樹,並透過區塊訪問列表(EIP-7928)而非重新執行來跟隨鏈尖。深入探討請參閱 EthCC 2026 簡報。
為什麼這對交易格式很重要?因為內存池的健康即是抗審查性。一個能本地驗證交易的節點可以維護內存池、向對等節點傳播交易,並參與 FOCIL 包含列表(EIP-7805)。如果節點無法驗證某種交易類型,就無法將其納入包含列表,也無法強制其被包含,該類交易的抗審查性就會悄然退化。能驗證的節點越少,審查就越容易。在大多數節點均為部分狀態化的後 ZKEVM 世界中,任何新的交易格式都必須針對這一現實進行評估。
Frame 交易驗證的需求
今天,在內存池中驗證一筆交易的成本很低。對於傳統和 EIP-1559 交易,節點對簽名執行 ecrecover 以推導發送者,檢查發送者的 nonce,並驗證發送者的餘額足以支付交易成本。這是純粹的計算加上單次帳戶查詢。任何擁有帳戶樹的節點(包括 VOPS 和 PS 節點)都能做到。
Frame 交易(EIP-8141)從根本上改變了這一點。Frame 交易在傳統意義上沒有加密簽名。相反,交易明確聲明其發送者,並將執行拆分為有序的 frames。其中一個 frame 的模式為 VERIFY:它執行發送者的帳戶代碼,該代碼必須調用 APPROVE 操作碼來授權交易。驗證邏輯是任意的——它可以透過讀取發送者的存儲並執行帳戶代碼定義的任何驗證邏輯,來實現任何簽名方案(後量子、多簽、社交恢復)。
這意味著驗證節點需要發送者的字節碼(bytecode)和驗證期間訪問的存儲插槽(storage slots)——而不僅僅是帳戶葉節點中的兩個欄位(nonce、餘額)。而且發送者是一個智能合約錢包:它可以是網絡上的任何帳戶。驗證從「查詢兩個欄位」轉變為「針對任意帳戶狀態執行任意代碼」。
圖:傳統交易驗證僅需帳戶樹查詢(約 3,000 gas,所有節點類型)。Frame 交易驗證需要針對發送者的字節碼和存儲執行 VERIFY frame(最高約 100k gas,僅限擁有相關狀態的節點)。
內存池策略及其假設
EIP-8141 的內存池策略文件提出了三種漸進且更具野心的政策,用於決定公共內存池將接受哪些 Frame 交易。每一種都在無許可性與 DoS 防護之間進行權衡。這裡重要的是每種策略對驗證節點所需的狀態要求。
策略 1(僅限自轉發,Self-Relay Only) 僅接受自費的 Frame 交易。VERIFY 期間的存儲讀取被限制在 tx.sender 的插槽內,且每個發送者僅允許一筆待處理的 Frame 交易。但「發送者的代碼和存儲」值得仔細拆解——實際的狀態佔用取決於發送者是什麼類型的帳戶。
任何帳戶都可以發送 Frame 交易。EIP 指定了三種驗證路徑:
普通 EOA(無代碼,無委託)。 EIP-8141 定義了「預設代碼」,透過針對發送者地址檢查 ECDSA (secp256k1) 或 P256 簽名並調用 APPROVE 來處理 VERIFY。無存儲讀取,無自定義字節碼。這與驗證傳統交易一樣便宜——任何擁有帳戶樹的節點(包括 VOPS)都能做到。
合約帳戶。 發送者自身部署的代碼在 VERIFY 期間運行,讀取發送者自身的存儲。這很直接——節點需要發送者的代碼和存儲。
7702 委託的 EOA —— AA 的有趣案例。 帳戶的代碼欄位是一個 23 字節的委託前綴(0xef0100 || delegate_address)。當 EVM 在 VERIFY frame 中遇到此情況時,它會跟隨指針並加載委託合約的字節碼——但在發送者的上下文中執行。address(this) 返回發送者的地址。SLOAD 讀取的是發送者的存儲樹,而非委託者的。這在語義上與代理合約(proxy contracts)的工作方式完全相同:委託者的編譯存儲佈局(插槽 0 = owner,插槽 1 = nonce 等)是針對發送者的原始鍵值存儲進行解釋的。委託者自身的存儲永遠不會被觸及。
7702 委託案例引出了一個直接的問題:EOA 的存儲從何而來?EOA 傳統上擁有空的存儲樹。答案是:一旦 EOA 透過 SetCode 交易進行委託,隨後的交易就會在 EOA 的上下文中執行委託代碼——而 SSTORE 寫入會進入 EOA 的存儲樹。第一次交互通常會初始化關鍵插槽(owner 地址、守護者、nonce)。從那時起,EOA 在狀態中其地址下就攜帶了一個真實的存儲樹,結構上與合約相同。EIP 未提供特殊的初始化機制;這留給了錢包實現(例如,首次使用的自初始化模式,或單獨的設置交易)。
另外兩個約束塑造了狀態訪問。首先,EIP-8141 的規則「SLOAD 限制於 tx.sender 存儲」與 7702 並非重複——它約束了傳遞調用(transitive calls)。如果委託代碼透過 CALL 調用輔助庫,該輔助庫會進入其自身的執行上下文,此時 SLOAD 通常會讀取輔助庫的存儲。EIP-8141 規則禁止這樣做:透過 CALL 到達的輔助庫只能執行純計算(簽名數學、哈希、預編譯調用)。如果委託代碼改用 DELEGATECALL,執行上下文仍保持為發送者的——SLOAD 依然讀取發送者的存儲,這是被允許的。其次,在 VERIFY 期間調用其他 7702 委託帳戶是被明確禁止的——它們的委託目標是可變的,因此一筆 SetCode 交易可能會使所有依賴於該帳戶當前行為的待處理 Frame 交易失效。
因此,策略 1 的實際狀態佔用取決於發送者類型:
普通 EOA(預設代碼):
tx.sender 的帳戶葉節點(nonce、餘額)——來自帳戶樹
無其他內容。簽名驗證是純計算。
7702 委託的 EOA(常見的 AA 案例):
tx.sender 的帳戶葉節點——nonce、餘額以及 23 字節的委託前綴
委託合約的字節碼——實際的 VERIFY 邏輯,位於另一個地址
tx.sender 的存儲插槽——由委託代碼透過 SLOAD 讀取,針對發送者(EOA)的存儲樹進行解析
輔助庫字節碼——非委託、已部署的合約,用於純計算
存儲被限制在一個帳戶內。字節碼可能跨越 2-3 個合約。不同發送者之間沒有共享狀態。
圖:策略 1 VERIFY 執行的狀態訪問模式。存儲讀取(綠色箭頭)始終解析為 tx.sender 的樹,無論正在執行哪段代碼。委託者和輔助庫的存儲樹永遠不會被訪問。
策略 2(規範代付者,Canonical Paymaster) 透過標準化的規範代付者合約增加了代付交易。策略 1 使用 self_verify(發送者調用 APPROVE(0x3) 在一個 frame 中同時授權執行和支付),而策略 2 則透過 only_verify → pay 序列將其拆分為兩個 frames。
EIP-8141 的 APPROVE 操作碼帶有一個範圍(scope)參數,將發送者授權與支付者授權分開。在策略 2 的代付流程中,only_verify frame 針對 tx.sender——執行發送者的代碼(與策略 1 相同的 7702 委託模式)並調用 APPROVE 以授權執行而不承諾支付。然後 pay frame 針對規範代付者合約——執行代付者的代碼,檢查其存款餘額,並調用 APPROVE 代表發送者授權支付。
規範代付者是透過**精確的運行時代碼哈希(runtime code hash)**來識別的——節點將部署的字節碼與已知哈希進行比對。這是一個內存池政策,而非共識規則:使用非規範代付者的交易仍可透過私有建構者通道納入區塊,只是無法透過公共內存池傳播。任何人都可以部署規範代付者的實例。多個實例可以共存,每個實例擁有獨立的存儲(其自身的存款池、提款時間戳)。被認可的字節碼集合也不是永久固定的——EIP 作者預計隨著時間推移會增加額外的規範代付者(例如 PQ 安全變體)。
代付者的安全性依賴於兩個結構性約束。首先是延遲提款:存入規範代付者實例的資金只能透過 gas 支付或有時間鎖的提款離開。代付者不能存入 ETH、代付 1000 筆交易後立即提款——時間鎖防止了這種大規模失效攻擊。其次是節點側待處理餘額追蹤:節點為每個代付者實例計算 effective_balance = deposited - pending_gas_commitments,其中 pending_gas_commitments 是使用該實例的所有待處理交易的最壞情況 gas 成本之和。如果有效餘額不足,新交易將被拒絕。
在 pay frame 期間,規範代付者獲得了通用 SLOAD 限制的豁免。雖然 only_verify 將存儲讀取限制在僅限 tx.sender(與策略 1 相同),但 pay frame 可以讀取代付者自身的存儲——其存款餘額和提款時間戳。這項豁免存在是因為規範代碼經過審核且廣為人知;它是透過「代碼匹配而非要求其單獨滿足每條通用驗證規則」而被接納的。
策略 2 的狀態佔用包含策略 1 的所有內容,外加:
規範代付者的字節碼——用於驗證代碼哈希是否匹配(或原生實現檢查,因為代碼是已知的)
規範代付者的存儲——存款餘額和提款時間戳,豁免於僅限 tx.sender 的 SLOAD 限制
節點本地會計——每個代付者實例的待處理 gas 承諾(非鏈上狀態)
這引出了一個規範中未提及的問題:實例激增(instance proliferation)。由於規範代付者是透過代碼哈希識別的,任何人都可以部署實例。每個實例都有獨立存儲。如果每條鏈只有 1-3 個知名實例,狀態負擔是微不足道的。如果有成百上千個——每個都需要追蹤其存款餘額——狀態需求會隨實例數量增長。協議層面沒有限制實例數量的機制。在最壞情況下,這會接近策略 3 的無限狀態問題。緩解的論點是經濟性的:擁有大額存款池的代付者比許多小額代付者更有用,因此碎片化在經濟上是低效的。但協議並不強制執行這一點。
還有第二個可能更深層的風險:規範代付者的採用率。由於內存池政策不是共識規則,錢包提供商可以自由構建具有更豐富功能的非規範代付者——更靈活的提款邏輯、多代幣 gas 支付、可編程的代付政策。如果這些非規範實現獲得多數採用,它們的交易就無法進入公共內存池,無法被任意建構者獲取,而且——關鍵是——無法被 FOCIL 強制執行。AA 交易的抗審查性完全取決於是否有足夠的用戶透過符合內存池規範的規範代付者進行路由。如果市場繞過它們,FOCIL 對於帳戶抽象交易在結構上將變得無能為力:它雖然存在,但什麼也覆蓋不了。EIP 作者對策略 2 的使用充滿信心,理由是公共內存池訪問的強大激勵(任何建構者都可以包含交易,外加 FOCIL 強制執行)。這種激勵是否能抵消規範與非規範代付者之間的功能差距,是一個將由市場回答的開放性問題。
圖:策略 2 將驗證拆分為兩個 frames。only_verify frame 訪問發送者狀態(與策略 1 相同)。pay frame 訪問規範代付者自身的存儲(豁免於僅限發送者的 SLOAD 規則)。實例激增決定了代付者狀態負擔是否受限。
策略 3(完整 ERC-7562) 允許任意代付者——任何合約都可以充當代付者,受質押和節點本地信譽系統的管控。這是最寬鬆的策略,也是對狀態要求最高的策略。
策略 2 將代付者限制在具有已知存儲佈局的單一規範字節碼,而策略 3 則移除了這一限制。任何願意質押 ETH 的合約都可以擔任代付者。質押實體獲得放寬的驗證規則:移除了對 tx.sender 存儲的 SLOAD 限制,允許質押代付者讀取其自身存儲,以及可能在驗證期間與之交互的其他合約的存儲。禁用操作碼列表也對質押實體放寬。安全模型從結構性約束(已知代碼、延遲提款)轉向經濟約束(風險質押、信譽追蹤)。
節點透過信譽系統管理 DoS 風險:它們追蹤每個質押實體的交易失效頻率、在失敗模擬中浪費了多少 gas,以及該實體是否導致級聯失效。表現不佳的實體會被限制或封禁。這需要持續觀察——節點必須模擬交易、觀察結果,並跨區塊維護每個實體的統計數據。
策略 3 的狀態佔用在多個維度上是無限的:
任意代付者字節碼——節點必須加載並執行任何代付者的代碼,而不僅僅是一個規範字節碼。每個代付者都有不同的邏輯、不同的存儲佈局、不同的驗證行為。
跨帳戶存儲讀取——質押實體在驗證期間可以讀取 tx.sender 以外合約的存儲。質押代付者可能會檢查白名單合約、價格預言機或訪問控制註冊表。這些都是節點必須擁有的額外狀態。
信譽數據庫——節點必須維護一個關於每個實體行為(模擬成功率、浪費的 gas、失效頻率)的本地數據庫。這需要看到並模擬所有涉及質押實體的交易——如果節點缺乏模擬所需的狀態,這是不可能的。
級聯失效風險——共享合約中的一次存儲更改可能會使所有驗證依賴於該合約的待處理交易失效。策略 1 在結構上防止了這一點(僅限發送者存儲)。策略 2 將其限制在規範代付者實例。策略 3 則沒有結構性限制——失效面與質押實體的存儲訪問範圍一樣廣。
這些策略在設計時考慮的是全節點。它們隱含地假設驗證節點可以按需訪問任何帳戶的代碼和存儲。
FOCIL、AA-VOPS 與資格橋樑
Frame 交易與部分狀態化節點之間的緊張關係不僅僅是內存池便利性的問題——它透過 FOCIL 直接影響抗審查性。
Thomas Thiery 的提案透過定義一個 FOCIL 可以強制執行的 Frame 交易合格子集來解決此問題,並引入了一個與此直接相關的概念:AA-VOPS。AA-VOPS 擴展了 VOPS,為每個帳戶緩存前 N 個存儲插槽(N 在 2-4 之間)。大多數智能錢包將其 nonce、owner 和守護者存儲在插槽 0-3 中,因此 N 個插槽覆蓋了常見的驗證模式。關鍵約束(提案中的約束 5):VERIFY 僅能讀取發送者和支付者的帳戶狀態及其前 N 個存儲插槽。任何超出此邊界的讀取都會使交易不合格——其被遺漏將從 FOCIL 強制執行中豁免。
AA-VOPS 部分解決了 Frame 交易驗證中的存儲問題。但正如策略 1 分析中所確立的,驗證還需要字節碼——委託合約的代碼(透過 7702 委託)以及可能的輔助庫代碼。約束 5 限制了存儲讀取,但未解決代碼可用性問題。一個為每個帳戶緩存 N 個插槽的 AA-VOPS 節點,如果缺乏委託者的字節碼,仍無法執行 VERIFY frame。這是 AA-VOPS 設計中的一個缺口:要麼必須透過某種外部機制獲取字節碼,要麼 FOCIL 合格的 Frame 交易必須僅限於那些委託代碼廣泛可用的帳戶(例如,一組少量的知名錢包實現)。
基本情況的緊張關係:瘦帳戶 vs. 胖錢包
無論採用哪種策略,都存在一種更根本的緊張關係:帳戶抽象使帳戶變得更重,而無狀態化需要帳戶保持輕量。
VOPS 的 8.4 GB 基準建立在一個特定假設之上:EOA 是瘦的。今天的 EOA 在帳戶樹中約為 40 字節——nonce、餘額、空 codeHash、空 storageRoot。4 億個帳戶每個約 40 字節,總計約 10 GB。這個數字是抗審查節點的底線:驗證網絡上任何發送者的傳統交易所需的最小狀態。
原生 AA 透過兩條路徑改變了每個帳戶的權重。EIP-7702 委託給了 EOA 一個非空的代碼欄位,並且——隨著委託代碼隨時間進行交易——一個不斷增長的存儲樹(owner 密鑰、錢包 nonce、守護者、會話密鑰、權限)。EIP-8141 的 deploy frame 可以在單筆交易中將一個地址轉換為具有代碼和存儲的完整合約。無論哪種方式,原本約 40 字節的帳戶都會獲得持久且增長的存儲樹。
AA-VOPS 的 N 插槽約束限制了每次驗證 VERIFY 可以讀取的內容,但它並未限制節點為了驗證來自任意發送者的 Frame 交易而必須持有的總狀態。每個採用 AA 的帳戶都會在驗證關鍵狀態集中增加 N 個緩存存儲插槽。以 N=4 且每個插槽 64 字節計算:如果 25% 的帳戶採用 AA 錢包(6000 萬個帳戶),這將增加約 15 GB——幾乎使 VOPS 基準翻倍。在 4 億個帳戶全面採用的情況下,AA-VOPS 將達到約 62 GB——比今天的 VOPS 增加 8 倍,儘管仍遠低於約 280 GB 的完整狀態。
圖:驗證關鍵狀態隨 AA 採用率線性增長。在每個帳戶緩存 N=4 個插槽的情況下,中度採用幾乎使 VOPS 基準翻倍;全面採用則導致 8 倍增長。完整狀態(約 280 GB)雖然仍有距離,但 VOPS 的「地板」大幅抬升。
Thomas Thiery 的 FOCIL 提案透過 AA-VOPS 提供了一個部分答案:為每個帳戶緩存 N=2-4 個存儲插槽,將 VERIFY 限制在這些插槽內,並將任何讀取超出此邊界的交易從 FOCIL 強制執行中豁免。這解決了每次驗證的問題——節點確切知道每筆交易要獲取什麼,且獲取集合是小型且確定的。它還激勵錢包實現盡量減少驗證存儲讀取,以保持 FOCIL 合格性。但它沒有解決總量問題:一個想要成為通用驗證者的節點仍需要為每個啟用了 AA 的帳戶緩存 N 個插槽,而這個總量隨採用率線性增長。
這種方法還創造了一個二級系統。來自簡單錢包、符合 N 插槽和 VERIFY gas 預算的交易獲得完整的 FOCIL 抗審查保護。而那些需要更多資源的交易——後量子簽名驗證(已經超過了 MAX_VERIFY_GAS_PER_FRAMETX)、隱私協議交互、複雜的多守護者恢復——則落在合格範圍之外。它們的遺漏是被允許的。最需要抗審查性的交易(新型加密技術、保護隱私的協議)恰恰是那些可能不符合合格子集的交易。
更根本的是,我們無法預測隨著錢包實現的演進,N=2-4 個存儲插槽是否依然足夠。今天的智能錢包可能只需要一個 owner 和一個 nonce 進行驗證。明天的錢包可能需要會話密鑰註冊表、跨鏈狀態或社交恢復圖譜。如果交付一個抽象帳戶的抗審查性在結構上受限於固定 N 的系統,風險在於未來的新用例會超出該限制——屆時無狀態化與抗審查性之間的互動將在最關鍵的時刻變得難以運作。
這不是單一策略的問題。策略 1 需要發送者存儲進行驗證。策略 2 在此基礎上增加了代付者存儲。策略 3 增加了任意合約存儲。但基本成本——所有採用 AA 帳戶的發送者存儲——適用於所有三種策略。策略的不同之處在於它們在此基礎之上需要多少額外狀態。這種緊張關係是結構性的:無狀態化希望最小可行節點隨時間持有更少狀態,以便更多節點能參與,從而提高抗審查性。帳戶抽象希望每個帳戶隨時間攜帶更豐富的狀態,以便錢包能實現更好的安全模型。這些目標並非矛盾——受限狀態訪問規則在兩者之間進行調解——但調解是有成本的,以 GB 為單位,且該成本隨採用率擴展。
兼容性摘要
| 全節點 | PS (含代付者) | PS (無代付者) | VOPS | AA-VOPS | |
|---|---|---|---|---|---|
| 帳戶 nonce + 餘額 | 是 | 是 | 是 | 是 | 是 |
| 委託 + 輔助字節碼 | 是 | 若有追蹤 | 若有追蹤 | 否 | 否* |
| 發送者存儲 (N 插槽) | 是 | 若有追蹤 | 若有追蹤 | 否 | 是 |
| 代付者存儲 | 是 | 若有追蹤† | 否 | 否 | 否 |
| 任意合約存儲 | 是 | 否 | 否 | 否 | 否 |
| 策略 1 (自轉發) | 是 | 部分 | 部分 | 否 | 否* |
| 策略 2 (規範代付者) | 是 | 部分–是† | 部分 | 否 | 否* |
| 策略 3 (ERC-7562) | 是 | 否 | 否 | 否 | 否 |
* AA-VOPS 緩存每個帳戶的 N 個存儲插槽,但不緩存字節碼。VERIFY 執行需要委託者的代碼。AA-VOPS 節點如何獲取字節碼是一個開放性問題——soispoke 的提案限制了存儲訪問,但未解決代碼可用性。
† 「若有追蹤」——PS 節點必須明確追蹤每個規範代付者實例。當實例較少(1-3 個)時兼容性強,隨實例激增而退化。參見上文關於實例激增的討論。
結語
Frame 交易是原生帳戶抽象的一個強大原語。但它們帶來的兩種緊張關係比內存池策略的選擇更為深層。
第一種是結構性的:無狀態化需要帳戶保持瘦身,而帳戶抽象需要它們變得更豐富。受限狀態訪問規則(每個帳戶 N 個插槽)透過限制每次驗證的讀取來調解這一點,但總狀態隨 AA 採用率線性增長。今天約 10 GB 的 VOPS 基準在中度採用時可能達到約 20 GB,在全面採用時則超過 60 GB。
第二種是經濟性的:策略 2 的抗審查保證僅適用於使用符合內存池規範的規範代付者的交易。如果錢包提供商構建了功能更豐富的非規範代付者,且用戶向其傾斜,那麼這些交易將透過私有建構者路由,而旨在防止審查的 FOCIL 對於大多數 AA 交易將毫無覆蓋。圍繞帳戶抽象所做的協議決策將塑造「抗審查」在實踐中的含義,以及我們為 AA 交易的 FOCIL 包含所構建的基礎設施是否真的有對象可包含。
我擔憂的是我們在未考慮無狀態化的情況下做出決定。一旦 ZKEVM 交付,絕大多數節點將是無狀態或部分狀態化的——如果內存池驗證所需的狀態增長得太大,幾乎沒人能保持內存池健康或參與 FOCIL。如果我們搞錯了規範代付者——如果錢包提供商因為它無法提供用戶想要的功能而繞過它——那麼即使是那些負擔得起狀態的節點也無從強制執行。FOCIL 存在,但無人受惠。我們將極大地削弱我們在 Hegota 努力爭取才最終獲得的抗審查性。
1 則貼文 - 1 位參與者
[閱讀完整主題](https://ethresear.ch/t/frame-transactions-through-a-statelessness-lens/24538)