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

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

在「更多資訊 (More Info)」區塊中的 Owner 欄位顯示為 BPF Loader,這與前文所述一致。
有些人可能會注意到「概述 (Overview)」部分的最後一個欄位是 Upgrade Authority,這在 AccountInfo 中並未出現。這是什麼意思呢?
正如前面提到的,帳戶將程式更新委託給 BPF Loader。在更新之前,BPF Loader 會驗證委託者是否為最初部署該程式的帳戶。由於程式帳戶的所有者已設為 BPF Loader,因此沒有空間來儲存此資訊,所以 Solana 將其放入了資料帳戶的 Data 欄位中。這就是為什麼「概述」中會有一個 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 位元組的地址格式儲存,而是放在交易訊息的帳戶地址陣列中,此欄位僅儲存一個指向該陣列地址的 u8 索引。
與第一個欄位類似,第二個欄位儲存帳戶地址索引,稱為 Compact Array of Account Address Indexes。此陣列指定了該指令涉及的所有帳戶。
最後一個欄位是一個位元組陣列,包含程式處理指令所需的額外資料,例如函式參數。
需要注意的是,Solana 會依順序處理交易中的所有指令,並確保交易的原子性執行。這意味著交易要麼所有指令全部成功處理,要麼全部失敗。不會出現部分指令已處理而其他指令未處理的情況。
🧐 在區塊鏈瀏覽器查看 Solana 交易
我們使用另一個 Solana 瀏覽器來查看 先前創建程式帳戶的交易。在「概述 (Overview)」部分,您可以看到 Solana 交易簽章、Recent Blockhash 以及其他資訊:

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

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

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



