
作者:NIC Lin,Medium
Pectra 硬分叉預計於 2025 年 3 月啟動主網部署。Pectra 升級包含 11 個技術協議(EIP),它們分別是:
-
EIP-2537: BLS12-381 曲線操作預編譯
-
EIP-2935: 在 State 中保存歷史區塊哈希值
-
EIP-6110: 提供鏈上 validator deposits
-
EIP-7002: 執行層觸發退出
-
EIP-7251: 增加 the MAX_EFFECTIVE_BALANCE
-
EIP-7549: 將 committee 索引移至驗證之外
-
EIP-7623: 增加 calldata 成本
-
EIP-7685: 通用執行層請求
-
EIP-7691: 增加 Blob 吞吐量
-
EIP-7702: 設置 EOA 帳戶代碼
-
EIP-7840: 在 EL 配置文件中添加 Blob 計劃
質押相關的技術協議
EIP-6110: BLS12-381 曲線操作預編譯
簡化用戶參與質押的處理流程,讓等待時間大幅縮短。
用戶參與質押的方式是在執行層上存入 32 個 ETH 並由事件日誌(Event Log)記錄,接著共識層執行解析事件日誌來判斷是否有人參與質押,然後參與質押的用戶就成為驗證者。
不過,共識層的驗證者首先需要針對哪一個時間點存入達成共識,否則,會發現有些驗證者看到 5 個新的存入,而有些驗證者只看到 3 個,因此共識層驗證者們會對要參考哪一個執行層區塊(eth1data)進行投票,確保大家看到的是一樣的執行層區塊。
不過,一開始設計時為了避免執行層出現重大錯誤導致鏈分叉,所以參考的執行層區塊(eth1data)會是一個約 10 多個小時以前的執行層區塊,確保當重大錯誤發生時,共識層的開發者們有足夠的時間反應處理,不過這也導致參與質押最快也要等上 10 多個小時才會生效。
△ CL 區塊裡的 10900000 eth1data,它裡面記載的 Block Hash 是執行層區塊 21683339,出現在它的 10 個小時以前。
執行 EIP-6110 技術協議之後 ,用戶在合約上的質押資料會直接變成執行層的一部分,而因為共識層區塊本身就會包含執行層區塊(但不是 eth1data),所以,共識層驗證者們就不用再考慮「要確認參考的執行層內存塊是⼀樣的」的問題,只要共識層內存塊獲得超過三分之二的驗證者們投票確認,則大家對看到的是同一個執行層區塊達成共識。因此,用戶在參與質押後,最快約 13 分鐘等執行層內存塊完成處理後就可以生效,而共識層客戶端也可以移除原本用來處理質押數據相關的複雜邏輯。
EIP-7002: 在 State 中保存歷史區塊哈希值
能夠用於改善驗證者退出質押或提領押⾦和收益的流程,降低驗證者的風險。
參與質押需要有兩把鑰匙,分別是 Validator Key 和 Withdrawal Credential。
Validator Key 用於驗證者⼯作內容,Withdrawal Credential 用於驗證者退出質押時,押⾦和收益會提取到的地址,另外,目前退出質押必須要用 Validator Key 操作。
如果遺失 Validator Key,則無法執⾏驗證者⼯作,且無法退出質押;如果遺失 Withdrawal Credential,則會丟失所有押⾦和收益。此外,部分用戶會使用諸如 Lido 的第三⽅質押服務,當使用這些平臺時,用戶需要自行保管 Withdrawal Credential,而此時 Validator Key 則是由服務提供商保管並代為執⾏驗證者的⼯作。
執行 EIP-7002 技術協議,用戶就可以自⼰用 Withdrawal Credential 呼叫「Withdraw 合約」(即部署在0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA)來退出質押(Exit)或提領押⾦和收益(Partial Withdrawal),可以降低使用第三方質押服務可能存在的相關風險。如果用戶自行參與質押但遺失了 Validator Key,也能藉此退出質押。
-
發起請求的參數包含 validator_pubkey 及 amount : validator_pubkey 是驗證者的 Validator(Public)Key,amount 是要提領的數量。
-
發起請求的 Withdrawal Credential 必須是 validator_pubkey 驗證者的 Withdrawal Credential。
-
呼叫 Withdraw 合約去發起請求時要附上 Gas 費(ETH),Gas 費會按照當前的提領請求數量計算,如果請求數量很多,Gas 費就會上升。
-
如果用戶的 Withdrawal Credential 是⼀個合約的話,那可以先去 Withdraw 合約取得當前⼿續費⾦額,然後再發起請求並附上⼿續費;但如果 Withdrawal Credential 是⼀個 EOA 帳戶的話,就沒辦法取得精準的⼿續費,只能事先鏈下模擬並付超額⼿續費(不會退還),確保請求發起會執⾏成功。
註:如果你的 Withdrawal Credential 還是 BLS 公鑰格式,記得要先進⾏切換,將它換成 EL 地址的格式。
EIP-7251: 增加 the MAX_EFFECTIVE_BALANCE
能夠⼤幅提高質押⾦額上限來減少驗證者數量,且未達上限的驗證者可以自動享受質押收益。
用戶質押成為驗證者要提供 MAX_EFFECTIVE_BALANCE 數量的 ETH,不能更少也不能更多(目前 MAX_EFFECTIVE_BALANCE 是 32 ETH)。如果用戶持有 1024 ETH 要質押,可以分 32 次參與質押、啟用 32 個驗證者,運⾏ 32 個驗證者節點。⽽⼤家積極參與質押也導致目前已有約 100 萬個驗證者並持續增加,這除了讓共識層的狀態數據變得更⼤更多,對共識層 p2p 網絡層的負荷更為顯著,因為每⼀個 Slot(每 12 秒)都有數萬個驗證者的籤名要在 p2p 網絡層裡不斷傳遞並聚合。
執行 EIP-7251 技術協議後,質押下限(MIN_ACTIVATION_BALANCE)仍然是 32 ETH,但上限(MAX_EFFECTIVE_BALANCE)將大幅調高為 2048 ETH,你可以質押 32~2048 之間任何數量的 ETH,可以獲得質押收益,不再需要定期取出收益,累積 32 ETH 後再繼續新質押。
目前,已存在的驗證者也不需要特別先退出質押再合併⼀起重新加⼊質押,⽽是可以直接利用執行層上新增的「合併押金用的合約」(部署在0x00431F263cE400f4455c2dCf564e53007Ca4bbBb),由驗證者的 Withdrawal Crendential 去呼叫合約發起合併押金的請求。
-
合併押金請求的參數包含 source_pubkey 及 target_pubkey:這兩個 key 都是驗證者的 Validator Key,source 驗證者會合併到 target 驗證者。
-
發起請求的 Withdrawal Credential 必須是 source 驗證者的 Withdrawal Credential。
-
呼叫合併押金合約去發起請求時要附上手續費(ETH),手續費用會按照當前的請求數量計算,如果請求數量很多,手續費就會上升。
-
如果用戶的 Withdrawal Credential 是⼀個合約的話,那可以先呼叫合併押金合約取得當前⼿續費⾦額,然後再發起請求並附上⼿續費;但如果 Withdrawal Credential 是⼀個 EOA 帳戶的話,就沒辦法取得精準的⼿續費,只能事先鏈下模擬並付超額⼿續費(不會退還),確保請求發起會執⾏成功。
註:如果你的 Withdrawal Credential 是 BLS 公鑰格式,需要先進⾏切換,將它換成 EL 地址的格式。
EIP-7685: 通用執行層請求
建立⼀個正式的 EL -> CL 信息管道,⽅便用戶及質押服務能直接送出請求給共識層。
用戶能直接從執行層發送請求給共識層,質押服務(例如 Lido)就可以以更去中心化的⽅式運⾏。例如前面提到的 EIP-7002 的退出質押的請求,以及 EIP-7251 的合併押金的請求。如果沒有這個技術協議,那 Lido 的用戶就必須要相信 Lido 節點服務提供商會如實在共識層去執⾏退出質押或是合併押金;有了這個技術協議,Lido 的用戶就可以在執行層上直接透過治理合約去送出請求。
這些請求會有 Request Type 來區分不同類型的請求,以及透過不同合約發起請求,最後這些請求都會被寫⼊到執行層內存塊裡,因此共識層可以直接透過執行層內存塊獲得這些信息,不必再寫個別的解析邏輯。
EIP-6110、EIP-7002 和 EIP-7251 都是以 EIP-7685 定義的標準來制定請求:
-
EIP-6110 加⼊質押請求:Request Type=0,透過 Deposit 合約
(0x00000000219ab540356cbb839cbe05303d7705fa)發起請求。
-
EIP-7002 退出質押請求:Request Type=1,透過Withdraw合約
(0x0c15F14308530b7CDB8460094BbB9cC28b9AaaAA)發起請求。
-
EIP-7251 合併押金請求:Request Type=2,透過Consolidation合約
(0x00431F263cE400f4455c2dCf564e53007Ca4bbBb)發起請求。
改善使用體驗的技術協議
EIP-7702: 設置 EOA 帳戶代碼
讓 EOA 帳戶能任意變身成合約帳戶,⼤幅提升使用體驗。
EOA 帳戶在使用上有一些不足包括:
-
需要記錄和保管私鑰或助記詞,對於新用戶註冊使用的門檻較高。
-
EOA 帳戶⼀筆交易只能執⾏⼀個操作,比如,要去 Uniswap 將 USDT 換為 ETH,要先發起⼀筆交易批准 USDT,然後才能送另⼀筆交易執⾏兌換。
-
無法細化的權限控管,像是將帳⼾的某些操作交給第三⽅代為操作,用戶必須要親自處理每⼀件雜事且每⼀個操作都要籤名發交易⼀次。
-
沒有 Recovery 機制,只能自⼰保管好私鑰或助記詞,如果遺失了就再也拿不回帳⼾的資產。
如果是⼀個智能合約帳⼾(例如 Safe),那以上的問題都可以被解決:
-
用戶可以用⼿機(或電腦)的安全晶片裡的私鑰來籤名授權,不用記任何私鑰或助記詞,或是用 Email 來籤名授權也可以,或其他各式各樣的授權⽅式。
-
可以將多個操作 Batch 起來在同⼀筆交易內⼀起執⾏,原先複雜的 DApp 操作都可以只用⼀次籤名授權、⼀次交易就可完成。
-
可以有非常細化的權限控管,用戶可以授權第三⽅來控制自⼰的帳⼾,但同時指定「可以和什麼合約互動」「不可以執⾏什麼操作」、「牽涉到資產轉移最多只能動用多少資產」或「每個禮拜最多不能超過多少次操作」等等限制。
-
可以新增 Recovery 機制,在自⼰遺失助記詞或⼿機或 Email 時還能透過 Recovery 機制將帳⼾的資產轉移⾄新的帳⼾。
EIP-7702 提案便是賦予 EOA 帳戶變身成為合約帳戶的能⼒。用戶用 EOA 私鑰對變身的訊息籤名,籤名內容包含「Chain ID」「變成的合約地址」及「EOA的 Nonce值」:
-
Chain ID:用來防止 A 鏈的籤名被拿到 B 鏈重放。不過,如果 Chain ID 填 0,則表示願意在每條鏈都變身。
-
想變成的合約地址:如果你填⼀個 Safe 合約地址,那你的 EOA 帳戶就會變成為⼀個 Safe 合約;如果填空地址(address(0)),那就表示要取消變化,變回單純的 EOA 帳戶。
-
EOA 的 Nonce 值:用來防⽌籤名被重放。如果 Nonce 值增加了,那原本的籤名就會失效。
不過有幾點需要注意:
1. EOA 私鑰⼀樣可以繼續使用
即便用戶的 EOA 帳戶變成⼀個合約,他還是可以繼續以原本 EOA 帳戶的⽅式使用。他的帳⼾,例如假設你的 EOA 帳戶變成⼀個 Safe 合約,則你可以使用 Safe 介面、走 Safe 交易流程,也可以繼續用原本的 EOA 錢包籤名送交易。不過這也表示帳⼾的安全性還是局限在那把私鑰。
2.仍然是 EOA 私鑰的安全性
即便用戶的 EOA 變成⼀個多籤,只要他沒有把 EOA 私鑰丟掉,他的帳戶安全性永遠都是 EOA 私鑰的安全性:他仍然要好好保管他的私鑰或助記詞,他的帳戶不會因此變得和多籤⼀樣安全。
3. EOA 帳戶的 Storage 不會格式化
當⼀個 EOA 帳戶變身成合約並寫⼊數據到其 Storage,除非明確執⾏刪除數據的動作,否則這些寫⼊到 Storage 的數據並不會因為 EOA 帳戶變身成其他合約或取消變身⽽格式化,所以開發者要注意 Storage 不要讀取到以前變身合約留下的數據,可以參考 ERC-7201。
4. EIP-7702 的流程不包含初始化
⼀般合約帳⼾都會需要⼀個初始化的步驟,在帳⼾部署時同步寫⼊帳⼾擁有者的信息(例如公鑰或地址),避免部署步驟被搶跑(Frontrun)導致失去帳⼾擁有權。這通常是由部署合約帳⼾的 Factory 合約來執⾏「部署+初始化」,但因為 EIP-7702 是直接變化,⽽不是由⼀個 Factory 來部署合約到 EOA 身上,所以攻擊者可以抄⾛用戶的變身籤名並搶先發送交易上鏈去替用戶變身但將帳⼾初始化為攻擊者可控制的,因此開發者需要留意 EIP-7702。可能的防範⽅法例如在初始化函式內檢查 EOA 帳戶的籤名,如此即便被搶跑,攻擊者也沒辦法產⽣該 EOA 帳戶的籤章來完成初始化。
5. 錢包要把關變化的請求
錢包需要替用戶做好把關,在惡意的 DApp 網站請求用戶籤⼀個變身的交易時把請求攔下來並警告用戶,否則如果用戶籤了惡意的變身交易,將導致資產瞬間被轉⾛。以下是⼀些變身合約的實作示例:
-
Modified Safe Ithaca Account
-
Ithaca Account
DApp 技術協議
EIP-2537: BLS12-381 曲線操作預編譯
讓基於 BLS 曲線的零知識證明應用的成本降低,變得更可⾏。
EIP-2537 新增數個預編譯合約(Precompile)來提供便宜的 BLS 曲線運算,如此基於 BLS 曲線來開發零知識證明的應用將變得更可⾏。
EIP-2935: 在 State 中保存歷史區塊哈希值
讓開發者或節點可以直接從系統合約的 Storage 中讀取過去內存塊的雜湊值(Block Hash)。
如果開發者需要證明某個以前內存塊的內容,例如假設 Optimismtic Rollup 的欺詐挑戰中要證明 1000 個以前的內存塊存在某筆交易,挑戰者沒辦法直接說。
「請相信我 1000 個內存塊以前真的存在這筆交易」,他必須要提出證據,但沒有⼀個直接的證據可以直接證明「1000 個以前的內存塊裡包含這些內容」,因此他必須以內存塊「鏈」的⽅式,⼀個內存塊⼀個內存塊往前證明,直到達到 1000 個以前的內存塊,然後再證明該內存塊裡存在該筆交易。
△ 每一個區塊都會指向一個母區塊,所以可以一路往前證明歷史中的任何一個區塊。
假設目前是編號為 10000 的內存塊,⽽詐欺挑戰要提供編號 9000 的內存塊存在某⼀筆交易 X 的證明,則挑戰者需要從內存塊 10000 的哈希值開始,先證明內存塊 10000 所連接的母內存塊 9999 的哈希值,然後再證明內存塊 9998…直到內存塊 9000,最後再提出內存塊 9000 的內容裡包含該筆交易 X。
EIP-2935之後,會有⼀個系統合約(部署在0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC),它的 Storage 會儲存最多 8192 個以前的內存塊的哈希值。每當⼀個新的內存塊產⽣時,這個系統合約就會自動更新,將前⼀個內存塊的哈希值寫進系統合約中(會複寫掉 8192 個以前的內存塊的哈希值)。
如此在 Optimismtic Rollup 欺詐挑戰的例⼦中,挑戰者就不必再往前⼀個內存塊⼀個內存塊慢慢證明,⽽是可以直接證明內存塊 10000 當下的鏈的狀態中,該系統合約的某⼀個 Storage(對應到內存塊 9000)的值是內存塊 9000 的哈希值。如果範圍超過 8192,例如內存塊 1000,那頂多就是多⼀步,先證明內存塊 1808(= 10000 – 8192)的哈希值,然後再證明內存塊 1808 當下的鏈的狀態中,系統合約裡的內存塊 1000 的哈希值。
這也為未來的無狀態客⼾端(Stateless Client)鋪路:未來的輕節點就不需要再儲存著歷史中所有的內存塊的頭文件(Block Header),⽽是當有需要用到歷史中某個內存塊的哈希值或是內存塊內容時,再請其他⼈用前面欺詐挑戰例⼦中的證明⽅式提供證明即可。
EIP-7623: : 增加 calldata 成本
調高利用 calldata 來發布數據的成本,以挪出⾜夠的安全空間來調高 Block Gas Limit 和 Blob 數量。
隨著 Rollup 的數據發布需求越來越高,在 EIP-4844 中引⼊ Blob 來讓 Rollup 以非常便宜的⽅式放數據之後,調⾼ Blob 數量便⼀直是社群所期待的⼀個升級,或像是最近社群在推動的調高 Block Gas Limit,都反應⽣態對提高資源的需求。
△ 越來越多的驗證者表示支持調高 Block Gas Limit。
但不管是調⾼ Block Gas Limit 或是 Blob 數量,都會因為交易的數據量變得更大而對 Ethereum 的 p2p 網絡造成更多壓⼒,這會使得攻擊者攻擊的效率提⾼,除非將發布數據的成本也提⾼。
EIP-7623 協議發布之後,calldata 的成本將會從原本的「Zero Byte: 4 Gas、Non-Zero Byte: 16 Gas」調⾼ 2.5倍為「Zero Byte: 10 Gas、Non-Zero Byte: 40 Gas」。
原本如果攻擊者將全部的 Block Gas Limit(30M)都拿來放垃圾數據的話,內存塊的數據⼤小約會是 1.79 MB(30M / 16),相比於平均內存塊⼤小只有約 100 KB;而如果 Block Gas Limit 調⾼到 40M 的話,攻擊者可以產⽣約 2.38 MB大小的內存塊。當 calldata 成本調高為 2.5 倍,攻擊者的效率會因此下降,變為 30M 最⼤ 0.72MB、40M 最⼤ 0.95MB,如此就可以更放⼼地調高 Block Gas Limit 和 Blob 數量。不過這個技術協議也不想因此影響到「不是將 calldata 拿來發布數據」的⼀般用戶,所以它會以兩種⽅式計算交易的總 Gas 用量,再取較高的:
-
原本的交易 Gas 用量計算⽅式,搭配舊的calldata成本來計算:也就是將 calldata 以「Zero Byte: 4 Gas、Non-Zero Byte: 16 Gas」的⽅式計算,並加上交易執⾏所消耗的 Gas 及部署合約所消耗的 Gas。
-
單純計算 calldata Gas 用量,但是是用新的成本來計算:也就是將 calldata 以「Zero Byte: 10 Gas、Non-Zero Byte: 40 Gas」的⽅式計算,但不計入執⾏所消耗的Gas或部署合約所消耗的 Gas 所以對⼀般「不是將 calldata 拿來發布數據」的用戶來說(例如去 Uniswap 兌換),本來主要的Gas 消耗就是在執⾏的部分,即便 calldata 以新的成本計算也不會超過執⾏所消耗的Gas,因此⼀般用戶將不會受影響。
真正受影響的會是規模還小的 Rollup,因為 Blob 是固定⼤小、固定費用,所以小 Rollup 使用 Blob 效率低,使用 calldata 還比較划算,但在 EIP-7623 之後,等於這些小 Rollup 的成本都會提升 2.5 倍,它們可能得因此轉為使用 Blob 或想辦法聯合起來共同分擔⼀個 Blob。
EIP-7691: 增加 Blob 吞吐量
提⾼ Blob 數量,增加更多資料發布的空間給Rollup。
EIP-7691 將 Blob 的數量由「目標:3 Blob,上限:6 Blob」調⾼為「目標:6 Blob、上限:9 Blob」,增加更多資料發布的空間給 Rollup。
註:另外 Blob ⼿續費市場還有⼀些設計需要微調,例如⼿續費調整的速度不夠即時及⼿續費底限太低,但這不在這個技術協議要解決的問題裡。
其他技術協議
EIP-7549: 將 committee 索引移至驗證之外
調整驗證者投票的內容,讓選票更⽅便被聚合起來,降低 p2p 網絡的壓⼒。
驗證者們每個 Epoch 都會被隨機分到⼀組⼀組的委員會(Committee)並對
內存塊投票,每個委員會的驗證者們的選票可以被聚合在⼀起,如此可以降低選票在 p2p 網絡中傳遞的數量,但驗證者的選票裡會包含「該驗證者屬於第幾個委員會」的信息,這導致不同委員會的選票不能被聚合在⼀起,即便他們都對相同的內存塊投票。
EIP-7549 將「該驗證者屬於第幾個委員會」的信息移出投票內容,使得不同委員會的驗證者在投票內容⼀樣的情況下可以被聚合在⼀起,進⼀步降低選票在 p2p 網絡中傳遞的數量,降低 p2p 網絡的壓⼒。
EIP-7840: 在 EL 配置文件中添加 Blob 計劃
在執行層為 Blob 參數建立⼀份設定檔,省去執行層節點要去詢問共識層節點 Blob 相關參數的麻煩。
Blob 相關參數目前都是儲存在共識層節點,但執行層節點在某些情況還是需要這些參數(例如 RPC eth_feeHistory),所以都必須去向共識層節點詢問。
EIP-7840 在執行層為 Blob 相關參數建立⼀份設定檔,執行層節點都可以直接透過這份設定檔讀取 Blob 相關參數,不需要再向共識層節點詢問。