W3

Rust(Solana / Anchor)

Anchor 0.30+ · Rust 1.79+

Solana / SVM

无状态程序 + 账户显式传入,性能极高但心智模型与 EVM 完全不同

Solana 程序本身不存储状态,所有状态放在调用方显式传入的账户里。因此「账户列表」就是参数列表的一部分,账户约束(ownership、签名、地址、PDA)必须在代码里显式校验。Anchor 框架用宏把这些约束写成声明式注解,是当前的主流开发方式。

3 个语法章节3 段可复制代码含在线练习

从 Solidity 视角看差异

如果已经会 Solidity,这张表比从头读语法快得多。

差异点说明
状态位置EVM 是「合约里存状态」,Solana 是「账户里存状态,程序只负责读写」。
账户模型每个账户有 owner 程序,只有 owner 能改它的 data 与 lamports;跨程序写别人的账户会被直接拒绝。
指令与交易一笔交易可包含多条指令,指令之间通过账户读写隐式传递状态,没有跨程序调用栈的 storage 概念。
PDA程序派生地址(PDA)让程序能「签自己的名」来拥有账户,是 Solana 版「合约内转账」的实现方式。
1

程序结构与账户约束

1 段代码

Anchor 用 #[derive(Accounts)] 描述指令需要哪些账户,以及每个账户必须满足什么条件。

  • mut 表示会被修改(可写),缺省是只读;漏写 mut 会直接报 constraint 错误
  • has_one / seeds / constraint 在反序列化前就完成校验,是防错的第一道闸门
  • payer 用于创建账户时支付租金(rent)
  • Signer<'info> 表示该账户必须签名,Missing 签名是链上最常见的失败原因
Anchor 指令与账户校验
Anchor 指令与账户校验Rust

space = 8 + 数据长度:前 8 字节是 Anchor 的类型判别符,漏算会导致反序列化失败。

2

PDA 与 CPI

1 段代码

PDA 由 seeds + program_id 派生,程序可以「用 PDA 身份」转账或调用其他程序。

  • PDA 不在椭圆曲线上,所以没有私钥,只能由派生它的程序签名
  • seeds 顺序与内容都必须完全一致,否则派生出不同地址
  • CPI(跨程序调用)通过 invoke / invoke_signed 完成,后者用于 PDA 签名
  • 被调用的程序必须出现在指令的账户列表里,否则调用失败
PDA 签名转账
PDA 签名转账Rust
3

错误处理与溢出

1 段代码

Rust 的 Result 把「可能失败」写进类型签名,链上失败一律回滚整笔交易。

  • 生产代码一律用 checked_add / checked_sub / checked_mul,禁止裸算术
  • require! / require_eq! 宏可以把断言写成一行
  • Err 返回即整笔交易回滚,指令之间不会留下部分成功
  • 日志用 msg! 宏,会写进交易日志,可作为调试与索引数据源
Result、require 与日志
Result、require 与日志Rust

本章练习

这一段要让你看懂:Solana 的账户存储要预先付费(租金押金):space 少写一个字节,账户会创建失败;写多了,多余的押金就永久躺在账户里。这就是 Anchor 里那句 space = 8 + Counter::LEN 的由来。

试一试 · 算账户空间与租金押金

可直接改代码 · 在浏览器沙箱里真跑
playground.jsJavaScript
运行环境:iframe 沙箱(无 cookie 权限)。只支持纯 JS 片段,不支持 import / require;需要模块请用下方的完整示例复制到项目里。
检查点(跑完后逐条核对)
  • 0 字节账户的押金约为 0.00089088 SOL
  • SPL Token 账户(165 字节)的押金约为 0.00203928 SOL
  • Anchor Counter 的数据区 41 字节,总 space 49(含 8 字节判别符)
  • 带 metadata 的 Vault 数据区 81 字节,总 space 89

切换其他语言