介紹
在 2024 年,Solana 強勢崛起,其總鎖倉量(TVL)從年初的十億美元飆升至近五十億美元,成為第四大公共區塊鏈。
與以太坊相比,Solana 以更快的速度和更低的成本為用戶提供更優越的體驗。基於歷史證明的共識機制和異步交易處理模型,為開發者提供了高交易吞吐量和低延遲,使其成為各類去中心化應用的熱門平台。
BlockSec 特別規劃了 「Solana 輕鬆學」 系列,涵蓋 Solana 的基本概念、分析 Solana 交易的實踐指南,以及編寫 Solana 智能合約的教程。
作為本系列的第一篇文章,本文將深入探討 Solana 網絡中的關鍵概念,包括其運作機制、帳戶模型和交易,為在 Solana 中編寫正確且高效的智能合約奠定基礎。
eBPF:Solana 交易執行的基石
為了編寫和執行智能合約,區塊鏈通常需要一種程式語言和一個圖靈完備的計算環境。
以太坊上的智能合約通常使用名為 Solidity 的高階語言編寫。編譯器將其轉換為位元組碼,然後在以太坊虛擬機(EVM)中執行。Solana 並未選擇開發全新的虛擬環境和語言,而是選擇充分利用現有的先進技術。eBPF(擴展型柏克萊封包過濾器)虛擬機最初設計用於擴展 Linux 核心功能,被 Solana 選定作為其底層執行環境。
那麼,eBPF 相較於 EVM 有哪些優勢?
與僅限於解釋執行的 EVM 不同,eBPF 支援即時編譯(JIT),能夠將位元組碼轉換為處理器可直接執行的機器指令。這一能力顯著提升了程式效率。
此外,eBPF 具備高效的指令集和成熟的基礎設施。開發者可以使用 Rust 語言編寫智能合約。借助 LLVM 編譯器框架的 eBPF 後端,Rust 程式可以直接編譯為 eBPF 位元組碼。
Solana 的帳戶模型
Solana 帳戶結構
資料在 Solana 上以帳戶的形式儲存。如下圖所示,Solana 中的所有資料可以概念化為一個龐大的鍵值資料庫。該資料庫中的鍵是帳戶地址。對於「錢包」帳戶(即由 Solana 用戶通過公私鑰對直接控制的帳戶),這些地址是使用 Ed25519 簽名系統生成的公鑰。資料庫中的值由每個帳戶的具體詳情組成,包括餘額和其他相關資訊。
Solana 使用以下稱為 AccountInfo 的結構來描述帳戶。
每個帳戶的 AccountInfo 包含四個欄位。以下是各欄位的說明:
-
Data欄位:此欄位儲存與帳戶相關的資料。如果帳戶是程式(即智能合約),則儲存 eBPF 位元組碼。否則,資料的格式通常由帳戶建立者定義。 -
Executable欄位:此欄位用於指示帳戶是否為程式。值得注意的是,與以太坊不同,Solana 中的程式可以更新。 -
Lamports欄位:此欄位記錄帳戶中 Solana 代幣的餘額。Lamports 實際上是 SOL 代幣的最小單位(1 SOL = 十億 Lamports)。 -
Owner欄位:此欄位表示帳戶的擁有者。在 Solana 中,每個帳戶都有一個「擁有者」。例如,所有「錢包」帳戶的擁有者是系統程式(System Program),這是 Solana 網絡上負責帳戶建立等功能的特殊帳戶。帳戶擁有者是唯一能夠修改帳戶資料和從餘額中扣除 Lamports 的人(但任何人都可以通過轉帳增加 Lamports)。
預定義的 Solana 帳戶
Solana 有一組預定義的可執行程式,稱為 Native Programs,部署在固定地址。隨著 Solana 網絡的升級,這些預定義程式也可以更新。它們作為 API 和函式庫函數,在 Solana 網絡中提供特定功能。
在 Native Programs 中,開發者最常互動的是 System Program。系統程式為開發者提供一組指令,每條指令執行一項獨立任務。例如,開發者可以使用 CreateAccount 指令建立新帳戶,或使用 Transfer 指令將 Lamports 轉移至其他帳戶。
另一個常見的 Native Programs 是 BPF Loader 程式。它是所有其他程式帳戶的擁有者,負責部署、更新和執行自定義程式。當「錢包」帳戶需要更新其部署的程式時,實際上是通過委託給 BPF Loader 程式來完成的,因為只有程式的擁有者才有直接修改資料的權限。
除了 Native Programs 之外,Solana 還提供一組稱為 Sysvars 的帳戶。這些帳戶為 Solana 上的程式提供與 Solana 網絡當前狀態相關的資訊和全域變數,例如當前時鐘和最新的區塊雜湊值。
帳戶租金
在 Solana 區塊鏈上,每個帳戶必須維持一定數量的 Lamports 作為最低餘額,稱為租金。與現實生活中的租金不同,Solana 上的租金是可以收回的。為了確保帳戶中的資料在鏈上可用,帳戶必須持有適當數量的 Lamports。租金的數量與帳戶佔用的資料大小相關。
任何試圖將帳戶餘額降低至租金金額以下的交易都將失敗,除非將餘額恰好降至零。將餘額降至零表示帳戶的租金已被收回,在交易結束時,Solana 將在垃圾回收過程中清除對應帳戶的資料。
🧐 在 Solana 區塊鏈瀏覽器中查看 Solana 帳戶
為了更好地理解上述概念,我們使用 Solana 的「Hello World」專案部署了一個程式帳戶,可以使用 Solana 的區塊鏈瀏覽器 Solscan 進行查看。

如上圖所示,我們首先可以看到該帳戶已被標記為「Program」。一部分 Lamports 從發送者的餘額中扣除作為此帳戶的租金,因此 SOL Balance 欄位不為空。此外,由於我們建立的帳戶是一個程式,其 Executable 欄位設置為 Yes。
您可能會疑惑,Executable Data 欄位儲存的是一個地址,而不是 eBPF 程式。如前所述,Solana 允許程式更新,這實際上是通過「代理」模式實現的。由於最初不允許直接修改程式帳戶,Solana 建立了一個獨立的資料帳戶來儲存 eBPF 程式,而程式帳戶中的 Data 欄位僅儲存此資料帳戶的地址。
每當需要更新程式時,只需修改資料帳戶的 Data 欄位。使用 Solscan 查看資料帳戶,我們可以發現它被標記為「Program Executable Data Account」,其 Data 欄位儲存實際的程式。

「More Info」部分的 Owner 欄位是 BPF Loader,與前面提到的一致。
有人可能會注意到「Overview」的最後一個欄位是 Upgrade Authority,這在 AccountInfo 中並不存在。這是什麼意思?
如前所述,「錢包」帳戶將程式更新委託給 BPF Loader。在更新之前,BPF Loader 會驗證委託者是否為最初部署該程式的帳戶。由於程式帳戶的 Owner 已設置為 BPF Loader,沒有空間儲存此資訊。因此 Solana 將其放入資料帳戶的 Data 欄位中。這就是為什麼「Overview」中有一個 Upgrade Authority 欄位,它實際上是部署程式的錢包地址。
下圖顯示了程式帳戶與資料帳戶之間的關係。請注意,資料帳戶的 Data 欄位由錢包地址和 eBPF 代碼兩部分組成。

Solana 中的交易與指令
在 Solana 中,用戶通過發出交易來執行程式。Solana 的一個獨特之處在於其能夠並行執行這些交易,這是其驚人交易速度背後的關鍵原因。現在讓我們仔細看看 Solana 中交易是如何設計的。
一筆 Solana 交易由簽名和訊息組成。一筆交易可以包含多個簽名。交易的訊息由四個部分組成,如下圖所示。

Header 和 Compact Array of Account Addresses 指定了交易中涉及的所有帳戶及其在交易期間的特性,包括帳戶是否為簽名者以及在執行期間是否可寫。有了這些資訊,Solana 可以驗證簽名者帳戶提供的簽名,並並行處理交易,只要這些交易不包含任何寫入相同狀態的帳戶。
Recent Blockhash 作為交易的時間戳記。如果交易的區塊雜湊值比最新區塊雜湊值舊 150 個區塊,則視為已過期且不會被執行。
Compact Array of Instructions 是交易中最重要的部分,包含一條或多條指令。一條指令本質上觸發了程式帳戶提供的常式執行。每條指令由三個欄位組成,如下圖所示。

第一個欄位 Program ID Index 指定了指令的接收者,即需要處理該指令的鏈上程式。該地址並非儲存 32 位元組的地址,而是將地址放置在交易訊息的 Compact Array of Account Addresses 中,該欄位僅儲存指向陣列中地址的 u8 索引。
與第一個欄位類似,第二個欄位儲存帳戶地址索引,稱為 Compact Array of Account Address Indexes。此陣列指定了此指令涉及的所有帳戶。
最後一個欄位是一個位元組陣列,包含程式處理指令所需的額外資料,例如函數參數。
值得注意的是,Solana 按順序處理交易中的所有指令,並保證交易的原子性執行。這意味著交易要麼完全完成(所有指令均成功處理),要麼完全失敗。不會出現部分指令被處理而其他指令未被處理的情況。
🧐 在 Solana 區塊鏈瀏覽器中查看 Solana 交易
我們使用另一個 Solana 瀏覽器來查看之前建立程式帳戶的交易。在 Overview 部分,您可以看到 Solana 交易簽名、最新區塊雜湊值和其他資訊:

在 Account Input 部分,列出了當前交易涉及的所有帳戶及其在交易中的特性。我們可以看到,除了發送者和程式帳戶地址之外,還包含了兩個 Native Programs 和 Sysvar 帳戶。

由於這是一個簡單的程式建立交易,它僅包含兩條指令。第一條指令的接收者是系統程式(System Program),負責建立程式帳戶。第二條指令的接收者是 BPF Loader,它建立一個資料帳戶來儲存部署的 eBPF 代碼,並將其地址寫入程式帳戶的 Data 欄位。

結論
Solana 上的智能合約使用 Rust 開發,並在 eBPF 虛擬機上運行。Solana 遵循帳戶模型,鏈上帳戶需要維持足夠的租金以避免資料被移除。一筆交易由一條或多條指令組成,這些指令定義了所有所需帳戶,從而實現並行處理,提升吞吐量同時降低回應延遲。這些特性共同促進了 Solana 的快速發展,使其成為備受青睞的區塊鏈之一。



