跳至内容
0%

什么是 Solana 虚拟机(SVM),它是如何工作的?

Usman Asim headshot

作者 Usman Asim

发布于 2025年12月18日8 分钟阅读

虚拟机的可视化展示

Solana 已成为加密领域使用最活跃的区块链之一,按日活跃地址数和交易量计算持续排名前五。仅在 2025 年 10 月,Solana 网络就处理了约7000 万笔日交易,促成了 1430 亿美元的 DEX 交易量,峰值时期的吞吐量足以让大多数其他链陷入停滞。

实现这一点的原因不仅仅是快速共识或强悍的硬件要求,Solana 性能的核心在于一个根本上不同的执行引擎:Solana 虚拟机(SVM)。

Solana 虚拟机是一个基于寄存器的运行时,构建在 eBPF 字节码之上,通过要求预先声明所有状态依赖关系来并行执行交易。与以太坊虚拟机的顺序交易模型不同,SVM 从一开始就是围绕并行执行设计的,能够跨 CPU 核心同时处理数千笔交易,而不是逐笔处理。

这一架构选择影响到方方面面:程序如何存储状态、交易如何构造、费用如何计算,以及开发者如何思考构建链上应用。

本指南从基本原理出发拆解 SVM。我们将从核心组件入手,解释它们各自的工作方式,然后展示它们如何组合起来实现 Solana 的性能。读完之后,你不仅会理解 SVM 做什么,还会理解它 为什么 是这样构建的。

什么是虚拟机?

在深入探讨 SVM 之前,先来搞清楚虚拟机究竟是什么,以及区块链为什么需要它们。

虚拟机(VM)是运行在另一台计算机内部的基于软件的计算机。它提供了一个受控环境,让代码可以执行而无需直接访问宿主系统的资源。VM 无处不在:Java 虚拟机运行 Java 字节码,你的浏览器在 VM 中运行 JavaScript,云服务器通常也运行在 VM 内部。

区块链需要 VM 有一个具体原因:对不可信代码进行确定性执行。当你部署一个智能合约时,全球数千个验证者需要运行这段代码并得出 完全一致 的结果。VM 提供:

  • 沙箱化:不可信代码无法访问宿主系统或其他程序的内存
  • 确定性:相同输入始终产生相同输出,与硬件无关
  • 计量:执行过程可被衡量和限制(gas/计算单元),以防止滥用
  • 可移植性:代码在不同机器和操作系统上运行结果一致

**以太坊虚拟机(EVM)**是第一个被广泛采用的区块链 VM。它使用基于栈的架构,顺序执行交易,并将代码和状态一起存储在合约中。它能work,但其设计选择带来了根本性的吞吐量限制。

**Solana 虚拟机(SVM)**采取了不同的方法。它使用基于寄存器的架构(更类似于物理 CPU),将代码与状态分离,最重要的是,它并行执行交易。

什么是 Solana 虚拟机(SVM)?

从核心来看,SVM 是 Solana 的执行引擎,负责运行程序逻辑、处理交易和更新状态的系统。如果你来自以太坊生态,可以把它理解为 Solana 对 EVM 的回应,但在架构上有几处关键的不同。

要理解 SVM,首先需要理解它操作的对象:

  • 账户(Accounts):Solana 的通用数据结构。一切都是账户:用户钱包、代币余额、程序状态,甚至程序本身。账户持有数据并有一个所有者(被允许修改它们的程序)。与将代码和存储捆绑在一起的 EVM 合约不同,Solana 将两者完全分离,所有状态都存在于账户中。
  • 程序(Programs):这是 Solana 对智能合约的称呼。程序是 无状态 的:它们只包含可执行代码,编译为一种称为 sBPF 的字节码格式。大多数 Solana 程序用 Rust 编写(尽管也支持 C 和 C++)。程序运行时,会读写传入的账户,但内部不存储任何东西。
  • 交易(Transactions):一个或多个指令的集合,每个指令针对一个程序,并指定它需要读取或写入哪些账户。这种对状态依赖关系的预先声明是一切的关键,也是并行执行得以实现的原因。

有了这些基础,理解 SVM 最简单的方式是:它是一个沙箱化的运行时环境,接收编译后的程序字节码,针对一组账户执行它,并确定由此产生的状态变化。Solana 上的每一笔交易都要经过 SVM。

SVM 与 EVM 的区别不仅仅是实现细节——而是基础设计的不同。SVM 从一开始就是围绕并行执行构建的。交易预先声明其状态依赖关系,使运行时能够识别不冲突的工作,并跨 CPU 核心并发处理。EVM 是顺序处理交易的;SVM 则是同时处理数千笔。

关于术语的说明:"SVM"一词根据上下文有不同含义。狭义定义特指执行程序代码的字节码解释器和 JIT 编译器(稍后我们会介绍字节码格式 sBPF)。广义定义是 Anza(Solana 的核心验证者团队)官方使用的定义,涵盖整个交易执行管线:调度、计算预算、程序加载、执行和状态更新。开发者说"SVM"时,通常指的是这个更广义的系统。本指南两者都会涵盖,我们会在讲解过程中说明具体所指。

理解 SVM 架构

现在我们已经知道 SVM 是什么,以及它与其他区块链 VM 有何不同,接下来理解它 实际上是如何工作的。本节将完整走一遍架构流程,从交易到达的那一刻到最终的状态变化。

我们将涵盖四个相互关联的部分:

  1. 交易如何在系统中流转(管线)
  2. 运行你代码的执行引擎(eBPF、编译、VM 本身)
  3. 程序操作的数据模型(账户、PDA、rent、CPI)
  4. 并行执行,以及 Sealevel 如何使其成为可能

每一部分都建立在前一部分的基础上。读完之后,你不仅会理解各个组件,还会理解它们如何组合在一起,实现 Solana 的性能特性。

第一部分:交易如何在 SVM 中流转

理解 SVM 的第一步是追踪一笔交易的旅程,从你点击"发送"的那一刻到区块确认。这条管线解释了 为什么 Solana 程序是这样结构的,为什么 你必须预先声明账户,以及并行处理 实际发生在哪里

当你向 Solana 提交一笔交易时,它不会简单地进入一个队列排队等待。它会流经一系列专门的子系统,每个子系统解决一个具体问题:

markdown
Copied
Transaction submitted ↓ Banking Stage (conflict detection, parallel scheduling) ↓ The Bank (state snapshot for this slot) ↓ BPF Loader (provisions sBPF VM instance) ↓ Program executes (reads/writes accounts within budget) ↓ State updates committed

让我们逐一走一遍每个阶段:

Banking Stage:并行处理发生的地方

这是交通调度员。当验证过的交易到达时,Banking Stage 会分析每一笔:它需要读取哪些账户?需要写入哪些账户?

有了这些信息,它就能确定哪些交易可以安全地同时运行:

  • 涉及完全不同账户的交易 → 并行运行
  • 都读取同一账户的交易 → 并行运行(读操作不冲突)
  • 都写入同一账户的交易 → 必须顺序运行

调度器使用账户级别的锁来强制执行这些规则。工作线程同时处理不冲突的交易批次。这正是 Solana 并行执行模型的核心,称为 Sealevel(我们会在第四部分深入探讨 Sealevel)。

Bank:某一时刻的状态

Banking Stage 负责 调度,而 Bank 负责 状态。可以把它理解为 Solana 在某个特定 slot(Solana 的时间单位,约为 400ms)上整个状态的快照。

Bank 管理账户数据,协调执行,并追踪哪个版本的状态是权威的。每个 Bank 会经历三个生命周期阶段:

Stage
What's Happening

Active

正在为该 slot 处理交易

Frozen

slot 已完成:不再允许更改

Rooted

已最终确定并提交至持久化存储

当 Banking Stage 执行交易时,它是针对一个特定的 Bank,也就是世界的一个特定版本进行操作的。这就是 Solana 在并行处理数千笔交易的同时保持一致性的方式。

BPF Loader:启动程序执行

当一笔交易调用某个程序时,需要有东西真正 运行 那个程序的代码。这就是 BPF Loader 的工作。

BPF Loader 负责处理整个程序生命周期:

  • 部署:将新的程序字节码上传到网络
  • JIT 编译:将字节码转换为原生机器码以加快执行速度
  • 升级:推送现有程序的新版本
  • 执行:在程序被调用时配置隔离的 VM 实例

每次程序调用都会得到自己独立沙箱化的 sBPF VM 实例,包含:

  • 专用内存区域
  • 一个计算预算(类似于 gas limit)
  • 与其他程序严格隔离

如果程序超出了计算预算?执行终止。试图访问不该访问的内存?执行终止。这种隔离性是设计上刻意做得很严格的。这正是 Solana 能够安全运行来自数千名开发者的不可信代码的方式。

典型的交易流程

以下是一笔典型交易的完整流程:

  1. 你提交一笔交易,指定要调用哪个程序以及它需要哪些账户
  2. Banking Stage 接收该交易,检查它与其他待处理交易是否有冲突,并进行相应调度
  3. Bank 为这个 slot 提供当前状态快照
  4. BPF Loader 为目标程序配置一个 sBPF VM 实例
  5. 程序执行,读取并写入指定的账户
  6. 状态变化提交至 Bank
  7. 最终,Bank 冻结并被根化(root),使这些变化永久生效

每个组件解决一个具体的问题:Banking Stage 实现并行性,Bank 提供一致的状态,BPF Loader 确保安全执行。它们共同构成了广义上的"SVM"。

想更深入了解交易吗?查看以下资源:

第二部分:执行引擎

BPF Loader 会配置 VM 实例来运行程序代码。但在该 VM 实例内部,实际发生了什么?

大多数区块链 VM 都是从零设计的。Solana 走了一条不同的路:它采用了 eBPF(extended Berkeley Packet Filter),这项技术最初是为 Linux 内核构建的。

BPF 起源于 1992 年劳伦斯伯克利实验室,用于高效的网络数据包过滤。随着时间推移,它演变为 eBPF,一个通用的、沙箱化的 VM,能在 Linux 内核内部安全运行。如果你用过 bpftrace 之类的可观测性工具,或者使用过基于 eBPF 的网络技术,你已经接触过这项技术。它是经过实战检验的基础设施,支撑着大规模的关键系统。

Solana 创始人 Anatoly Yakovenko 在操作系统方面的背景(在高通工作超过 13 年)让他得出了一个关键洞见:既然已有一个 VM 解决了这些难题,为什么还要从零构建一个新的?

eBPF 恰好提供了 Solana 所需要的:

  • 无开销的安全性: eBPF 程序在一个受限环境中运行,不会使宿主系统崩溃或破坏内存。字节码在加载前经过静态验证——不允许非法内存访问、越界跳转或未经授权的操作。这种安全性不带来运行时开销,不像需要垃圾回收的托管运行时那样。
  • 接近原生的性能: 基于寄存器的架构(不同于 EVM 基于栈的设计)使得 JIT 编译到原生机器码成为可能。程序运行速度接近原生水平。
  • 成熟的工具链: LLVM 已经内置了 eBPF 后端。Rust、C、C++ 以及其他 LLVM 支持的语言可以直接编译为 eBPF 字节码。你用自己熟悉的语言编写代码,工具链处理剩下的事情。

sBPF:Solana 定制的变体

Solana 并没有使用原版 eBPF。它也无法这么做,因为标准 eBPF 是为内核空间操作设计的,存在严格约束,无法映射到区块链执行场景。所以 Solana 对其进行了分叉。

结果就是 sBPF(Solana Bytecode Format),一个针对链上程序执行定制的修改版本:

Feature
Standard eBPF
Solana sBPF

Environment

内核空间

用户空间

Stack size

512 字节

每帧 4KB

Loops

受限(必须可证明终止)

允许(受计算单元限制)

Custom syscalls

不支持

支持(日志、CPI、加密操作)

那些让 eBPF 在内核空间中保持安全的约束——极小的栈空间、禁止循环——如果照搬到 Solana 上会严重限制智能合约开发。sBPF 放宽了这些限制,同时通过计算单元预算维持安全性:你可以循环,但最终会耗尽计算量。

自定义系统调用同样重要。程序需要记录日志、调用其他程序(跨程序调用)以及执行加密操作。标准 eBPF 没有这些概念,而 sBPF 将它们作为一等原语加入进来。

如果你在编译 Solana 程序,会在工具链中看到目标三元组 sbf-solana-solana。这就是这个 Solana 专用变体的标识符。

从 Rust 到字节码:编译管线

当你运行 cargo build-sbf 时,你的 Rust 代码会经过一个多阶段的编译管线:

1. Rust 前端: 编译器解析你的代码,展开宏,执行类型检查,并运行借用检查器来验证内存安全性。代码离开这个阶段时,Rust 已经消除了整整一类 bug(悬垂指针、数据竞争、空指针),这些问题困扰着其他系统级语言。这是 Solana 一个未被充分认识到的优势:内存安全在编译时就得到强制执行,早在程序接触链之前。

2. LLVM 优化: 代码转换为 LLVM IR,一种与平台无关的表示形式,真正的优化在这里发生:常量折叠、函数内联、死代码消除、循环展开。这些优化很重要,因为计算单元是要花钱的。更小、更紧凑的字节码意味着更便宜的交易。

3. sBPF 后端: Solana 对 LLVM BPF 后端的自定义分支将优化后的 IR 转换为 sBPF 字节码,打包为一个 ELF 文件(.so)。这就是你部署到网络上的东西——也是程序被调用时 BPF Loader 配置进 VM 实例的内容。

text
Copied
Rust source (.rs) ↓ Rust compiler (type checking, borrow checker) ↓ LLVM IR (optimizations) ↓ sBPF bytecode (.so) ↓ Deployed to Solana

sBPF VM 内部

现在我们来到最底层:实际执行你字节码的虚拟机。

sBPF 指令集使用 64 位指令(每条 8 字节),采用类似 RISC 的设计,大约有 100 个操作码。程序可以访问 11 个 64 位寄存器:

Column
Purpose

R0

返回值

R1-R5

函数参数

R6-R9

被调用者保存(跨调用保留)

R10

帧指针(只读)

内存布局

VM 将内存组织为固定区域,每个区域从特定地址开始:

Address
Region
Purpose

0x000000000

.text

程序代码

0x100000000

.rodata

常量和只读数据

0x200000000

Stack

每个调用帧 4KB

0x300000000

Heap

默认分配 32KB

0x400000000

Input

账户和指令数据

这种严格的布局让 VM 能够强制执行严格的边界,让你的程序不能意外(或恶意)地访问不该访问的内存。

JIT 编译与安全性

sBPF VM 支持两种执行模式:

  • 解释器: 逐条遍历指令。启动快,运行慢。适用于本地测试和调试。
  • JIT 编译: 在执行前将 sBPF 字节码转换为原生 x86_64 机器码。启动较慢,但运行时速度大幅提升。这是验证者在生产环境中使用的方式。

Agave 验证者会将 JIT 编译后的程序缓存在 ProgramCacheForTxBatch 中以便复用。像 Token Program 这类高频使用的程序不会在每笔交易上重新编译,它们已经在缓存中了。

安全强制执行发生在两个层面:

  1. 静态验证(执行前):
  • 拒绝格式错误或无效的指令
  • 验证所有内存访问模式
  • 确保跳转目标落在有效的指令边界上
  • 捕获不可达的代码路径

如果你的程序未通过验证,它就无法部署,没有例外。

  1. 运行时计量(执行期间):
  • 每条指令消耗计算单元
  • VM 在每一步之后检查预算
  • 超出预算会立即终止执行

这种双层方法可以防止无限循环、资源耗尽攻击和失控程序。即使恶意字节码不知怎么通过了静态验证,它也不能永远运行下去,一旦达到计算限制就会终止。

如果你想进一步了解执行引擎,可以查看以下资源:

第三部分:数据模型

我们已经追踪了交易如何流经 SVM,以及字节码如何在 sBPF VM 内执行,现在来看看程序操作的对象是什么。

在大多数编程环境中,你有变量、数据库、文件系统,以及各种存储和检索数据的方式。区块链需要类似的东西:一种在交易之间持久化状态的方法。EVM 的解决方式是为每个合约分配自己的存储,一个内置在合约本身的键值存储。

Solana 采取了一种截然不同的方法,理解这种差异至关重要,因为它塑造了你在该平台上构建的一切。

Solana 上一切都是账户

可以把 Solana 想象成一个巨大的键值数据库:

  • 键(Key):一个 32 字节的地址(通常是公钥或衍生地址)
  • 值(Value):一个账户(持有字节数据、余额和元数据的数据结构)

这种一致性乍看起来可能有点奇怪,但正是这一点使得 Solana 的性能特性成为可能。每一份状态都有明确的地址、明确的所有者,以及关于谁能修改它的明确规则。运行时不需要遍历嵌套的合约调用来搞清楚哪些状态可能会改变,它从交易的账户列表中就能提前知道。

我们来看看账户内部实际包含什么,每个账户都包含相同的五个字段:

Field
Description

lamports

以 Solana 最小单位表示的余额(1 SOL = 10 亿 lamports)

data

存储账户状态的任意字节数组

owner

被允许修改该账户数据的程序 ID

executable

布尔标志——程序账户为 true

rent_epoch

用于 rent 追踪的历史遗留字段(大部分已弃用)

owner 字段至关重要。只有拥有该账户的程序才能修改其 data 字段或扣除其 lamports。任何人都可以读取任何账户(Solana 上所有状态都是公开的),任何人都可以向任何账户增加 lamports。但写操作受所有权限制。

这种所有权模型正是并行执行得以实现的原因。运行时确切地知道哪个程序可以修改哪些账户,因此它能够安全地同时运行不冲突的交易。

程序:设计上的无状态

Solana 程序是包含已编译 sBPF 字节码的可执行账户。但这里的关键洞见是:程序不能在内部存储状态。它们是处理指令并修改传入账户的纯函数。

每个 Solana 程序共享相同的入口点签名:

rust
Copied
pub fn process_instruction( program_id: &Pubkey, // This program's address accounts: &[AccountInfo], // All accounts passed to this instruction instruction_data: &[u8], // Arbitrary data (parameters, method selectors, etc.) ) -> ProgramResult

当你的程序运行时,它会收到:

  1. 自身的地址(以便验证它衍生出的 PDA)
  2. 一个它被允许读写的账户数组
  3. 包含调用者传入参数的指令数据

程序执行其逻辑,修改它被允许修改的账户,然后返回成功或错误。它在调用之间不存储任何内部状态。

为什么无状态?因为这能实现清晰的所有权边界。如果程序自行存储状态,你就需要复杂的规则来决定哪些程序可以访问哪些存储。通过强制所有状态进入有明确所有者的账户,这个模型保持简单,并行化也就得以保持可能。

设计说明:与默认不可变的 EVM 合约不同,Solana 程序默认是可升级的。升级权限可以随时推送新的字节码。开发者可以撤销升级权限来使程序不可变,但这是一个显式的选择。这反映了 Solana 的实用主义方法——大多数程序需要 bug 修复和功能更新。

程序衍生地址(PDA)

如果程序是无状态的,所有数据都存放在账户中,那么程序如何创建和管理自己的账户?它们不能持有私钥。这正是程序衍生地址(Program Derived Addresses,PDA)发挥作用的地方。

PDA 是落在 Ed25519 椭圆曲线之外的特殊地址,这意味着不存在与之对应的有效私钥。这种密码学特性使得程序能够为这些地址"签名"而无需持有私钥,运行时会在内部验证衍生过程。

PDA 的衍生方式是对种子(seeds)加程序 ID 加一个"bump seed"进行哈希:

rust
Copied
// Find a PDA for storing a user's balance let (user_balance_pda, bump) = Pubkey::find_program_address( &[ b"balance", // Static seed user.key().as_ref() // User's public key as seed ], program_id );

该算法从 255 开始尝试递减 bump 值,直到找到一个能产生曲线外地址的值。第一个有效的 bump 值就是"canonical bump"。

为什么 PDA 很重要

  • 确定性寻址:给定相同的种子,你总是能得到相同的地址,无需单独存储地址。
  • 程序控制的账户:程序可以在其衍生出的 PDA 处创建账户,并且只有它们能为这些 PDA 签名。
  • 键值模式:种子可以编码关系(用户 + 代币类型 → 余额账户),从而实现类似映射的数据结构。
rust
Copied
// Common PDA patterns // User-specific data let (user*profile, *) = Pubkey::find_program_address( &[b"profile", user.key().as_ref()], program_id ); // Token account for a specific mint let (token*vault, *) = Pubkey::find_program_address( &[b"vault", mint.key().as_ref()], program_id ); // Unique item with incrementing ID let (item, _) = Pubkey::find_program_address( &[b"item", &item_id.to_le_bytes()], program_id );

Rent:为状态付费

区块链状态不是免费的。每个账户都占用验证者磁盘上的空间,而这些空间是有实际成本的。不同的链有不同的处理方式。以太坊为存储操作收取 gas,但一旦写入,状态就永久存在,导致状态不断膨胀。

Solana 采取了不同的方法。有一个称为"rent"的机制,网络大约按每字节每年 3480 lamports 的标准收取费用,以保持数据留在链上。实际操作中,所有主网账户都必须"免租"(rent-exempt),即预先持有至少两年的租金:

rust
Copied
rent_exempt_minimum = (account_size + 128 bytes overhead) × 3,480 × 2

对于一个典型的代币账户(165 字节)来说,这大约相当于 0.002 SOL。

但这里与其他链的关键区别是:关闭账户会返还全部租金押金。这创造了清理未使用状态的经济激励,而这在存储永久存在的模型中是不存在的。

rust
Copied
// Closing an account returns lamports to a recipient ctx.accounts.account_to_close.close(ctx.accounts.recipient.to_account_info())?;

跨程序调用(CPI)

程序不是孤立存在的。一个 DeFi 协议可能会调用 Token Program 来转移代币,而后者可能会调用 Associated Token Account Program。这些跨程序调用(Cross-Program Invocations)正是 Solana 生态系统实现组合性的方式。

两个函数使 CPI 成为可能:

rust
Copied
// Standard CPI - passes existing signers through invoke( &instruction, &[account1, account2, ...] )?; // CPI with PDA signing - program "signs" for a PDA it controls invoke_signed( &instruction, &[account1, account2, ...], &[&[b"seed", &[bump]]] // Seeds that derive the PDA )?;

当你使用 PDA 种子调用 invoke\_signed 时,运行时会验证该衍生结果与预期地址匹配,并为该次调用授予签名权限。这正是程序在不持有私钥的情况下也能控制资产的方式。

重要的约束条件:

  • 最大调用深度为 5(从初始交易起最多 4 层嵌套 CPI)
  • 签名者权限会沿调用链级联
  • 计算预算在一笔交易中的所有 CPI 之间共享

想进一步了解账户,可以查看以下内容:

  • 账户概览:Solana 账户完整指南
  • PDA:程序衍生地址详解
  • CPI:跨程序调用指南

第四部分:并行执行(Sealevel)

到目前为止,我们已经涵盖了所有基础部分:交易如何流经管线,sBPF VM 如何执行字节码,以及账户模型如何以明确的所有权存储状态。

现在我们终于可以回答一直在铺垫的那个问题了:Solana 究竟是如何实现并行执行的?

我们在整篇文章中一直有所暗示:Banking Stage 调度不冲突的交易,账户预先声明所有者,交易指定它们将涉及哪些账户。这些并不是独立的功能特性,它们都是一个称为 Sealevel 的单一系统的组成部分。

Sealevel 是 Solana 的并行智能合约运行时,是使 SVM 吞吐量得以实现的核心创新。我们所讨论过的一切——账户模型、所有权规则、预先的账户声明——都是为了使 Sealevel 成为可能而存在的。

其根本洞见看似简单:

如果交易在执行开始前就声明它们要读取和写入哪些账户,运行时就能识别出不重叠的交易并并发执行它们。

就是这样。这就是整个诀窍。但要在实践中让它运作起来,需要围绕这一约束设计系统的其他每一部分。

并行执行的规则

Sealevel 的调度遵循简单直接的规则:

Scenario
Execution

涉及不同账户的交易

并行

只读同一账户的交易

并行

写入同一账户的交易

顺序

就是这样。读操作与读操作不冲突。写操作与一切都冲突。

text
Copied
TX1: [Account A (write), Account B (read)] TX2: [Account C (write), Account D (read)] ──► PARALLEL TX3: [Account B (read), Account E (write)] TX4: [Account A (write), Account F (read)] ──► SEQUENTIAL with TX1 (conflicts with TX1 on Account A write)

这就是为什么你必须在 Solana 交易中预先声明所有账户。这不是官僚形式主义:这是运行时并行化你的交易所需要的信息。

调度算法

Banking Stage 通过账户级别的锁定来实现 Sealevel:

  1. 交易到达,指定带有读写标志的账户
  2. 对每个可写账户:获取独占锁
  3. 对每个可读账户:获取共享锁(允许多个读者)
  4. 如果所有锁都已获取:安排执行
  5. 如果有任何锁被阻塞:重新入队并稍后重试

当前实现使用 6 个线程:4 个用于非投票交易,2 个用于投票交易。每个线程维护一个按优先费(每计算单元费用)和到达时间排序的队列。

一个更新的 Central Scheduler 架构使用单个调度线程配合 Prio-Graph 算法,这是一种惰性填充的依赖图,通过前瞻窗口来识别冲突。这提高了高争用工作负载下的调度效率。

实践中的性能

Metric
Value

理论最大 TPS

约 65,000(简单转账)

测试网基准

47,370 TPS(200 个节点,23 个地区)

主网典型范围

800–3,600 TPS(真实用户交易)

目标出块时间

400ms

真实世界中的吞吐量在很大程度上取决于交易组合。涉及独立账户的简单转账能完美并行化。都命中同一流动性池的复杂 DeFi 交易则会产生争用并被串行化。

这实际上是一个特性:争用是局部化的。某个去中心化交易所交易量激增,并不会拖慢一个新型银行上的代币转账速度,因为它们涉及不同的账户。这与所有交易都争夺同一个全局吞吐量的链有着根本性的不同。

为什么顺序 VM 不能简单地采用这种方式

你可能会想:为什么 EVM 不能直接加上并行执行?

根本问题在于,EVM 的状态访问是在执行时决定的,而不是提前决定的。当你调用一个 Solidity 合约时,在你实际运行它之前,没有办法知道它会读取或写入哪些存储槽。该合约可能会调用另一个合约,后者又调用另一个,每次访问都是不可预测的状态。

这种"读写无感知"模型使得在没有推测执行的情况下无法实现安全的并行化。一些较新的链实现了"乐观并行执行":假设没有冲突进行推测性执行,然后在冲突发生时检测冲突并顺序重新执行。这种方式可行,但增加了复杂性和开销。

Solana 的方法不同:冲突是被避免的,而不是被解决的。通过要求预先声明,运行时在执行开始之前就确切知道每笔交易需要什么。这种约束正是实现优化的原因。

EIP-2930 为以太坊引入了可选的"访问列表"以获得 gas 折扣,但这不是强制性的。Solana 使声明成为强制性和普遍性的要求,这就是关键区别。

SVM 生态系统:超越 Solana 主网

SVM 已经不再仅仅是 Solana 了。2024 年 6 月,Anza 推出了 SVM API,将执行引擎与 Solana 的验证者客户端解耦。这种模块化推动了全新的应用场景。

Eclipse:以太坊上的 SVM

Eclipse 于 2024 年 11 月上线,是第一个在以太坊上运行的生产级 SVM rollup:

Layer
Provider

结算层

Ethereum

执行层

Solana 的 SVM

数据可用性

Celestia

欺诈证明

RISC Zero(ZK 加速)

上线时已有超过 60 个应用部署,包括 Orca。Eclipse 筹集了 6500 万美元来构建这座桥梁,证明了 SVM 具有独立于 Solana 共识层的价值。

SOON 网络

SOON(Solana Optimistic Network)于 2025 年初实现了 alpha 主网,成为第一个"解耦 SVM"rollup。与简单的分叉不同,SOON 将执行与共识完全分离,采用 Merkle Patricia Trie 进行状态管理(不同于 Solana 的 AccountsDB)。目标:借助 Firedancer 集成实现 5K–600K TPS。

Sonic SVM

Sonic 于 2025 年 1 月上线,是 Solana 上第一个用于游戏的原子级 SVM Layer-2。由 Mirror World Labs 构建,包含 HyperGrid Framework,用于为每个游戏启动定制化的 SVM 链。测试网处理了超过 6 亿笔交易,来自超过 200 万个月活跃钱包。

MagicBlock:临时性 rollup

MagicBlock 引入了"临时性 rollup"(ephemeral rollups),即临时的、按需的 SVM 执行环境。可以正常在 Solana 上部署合约,然后在需要低于 50ms 延迟时将特定账户委托给 MagicBlock。写操作在临时会话中进行,然后提交回 Solana。

这非常适合游戏和实时应用场景,因为 400ms 的出块时间对它们来说仍然太慢。

Firedancer:性能突破

Jump Crypto 的 Firedancer 客户端可能是最重要的 SVM 发展。它完全用 C 编写,不与 Agave 共享任何组件,采用基于 tile 的架构,每个功能运行在专用的 CPU 核心上,并使用内核旁路网络技术。

Benchmark
Result

数据包接收

100 万 TPS

SVM 执行(简单程序)

5 亿 TPS

这些是合成基准测试数据,但它们表明当前主网性能之上还有巨大的提升空间。

时间线:

  • 2024 年 9 月:Frankendancer(混合版)在主网上线
  • Breakpoint 2024:完整版 Firedancer 以非投票模式运行
  • 2025 年:预计完整生产版本发布

在 SVM 上构建

我们已经介绍了架构,现在来讲点实际的。如果你想开始在 Solana 上构建,实际需要什么?

工具链一览

Tool
What It Does

Solana CLI

核心工具包,负责密钥对管理、部署以及与集群交互

Anchor

用于构建程序的主流框架——处理样板代码、序列化、账户验证和测试

Rust + cargo-build-sbf

将你的 Rust 代码编译为用于部署的 sBPF 字节码

Bankrun / LiteSVM

无需启动完整验证者即可进行快速本地测试

solana-test-validator

用于结合主网状态进行集成测试的完整本地验证者

Alchemy

为 Solana 提供高性能 RPC 节点和 API,提供可靠的区块链数据访问、增强的历史查询,以及用于开发、测试和交互的工具

对大多数开发者来说,路径是:Solana CLI + Anchor + Bankrun。这个组合覆盖了 90% 的使用场景。

快速上手:5 分钟设置

bash
Copied
# Install Solana CLI sh -c "$(curl -sSfL <https://release.anza.xyz/stable/install>)" # Install anchor cargo install --git <https://github.com/coral-xyz/anchor> anchor-cli # Create a new project anchor init my_project && cd my_project # Build and test anchor build anchor test

就是这样。你现在拥有了一个可用的 Solana 开发环境:一个初始程序、测试套件,以及可用的本地验证者集成。

从这里开始,Anchor Book 会带你构建你的第一个真正的程序,Solana Cookbook 则为你会遇到的常见模式提供了配方。

想深入了解,可以参考:

结论:架构上的赌注

SVM 代表了一种连贯的架构理念:接受预先的约束(明确的账户声明、无状态程序、复杂的交易构造)以换取并行性、吞吐量和局部化的费用市场。这些约束并非偶然产生的附带结果——它们正是实现这种性能的机制。

如果你想探索其中的可能性,Alchemy 的 Solana API 让你能从一个平台访问 Solana 主网、devnet 以及更广泛的 SVM 生态系统。开始构建,亲自体验一下。

常见问题

什么是 Solana 虚拟机(SVM)?

SVM 是 Solana 的执行引擎,一个基于寄存器的运行时,构建在 eBPF 字节码之上,通过要求预先声明所有状态依赖关系来并行执行交易,从而实现跨 CPU 核心的数千笔并发交易。

SVM 与以太坊虚拟机(EVM)有何不同?

与 EVM 基于栈的顺序架构不同,SVM 采用基于寄存器的设计并支持并行执行,通过账户将代码与状态分离,并要求预先声明账户以实现并发处理。

什么是 Sealevel,为什么它很重要?

Sealevel 是 Solana 的并行智能合约运行时,它调度不冲突的交易在多个 CPU 核心上同时执行,通过并行处理涉及不同账户的交易实现数千 TPS 的吞吐量。

我可以用哪些编程语言在 SVM 上构建?

程序主要用 Rust 编写,通过 LLVM 编译为 sBPF 字节码,不过其他 LLVM 兼容语言,如 C、C++ 和 Zig 也受支持。

什么是程序衍生地址(PDA)?

PDA 是落在 Ed25519 曲线之外、没有有效私钥的特殊地址,使程序能够确定性地生成并为它们控制的地址"签名",而无需持有私钥,从而使程序能够管理自己的账户。

SVM 的账户模型是如何工作的?

Solana 上一切都是账户,一种包含 lamports(余额)、任意数据字节、所有者程序 ID 和元数据的数据结构。程序是无状态的,只能修改它们所拥有的账户,这为并行执行提供了清晰的所有权边界。

什么是 sBPF,它与 eBPF 有什么关系?

sBPF(Solana Bytecode Format)是 Solana 定制的 eBPF 变体,针对区块链使用场景做了修改,拥有更大的栈空间(4KB 对比 512 字节)、支持受计算单元限制的循环,以及用于日志记录、CPI 和加密操作的自定义系统调用。

什么是跨程序调用(CPI)?

CPI 使 Solana 程序能够在执行期间调用其他程序,最大调用深度为 5,在保持共享计算预算和级联签名者权限的同时,实现了整个生态系统的可组合性。

SVM 可以在 Solana 主网之外使用吗?

可以,模块化的 SVM API 使其能够在 Solana 之外使用:Eclipse 将 SVM 作为以太坊 rollup 运行,SOON Network 作为解耦的 SVM rollup 运行,而 Sonic 和 MagicBlock 等项目则构建了专门化的 SVM 执行环境。

我该如何开始在 SVM 上构建?

安装 Solana CLI 和 Anchor 框架,然后使用 anchor init 创建一个包含初始程序、测试套件和本地验证者集成的项目,Anchor Book 和 Solana Cookbook 提供了全面的开发指南。

Background gradient

构建区块链应用

Alchemy 将最强大的 Web3 开发者产品和工具与资源、社区及专业支持结合在一起。