有效載荷分塊

本文為機器翻譯
展示原文

有效載荷分塊

簡而言之:將一個 EL 區塊( =payload )拆分成多個小區塊(“ chunk ”),每個區塊的 Gas 預算固定(例如2**24 = 16.77M ),並以 Sidecar 的形式獨立傳播。每個小區塊都承載著無狀態執行所需的預狀態,並提交到其後狀態 diff。小區塊按順序排列,但可以完全獨立地並行執行。CL 提交到一組區塊頭;Sidecar 則承載區塊主體和包含證明。
驗證變得更加連續。

動機

如今,區塊已經是巨大的、單片化的對象,未來規模還會更大。驗證需要先收到完整的區塊才能開始執行。這會導致區塊傳播和執行的延遲瓶頸。

通過 P2P 網絡接收The Block後,交易將按順序執行。我們無法在下載時開始驗證,也無法並行執行。

時間線顯示了今天的區塊驗證瓶頸:首先下載完整的區塊,然後順序執行
時間線顯示了今天的區塊驗證瓶頸:首先下載完整區塊,然後順序執行1100×580 29.3 KB

P2P 層上的消息通常使用 Snappy 進行壓縮。以太坊上使用的 Snappy區塊格式無法進行流式傳輸。因此,我們需要先將The Block切分成多個塊,然後再進行壓縮。

有了EIP-7928:塊級訪問列表,情況有所改善,但我們仍在等待下載完成才能開始區塊驗證。使用 4 個核心,我們得到了以下甘特圖:

EIP-7928 下的時間線:執行可以使用訪問列表,但仍然必須等待區塊下載
EIP-7928 下的時間線:執行可以使用訪問列表,但仍必須等待區塊下載1101×580 33.3 KB

相反,我們可以將塊作為塊進行流式傳輸

  • 每個塊包含≤2 2**24 gas的交易。
    • 也可以讓塊大小以 gas 為單位呈幾何級數增長( 2**22 2**23 、……、 2**25 )。這樣可以調整塊的延遲,從而實現更好的並行化——但我不確定這樣做是否值得,因為這會增加複雜性。
  • 交易保持有序。區塊被索引並排序,但彼此獨立,因此可以並行驗證。然而,區塊 0 的後狀態是區塊 1 的前狀態。
  • (可選)每個塊都帶有無狀態執行所需的狀態。
帶有有效載荷分塊的時間線:下載繼續時,塊流入並並行執行。
帶有有效載荷分塊的時間線:下載繼續時,數據塊流入並並行執行。1101 ×580 37.7 KB

這將驗證從“下載完整區塊,然後處理”轉變為“在接收剩餘部分的同時進行處理”。


執行層變化

我們擴展了 EL 塊格式以支持分塊:

class ELHeader :parent_hash: Hash32fee_recipient: Addressblock_number: uint64gas_limit: uint64timestamp: uint64extra_data: ByteList[MAX_EXTRA_DATA_BYTES]prev_randao: Bytes32base_fee_per_gas: uint256parent_beacon_block_root: Rootblob_gas_used: uint64excess_blob_gas: uint64transactions_root: Rootstate_root: Rootreceipts_root: Rootlogs_bloom: Bloomgas_used: Uintwithdrawals_root: Rootblock_access_list_hash: Bytes32 # New fields chunk_count: int # >= 0

EL 標頭中對各個塊沒有任何承諾。我們只會將塊計數添加到其中。執行輸出( state_rootlogs_bloomreceipts_rootgas_used )必須與最後一個塊中的值相同(適用於狀態根和提款根),或者與彙總塊值後的根相同(適用於交易、收據、日誌、已用 gas 和The Block訪問列表)。

執行塊

區塊永遠不會被放到鏈上;只有它們的根被提交。

區塊包含我們通常在 EL 區塊主體中期望的字段。交易被拆分成多個區塊,每個區塊的 Gas 消耗上限為2**24 。提現操作只能包含在最後一個區塊中。與區塊級訪問列表類似,每個區塊都擁有自己的區塊訪問列表,並且還可以為區塊添加預狀態值,從而解鎖無狀態性。

class Chunk :header: ChunkHeadertransactions: List [Tx]withdrawals: List [Withdrawal] # only in chunk at index -1 chunk_access_list: List [ChunkAccessList]pre_state_values: List [(Key, Value)] # optional

每個塊都帶有一個包含塊索引的頭。交易按照chunk.header.index及其在塊中的索引進行排序。每個塊的執行輸出的承諾也包含在頭中。

class ChunkHeader :index: int txs_root: Rootpost_state_root: Rootreceipts_root: Rootlogs_bloom: Bloomgas_used: uint64withdrawals_root: Rootchunk_access_list_root: Rootpre_state_values_root: Root # optional

為了防止提議者將其區塊分割成過多的塊,協議可以強制要求塊必須至少半滿( \geq\frac{chunk\_gas\_limit}{2} c h u n k _ g a s _ l i m i t 2 ) 或chunk.header.index == len(beaconBlock.chunk_roots)= 該塊中的最後一個塊)。


共識層變化

共識變化圖:信標塊跟蹤塊根,而執行塊通過邊車傳播。
共識變化圖:信標區塊追蹤區塊根,執行區塊通過 Sidecar 進行傳播。1180 ×593,91.5 KB

信標塊使用新字段來跟蹤塊:

class BeaconBlockBody :...chunk_roots: List [ChunkRoot, MAX_CHUNKS_PER_BLOCK] # SSZ roots of chunks class ExecutionPayloadHeader :...chunk_count: int

CL 通過一個新的ChunkBundle容器從 EL 接收執行塊,該容器包含 EL 頭和塊(類似於 blob )。
CL 使用 SSZ 的hash_tree_root計算塊根並將其放入信標塊主體中。

邊車設計

塊由邊車運送:

class ExecutionChunkSidecar :index: uint64 # chunk index chunk: ByteList[MAX_CHUNK_SIZE] # Opaque chunk data signed_block_header: SignedBeaconBlockHeaderchunk_root_inclusion_proof: Vector[Bytes32, PROOF_DEPTH]

共識層確保所有塊可用,並通過針對chunk_roots類似於 blob )的 Merkle 證明正確鏈接到信標塊主體。

聯網

提議者在普通的beacon_block主題上僅傳播具有承諾( chunk_countchunk_headers_root )的輕量級信標塊,而重度執行數據則作為ExecutionChunkSidecar分別在X 個並行子網beacon_chunk_sidecar_{0..X} )上傳輸,並按(block_root, index)進行重複數據刪除。

最初,所有節點必須訂閱所有子網並託管所有區塊。雖然這暫時不會降低帶寬/存儲需求,但它能夠帶來並行化的直接好處。一旦基本機制得到驗證和/或零知識證明變得可行,可以在未來的升級中添加部分託管功能。

網絡視圖:輕量級信標塊傳播速度快,而重量執行塊則在並行子網之間傳輸。
網絡視圖:輕量級信標塊傳播速度快,而重量執行塊則在並行子網間傳輸。1090 ×430 260 KB

叉子選擇

分叉選擇要求所有 Sidecar 都可用且已成功驗證,區塊才會被視為有效。帶有chunk_roots的信標區塊會快速傳播,但只有當所有區塊都已接收並針對根區塊進行了包含驗證後,The Block才有資格進行分叉選擇。信標區塊仍然包含 EL 區塊頭,其中包含所有必要的承諾(=對父區塊的承諾和執行輸出)。在本設計中,EL 上的區塊主體部分保持為空。


好處

  • 流式驗證:當The Block的其他部分仍在下載或忙於從磁盤加載時,即可開始執行。區塊之間是獨立的(如果提供了預狀態),或者依賴於區塊訪問列表(包含區塊級狀態差異)和區塊預狀態;多個 CPU/核心可以同時驗證區塊;帶寬使用情況在時隙內分配,而不是在時隙開始時突發。
  • 流線型證明:ZK 證明器可以同時並行證明多個塊,從而受益於塊的獨立性。
  • 無狀態友好性:由於單個塊小於一個區塊,我們可以考慮添加預狀態值,這樣就無需訪問本地狀態。一個實用的折中方案是僅在塊0中包含預狀態值,以保證在節點將其他塊所需的狀態從磁盤加載到緩存時,始終至少有一個塊可以執行。
  • 未來的可擴展性:在塊上集成 zk-proofs 或進行分片執行的明確路徑。

設計空間

區塊大小

2**24 gas(~16.7M)成為自然的塊大小:

  • 最大交易規模:截至 Fusaka(EIP-7825), 2**24是最大可能交易規模。
  • 當前區塊: 45M gas 區塊自然分成約 3 個區塊,提供即時並行
  • 未來區塊:規模化發展——1 億個 gas 區塊將包含約 6 個區塊

驗證器

  1. 執行引擎在內部將The Block拆分為塊(對 CL 不透明),並通過ExecutionChunkBundle將它們傳遞給 CL。
  2. 提議者將每個塊封裝在帶有包含證明的 Sidecar 中。提議者還計算每個塊的哈希樹根,並將其放入信標塊主體中。
  3. 所有子網中並行發佈
  4. 證明者等待所有區塊並驗證它們後再進行投票

建造者

提議者可以在區塊構建完成後發佈它們,而驗證者甚至可以在收到信標區塊之前就開始驗證它們。由於區塊包含已簽名的信標區塊頭及其包含證明,因此人們可以在區塊提交時進行驗證( =執行),並信任其來源( =提議者)。

未解決的問題和未來工作

漸進式塊大小?

幾何級數增加塊大小( 2**22 2**23 、……、 2**25 )的想法看似有益,但會增加複雜性。第一個塊可以較小(5M gas),並保留預狀態值以便立即執行,而後面的塊可以較大。這仍然是一個有待實驗的領域。

部分監護路徑

雖然初始實施需要完全託管,但該架構自然支持部分託管:

  • 節點只能保管 X 個子網中的 Y 個
  • 重建機制(類似於 DAS)可以恢復丟失的塊

兼容 ePBS 和延遲執行

乍一看,提議的設計似乎與EIP-7732EIP-7886兼容。在 ePBS 下,塊根可能會移至ExecutionPayloadEnvelope中,並且我們會在塊根之上添加一個額外的根,並將其放入ExecutionPayloadHeader中。PTC 不僅需要檢查單個 EL 有效載荷是否可用,還需要檢查所有塊是否可用。這與 blob 並沒有太大區別。

塊分塊和獨立驗證的優勢在於可以隨著更高的 gas 限制而擴展,並且可能有助於減少節點帶寬消耗的峰值。


來源
免責聲明:以上內容僅為作者觀點,不代表Followin的任何立場,不構成與Followin相關的任何投資建議。
喜歡
收藏
評論