乾貨 | 以太坊 2.0 Phase 0 V0.8.0 技術規範詳解(上)
(接上)信標鏈區塊
BeaconBlock
這個可以被認為是一個信標鏈區塊的 主要容器/區塊頭。
注意
hash_tree_root(BeaconBlock) == hash_tree_root(BeaconBlockHeader)
所以每一個簽名都是等價的。欄位
slot
—— 該區塊建立時候的 slot。必須比parent_root
所定義的上一區塊的時隙數更大parent_root
—— 父區塊的區塊根,以此形成一條區塊鏈state_root
—— 使用當前區塊執行完狀態轉換函式後的狀態的雜湊根body
—— 上述所有的信標鏈操作物件以及一些補充性欄位都包含在這一欄位中signature
—— 區塊提議者對該區塊的簽名BeaconBlockBody
randao_reveal
—— (區塊提議者)對當前時段(epoch)的簽名,以及,當該欄位與其他驗證者揭示的值(reveal)混合在一起時,可以繼續生成隨機性種子Eth2Data
—— 一個對 Eth2 鏈上近期資料的投票。它維護著下列欄位:deposit_root
—— 保證金合約中儲存資金的 SSZ 列表hash_tree_root
deposit_count
—— 迄今為止已經發生的保證金筆數block_hash
—— 包含了deposit_root
的 Eth2 區塊雜湊值。這一block_hash
可能在未來用於為 Eth2 鏈提供 Finality(類似於原來的用 FFG 合約來敲定 Eth2 鏈的計劃)。graffiti
—— 這是一個驗證者可以隨意填寫的空間。該欄位沒有協議層的用途。proposer_slashings
,attester_slashings
,attestations
,deposits
,voluntary_exits
,transfers
即可以被包含到
BeaconBlockBody
中的操作型別的列表(有最大長度)
信標鏈狀態
BeaconState
即是從創世區塊開始、用一系列區塊執行狀態轉換函式後所得的結果。它包含了驗證者註冊器、關於隨機數的資訊、關於 Finality 的資訊、相關的快取,以及 eth2 鏈的資料。
Versioning
genesis_time
—— 跟蹤創世事件發生的事件。這一資料讓客戶端可以根據經過的時間計算現在該是哪個 slot 了slot
—— 時間被劃分為固定長度的 slot(“時隙”),所有行動和狀態轉換都在具體的時隙中發生。這一欄位追蹤相應狀態的時隙fork
—— 一種處理信標鏈上分叉(升級)的機制。該欄位的主要用意在於處理簽名的版本控制,並處理分叉前後不同的簽名物件。歷史(History)
latest_block_header
—— 儲存所看到最新區塊頭。在一個區塊所在的 slot 中,區塊頭會不帶狀態根儲存起來;等到下一個時隙開始的時候,狀態根才會加入到區塊頭中。這是為了消除嵌入區塊頭中的狀態根所導致的迴圈依賴性block_roots
—— 逐 slot 儲存的近期區塊根。一個時隙的區塊根在下一個時隙開始時才會加入,以避免因為狀態根嵌入區塊而導致的迴圈依賴性。至於那些被跳過的時隙(即在給定時間內沒有產生區塊),就儲存前一個有效的區塊根state_roots
—— 逐 slot 儲存的近期狀態根。一個時隙的狀態根在下一個時隙開始時才會加入historical_roots
—— 一個雙批次的最新區塊和狀態根默克爾累加器來產生對 XXX 的歷史性默克爾證明Eth2
eth2_data
—— 驗證者達成共識並儲存在狀態中的Eth2Data
eth2_data_votes
—— 儲存在狀態中的Eth2Data
的實時列表。任何Eth2Data
只要在一個投票期中拿到了> 50%
的提議者投票,資料就會存進狀態中,而新的準備金也可以得到處理eth2_deposit_index
—— 新的要被處理的準備金的索引。只要eth2_data.deposit_count > eth2_deposit_index
,準備金就必須被新增到下一個區塊中登錄檔(Registry)
validators
—— 一個Validator
記錄的列表,用來跟蹤完整的當前登錄檔。每個驗證者都儲存著與之相關的資料,比如公鑰、有效餘額,還有 status(pending、活躍、已退出,等等)balances
—— 一個與validator_registry
一一對應的列表。頻繁且顆粒式變化的餘額被抽取出來,以減少每個時段所需執行的重雜湊數量的。混洗(Shuffling)
start_shard
—— 跟蹤當前時段的 “啟動分片”,作為基礎去計算一個時段中為各委員會安排哪個分片 ——(shard_shard + committee_offset) % SHARD_COUNT
randao_mixes
—— 每一時段中的 Randao 混合值(mix)。每一時段開始的時候,上一時段的 randao_mix 會複製下來用作新一時段的計算基礎。每個區塊中,block.randao_reveal
的hash
會跟實時的混合值(running mix)進行異或運算(XOR)。active_index_roots
—— 逐時段儲存的活躍驗證者索引的雜湊根。主要是為了更好地服務輕客戶端compact_committee_roots
—— 逐時段儲存的當前時段的CompactCommittee
列表的雜湊根。這也是委員會的簡潔代表,用來更好地服務輕客戶端。預計會在 Phase 1 把常設委員會加入這個根中。罰沒(Slashing)
slashings
—— 逐時段儲存的該時段內被罰沒的總額。任意時間點,一個列表的總和都給出了 “近期被罰沒的餘額”,並被用於計算相關驗證者需要被罰沒的餘額比例見證(Attestation)
來自區塊的
Attestations
被轉化為PendingAttestations
並儲存在狀態中,用於跨越時段邊界時候的批次記賬(bulk accounting)。我們儲存了兩個獨立的列表previous_epoch_attesations
—— 上一時段的各時隙的PendingAttestations
的列表。注意:這些乃是在上一時段各時隙中發出的見證,並不必然就是那些在上一時段中被打包到區塊中的見證current_epoch_attesations
—— 當前時段的各時隙中的PendingAttestations
列表。在當前時段處理結束後被轉移到previous_epoch_attestations
交聯(Crosslink)
我們儲存過往和當前時段的交聯,因為交聯必須形成一條鏈,所以
Attestation
要在建立過程中原樣引用交聯。要在當前時段驗證來自以往時段的見證中的交聯引用,我們使用previous_crosslinks
。current_crosslinks
—— 當前時段的交聯列表(每個分片一個交聯)previous_crosslinks
—— 以往時段的交聯列表(保持原樣不變)Finality
justification_bits
—— 4 個 bit 的、用來跟蹤最新 4 個時段中的確定性辯護(justification),以幫助確定性計算previous_justified_checkpoint
—— 以往時段最新被合理化(justified)的Checkpoint
,保持它在以往時段中的原樣。用來驗證以往時段的見證current_justified_checkpoint
—— 當前時段最新被合理化的Checkpoint
。用來驗證當前時段的見證,並用於分叉選擇finalized_checkpoint
—— 最新被敲定的Checkpoint
,該點以前的區塊將永遠保持在主鏈上,不會被重組
狀態轉換
state_transition
這是狀態轉換的頂層函式。它以一箇舊狀態和一個信標鏈區塊為輸入,然後輸出一個新狀態
process_slots
狀態轉換函式的第一個元件,處理所有發生在時隙中的操作(無論屬於哪個區塊)。如果在執行狀態轉換函式的區塊與其父塊之間存在被跳過的 slot,那麼區塊所在時隙前的多個時隙都會在
process_slots
期間得到處理在見證區塊或者產生區塊的時候,參與共識的客戶端有時候呼叫這個函式來轉換狀態,以跳過空的時隙
每個時隙要快取近期資料的時候都要呼叫
process_slot
只有跨越時段邊界的時候才需要呼叫
process_epoch
。注意,因為state.slot
尚未增加,呼叫會在slot % SLOTS_PER_EPOCH == 0
開始的那個時段的狀態轉換中發生process_slot
每個時隙都要執行一些對上一時隙的簿記工作。注意,因為
state
還未更新,所以仍表示著上一時隙完成後的狀態。同樣地,state.slot
仍等於上一時隙(process_slot
在process_slots
內完成之後state.slot += 1
)。前一時隙的完成後狀態根會在下一時隙中插入到狀態中,以避免迴圈依賴性
快取狀態根
上一時隙的狀態根會快取在狀態中。注意
hash_tree_root(state) == root_of_previous_state
,因為state
還是上一時隙完成後的狀態,還沒有改變過來。快取最新的區塊頭狀態根
如果上一時隙產生了一個區塊(既並非被跳過的空時隙),那麼我們將
previous_state_root
插入到快取的區塊頭中。如果遇到空時隙,這個區塊頭會一直儲存在狀態中,直到產生下一個區塊。快取區塊根
我們會在每個時隙中將最新的區塊快取入
latest_block_roots
。如果該 時隙被跳過了,那就會快取來自最新的沒有被跳過的時隙的區塊。
時段處理
時段處理過程在每個時段的第 0 個時隙(slot % EPOCH_LENGTH == 0
)開始的時候開始。注意,執行 process_epoch
的時候 state.slot
仍舊等於上一時隙(slot % EPOCH_LENGTH == EPOCH_LENGTH - 1
),只在前者完成後,後者才增加。
process_epoch
主要是個容器函式,會呼叫其它的時段處理次級函式。
辯護與確定性(Justification and Finalization)
process_justification_and_finalization
Justification 的更新首先要估計有多少驗證者(用餘額來加權)投票給上一個時段作為辯護的目標。只要超過 2/3 的活躍餘額給相同時段做了見證,而該時段是上一時段,那就將 justification 的狀態更新為上一時段。然後考慮當前時段,如果超過 2/3 的活躍餘額都給當前時段做了見證,則當前時段也被合理化。
只有最近的 2 個、3 個、4 個時段可以被敲定。實現方式是檢查最近的 justification 用作來源的那個時段,以及被近期合理化時段用作來源的最新被合理化的時段(在過去 4 個時段以內),是否已被敲定。我們只考慮在草案的 5.5 中討論的
k=1
和k=2
確定性規則。
交聯(Crosslink)
process_crosslinks
對每一個分片,只要至少 2/3 的委員會成員見證了相同的交聯,就將該分片(在信標鏈視角中)的最新交聯更新為該勝出的交聯。信標鏈會檢查上一時段和當前時段,以防止上一時段加入了更多交聯。
交聯必須透過
crosslink.parent_root
形成一條鏈;只有那些符合鏈標準的交聯才會在get_winning_crosslink_and_attesting_indices
中被考慮。
獎勵和懲罰(Rewards and Penalties)
process_rewards_and_penalties
所有最後一個時段對驗證者餘額的獎勵和罰沒都用這個函式來收集。獎勵和懲罰從
get_crosslink_deltas
和get_attestation_deltas
處收集,後兩者會以列表的元組(tuples of lists)的形式返回每一個驗證者所得的獎勵和懲罰。獎勵和懲罰是分開的,以避免出現 signed integer。get_base_reward
所有獎勵都會乘以一個 1/[TotalBalance^(1/2)] 。想理解為什麼,請看設計哲學
get_attestation_deltas
根據每個驗證者在上一時段的見證行為的函式來決定驗證者的餘額如何更改
對每一個活躍的驗證者來設:
FFG 的 Source 、Target 和 Head 獎勵 —— 如果一個驗證者的 source、target 或者 head 見證與上一時段當時的 source、target 以及 head 相匹配,那就為他發放獎勵,否則就發放懲罰。
見證被接受的速度進行獎勵 —— 找出每個驗證者的最快被打包的 attestation,並給相應的區塊提議者一小筆獎勵、給相應被打包的驗證者一筆與其見證被打包的速度成比例的獎勵
怠惰懲罰 —— 如果鏈不能敲定,那就懲罰所有人,尤其是那些不參與的驗證者。注意,怠惰懲罰不會降臨到那些完全參與的驗證者頭上
get_crosslink_deltas
每一個為(在他們的委員會中)勝出的交聯做見證的驗證者都可以收到一個與參與程度成比例的獎勵,反之就會受到懲罰
登錄檔更新(Registry updates)
process_registry_updates
餘額足以啟用驗證者身份,但還沒有被新增佇列中的,將被新增到啟用佇列中
餘額太低的驗證者將被 “彈出”,放到 “取款佇列” 中
啟用佇列中的驗證者會在一段時間內(within the churn limit)啟用
罰沒(Slashings)
process_slashings
驗證者被罰沒的力度會與在一定時間內被罰沒的驗證者數量成比例。這一點與驗證者被罰沒的順序是相互獨立的。
process_slashings
會遍歷近期的罰沒事件,併成比例地罰沒驗證者。
最終更新(Final updates)
process_final_updates
該方程處理需要隨時段運作的各種功能,即:
在新一輪投票期開始的時候,重置 eth2 資料投票
重新計算有效餘額(使用 husteresis)
確定下一時段開始的新分片
給眾所周知索引要確定下來的最近一個時段設定索引根 (
next_epoch + ACTIVATION_EXIT_DELAY
)為下一個時段設定委員會根
將下一個時段的被罰沒餘額設定為 0
將當前時段的 randao 混合值結果設定為下一時段的基本 randao 混合值
(潛在地)將狀態追加到歷史根
將
current_epoch_attestations
移動到previous
,然後將current
設為空值
區塊處理
process_block
是呼叫區塊處理流程的次級函式的主函式。如果在塊處理中丟擲了任何斷言或者異常,該塊就會被視為無效的,並被丟棄。
區塊頭
(抽象來說)process_block_header
決定了一個區塊是否有效。驗證方式有:
該區塊是從合適的時隙中產生的
父區塊的雜湊值是正確的
區塊提議者沒有被罰沒
相應提議者對區塊的簽名是有效的
process_block_header
也會在 state
中儲存區塊頭,以便後續用於狀態轉變函式。注意, state_root
會被設為空值,以避免迴圈依賴。狀態根會在下一個時隙開始的時候透過 process_slot
新增進去。
RANDAO
process_randao
驗證該區塊的 RANDAO 揭示值是當前時段區塊提議者的有效簽名,並且,若然,則將它混合進當前時段的混合值中。
Eth2 data
process_eth2_data
把該區塊的 eth2-data 新增到狀態的 eth2-data-vote 中。如果該投票期中超過半數的票都投給了相同的 eth2-data,就更新 state.eth2_data
。
操作
process_operations
保證罰沒、見證、保證金存入、保證金退出、保證金轉移的數量都如後續部分的函式定義的那樣發生。這是透過處理 ProposerSlashing
, AttesterSlashing
、Attestation
、Deposit
、VoluntaryExit
和 Transfer
物件來實現的。
(完)
(文內提供了許多超連結,請點選閱讀原文到 EthFans 網站上獲取)
原文連結:
https://notes.ethereum.org/jDcuUp3-T8CeFTv0YpAsHw?view#Phase-0-accompanying-resource-v080
作者: Danny Ryan
翻譯: 阿劍
你可能還喜歡: