作者: toly , Solana共同創辦人

編譯:Felix, PANews

每天大約有100萬個新帳戶被加入到Solana中,現在的總狀態已超5億,而快照大小約為70GB。隨著硬體的改進,這些數字本身是完全可管理的,但是SVM運行時的目標是提供最便宜的硬體存取方式,為了實現這一點,必須在當前硬體限制內管理狀態和記憶體。

PCI頻寬

截至2024年,最新的PCI頻寬可以達到0.5 Tbs到1 Tb的吞吐量。或每秒64GB到128GB。雖然聽起來很大,但如果一個tx讀取/寫入為128MB, 128GBps的PCI頻寬會將鏈的TPS限制在1000左右。實際上,大多數txs訪問的是最近載入並快取到RAM中的記憶體。理想的設計應該是允許載入1000個具有128MB新狀態的txs,再加上10k或更多讀取和寫入現有快取狀態的txs。

帳戶索引

建立新帳戶需要證明該帳戶目前不存在。這通常是在每個驗證器上自動完成,因為每個驗證器都有當前所有有效帳戶的完整索引。即使帳戶資料不儲存在本地,只儲存資料的哈希,5億個帳戶也將是32位元組的金鑰+ 32位元組的資料雜湊或每項64位元組,即32 GB。這已經足可以保證RAM和磁碟的分離。

快照大小

在某些快照大小(Snapshot Size)下,如果部分網路出現硬體故障,冷啟動新系統所需的時間足以延長最壞情況的重新啟動時間。隨著頻寬和硬體的改進,情況每天都在變化,而Solana並沒有接近這個限制,但該限制在任何時間點都存在。

概要

記憶體和磁碟具有不同的效能特徵和限制。如果SVM不區分,那麼交易和限制就必須針對最壞的情況進行定價,進而限制了效能。在交易執行期間,所有帳戶金鑰至少必須可用,且總帳戶數量將影響RAM和磁碟PCIi頻寬利用率。快照不能任意增大。理想的解決方案是:

  • 允許將更多不需要PCI資源的txs打包到區塊中
  • 管理總索引大小和快照大小

Chilly、Avocado、LSR。糟糕的名字通常是優秀軟體設計的標誌。 Anza和Firedancer的工程師想出了以下方案。

Chilly

帳戶執行時的快取由所有實例(instances)進行確定性管理。從更高層次看,這是存取狀態的LRU快取。在區塊建置和調度期間,此實作(implementation)可以輕鬆檢查帳戶,不需要鎖定或迭代LRU快取。快取是用一個非常簡單的計數器機制來實現。

  • 總載入位元組被追蹤為Bank::loaded_bytes:u64
  • 每個帳戶在使用時都會用目前運行總數account::load_counter:u64進行標記
  • 載入帳戶時,如果Bank::loaded_bytes - Account::load_counter > CACHE_SIZE,則帳戶被視為冷帳戶,其大小是根據每個區塊的LOAD_LIMIT計算
  • 新帳戶load_counter為0,因此所有新帳戶都是冷帳戶
  • Leader的排程器將LOAD_LIMIT當作一個浮水印,類似寫鎖CU限制。

這種設計的絕妙之處在於,它自然適合當前的調度程序。用戶只需要擔心他們的優先費。調度程序必須處理將所有低於LOAD_LIMIT和帳戶寫鎖限制的tx放入背包問題。最高優先權的tx可以先載入並使用LOAD_LIMIT。一旦達到這個限制,所有其他tx仍然可以放入一個區塊中。因此,驗證器可以最大化緩解txs的快取局部性。

Avocado

Avacado由兩部分組成,狀態壓縮和索引壓縮。首先用哈希替換帳戶數據,然後將帳戶索引遷移到Binary Trie / patricia Trie。新帳戶必須提供證明,證明他們不在“trie”中。

狀態壓縮

大致設計如下:

  • 在分配期間,每個帳戶每位元組綁定X個lamports。
  • 如果X < 當前經濟底價,則將帳戶保留在記憶體中,該帳戶將被壓縮
  • 壓縮是一個多步驟的過程,運行在一個epoch上
  • 帳戶資料被替換為哈希值(data)
  • 帳戶金鑰仍處於狀態之中
  • 引用壓縮帳戶的交易失敗
  • 解壓縮需要上傳類似載入程式的數據
  • 解壓縮的成本應該與分配新帳戶的成本相同

估計75%的帳戶在超過6個月的時間裡沒有被訪問,而且很可能永遠不會被訪問。壓縮它們可以節省50%的快照大小。

索引壓縮

這是一個更難解決的問題。僅通過狀態壓縮,驗證器仍然擁有系統中所有可能的有效帳戶。建立新帳戶需要檢查此資料庫。驗證器儲存此資料庫的成本很高,但使用者建立新帳戶的成本很低。要保證新私鑰不會與現有帳戶發生任何衝突。

Binary Trie mining

  • Binary Trie作為快照的一部分被跟踪
  • 想要獲得額外sol的驗證者可以建立一個交易,從狀態中刪除壓縮的帳戶kv對,並將它們加入Binary Trie中
  • 使用者可以在解壓縮過程中將kv從Trie中移除,從而在不被允許的情況下反向執行此操作(這可能需要在解壓縮時進行原子操作,以便在後台服務壓縮帳戶時更容易)。
  • 對於驗證器,無論它包含多少kv對,Trie根的大小都是恆定的
  • 使用zkp,每個tx可以壓縮約30個帳戶
  • 假設每個區塊只有一個,那麼壓縮5億個帳戶需要大約80天的時間

這個過程的關鍵之處在於,執行此操作的驗證者將獲得獎勵,但並非所有驗證者都必須執行此操作。如果所有驗證器都必須執行此操作,那麼所有驗證器都必須維護目前Binary Trie中的內容,這意味著整個狀態必須是快照的一部分。想要維護整個狀態的驗證器應該提交一個交易,將索引中的N個帳戶壓縮到Trie中。

新帳戶證明

要建立一個新帳戶,使用者必須證明該帳戶在Trie中不存在。維護整個狀態的驗證器可以產生帳戶不在Trie中的證明。這給用戶帶來了負擔,他們必須始終與大型狀態提供者連接以產生這些證明。

或者,用戶可以證明他們的帳戶是用最近的PoH哈希創建的。支持這一點的最簡單的方法是:

  • 產生新的PKI
  • 帳號位址是哈希(最近的PoH哈希,PKI::public_key)

鑑於Trie中的帳戶必須先進行狀態壓縮,這需要一個完整的epoch。 Trie中的任何帳戶都不可能使用最近的PoH雜湊來產生位址。

其他可以支援的方法是PKI創建本身可以提供一個證明,證明私鑰是用哈希(用戶隱藏的秘密,最近的PoH雜湊)創建的。

LSR

Lightweight Simple Rent,又稱Less Stupid Rent。如何為分配新帳戶的成本定價,以及如何確保舊的廢棄帳戶最終得到壓縮,並減少系統的整體負載和新用戶的價格?

需要恢復租金(Rent)制度。 Rent是指目前狀態下的帳戶應該支付X美元/位元組/天的費用,就像AWS上的帳戶支付儲存費用一樣。

Rent Rate bonding curve

RentRate = K*(state_size)^N

無論當前狀態大小如何,如果很小,費率應該很低,如果接近快照限制,費率應該非常高。

Allocation Minimum Bonding Price

帳戶必須至少存在一個epoch。分配需要將帳戶帶入Hot狀態。熱帳戶應該在快取期間存在。

New Account bond = Epoch Slots * RentRate * Account::size

新帳戶的餘額中必須至少有這麼多的lamports才能創建。

Hot Account Burn

lruturnverrate = 每個帳戶在LRU快取中平均佔用的時間,最大值為1 epoch。這個值可以是一個常數,也可以在鏈下計算,並作為中位數權益加權常數報告給SVM。

壓縮

當(current slot - account::creation_slot) * RentRate * account::size > account::lamports時,壓縮帳戶並燒毀所有lamports。

上述解決方案,應該會讓State很便宜,因為隨著時間的推移,未使用的帳戶最終會達到lamports 0,並將被壓縮。所以資料開銷會減少,甚至索引開銷也會減少,這將減少目前狀態的大小。減少狀態的大小將降低超二次分配的成本。

相關閱讀: Solana最新研究:生態充滿韌性,成長與挑戰並存