本文轉載自 https://medium.com/taipei-ethereum-meetup/ethereum-pectra-eips-introduction-1f90f4ea25d5 ,部分字詞有修訂。
Pectra 包含 11 個 EIP,它們分別是:
- EIP-2537: Precompile for BLS12–381 curve operations
- EIP-2935: Save historical block hashes in state
- EIP-6110: Supply validator deposits on chain
- EIP-7002: Execution layer triggerable exits
- EIP-7251: Increase the MAX_EFFECTIVE_BALANCE
- EIP-7549: Move committee index outside Attestation
- EIP-7623: Increase calldata cost
- EIP-7685: General purpose execution layer requests
- EIP-7691: Blob throughput increase
- EIP-7702: Set EOA account code
- EIP-7840: Add blob schedule to EL config files
質押(Staking)相關 EIP
EIP-6110: Supply validator deposits on chain
簡化使用者參與質押的處理流程,讓等待時間大幅縮短
使用者參與質押的方式是在 EL 上透過一個 Deposit 合約存入 32 ETH 並由事件日誌(Event Log)記錄,接著 CL 節點會去解析 EL 區塊裡的 Deposit 合約的 Event Log 來判斷是否有人質押並登錄其質押資料,然後質押的使用者就可以成為驗證者。
不過 CL 驗證者們首先要針對哪一個時間點的 Deposit 去解析達成共識,否則會發生有些驗證者看到有 5 個新的 Deposit,而有些驗證者只看到 3 個,因此 CL 驗證者們會對「要參考哪一個 EL 區塊(稱為 eth1data)」進行投票,確保大家看到的是一樣的 EL 區塊。不過一開始設計時為了避免 EL 出現重大錯誤導致鏈分叉,所以參考的 eth1data 會是一個約 10 多個小時以前的 EL 區塊,確保當重大錯誤發生時,CL 的開發者們有足夠的時間反應。不過這也導致現在參與質押最快也要等上 10 多個小時才會生效。
△ CL 區塊 10900000 裡的 eth1data,它裡面記載的 Block Hash 是 EL 區塊 21683339,出現在它 10 個小時以前
EIP-6110 之後,使用者在 Deposit 合約上的質押資料會直接變成 EL 區塊的一部分。而因為 CL 區塊本身就會包含 EL 區塊(但不是 eth1data),所以 CL 驗證者們就不用再煩惱「要確認參考的 EL 區塊是一樣的」的問題,只要 CL 區塊獲得超過 2/3 驗證者們投票並 Finalized,就可以相信大家看到的是同一個 EL 區塊。因此使用者參與質押後,最快約 13 分鐘等 EL 區塊 Finalized 之後就可以生效,而且 CL 客戶端也可以移除原本用來處理質押資料相關的複雜邏輯。
EIP-7002: Execution layer triggerable exits
改善驗證者退出質押或提領押金和收益的流程,降低驗證者的風險
當一個使用者參與質押,他需要有兩把鑰匙:(1) Validator Key 及 (2) 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 合約去發起請求時要附上手續費(ETH),手續費會按照當前的提領請求數量計算,如果請求數量很多,手續費就會上升。
- 如果使用者的 Withdrawal Credential 是一個合約的話,那可以先去 Withdraw 合約取得當前手續費金額,然後再發起請求並附上手續費;但如果 Withdrawal Credential 是一個 EOA 的話,就沒辦法取得精準的手續費,只能事先鏈下模擬並付超額手續費(不會退還),確保請求發起會執行成功。
註:如果你的 Withdrawal Credential 還是 BLS 公鑰格式,記得要先進行切換,將它換成 EL 地址的格式。
EIP-7251: Increase the MAX_EFFECTIVE_BALANCE
大幅提高質押金額上限來減少驗證者數量,且未達上限的驗證者可以自動享受複利
使用者質押成為驗證者要提供 MAX_EFFECTIVE_BALANCE 數量的 ETH,不能更少也不能更多(目前 MAX_EFFECTIVE_BALANCE 是 32 ETH)。如果你有 1024 ETH 要質押,你要自己分 32 次質押、啟用 32 個驗證者,運行 32 個驗證者節點。而大家積極參與質押也導致目前已有約 1M 個驗證者並持續增加,這除了讓 CL 的狀態資料變得更大更多,對 CL p2p 網路層的負荷更為顯著,因為每一個 Slot(每 12 秒)都有數萬個驗證者的簽名要在 p2p 網路層裡不斷傳遞並聚合。
EIP-7251 之後,質押下限(MIN_ACTIVATION_BALANCE)仍然是 32 ETH,但上限(MAX_EFFECTIVE_BALANCE)大幅調高為 2048 ETH,你可以質押 32~2048 之間任何數量的 ETH,而且只要沒有達到上限,你都會自動享受到複利,不需要再像原本要主動操作才能獲得複利的效果,不再需要定期取出收益、累積 32 ETH 後再繼續新質押。
目前已存在的驗證者也不需要特別先退出質押再合併一起重新加入質押,而是可以直接利用 EL 上新增的「合併押金用的合約」(部署在 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: General purpose execution layer requests
建立一個正式的 EL -> CL 訊息管道,方便使用者及質押服務能直接送出請求給 CL
讓使用者能直接從 EL 送請求給 CL,質押服務(例如 Lido)就可以以更去中心化的方式運行,例如前面提到的 EIP-7002 的退出質押的請求,以及 EIP-7251 的合併押金的請求。如果沒有這個 EIP,那 Lido 使用者就必須要相信 Lido 節點服務提供商會如實在 CL 去執行退出質押或是合併押金;有了這個 EIP,Lido 使用者就可以在 EL 上直接透過治理合約去送出請求,不需相信 Lido 節點服務提供商。
這些請求會有 Request Type 來區分不同類型的請求,以及透過不同合約發起請求,最後這些請求都會被寫入到 EL 區塊裡,因此 CL 可以直接透過 EL 區塊獲得這些資訊,不必再寫個別的解析邏輯。
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
EIP-7702: Set EOA account code
讓 EOA 帳戶能任意變身成合約帳戶,大幅提升使用體驗
EOA 帳戶有不少缺點:
- 需要記錄和保管私鑰或助記詞,提高新使用者的 Onboarding 門檻。
- 一筆交易只能執行一個操作,例如要去 Uniswap 將 USDT 兌換為 ETH,要先發起一筆交易 Approve 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 網站請求使用者簽一個變身的交易時把請求攔下來並警告使用者,否則如果使用者簽了惡意的變身交易,將導致資產瞬間被轉走。
以下是一些變身合約的實作範例:
DApp 開發者相關 EIP
EIP-2537: Precompile for BLS12–381 curve operations
讓基於 BLS 曲線的零知識證明應用的成本降低,變得更可行
EIP-2537 新增數個預編譯合約(Precompile)來提供便宜的 BLS 曲線運算,如此基於 BLS 曲線來開發零知識證明的應用將變得更可行。
EIP-2935: Save historical block hashes in state
讓開發者或節點可以直接從系統合約的 Storage 中讀取過去區塊的雜湊值(Block Hash)
如果開發者需要證明某個以前區塊的內容,例如假設 Optimismtic Rollup 的詐欺挑戰中要證明 1000 個以前的區塊存在某筆交易,挑戰者沒辦法直接說「請相信我 1000 個區塊以前真的存在這筆交易」,他必須要提出證據,但沒有一個直接的證據可以直接證明「1000 個以前的區塊裡包含這些內容」,因此他必須以區塊「鏈」的方式,一個區塊一個區塊往前證明,直到達到 1000 個以前的區塊,然後再證明該區塊裡存在該筆交易。
△ 每個區塊都會指向一個母區塊,所以可以一路往前證明歷史中的任何一個區塊。source
假設目前是編號為 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: Increase calldata cost
調高利用 calldata 來發佈資料的成本,以挪出足夠的安全空間來調高 Block Gas Limit 和 Blob 數量
隨著 Rollup 的資料發佈需求越來越高,在 EIP-4844 引入 Blob 來讓 Rollup 以非常便宜的方式放資料之後,調高 Blob 數量便一直是社群所期待的一個升級,或像是最近社群在推動的調高 Block Gas Limit,都反應生態對提高資源的需求。
△ 越來越多驗證者示意支持調高 Block Gas Limit。source
但不管是調高 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.72 MB、40M 最大 0.95 MB,如此就可以更放心地調高 Block Gas Limit 和 Blob 數量。
不過這個 EIP 也不想因此影響到「不是將 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 throughput increase
提⾼ Blob 數量,增加更多資料發佈的空間給Rollup
EIP-7691 將 Blob 的數量由「目標:3 Blob、上限:6 Blob」調高為「目標:6 Blob、上限:9 Blob」,增加更多資料發佈的空間給 Rollup。
註:另外 Blob 手續費市場還有一些設計需要微調,例如手續費調整的速度不夠即時及手續費底限太低,但這不在這個 EIP 要解決的問題裡,更多資訊可以參考這篇分析文章。
其他技術協議
EIP-7549: Move committee index outside Attestation
調整驗證者投票的內容,讓選票更方便被聚合起來,降低 p2p 網路的壓力
驗證者們每個 Epoch 都會被隨機分到一組一組的委員會(Committee) 並對區塊投票,每個委員會的驗證者們的選票可以被聚合在一起,如此可以降低選票在 p2p 網路中傳遞的數量,但驗證者的選票裡會包含「該驗證者屬於第幾個委員會」的資訊,這導致不同委員會的選票不能被聚合在一起,即便他們都對相同的區塊投票。
EIP-7549 將「該驗證者屬於第幾個委員會」的資訊移出投票內容,使得不同委員會的驗證者在投票內容一樣的情況下可以被聚合在一起,進一步降低選票在 p2p 網路中傳遞的數量,降低 p2p 網路的壓力。
EIP-7840: Add blob schedule to EL config files
在 EL 層為 Blob 參數建立一份設定檔,省去 EL 節點要去詢問 CL 節點 Blob 相關參數的麻煩
Blob 相關參數目前都是儲存在 CL 節點,但 EL 節點在某些情況還是需要這些參數(例如 RPC eth_feeHistory),所以都必須去向 CL 節點詢問。
EIP-7840 在 EL 層為 Blob 相關參數建立一份設定檔,EL 節點都可以直接透過這份設定檔讀取 Blob 相關參數,不需要再向 CL 節點詢問。