10 月 12 日這一天,Hoodi 的 Glamsterdam 排程在 UTC 00:45 到 18:21 之間一口氣合進四個客戶端(Nethermind、Lighthouse、Besu、Reth),Lodestar 同日 13:02:48 UTC 發出第一個含 Hoodi 時間戳的穩定版 v1.50.0;承 昨天的區塊鏈,昨天 10 月 11 日 23:30 UTC 的記分板是執行層 0/6、共識層 4/6,我今天 10 月 12 日 23:01 UTC 重讀是執行層 3/6、共識層 5/6。同一天的第 100 次測試電話會議(ACDT)還做了一個昨天沒人預期的決定:EIP-8045(把被罰沒的驗證者排除在出塊者之外)被發現有一個「自己罰沒自己來重抽出塊者」的操縱槓桿,會議決定不在 Glamsterdam 修,留到下一個分叉。這個槓桿我自己用共識規格的原始碼寫了模擬,下面有數字;另外順手驗算了會議上 jochem 說的「最壞區塊在 500 MB/s 的磁碟上要跑 8 秒」,用 EIP 裡的參數推得 8.74 秒,吻合。

📖 學

一、24 小時記分板:四筆合併、一個穩定版

資料用 GitHub API(gh api)在 10 月 12 日 23:01 UTC(台北 10 月 13 日 07:01)讀取。分叉時間 10 月 26 日 17:42:48 UTC(時間戳 1793036568,epoch 132352),下表「距分叉」是自己算的。

項目狀態合併/發布時間(UTC)距分叉
Nethermind 第 14489 號 PR已合併10/12 00:45:2014.707 天
Lighthouse 第 10304 號 PR已合併,僅 1 個檔案(+8 -1)10/12 04:53:4014.534 天
Besu 第 11531 號 PR已合併10/12 06:32:2414.466 天
Lodestar v1.50.0(穩定版)發布10/12 13:02:4814.194 天
ACDT 第 100 次(預定時間)開會10/12 14:0014.155 天
Prysm 第 17662 號 PR(清除被罰沒提案者的待付款項)已合併10/12 17:25:2514.012 天
Reth 第 27811 號 PR已合併10/12 18:21:2613.973 天
Ethrex 第 7391 號 PR仍 open,10/9 後無更新
Geth、Erigonhoodi.json 仍只到 bpo2Time,我用 PR 搜尋沒找到相關 PR
Grandine搜尋沒找到 Hoodi 排程 PR

幾個細節值得記下:

Lodestar v1.50.0 確實含 Hoodi。 我用 compare/<第 10313 號 PR 的合併 commit>...v1.50.0 比對,狀態是 ahead、領先 26 個 commit;預發布 v1.50.0-rc.0(10 月 9 日 21:44 UTC)也是 ahead(25 個)。所以 rc.0 在發布前就含 Hoodi 排程,穩定版比 rc.0 晚 2.64 天。第 10313 號 PR 的標題是「排程 Gloas 並設 2 億 gas limit」,合併於 10 月 8 日 20:31:57 UTC,到穩定版 3.69 天(自算:10/8 20:31:57 到 10/12 13:02:48)。這比我昨天用 Sepolia 算出的「合併到穩定版」中位數 6.61 天快。

Reth 昨天的相依問題已解。 昨天我記錄這個 PR 是草稿,靠 [patch.crates-io] 指向上游 alloy-hardforks 的 git commit。今天的版本 Cargo.toml 只改 1 行,PR 本文寫「把 alloy-hardforks 升到 0.4.10,其中含上游第 108 號 PR」,所以上游已發布,不再靠 git 補丁。PR 本文還寫了一個驗算,我自己重算:1742213400 + 132352 × 32 × 12 = 1793036568,其中 132352 × 32 = 4,235,264(分叉的 slot),× 12 = 50,823,168 秒,加上 Hoodi 信標鏈創世時間 1742213400,得到 10 月 26 日 17:42:48 UTC,完全一致。(創世時間 1742213400 是從 PR 本文讀來的,我沒獨立查。)

Prysm 的兩個 PR 只動了一個。 第 17662 號(12 個檔案,+148 -239)合併進 develop;第 17664 號「把共識規格升到 v1.7.0-beta.4」仍 open,且它的 base 不是 develop 而是一個疊加用的分支 builder-sweep-balance-after-withdrawals,規模 33 個檔案、+1831 -984,10 月 12 日 21:32 UTC 還有更新。也就是說這個 PR 要先等它底下那個分支進 develop,我沒查底下那個分支的狀態。

把昨天與今天的記分板併排(昨天資料取自昨天文章的 10 月 11 日 23:30 UTC 快照):

昨天今天
共識層已合併 Hoodi 時間戳4(Lodestar、Teku、Nimbus、Prysm)5(加 Lighthouse),Grandine 仍無
執行層已合併03(Nethermind、Besu、Reth)
含 Hoodi 時間戳的穩定版01(Lodestar v1.50.0)
執行層未合併6Geth、Erigon、Ethrex

距離 10 月 16 日 23:59:59 UTC 的發布期限還有 4 天 0 小時 58 分 50 秒(自算),期限距分叉 9.738 天。10 月 15 日 14:00 UTC 的第 189 次共識層電話會議(ACDC)議程只有三行:Glamsterdam、Hegotá(其中一項是吉祥物)、以及「硬分叉流程與敏捷性」,議程本文沒有寫 Hoodi 發布細節。

昨天預測的結算(都還沒到期,先記現況):

  • 預測一(共識層穩定版不超過 3 個):現況 1 個(Lodestar)。Lighthouse 最新穩定版仍是 v8.2.3(10/1),Teku 26.10.0(10/8 22:05 UTC)發布時間早於它的 Hoodi 合併,所以兩者都不含;Nimbus v26.10.0(10/4)、Prysm v7.2.1(10/5)同樣早於各自的合併。要超過 3 個,需要再有 3 個穩定版在 4 天內出現。
  • 預測二(Geth 的 hoodi.json 在期限前出現 amsterdamTime):今天讀還是沒有。
  • 預測三(Prysm 第 17662 與 17664 號都合併):17662 已合併,17664 未合併,算一半。
  • 預測四(Lighthouse 或 Grandine 至少一個合併 Hoodi 時間):已成立,Lighthouse 10 月 12 日 04:53:40 UTC。
  • 預測五(10 月 23 日前 Hoodi 日期不變):eth-clients/hoodi 的 metadata/genesis.json 仍是 amsterdamTime: 1793036568;ethereum/pm 的第 2263、2266 號 PR 仍 open,最後更新在 10 月 8 日。

二、ACDT 第 100 次:一個決定、一個爭議

會議逐字稿放在 ethereum/forkcast 的 public/artifacts/acdt/2026-10-12_100/,我讀了 tldr.json 與 transcript_corrected.vtt 中與下面兩件事相關的段落。逐字稿是 AI 校正版,我沒有對照影片。會議前半是例行:devnet 上 Nimbus、Erigon、Besu、Lighthouse、Grandine 的節點離線,請各隊檢查;Sepolia 分叉後一週「非常穩定」,每個節點營運者都升級成功,偶有少數漏塊,參與率接近 100%;Stefan 啟動了第二版 jochemnet 影子分叉(分叉後狀態、含 64 KB 合約,用來做基準),第一版測出多個客戶端在快照同步時選錯頭的穩定性問題。Hoodi 的部分,主持人 Justin Traglia 重申發布期限是 10 月 16 日週五,Alex Stokes 在寫部落格文章、預計當天發布,各隊發布後要通知他,並點名 Lodestar 已發。這和上一節的資料一致。

接著是一個我認為今天最有學習價值的議題:提案者選擇(proposer selection)的重抽問題。主持人說這是「過去 24 小時內冒出來的」,Barnabas Busa 說是在 ETH R&D 收到的回報,而且他認為是真問題。同一天他開了兩個共識規格 PR(第 5733 號、第 5734 號),PR 本文把機制寫得很清楚,我對照規格原始碼讀過一遍,下一節完整拆解。會議上的結論記錄在 tldr.json 的決議欄:「提案者選擇的缺陷延到 Hegotá(或更晚),Glamsterdam 不修」。逐字稿裡的理由有三層,我照原話歸類:

  1. 相容性: Justin 說,若現在改,Sepolia(已經在 10 月 6 日跑 Gloas)很快就會壞,而且得維護兩套實作。
  2. 客戶端工程: Nimbus 的 Dustin 說絕不接受「分叉」「三叉」發布,只修主網是行不通的:「主網版或 Hoodi 版,Nimbus 就是一個版本,結束」。Barnabas 提過一個折衷:只要測試網沒發生罰沒事件,就不會觸發差異,Sepolia 節點可以另外更新;但他也承認這在 Hoodi 上不成立。
  3. 嚴重性: 利用者必須罰沒自己才做得到、好處有限;Barnabas 甚至說「我不確定 Hegotá 要不要修,它大概永遠不會發生」。他希望週四再做最終決定,但 Justin 指出客戶端發布在週五前,太晚。最後 Justin 問大家能否同意推到下一個分叉,沒有人反對。

我需要誠實標註的邊界:逐字稿有 AI 校正,「沒有人反對」是我從逐字稿沒有出現反對聲音推得的,不是官方宣告。

三、自己拆:為什麼自己罰沒自己可以重抽出塊者

先把規格講清楚(以下來自 consensus-specs 主分支的 specs/fulu/beacon-chain.md 與 specs/gloas/beacon-chain.md,我今天直接讀了原始碼)。

出塊者名單怎麼算。 Fulu 的 EIP-7917 讓信標狀態存一個 proposer_lookahead,裡面是未來幾個 epoch 的出塊者。每個 epoch 結束時,process_proposer_lookahead 把最前面一個 epoch 移出,並為「目前 epoch 加 MIN_SEED_LOOKAHEAD(= 1)再加 1」,也就是第 k + 2 個 epoch,算新的 32 個出塊者。種子來自 get_seed(state, epoch, DOMAIN_BEACON_PROPOSER),它取的 RANDAO 混合值在 epoch + EPOCHS_PER_HISTORICAL_VECTOR − MIN_SEED_LOOKAHEAD − 1 的位置,換算下來就是第 k 個 epoch 的混合值。第 k 個 epoch 的最後一個區塊(第 31 個 slot)是對這個混合值最後一次貢獻 RANDAO 揭露的人,所以他在發出區塊之前就知道最終的種子。這件事本來就存在,PR 本文稱為「發布或扣住區塊」的選擇,每個 epoch 對應兩種可能的種子。

每個 slot 怎麼抽。 對 32 個 slot 各算一個子種子 sha256(seed + slot),再呼叫 compute_balance_weighted_selection(…, size=1, shuffle_indices=True):反覆取 i = 0, 1, 2, …,把 i % total 經 compute_shuffled_index(·, total, seed) 洗牌,得到候選者,以「有效餘額 / 2048 ETH」的機率接受。32 ETH 的驗證者每次被接受機率 1/64(自算:32 × 65535 / 2048 = 1023.98,隨機值是 16 位元,所以接受機率是 1024/65536 = 1/64)。total 就是候選名單的長度。

EIP-8045 改了什麼。 Gloas 的 get_beacon_proposer_indices 在算名單前先濾掉 slashed 為真的驗證者,所以 total 變成「活躍且未被罰沒」的人數。這個過濾動機本身合理:被罰沒者的區塊在狀態轉換裡本來就無效,選到他們只會多一個漏塊(我讀了 EIP-8045 的動機段)。

問題在這裡。 compute_shuffled_index 是「swap-or-not」洗牌,90 輪,每一輪的樞紐(pivot)是 hash(seed + 輪數) % total。total 只要差 1,每輪的樞紐都換,整個排列完全不同。所以,**只要有任何一個被罰沒的驗證者還在活躍集合裡,新算的 epoch 的 32 個出塊者就會全部重排。**PR 本文說的攻擊流程:第 k 個 epoch 最後一個 slot 的出塊者,看得到最終種子,他可以在自己的區塊裡放入對自己(或自己另一把金鑰)的罰沒證明。罰沒在區塊處理時生效,隨後 epoch 結束才算第 k + 2 個 epoch 的名單,這時 total 已經少了他罰沒的人數。罰沒 0 個、1 個、2 個……每一個「不同的罰沒個數」就是一次重抽,疊加在原有的「發布或扣住」上。

被罰沒的人為什麼還在名單裡? 我讀了 compute_activation_exit_epoch:epoch + 1 + MAX_SEED_LOOKAHEAD,而 MAX_SEED_LOOKAHEAD = 4。罰沒會呼叫 initiate_validator_exit,所以被罰沒者的退出 epoch 至少是第 k + 5 個 epoch,在第 k + 2 個 epoch 仍然算「活躍」。這是 PR 本文「只要有任何被罰沒者還活躍就不相容」這句話的背景,我的推論是:這個機制讓 EIP-8045 的過濾在名單計算那一刻確實會改變 total。

我的驗證 1:洗牌確實會整個重排。 我把規格的 compute_balance_weighted_selection 與 90 輪洗牌用 Python 重寫(約 60 行),取 10 萬個全是 32 ETH 的驗證者,隨機種子 24 組,每組比較「罰沒 0 個」與「罰沒 1、2、5、10、20 個隨機驗證者」下 32 個 slot 的出塊者。依 EIP-8045 原本的做法(先過濾),5 種罰沒個數 × 24 組種子,新舊名單相同的 slot 數全是 0 / 32(也就是每個 slot 都換人)。這些被罰沒者本來並不是出塊者(基準名單裡屬於被罰沒集合的 slot 平均 0.000 個),所以那些重排完全不是因為「被罰沒者的 slot 被取代」。

我的驗證 2:PR 5733 的做法只動該動的。 該 PR 改成「保留所有活躍驗證者為候選,抽到被罰沒者就拒絕、繼續抽下一個」。同樣的 24 組種子與罰沒個數,相同 slot 數都是 32 / 32。再做一個強制測試:把基準名單裡第 5 個 slot 的出塊者罰沒,12 組種子,每一組都只有第 5 個 slot 被換人,其餘 31 個不變(對照原做法:0 個不變)。這與 PR 本文「罰沒只重新分配被罰沒者本來會拿到的 slot」一致。

重抽有多少價值? 這和攻擊者持股比例 f 有關。為了不用推導,我直接模擬:10 萬個 32 ETH 驗證者,攻擊者控制 5000 個(f = 5%),每次試驗讓攻擊者依序罰沒自己的前 c 個驗證者(c = 0 到 15,共 16 個不同的 total),記錄第 k + 2 個 epoch 裡仍屬於攻擊者且未被罰沒的 slot 數,共 150 次試驗。

  • 單次抽樣的分布:2400 筆樣本平均 1.58 個 slot(二項分布 32 × 0.05 = 1.6);0 到 4 個 slot 的經驗機率 18.4%、33.9%、26.9%、14.4%、5.1%,二項分布是 19.4%、32.6%、26.6%、14.0%、5.3%。夠接近,所以把每個 total 當成一次獨立的二項抽樣是合理的近似。
  • 抽到「至少 3 個 slot」的機率:不重抽 21.3%(解析值 21.4%);最多重抽到 c = 3(4 次) 62.0%(獨立假設的解析值 61.8%);c = 7(8 次)84.0%(85.4%);c = 15(16 次)96.0%(97.9%)。
  • 抽到「至少 4 個」:不重抽 6.0%(解析 7.4%);4 次 20.7%(26.4%);8 次 35.3%(45.8%);16 次 62.0%(70.7%)。
  • 抽到「至少 5 個」:0.7%(2.0%);5.3%(7.9%);10.0%(15.2%);16.0%(28.0%)。
  • 「最好的那一次」的平均 slot 數:不重抽 1.64,4 次 2.83,16 次 3.81。

尾端的經驗值比獨立假設低一截(例如 16 次、至少 5 個:經驗 16.0% 對解析 28.0%)。我不確定原因:可能是 150 次試驗的抽樣誤差(這個數量級的標準誤約 3 到 4 個百分點,但差 12 點超過一點),也可能是不同 total 下的排列有輕微相關(各 c 共用同一組子種子與同一串接受用的隨機值,只有洗牌不同)。所以我把解析值看成上界、經驗值看成實測下界,兩者都說明槓桿真實存在。再用解析式看其他持股比例的「最好的一次」期望 slot 數(r 是抽樣次數):f = 1% 平均 0.32,r = 8 時 1.24;f = 5% 平均 1.6,r = 8 時 3.50;f = 10% 平均 3.2,r = 8 時 5.76;f = 33% 平均 10.56,r = 8 時 14.40。

要付多少代價? 這是我最想算清楚的一項,因為決定了這個槓桿是不是「理論上有、實際上沒人會用」。讀 Electra 的常數與 Gloas 的 slash_validator:

  • MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA = 4096,罰沒的立即懲罰是 有效餘額 // 4096。32 ETH 就是 7,812,500 Gwei(0.0078125 ETH)。
  • WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA 同樣 4096,檢舉獎勵 = 有效餘額 // 4096 = 7,812,500 Gwei。slash_validator 把其中 1/8(PROPOSER_WEIGHT/WEIGHT_DENOMINATOR = 8/64)給出塊者、其餘給檢舉者,而檢舉者預設就是出塊者。我逐 Gwei 算:976,562 + 6,835,938 = 7,812,500。所以出塊者自己罰沒自己的驗證者,在該區塊裡立即損益剛好是 0。(前提:區塊含罰沒時出塊者與檢舉者都是攻擊者本人。)
  • 剩下的代價是長期的:被罰沒者的 withdrawable_epoch 至少是 epoch + EPOCHS_PER_SLASHINGS_VECTOR(8192 個 epoch = 36.41 天),期間資金鎖住、不再賺獎勵。我假設年化報酬 2.5% 到 3%(假設值,不是查到的),機會成本是 32 × 0.025 到 0.03 × 36.41/365 = 0.080 到 0.096 ETH 每個驗證者。
  • 相關性罰沒(在 withdrawable_epoch − 4096 時依總罰沒量比例扣):以 c = 15 個 32 ETH 為例,sum(state.slashings) 乘 3 約 1,440 ETH,若全網活躍餘額不低於 1,000 萬 ETH(我假設,沒查現況),每個被罰沒者約再扣不到 0.005 ETH。

我的結論是推論,不是定論:**每增加一次重抽,成本是「一個驗證者被鎖 36 天的機會成本,約 0.1 ETH 的量級」,而不是被罰沒的重懲罰。**這個成本相對多拿到幾個出塊 slot 的好處是大還是小,取決於出塊 slot 的價值(優先費、MEV、連續出塊的組合價值),我沒有可靠的當前數字,所以不下判斷,也不是投資評論。這也能解釋會議上「好處有限」與「不會發生」的看法與 PR 作者「這是真問題」的看法為什麼並存:兩邊對成本的看法其實相近(都承認要先罰沒自己),分歧在於攻擊者願意付 0.1 ETH 的量級去換什麼。

**再補一條規範面的觀察。**EIP-8045 目前狀態是 Last Call,截止日 2026-11-01(我讀了 EIP 檔頭)。它的「設計決定」段落寫過「先過濾」與「抽到才拒絕」兩種做法「選擇結果不完全相同,但達成同樣目標,複雜度都低」,最後選了前者。「安全考量」段說「罰沒不影響既有的 proposer_lookahead」,這句話對已存好的名單是對的,但對「這一刻才算出的第 k + 2 個 epoch 名單」並不成立,漏洞就在這一句沒涵蓋的縫隙。這是我的閱讀。第 5733 號 PR 已關閉未合併,第 5734 號(把同樣修法放進 Heze 規格,specs/heze/beacon-chain.md +163 行)仍 open;兩個 PR 本文都寫了作者在最小預設的 devnet(Gloas 從創世開始,兩個 Lighthouse 加一個 consensoor 用舊規則、另一個 consensoor 用新規則)驗證:slot 73 放入一個提案者罰沒,在下一個 epoch 邊界 slot 80 就出現 state_root 不一致,新規則節點卡在 slot 79。這是 PR 作者的實驗,我沒有重現客戶端層級的版本,只重現了名單層級的差異。

四、順手驗算:EIP-7870 的「8 秒」

會議第二個實質議題是 jochem 提出的:EIP-7870(硬體與頻寬建議,狀態是「活文件」)目前寫的循序讀寫最低約 500 MB/s、隨機 4K 讀約 5 萬 IOPS、寫約 1.5 萬 IOPS(我讀了 EIP 本文),而 Glamsterdam 同時把合約大小上限從 24 KB 提到 64 KB(EIP-7954,Last Call)、gas limit 從 6,000 萬提到 2 億、冷帳戶存取從 2600 提到 3000(EIP-8038,Last Call)。他說用現在的最低規格,最壞的區塊要 8 秒才跑完,建議把循序速度改成 1000 或 2000 MB/s。

我用 EIP 裡的參數重算最壞情形(模型假設很強,只是量級驗算):每個帳戶冷存取花 COLD_ACCOUNT_ACCESS,假設整個 gas 預算全拿去冷存取不同的合約,每個都讀完整程式碼、不經快取:

方案可冷存取的合約數每個合約位元組總讀取量500 MB/s 需要1000 MB/s2000 MB/s
現行:6,000 萬 gas、2600、24 KiB23,07724,576約 567 MB1.13 秒0.57 秒0.28 秒
Glamsterdam:2 億 gas、3000、64 KiB66,66765,536約 4.37 GB8.74 秒4.37 秒2.18 秒

比值是 7.70 倍,可拆成 (200/60) × (2600/3000) × (65536/24576) = 3.333 × 0.8667 × 2.667(自算)。8.74 秒與 jochem 說的「8 秒」同一量級,若把 MB 當 MiB 算是 8.33 秒,我不知道他實際用的模型,只能說這個粗估能重現他的量級。

Barnabas 在聊天室補的觀點(隨機 4K IOPS 比循序 MB/s 重要)也能量化:若每個 64 KiB 程式碼被拆成 16 次獨立的 4 KiB 隨機讀,在 5 萬 IOPS 下 66,667 個合約是 66,667 ÷ (50,000 ÷ 16) = 21.3 秒;若只是每個合約一次隨機定位再循序讀,定位就是 66,667 ÷ 50,000 = 1.33 秒,再加循序的 8.74 秒。兩個極端差一個數量級,所以「用哪個規格欄位約束」比「把數字調高」更重要,實際客戶端的讀取粒度、快取、預取我都不知道。

另一個值得記的觀察,是這種最壞區塊在主網上還不存在:今天鏈上合約不超過 24 KiB,要準備 66,667 個 64 KiB 的不同合約得先部署。在 EIP-8037 之下,程式碼存放的狀態 gas 是每位元組 1,530(CPSB),64 KiB 一個合約是 65,536 × 1,530 = 100,270,080 gas,約半個 2 億 gas 的區塊;現行 24 KiB × 200 gas = 4,915,200。部署 66,667 個就是 6.69 × 10 的 12 次方 gas,約 33,424 個滿載的 2 億 gas 區塊,連續 4.64 天(自算,忽略其他成本與單筆交易上限)。所以這個 8 秒更像基準測試(jochemnet 預先填入 64 KB 合約)的設計情境,不是現在可以發動的攻擊,這是我的推論。

會議決議是 EIP-7870 保持活文件、原地更新並加分叉別的歷史小節(Łukasz 與 Pooja 的建議被採納),不另開每個分叉一個 EIP;數字改多少沒決定,等 EL 頻道討論。

五、Hegotá 側的快速記錄

同一場會議還排定了兩個 devnet(來自 tldr.json,逐字稿我只讀了片段):CL 的 heze-devnet-2 要含 EIP-7805(FOCIL)、EIP-8015(移除 eth1data)、EIP-8365(禁止 0x00 提款憑證的驗證者)、EIP-8198(縮短 slot,devnet 保持 12 秒,10 秒版延後),最晚 10 月 28 日啟動、需要至少 3 個共識層客戶端;EL 的 bogota-devnet-1 預計 10 月 15 日(週四)啟動,含 EIP-8141、8250、8272、7906,測試版標籤 v1.1.0 納入 keyed nonce 的共識改動;bogota-devnet-2 的候選有 SETCODEFROM、資料重新定價(EIP-8279)、nonce bump(EIP-8253)與停用 self-destruct。命名也改了:focil-devnet-* 改 heze-devnet-*,frames-devnet-* 改 bogota-devnet-*。這些與 Glamsterdam 的發布無關,但說明 10 月 26 日 Hoodi 與 11 月底以後主網日期之外,工程隊伍的注意力已經分到下一個分叉了。

🧠 記

  • 記分板(10 月 12 日 23:01 UTC): Hoodi 時間戳已合併,共識層 5/6(缺 Grandine)、執行層 3/6(Nethermind、Besu、Reth;缺 Geth、Erigon、Ethrex);含時間戳的穩定版 1 個(Lodestar v1.50.0,13:02:48 UTC,距分叉 14.194 天);距發布期限 4 天 0 小時 58 分,期限距分叉 9.738 天。
  • 昨天預測: 預測四(Lighthouse 或 Grandine 至少一個合併)已成立;預測三一半(Prysm 第 17662 合併、17664 未);預測一、二、五仍開著。
  • 提案者重抽: EIP-8045 先過濾被罰沒者,使 total 改變,洗牌 90 輪的樞紐都用 % total,所以任何仍活躍的被罰沒者都讓新算 epoch 的 32 個出塊者全部重排(我模擬 5 種罰沒個數 × 24 組種子,新舊相同 slot 數全是 0);第 k 個 epoch 最後一個 slot 的出塊者知道最終種子,可以用自罰沒來選擇「罰沒個數」。
  • 成本: 出塊者自己罰沒自己,立即懲罰(有效餘額 ÷ 4096)與檢舉獎勵(有效餘額 ÷ 4096)相等,淨 0;長期成本是鎖資金 8192 個 epoch(36.41 天),假設年化 2.5% 到 3% 約 0.08 到 0.096 ETH 每個驗證者。
  • 重抽價值(f = 5%): 單次平均 1.6 個 slot;至少 3 個的機率由 21.3% 隨重抽次數升到 62.0%(4 次)、96.0%(16 次);解析值是上界(獨立假設)。
  • 決議: ACDT 第 100 次決定 Glamsterdam 不修,延到 Hegotá(第 5734 號 PR,open;第 5733 號關閉);理由是 Sepolia 已在跑 Gloas,改規則會讓任何一次一般罰沒造成分叉。
  • EIP-7870: 現行最低循序 500 MB/s;我推得 Glamsterdam 最壞區塊約 4.37 GB 的程式碼讀取,500 MB/s 下 8.74 秒,1000 MB/s 下 4.37 秒,2000 MB/s 下 2.18 秒;與 jochem 的 8 秒同量級。

邊界: GitHub 資料用 gh api 讀,以 10 月 12 日 23:01 UTC 為準;「沒找到」的 Geth、Erigon、Grandine Hoodi PR 是搜尋結果,Teku 倉庫的 PR 搜尋對我的存取失敗(回傳驗證錯誤),所以 Teku 的狀態沿用昨天的紀錄,沒有今天重查。ACDT 第 100 次逐字稿是 AI 校正版,我讀了提案者選擇與 EIP-7870 兩段的全文、其餘只讀 tldr.json。模擬用的是 10 萬個全為 32 ETH 的驗證者與攻擊者 5% 的假設,不代表主網的實際分布(實際有 2048 ETH 的合併驗證者、驗證者總數也不同),只回答「機制是否成立」與「量級」,而且尾端經驗值低於獨立假設的解析值,原因不明。年化報酬、全網活躍餘額、攻擊者出塊 slot 的價值都是假設或沒查,不構成任何投資或質押建議。EIP-7870 的 8 秒驗算是自己的粗估,不是 jochem 的模型。

✍️ 實踐

全部唯讀,約 25 分鐘。

  1. 重做記分板(約 5 分鐘):
for r in NethermindEth/nethermind:14489 hyperledger/besu:11531 paradigmxyz/reth:27811 sigp/lighthouse:10304 OffchainLabs/prysm:17662; do
  repo=${r%%:*}; n=${r##*:}
  echo "$repo $n"; gh api repos/$repo/pulls/$n --jq '"\(.state) merged=\(.merged_at) \(.title)"'
done
# Lodestar 穩定版是否含 Hoodi 排程
M=$(gh api repos/ChainSafe/lodestar/pulls/10313 --jq .merge_commit_sha)
gh api repos/ChainSafe/lodestar/compare/$M...v1.50.0 --jq '{status,ahead_by}'
# Geth 是否已有 amsterdamTime
gh api repos/ethereum/go-ethereum/contents/params/chainspecs/hoodi.json --jq .content | base64 -d | grep -i time
  1. 驗算分叉時間(約 1 分鐘):python3 -c "print(1742213400 + 132352*32*12)",應得 1793036568。
  2. 自己跑一遍洗牌重排(約 10 分鐘),核心只要這一段;重點是看 total 差 1 以後,同一個種子選出的出塊者是否整串改變:
import hashlib, struct
sha = lambda b: hashlib.sha256(b).digest()
def shuffled(index, total, seed):
    pivots = [struct.unpack('<Q', sha(seed + bytes([r]))[:8])[0] % total for r in range(90)]
    for r in range(90):
        flip = (pivots[r] + total - index) % total
        pos = max(index, flip)
        src = sha(seed + bytes([r]) + struct.pack('<I', pos // 256))
        if (src[(pos % 256) // 8] >> (pos % 8)) & 1:
            index = flip
    return index
def proposer(indices, seed, eff=32 * 10**9):
    total, i = len(indices), 0
    while True:
        if i % 16 == 0:
            rb = sha(seed + struct.pack('<Q', i // 16))
        o = i % 16 * 2
        cand = indices[shuffled(i % total, total, seed)]
        i += 1
        if eff * 65535 >= 2048 * 10**9 * struct.unpack('<H', rb[o:o + 2])[0]:
            return cand
seed = sha(b"demo")
a = [proposer(list(range(100000)), sha(seed + struct.pack('<Q', s))) for s in range(8)]
b = [proposer([x for x in range(100000) if x != 777], sha(seed + struct.pack('<Q', s))) for s in range(8)]
print(a); print(b)   # 只去掉一個驗證者,兩串應幾乎全不同
  1. 讀 consensus-specs 第 5734 號 PR 的 specs/heze/beacon-chain.md 差異(約 10 分鐘),找 exclude_slashed 參數,想一想為什麼同步委員會與 PTC 的呼叫要明確傳 exclude_slashed=False。
  2. 讀 EIP-8045 的「設計決定」與「安全考量」兩段,自己判斷「罰沒不影響既有 lookahead」這句有沒有涵蓋第 k + 2 個 epoch 的新名單。

可證偽預測(沒特別註明的都在 10 月 16 日 23:59:59 UTC 到期):

  • 預測一: 含 Hoodi 時間戳的共識層穩定版(非預發布)最終是 2 或 3 個(含 Lodestar)。理由:Lodestar 已有;Teku 約每 10 到 11 天一版,下一版約 10 月 18 日;Lighthouse 最新穩定版 v8.2.3 是 10/1,合併後以中位數 6.61 天推約 10 月 18 日。若 4 個以上或只有 1 個,我的判斷錯。
  • 預測二: Geth 的 hoodi.json 在期限前出現 amsterdamTime: 1793036568。我對這條把握不高,Sepolia 上 Geth 是最快的客戶端之一,但現在已經落在 Sepolia 同距離之後。
  • 預測三: Prysm 第 17664 號 PR 在期限前合併(它依賴一個疊加分支,所以我只給中等把握)。
  • 預測四: 執行層穩定版含 Hoodi 時間戳的客戶端數量,期限前不超過 2 個(現在 0 個;Nethermind、Besu、Reth 已合併但都還沒發版)。
  • 預測五(10 月 23 日 23:59 UTC 到期): consensus-specs 第 5734 號 PR 在這之前合併進主分支;同時 Hoodi 分叉時間仍是 10 月 26 日 17:42:48 UTC(沿用)。

明天接的待辦:Geth、Erigon、Ethrex 的 Hoodi PR、Prysm 第 17664 號、Teku 與 Lighthouse 的發布、10 月 15 日 ACDC 對期限與 EIP-8045 的討論、EL 頻道對 EIP-7870 數字的決定、第 5734 號 PR。

🔗 延伸學習

💬 問 AI

我在研究 Ethereum Glamsterdam(Gloas)的提案者選擇與 EIP-8045(查證時間 2026-10-12 23:01 UTC,資料來自 consensus-specs 主分支原始碼、GitHub API 與 ethereum/forkcast 的 ACDT 第 100 次逐字稿)。以下是我自己整理的主張,請協助查證並嚴格區分來源:
 
1. 規格:process_proposer_lookahead 在每個 epoch 結束時,用 get_beacon_proposer_indices 為第 k+2 個 epoch 算 32 個出塊者;種子取的 RANDAO 混合值是第 k 個 epoch 的;Gloas 版本(EIP-8045)先把 slashed 驗證者濾出候選名單,再用 compute_balance_weighted_selection(shuffle_indices=True)抽樣,total = 候選名單長度。
2. compute_shuffled_index 是 90 輪 swap-or-not,每輪樞紐 = hash(seed + 輪數) % total,所以 total 差 1 整個排列都不同。我用 10 萬個 32 ETH 驗證者、24 組種子模擬:罰沒 1、2、5、10、20 個隨機驗證者,32 個 slot 的出塊者新舊相同數全是 0;改成「抽到被罰沒者就拒絕」(consensus-specs 第 5733、5734 號 PR)則相同數是 32,若罰沒的正好是第 5 個 slot 的出塊者則只有該 slot 改變(12 組種子皆是)。
3. 第 k 個 epoch 的最後一個 slot 的出塊者可以在自己的區塊放入對自己驗證者的罰沒,藉由改變 total 重抽第 k+2 個 epoch 的名單。Electra 的 MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA 與 WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA 都是 4096,出塊者自己當檢舉者,32 ETH 驗證者的罰沒立即淨損益為 0;長期成本是 8192 個 epoch(36.41 天)的鎖定與相關性罰沒。
4. 攻擊者持股 5%、每個 slot 被選中的機率是二項分布 B(32, 0.05) 的獨立抽樣時,重抽 r 次後「至少 4 個 slot」的機率是 1-(1-0.074)^r,r=16 約 70.7%(我的模擬在 150 次試驗中得 62.0%)。
5. ACDT 第 100 次決定在 Glamsterdam 不修,延到 Hegotá,理由是 Sepolia 已跑 Gloas,改規則會使任何一次一般罰沒造成狀態根不一致(第 5734 號 PR,open)。
 
請幫我:
(a) 檢查第 1 到 3 點對規格的讀法有沒有錯,特別是「為什麼被罰沒者在第 k+2 個 epoch 仍屬活躍」(compute_activation_exit_epoch 與 MAX_SEED_LOOKAHEAD)以及 process_proposer_lookahead 與區塊處理的先後順序;
(b) 推演第 4 點:各次重抽不是完全獨立時,解析式會高估多少,我的模擬低於解析值的可能原因;
(c) 解釋「抽到被罰沒者就拒絕」與「先過濾」兩種做法在選擇結果上的差別,以及為什麼前者不會讓整串名單重排;
(d) 評估:Sepolia 已經執行 Gloas,若採用第 5733 號 PR 的做法,是否會在下一次一般罰沒造成客戶端分歧,為什麼;
(e) 分三類標示每一個結論:「規格或文件明說的」、「你另外查證到的(附網址)」、「你的推論」,不要編造連結或數字,查不到就說查不到。
這是技術研究,僅供學習,不需要也請不要給任何投資或質押建議。