上週 @redacted_noah 發表了一篇關於 Zero Copy™️ 在 @anchorlang 上是每個 @solana 開發者的完美 alpha 的長篇大論 我原以為 zero copy 只用於非常大的帳戶 我意識到我有時候使用它卻不知道為什麼 我決定深入研究,讓我帶你一起來 👇
@SuperteamFRANCE @SuperteamJapan 首先,我們為什麼要談論零拷貝數據解析? Anchor 的默認數據解析器稱為 Borsh。 當調用 Anchor 指令時,Borsh 將會把你的帳戶數據複製到 Borsh 結構中(到一個稱為 "堆" 的內存槽,稍後會詳細說明)
當您在指令中包含一個帳戶時,您使用的格式看起來像這樣。
使用零拷貝時,您的代碼將如下所示。
那麼那裡實際上發生了什麼? 一開始並不明顯! 首先,我們需要了解 Solana 如何使用其 Rust 應用數據:堆、棧和 "零拷貝" 空間。
1. 堆疊: 這是我們儲存本地和簡單數據類型的地方。 每個堆疊有 4KiB 的空間,每次函數調用都會獲得自己的 4KiB 配置。 當你超過最大堆疊大小時,會出現 "在堆疊幀 X 的地址 XXXXX 的大小 X 中發生訪問違規。" 這類錯誤。 在 Anchor 中,解決此錯誤的第一個方法是使用 `Box` 將數據從堆疊移動到 "堆" 👇
2. Solana 的堆積區: 程式在 BPF 虛擬機中運行,預設有 32KB 的堆積區。這是一次性分配,用於整個調用。 這裡是您將存儲更多動態數據類型(Vec、String)的地方。 使用 Borsh 反序列化帳戶會將數據複製到堆積區,快速佔用空間。
3. 零拷貝: 如果你必須繞過堆和棧,因為你的完整數據預算超出了(大量的 CPI,擁有大型帳戶),你將使用零拷貝。 零拷貝使你能夠在不必先分配或複製數據的情況下直接處理數據,通過跳過反序列化來實現。
何時使用 Zero copy 是有意義的? 1. 大型數據 2. 處理大量 CPI 讓我們繼續:
1. 大型數據 假設您想要追蹤一個錢包列表,直接進入您的狀態,以便能夠進行完全的鏈上檢查(如果您需要這樣做,請查看梅克爾樹😅,這不是正確的方法) 就像在抽獎中,在進行最終抽獎並選擇獲勝者之前,存儲每位參與者的地址。 這將輕易超過32kb的內存。一位參與者 = 32字節,因此如果您計劃成功並為1000位參與者分配空間,這已經佔用了整個堆大小(32,000字節) 在這種情況下,您可以使用零拷貝來繞過限制,並啟用處理更大帳戶而不會觸及堆或堆疊限制。
如何修復? 簡單!只需在任何地方使用 Zero Copy。 就像這樣簡單 👇(將 #[account("zero_copy")] 宏屬性添加到 RootEscrow 帳戶) 但 Zero Copy 也帶來了另一個挑戰,這就是為什麼 Anchor 最初選擇 Borsh 的原因:位元組對齊。
位元組對齊是一種每個 Solana 開發者都應該理解的低級技術,無論是否使用零拷貝。 它要求結構體通過 bytemuck 來確保零拷貝安全(如果處理不當,位元組對齊可能會導致恐慌)。 我將很快發佈另一個關於這個 *令人興奮* 主題的討論 🔥
同時,查看 @legendsdotfun 這個我自九月中以來一直在開發的產品,並參加 @colosseum Cypherpunk 黑客馬拉松 註冊你的產品,給有潛力的新團隊投票 讓每個 Solana 傳奇都閃耀 🤝
非常感謝這些大牛們: - @redacted_noah - @blockiosaurus - @0xIchigo 感謝他們校對這個即時發現的討論串!
5.66K