设想一家顶级连锁餐厅的后厨。老式餐厅只有一位主厨,所有订单必须按顺序一道道做,哪怕两份完全无关的菜品也要排队——这就是以太坊式的串行厨房。而 Solana 是一间现代中央厨房:多位厨师在各自工位上并行出餐,每位厨师只需在开工前看一眼订单上标注了哪些“食材”,只要两份订单不抢同一份食材,就能同时料理。这样的厨房需要更锋利的刀具、更严密的防割手套,以及一套清晰的餐盒标签体系。本文就用这间“并行厨房”带你看懂 Rust 与 Solana 合约开发:Rust 是安全刀具,账户模型是餐盒标签,Sealevel 是并行流水线,资源租赁是保鲜押金,PDA 是免钥匙储物柜。读完你会明白,为什么 Solana 能成为高性能公链的代表,以及它如何为 AI 提供可信的数据与算力底座。

岗位关联

掌握 Solana 高性能合约开发,你将在 Web3 与去中心化 AI 的交叉地带,拥有从“看得懂”到“写得动”的真实竞争力。

目录
  1. 可视化演示
  2. Rust语言特性
  3. 账户模型
  4. Sealevel并行运行时
  5. 资源租赁机制
  6. PDA派生机制
  7. 合约开发实战
  8. 部署与生态
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

演示Solana高性能合约开发:Sealevel并行执行架构、账户模型与资源租赁、交易生命周期执行流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

Sealevel并行执行 Sealevel按账户写入分组交易,无冲突交易并行执行 多核并行调度充分利用CPU资源实现高TPS 合约(Program)无状态,数据存储在独立账户中 Throughput = Parallel(Account_Groups) × Cores Sealevel运行时实现Solana高吞吐并行执行

Rust语言特性

走进那间 Solana 中央厨房,你最先注意到的会是厨师的装备:碳纤维菜刀快得惊人,防割手套薄却坚韧。Rust 就是区块链世界里的这套“安全刀具”。它不像 C++ 那样把锋利刀口毫无遮拦地交给厨师,也不像 Python 那样让厨师穿着厚重的防护服(运行时检查)牺牲速度。Rust 在编译期就替你把所有“切到手”的可能拦截下来,并且不额外花一分钱运行时成本。

为什么 Solana 偏偏选中 Rust?因为链上跑的是真金白银。合约一旦出现内存越界或悬垂指针,轻则程序崩溃,重则资金被恶意利用。Solidity 像家用菜刀——上手快但需要虚拟机层层保护;Rust 则把安全防线前移到编译阶段:写错不合格,根本过不了“上岗培训”。官方 SDK(Anchor / Solana Program Library)的底层几乎全部用 Rust 编写,足以说明它的地位。

Rust 的安全核心是三件事:所有权、借用和生命周期。每个值有且只有一个所有者;赋值或传参默认发生“所有权转移”(move);借用时要么多个只读借用并存,要么一个可变借用独占。这三条规则全部在编译期检查,不会拖累运行速度,因此兼顾了安全与性能——这正是“零成本抽象”的含义。

∀ t, ∃! owner(v);v→moveu  ⟹  v 失效,u 接管\displaystyle \forall\, t,\ \exists!\, \mathrm{owner}(v);\quad v \xrightarrow{\mathrm{move}} u \implies v \text{ 失效,} u \text{ 接管}

1. 唯一所有者:∃! 表示“存在且唯一”。任何时候一个内存值只允许一个变量拥有它,编译器据此决定何时自动释放内存。

∀ t, ∃! owner(v)\forall\, t,\ \exists!\, \mathrm{owner}(v)

2. Move 转移语义:赋值或传参时,所有权整体移交,新变量 u 接手,旧变量 v 立刻作废,防止两处同时释放。

v→moveuv \xrightarrow{\mathrm{move}} u

3. 借用规则:要临时用一下值,只能“借”——要么多个只读借用,要么一个可变借用。生命周期约束保证借用不会活得比主人更久。

只读借用×N ⊕ 可变借用×1\text{只读借用} \times N \ \oplus \ \text{可变借用} \times 1

回到厨房:Rust 就像要求每个厨师在入职前通过“刀工安全考试”,考试不通过连后厨门都进不去。正因如此,Solana 才敢让成千上万个合约在一条链上高速运转,而不必担心一个新手厨师的血溅到隔壁灶台。

账户模型

在中央厨房里,每份食材都装在一个贴着标签的餐盒里:盒子外面写着“里面装的是什么”“由哪位大厨负责”“需要多少保鲜费”。Solana 的一切都是账户——它不是简单的一个余额数字,而是一个带标签的存储容器。你转账、存数据、部署合约,本质上都是在操作这些餐盒。

以太坊的账户只分“外部账户”和“合约账户”两类,而 Solana 把规则简化并统一:所有账户都是同一套结构,区别只在于标签内容。这个设计让运行时可以快速判断“谁能碰这个盒子”“碰了要不要排队”,是 Sealevel 能并行处理的底层前提。

一个 Solana 账户由五个字段组成:pubkey 是全局唯一的门牌号;owner 标注谁能修改 data(只有 owner 字段指向的程序才允许写);lamports 是账户里的 SOL 最小单位余额;data 是任意字节串,合约状态全存在这里;executable 标记该账户是否为程序本体。注意,合约自己也是一个账户——一个 executable 为真的“餐盒”,里面装的是机器码。

A=(pubkey, owner, lamports, data, executable)\displaystyle A = (\text{pubkey},\ \text{owner},\ \text{lamports},\ \text{data},\ \text{executable})

1. pubkey 门牌号:账户地址,由 32 字节公钥表示,全局唯一,交易靠它定位账户。

pubkey=ed25519 公钥\text{pubkey} = \text{ed25519 公钥}

2. owner 控制者:指向某个程序的地址。只有该程序调用时才能写 data,其他程序只能读——这是权限模型的核心。

write(A,P)  ⟺  owner(A)=P\text{write}(A, P) \iff \text{owner}(A) = P

3. lamports 余额:SOL 的最小单位(1 SOL = 10⁹ lamports),用于支付手续费和租金。

lamports∈N≥0\text{lamports} \in \mathbb{N}_{\ge 0}

4. data 数据区:任意字节串,合约通过它读写状态;程序账户的 data 则是可执行机器码。

data={0,1}∗\text{data} = \{0,1\}^*

5. executable 标记:布尔值。为真时表示这是程序账户,链上禁止普通交易直接修改它的 data。

executable∈{true, false}\text{executable} \in \{\text{true},\ \text{false}\}

餐盒标签一目了然,后厨调度就简单了:谁负责什么食材、这道菜能由谁动刀,全都写死在标签上。合约开发者要做的,就是像设计菜单一样设计好这些标签,让每个账户各司其职。

Sealevel并行运行时

老式餐厅只有一位主厨,所有订单必须按顺序一道道做。Solana 的中央厨房则布置了多条流水线,多位厨师可以同时开工。关键在于:订单(交易)必须预先声明自己会用到哪些食材(账户)。只要两份订单不抢同一份食材,流水线就同时料理;一旦发现都要动同一个番茄,后到的订单就得等前一份做完。

这种“先声明、后调度”的设计叫 Sealevel 并行运行时,它是 Solana 区别于以太坊的灵魂。以太坊的 EVM 是单线程的,所有交易排队执行,哪怕两笔交易毫无关联也要等前面那笔跑完。Sealevel 则把交易按账户依赖关系做图着色:无依赖的交易进入不同执行线程并行处理,有冲突的交易在冲突账户串行化。由此,吞吐量从几百 TPS 跃升到数千甚至数万 TPS。

并行不是免费的。调度器需要先扫描每笔交易声明的账户列表,建立锁表;当两个线程同时请求同一账户时,必须有一个等待。此外,交易本身被设计成“无状态的”——交易里只写账户引用和指令,不隐含全局状态假设,这样任何节点都能独立验证同一笔交易是否合法。

Sp=1(1−P)+PN\displaystyle S_p = \frac{1}{(1 - P) + \dfrac{P}{N}}

1. P 并行占比:交易中访问互不冲突账户的比例。Solana 上大部分转账、代币操作天然无冲突,P 很高。

P=无冲突交易数总交易数P = \frac{\text{无冲突交易数}}{\text{总交易数}}

2. 1–P 串行部分:必须串行的部分,如同账本排序、冲突账户处理,是加速的天花板。

串行时间∝(1−P)\text{串行时间} \propto (1 - P)

3. N 执行单元数:Sealevel 可同时运行的线程数,取决于验证节点的 CPU 核数。

N=可用逻辑核心数N = \text{可用逻辑核心数}

4. Sp 加速比:分母越小、P 越接近 1,加速比越大——这就是 Solana 高吞吐的理论来源。

Sp=T串行T并行S_p = \frac{T_{\text{串行}}}{T_{\text{并行}}}

打开本文开头的可视化演示,你会看到这间并行厨房的真实运转:四条轨道上的交易各做各的,唯独抢同一账户时变红等待。Solana 的秘诀不是让厨师更快,而是让更多厨师同时干活。

资源租赁机制

中央厨房的冷藏柜空间有限,不能让人免费占用一辈子。Solana 的链上存储同理:验证节点的磁盘是稀缺资源,每个账户的 data 字节都占用真实硬件。因此 Solana 引入“租金”——账户必须为它占用的字节支付保鲜费,防止有人恶意囤积存储空间。

租金按“每个字节每年”计价,锁定期约为两年。开发者有两条路:一是存入足额押金,使余额达到“租金豁免最小值”,从此永久免费;二是只放少量 lamports,系统每个 epoch(约 2 天)自动扣除租金,扣到余额为 0 时账户可以被清空回收。实践中几乎所有人选择前者——一次押金,永久使用,像健身房买断年卡。

为什么要保留“不足额就扣”的选项?因为 Solana 允许零余额账户,比如只在短期内使用的临时数据。但如果真的一分钱不存,垃圾账户就会堆积。租金机制的经济学意义是:让存储成本显性化,激励开发者只保留必要数据,把大文件放 IPFS 等链外存储,链上只存指纹。

Bmin⁡=⌈sizebyte×Rrent⌉,Rrent≈0.00000348 SOL / byte / year\displaystyle B_{\min} = \left\lceil \text{size}_{\text{byte}} \times R_{\text{rent}} \right\rceil,\quad R_{\text{rent}} \approx 0.00000348\ \text{SOL / byte / year}

1. size_byte 数据大小:账户 data 字段的实际字节数,是计费基准。

sizebyte=len(data)\text{size}_{\text{byte}} = \text{len}(\text{data})

2. R_rent 费率:每个字节每年需要支付的 SOL 数,由集群全局参数决定。

Rrent≈3.48×10−6 SOLR_{\text{rent}} \approx 3.48 \times 10^{-6}\ \text{SOL}

3. 向上取整:⌈·⌉ 保证结果为整数 lamports,避免余额出现小数。

⌈x⌉=min⁡{n∈Z∣n≥x}\left\lceil x \right\rceil = \min\{n \in \mathbb{Z} \mid n \ge x\}

4. 豁免判定:账户余额大于等于 B_min 时,不再按 epoch 扣租,相当于“押金永久锁定”。

免租  ⟺  lamports≥Bmin⁡\text{免租} \iff \text{lamports} \ge B_{\min}

保鲜押金这个设计让整个厨房秩序井然:想长期存放食材,就一次付清冷藏柜押金;只想临时放一下,就按天付费,过期清走。我们的合约开发中,所有创建的账户都要精打细算这笔开销。

PDA派生机制

储物柜没有钥匙,怎么取物?寄存处给你一张小票,凭票取物。Solana 的程序没有私钥,怎么“签名”控制账户?靠 PDA——程序派生地址。PDA 是一类特殊的账户地址,它由程序地址、业务种子和修正值经哈希派生而来,任何人都能根据公开信息算出来,但它本身不在椭圆曲线上,所以没有对应的私钥。

为什么需要 PDA?想象一个“用户存钱罐”合约:用户存款后,合约要能安全地管理这笔资金,又不能把私钥交给任何人。PDA 恰好解决这个问题——地址由 program_id + seeds + bump 确定性派生,只有拥有该 program_id 的程序,才能在交易中通过 invoke_signed 对该地址行使签名权。攻击者无法伪造,因为伪造需要找到同一个 program_id。

具体派生过程:Seeds 是业务自定义的字节序列,比如 ["user-123", "order-45"];把 program_id、所有 seeds 和 bump 拼接后做 SHA-256 哈希;如果结果恰好落在 ed25519 曲线上的合法公钥位置(概率约 50%),就换一个 bump 重试,通常从 255 向下递减,第一个“落在线外”的就是合法 PDA。Bump 因此成为派生参数的一部分,必须永远记住。

PDA=SHA-256(program_id ∥ seeds ∥ bump),PDA∉Eed25519\displaystyle \text{PDA} = \text{SHA-256}(\text{program\_id} \,\|\, \text{seeds} \,\|\, \text{bump}),\quad \text{PDA} \notin \mathbb{E}_{\text{ed25519}}

1. program_id 程序身份:派生时强制掺入合约自身地址,防止其他程序“借壳”签出同一地址。

program_id=合约部署地址\text{program\_id} = \text{合约部署地址}

2. seeds 业务种子:由业务规则决定的字节序列,比如用户 ID 或订单号,让不同业务得到不同 PDA。

seeds=[b"user-1001", b"recipe-42"]\text{seeds} = [\text{b"user-1001"},\ \text{b"recipe-42"}]

3. bump 曲线修正:0–255 的整数。哈希结果落在曲线上时递增/递减调整,直至脱离曲线。

bump∈{0,1,…,255}\text{bump} \in \{0, 1, \ldots, 255\}

4. 曲线外判定:PDA 必须是非法 ed25519 公钥。曲线外点没有私钥,只有程序可代签。

PDA∉Eed25519\text{PDA} \notin \mathbb{E}_{\text{ed25519}}

PDA 像一张可复制的“万能小票”:谁都能凭公开信息推导出它,但只有指定程序才能凭它打开储物柜。你的 AI 数据存证合约里,每个数据集的指纹账户都可以用 PDA 管理,既透明又安全。

合约开发实战

后厨的运转规则清晰:接单 → 看菜单 → 备菜 → 出餐。Solana 合约的结构同样是一条固定流水线:程序入口、指令处理、数据序列化、错误处理。开发者先声明程序 ID,然后实现唯一的入口函数 process_instruction,所有外部调用都从这一道门进来。

入口函数收到三样东西:program_id(调用者声称的程序地址)、accounts(本次交易涉及的全部账户引用及权限标记)、instruction_data(调用方传来的指令字节)。合约第一步先把指令数据反序列化(主流用 Borsh 格式),得到一个枚举值,比如“转账”“存证”“查询”;然后逐一校验账户:签名者是否到齐、owner 是否匹配、PDA 种子是否正确;校验通过后才更新状态,最后返回 Ok 或 Err。任何一步出错,整个交易回滚——就像出餐时发现食材不对,整份订单作废重做,但厨房其他流水线不受影响。

错误处理是合约安全的重中之重。Solana 的合约错误码是 u32 的枚举,比如自定义 ErrorCode::Unauthorized。返回错误后,本次交易修改的所有账户状态都会被回滚,但交易费照扣。新手常犯的错是“先改状态后校验”——这等于先切了菜才发现拿错食材,白费功夫还可能留下脏数据。正确顺序永远是:校验 → 计算 → 写入。

process_instruction(program_id, accounts, data)⟶Result\displaystyle \text{process\_instruction}(\text{program\_id},\ \text{accounts},\ \text{data}) \longrightarrow \text{Result}

1. program_id 自证:合约先检查传入地址是否等于自身 ID,防止重放攻击。

assert(program_id=self id)\text{assert}(\text{program\_id} = \text{self id})

2. accounts 账户清单:结构体数组,每项含公钥、账户数据、权限元数据(是否签名、是否可变)。

accounts=[AccountMeta;n]\text{accounts} = [\text{AccountMeta}; n]

3. data 指令反序列化:用 Borsh 解析指令枚举和参数,得到明确的业务动作。

instruction=BorshDeserialize(data)\text{instruction} = \text{BorshDeserialize}(\text{data})

4. Result 返回类型:成功返回 Ok(()),失败返回带错误码的 Err,触发状态回滚。

Result=Result⟨(),ProgramError⟩\text{Result} = \text{Result}\langle (), \text{ProgramError} \rangle

一条清晰的后厨流水线,就是一个好合约。把校验放在最前、写入放在最后,每个环节都有专人负责,出错就整体回滚——这套纪律让 Solana 上动辄管理千万美元资产的合约能安稳运行。

部署与生态

厨房装修好、菜谱定好,不能直接开店——得先在自家小厨房试菜,再开分店,最后接入外卖平台。Solana 合约的开发部署也是三层:本地测试、测试网验证、主网发布。开发者在本地启动 Solana 验证节点(solana-test-validator),用脚本模拟交易调用合约,跑通再部署到 devnet 或 testnet 做集成测试,最后才上主网。

主网部署涉及升级权限管理:合约的可执行账户由 authority 控制,authority 可以在重新编译后用 solana program deploy 覆盖旧程序。为了安全,很多项目部署后会把 authority 交给 DAO 或多签,甚至置空——一旦置空,合约永久不可升级。同时,链上账户的资源租赁费用、PDA 初始化成本,都要在部署前用脚本预算好。

Solana 生态已经长出丰富的应用:DeFi 的订单簿和借贷协议、NFT 市场的元数据存储、DePIN 网络的设备身份管理。而它与 AI 的交汇点越来越清晰——AI 训练需要真实可信的数据集和充足的算力,Solana 恰好提供高速低费的数据存证与结算通道:数据集指纹、模型哈希、算力订单都可以写成合约账户,让训练过程可追溯、可验证。

TPS=ntxΔtslot,Δtslot≈400 ms\displaystyle \text{TPS} = \frac{n_{\text{tx}}}{\Delta t_{\text{slot}}},\quad \Delta t_{\text{slot}} \approx 400\ \text{ms}

1. n_tx 每槽交易数:一个 slot 内打包并执行的交易总数,受并行度影响。

ntx=∑slotexecuted txsn_{\text{tx}} = \sum_{\text{slot}} \text{executed txs}

2. Δt_slot 出块周期:Solana 约 400 毫秒出一个 slot,远快于以太坊的 12 秒。

Δtslot≈0.4 s\Delta t_{\text{slot}} \approx 0.4\ \text{s}

3. TPS 吞吐量:两者相除得到每秒交易数。Solana 通过并行和流水线把 n_tx 推高,TPS 因此达到数千级。

TPS=ntx0.4\text{TPS} = \frac{n_{\text{tx}}}{0.4}

高吞吐的出餐能力,让 Solana 成为数据密集型应用的理想厨房。对 AI 从业者来说,这意味着你可以把训练数据的每一条指纹都搬上链,用近乎实时的速度完成可信存证——区块链不只是炒币,更是给 AI 提供“可信食材”的供应链。

AI 应用场景

去中心化 AI 数据集指纹存证

阶段:数据准备与治理

解决的问题:传统数据集托管在中心服务器,训练方无法证明数据未被篡改或投毒。AI 事故追责时,往往连“这份数据到底是谁、何时、以什么版本进入训练集”都说不清。Solana 合约把数据集的哈希指纹、来源、版本写入链上账户,任何参与者都能验证同一份数据,天然满足审计需求。

具体案例:某医疗 AI 团队发布眼底影像数据集,将每个子集的 SHA-256 哈希通过 Solana 合约存证,并附带标注者签名。下游机构训练前先对账哈希,发现不一致立即拒收,投毒数据在源头被拦截。

分布式算力结算市场

阶段:模型训练与推理

解决的问题:传统算力交易依赖中心化平台撮合和记账,存在不透明、拖欠结算、漫天要价等问题。Solana 合约作为“自动收银台”,按训练任务的完成证明自动结算,每一笔算力买卖都在链上可查。

具体案例:一个去中心化训练平台把 GPU 任务切成小片,训练节点跑完后提交模型权重哈希作为工作量证明,合约校验通过即秒级发放 SOL 报酬,账本公开,没有中间商赚差价。

联邦学习奖励自动分发

阶段:激励与社区治理

解决的问题:联邦学习中成千上万参与者贡献本地梯度,人工发放奖励低效且容易出错。Solana 用 PDA 为每个参与者分配贡献账户,合约按贡献度自动 mint 并分发 token,全程无需人工干预。

具体案例:某开源语言模型项目采用联邦学习,用户提交梯度摘要后,合约根据数据质量评分自动发放治理代币;恶意提交者因质量分过低颗粒无收。整个激励机制写死在合约里,社区信任度大幅提升。

Python 演示

python42 行
# -*- coding: utf-8 -*-"""模拟 Solana PDA 派生与 Bump 搜索(教学简化版)真实实现使用 ed25519 曲线判定曲线外地址,这里用"首字节非零"做近似。"""import hashlib  def derive_pda(program_id: bytes, seeds: list, bump: int) -> bytes:    """按 Solana 规则拼接 program_id || seeds || bump 并做 SHA-256"""    seed_data = b"".join(seeds)    return hashlib.sha256(program_id + seed_data + bytes([bump])).digest()  def is_off_curve(pda: bytes) -> bool:    """简化判定:首字节不为 0 视为落在椭圆曲线之外"""    return pda[0] != 0  def find_valid_bump(program_id: bytes, seeds: list):    """从 255 向下搜索第一个合法 Bump 值"""    for bump in range(255, -1, -1):        pda = derive_pda(program_id, seeds, bump)        if is_off_curve(pda):            return bump, pda    return None  def main():    program_id = b"cookbook-demo"    seeds = [b"user-1001", b"recipe-42"]    bump, pda = find_valid_bump(program_id, seeds)    print("Bump:", bump)    print("PDA :", pda.hex())     # 同一组 program_id + seeds + bump 永远派生出同一个地址    bump2, pda2 = find_valid_bump(program_id, seeds)    assert pda == pda2    print("确定性校验通过:链上任何节点都能复现该地址")  if __name__ == "__main__":    main()
目的:用 Python 模拟 Solana PDA 的确定性派生和 Bump 搜索,帮助理解“没有私钥却能签名”的数学原理。
  1. seed_data = b"".join(seeds)把所有种子拼接成一段字节,种子必须按约定顺序排列,顺序变了地址就变了。
  2. hashlib.sha256(program_id + seed_data + bytes([bump])).digest()核心派生操作:拼上程序 ID 和修正值再做哈希,任何节点都能复现同样结果。
  3. for bump in range(255, -1, -1)从 255 向下穷举 Bump,确保拿到符合“曲线外”要求的最大候选值。
  4. if is_off_curve(pda)简化判定“地址不在椭圆曲线上”,真实实现会用 ed25519 库检查公钥合法性。
  5. assert pda == pda2验证确定性:同输入必同输出,这是 PDA 可被公开验证的根基。

常见误区

误区“账户不就是一串地址吗?我的钱包余额存在这个地址下面,跟以太坊没什么区别。”

正解以太坊账户的核心是“余额+nonce”,而 Solana 账户更像餐厅的“食材餐盒”——它是一块可容纳任意数据的存储空间,owner 字段决定谁能修改。同一个程序可以派生成千上万个业务账户,每个都有独立的数据和余额。理解这个差异,才能明白为什么 Solana 能在账户粒度上做并行。

为何常见:几乎所有公链教程都从“钱包地址”讲起,用户容易把“地址”和“账户”划等号;实际上 Solana 账户是数据容器,地址只是它的门牌号。

误区“PDA 肯定有一把私钥,只是被程序藏起来了,找到就能转走里面的资产。”

正解PDA 的数学本质是“不在 ed25519 椭圆曲线上”的地址,它根本不存在对应的私钥。它的签名权来自哈希约束:只有派生它的那个程序能通过 invoke_signed 代它签名。正因没有私钥,PDA 资产才不会被单点密钥泄露威胁。

为何常见:人们习惯了“地址=公钥、有公钥必有私钥”的直觉,不知道 PDA 是刻意构造的“曲线外点”,这是密码学反直觉的典型例子。

误区“Rust 和 Go 一样有 GC,运行时自动回收垃圾,所以不会有内存泄漏。”

正解Rust 根本没有垃圾回收器。它靠所有权系统在编译期确定每个值的生命周期,编译器在代码“上岗前”就把悬垂引用、双重释放等问题拦截掉。运行时零额外开销,这正是 Solana 选择它而不是 Go 的原因——链上每一纳秒都宝贵。

为何常见:现代语言“安全”几乎都与 GC 绑定,初学者自然会往这个方向联想;Rust 的非 GC 安全模型是它最需要重新理解的部分。

误区“账户只要创建了,就得一直交租金,像 AWS 月租一样,钱少了服务就停了。”

正解Solana 租金按 epoch(约 2 天)扣除,但只要你一次性存入 ≥ 租金豁免最小值,就永久不再扣。只有余额不足的账户才按周期扣,扣到 0 才可能被回收。合理设计是用最小豁免额买断存储,而不是持续付费。

为何常见:“租”这个字自带“持续付费”的语义,加上多数教程只讲“要交租金”没讲“豁免机制”,造成了普遍误解。

误区“Solana 能让所有交易并行,所以永远不会堵车,TPS 无限高。”

正解并行是有条件的——只有访问互不冲突账户的交易才能并行。两笔交易都要改同一个账户时,后者必须等待前者完成(这正是动效里红点等待的场景)。阿姆达尔定律决定了串行部分始终存在,TPS 有上限,只是远高于串行链。

为何常见:营销宣传强调“并行高吞吐”,用户容易忽略“账户冲突”这个前提条件,把并行误解为无限扩容。

面试题

Q1. Rust 保证内存安全的核心理念是什么?

单选题 · easy

  • A.依靠垃圾回收器自动清理
  • B.所有权系统在编译期检查← 正确答案
  • C.运行时引用计数追踪管理
  • D.由程序员手动管理分配内存

答案:B。Rust 靠所有权 + 借用 + 生命周期在编译期完成安全检查,没有 GC 也没有手动释放。A、C 是 Go/Java 等语言的做法,D 是 C/C++ 的做法,都会带来运行时开销或人为错误风险,而 Solana 需要零运行时成本的安全保证。

Q2. Solana 并行处理交易依赖的核心运行时是哪一个?

单选题 · easy

  • A.EVM 以太坊虚拟机
  • B.WASM 网页沙箱技术
  • C.Sealevel 并行运行时← 正确答案
  • D.Substrate 通用框架

答案:C。Sealevel 是 Solana 的并行智能合约运行时,能扫描交易声明的账户依赖并安排并行执行。EVM 是单线程串行执行,WASM 只是底层沙箱技术,Substrate 是另一条链(Polkadot)的框架,均不对应 Solana 的并行能力。

Q3. Solana 账户中决定“谁可以修改账户数据”的字段是哪个?

单选题 · mid

  • A.lamports 余额字段
  • B.data 数据内容字段
  • C.owner 所有者控制字段← 正确答案
  • D.executable 可执行标记

答案:C。owner 字段指向某个程序,只有该程序能写 data。lamports 只存余额,data 是数据本体,executable 标记是否为程序账户,它们都不具备权限控制功能。类比厨房:owner 是“负责这盒食材的大厨”标签。

Q4. 关于 Solana 账户租金制度,下列说法正确的是哪一项?

单选题 · mid

  • A.每一笔交易都必须支付租金
  • B.余额达到最小豁免额即可永久免费← 正确答案
  • C.租金按验证节点数量动态计算
  • D.租金会在交易后自动原路退回

答案:B。账户余额 ≥ 租金豁免最小值(约为两年租金)后,按 epoch 扣费自动停止,账户永久免费。租金与交易无关,与验证节点数量也无关,更不会退回。类比:冷藏柜押金一次付足,终身免月租。

Q5. Rust 中变量默认拥有“移动语义”,这意味着什么?

单选题 · easy

  • A.赋值后两个变量都可以使用
  • B.赋值后原变量不再可用← 正确答案
  • C.赋值操作会自动复制一份
  • D.变量自动提升为全局变量

答案:B。Rust 中赋值 let u = v 默认发生 move,所有权转移给 u,v 立即失效,防止双重重释放。A、C 是 Copy 类型或深拷贝行为,D 与作用域无关。这正是“所有权唯一”规则的具体表现。

Q6. PDA(程序派生地址)最重要的特性是什么?

单选题 · mid

  • A.拥有完全独立的私钥
  • B.处于椭圆曲线之外所以没有私钥← 正确答案
  • C.可以随时更换自己的公私钥对
  • D.由钱包的助记词加密生成

答案:B。PDA 通过哈希派生刻意落在 ed25519 椭圆曲线之外,数学上不存在私钥,只能由派生它的程序代签。A、C、D 都隐含“存在密钥对”的假设,与 PDA 的设计初衷相悖。没有私钥反而更安全——不存在可被窃取的私钥文件。

Q7. 两笔 Solana 交易要访问同一个账户时,Sealevel 会如何调度?

单选题 · hard

  • A.两者同时并行执行互不干扰
  • B.后者永久失败无法再提交
  • C.冲突账户部分会串行处理← 正确答案
  • D.节点随机拒绝其中一笔交易

答案:C。Sealevel 对无冲突交易并行,对有冲突账户的交易做串行化:前者执行完,后者才进入同一账户。B 说“永久失败”过于绝对,D 的随机拒绝不符合可预测性要求。这就像两位厨师抢同一个番茄,一个做完下一个再接。

Q8. Solana 实现高吞吐的来源包括哪些?

多选题 · hard

  • A.Sealevel 并行执行无冲突交易← 正确答案
  • B.交易无需声明所访问的账户
  • C.所有交易强制共享同一状态
  • D.交易预先声明所需账户引用← 正确答案

答案:AD。Solana 要求每笔交易预先列出要访问的账户,调度器据此识别冲突并并行执行,A 和 D 是因果配套。B 恰好说反——不声明就无法并行;C 与并行设计矛盾,共享全局状态恰恰会导致串行。预声明让“不抢食材”的订单能同时做。

Q9. 关于 PDA 的 Bump 搜索,下列说法正确的有哪些?

多选题 · hard

  • A.Bump 决定最终派生地址的哈希结果← 正确答案
  • B.Bump 通常从 255 向下递减搜索← 正确答案
  • C.Bump 需要用户私钥参与计算
  • D.Bump 的作用是让地址落在曲线之外← 正确答案

答案:ABD。Bump 拼接进哈希输入,直接影响结果;官方约定从 255 向下找第一个曲线外地址;其目的正是把 PDA 推出椭圆曲线点集。C 错误——PDA 派生只用 program_id、seeds 和 bump,与任何私钥无关。

Q10. 关于 Solana 账户模型,下列说法正确的是哪一项?

单选题 · mid

  • A.程序本身也是一个特殊账户← 正确答案
  • B.每个账户都强制存储代币
  • C.账户数据量越大租金豁免额越低
  • D.一个账户可以属于多个所有者

答案:A。程序账户是 executable 为真的账户,data 里装的是机器码,A 正确。B 错误——账户可以只有 lamports 没有 data;C 说反,数据越多豁免额越高;D 错误——owner 字段唯一,只能由一个程序控制。这就像餐盒标签上只能有一个“负责大厨”。