欢迎订阅专栏:10分钟Solana-性能web3
Solana 上的智能合约被称为程序(Program)。与以太坊合约不同,Solana 的程序是无状态的——程序的代码与它处理的数据(账户)是分离的。所有可变的状态都存储在独立的数据账户(Data Account) 中,由程序负责读写。
🧬 开发语言与工具链
Solana 程序主要用 Rust 编写,通过 LLVM 编译器框架编译为 eBPF 字节码,在 Solana 虚拟机 (SVM) 上执行。
核心工具链包括:
- Rust & Cargo:主要的编程语言和构建系统。
- Solana CLI:用于与网络交互,如创建钱包、部署程序等。
- solana-program SDK:提供编写链上程序所需的基础类型和宏。
🏗️ Anchor 框架:Solana 开发的“标准答案”
在实际开发中,Anchor 是事实上的标准框架。它通过 Rust 宏极大地简化了开发流程。
- 主要功能:
- 项目脚手架:
anchor init命令一键生成完整的项目结构,包含程序、测试、部署配置和 TypeScript 类型。 - 账户验证与序列化:通过
#[derive(Accounts)]宏声明式地定义和验证交易账户。 - 程序逻辑:通过
#[program]宏定义指令处理函数。 - 状态定义:通过
#[account]宏定义链上账户的数据结构。
- 项目脚手架:
💻 一个标准的 Solana 程序
这是一个由 Anchor 框架生成的极简计数器程序,它定义了一个初始化指令,用于创建一个新账户并存储一个数字。
// 引入 Anchor 框架的预导入模块
use anchor_lang::prelude::*;
// 声明程序的链上地址(部署时会自动更新)
declare_id!("11111111111111111111111111111111");
// #[program] 宏定义了程序的指令入口
#[program]
mod hello_anchor {
use super::*;
// 这是一个名为 initialize 的指令
// 它接收一个 Context<Initialize> 和一个 u64 类型的 data
pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
// 将传入的 data 存储到新账户的 data 字段中
ctx.accounts.new_account.data = data;
// 打印日志
msg!("Changed data to: {}!", data);
Ok(())
}
}
// #[derive(Accounts)] 宏用于定义指令所需的账户列表及约束
#[derive(Accounts)]
pub struct Initialize<'info> {
// 定义了一个新账户,它将被初始化 (init)
// 由 signer 支付创建账户的费用 (payer)
// 并分配 8(Anchor 账户鉴别器)+ 8(u64 数据)字节的空间 (space)
#[account(init, payer = signer, space = 8 + 8)]
pub new_account: Account<'info, NewAccount>,
// 交易签名者,被标记为可变 (mut) 以支付 lamports
#[account(mut)]
pub signer: Signer<'info>,
// 系统程序,用于创建新账户
pub system_program: Program<'info, System>,
}
// #[account] 宏定义了链上账户的数据结构
#[account]
pub struct NewAccount {
data: u64, // 存储一个 64 位无符号整数
}
简单来说,这个合约的 initialize 指令会创建一个由 NewAccount 结构定义的新账户,并将传入的数字保存其中。
🚀 部署与调用
部署和调用 Solana 程序,本质上是链上账户的创建与使用:
- 编译:将 Rust 代码编译为 eBPF 字节码(
.so文件)。 - 部署:使用
solana program deploy命令将编译好的字节码部署到链上,这会创建一个程序账户(Program Account)。 - 调用:通过构造交易(Transaction) 来调用程序。交易中必须明确列出所有被读取或修改的账户,包括程序本身、指令涉及的账户和签名者。
- 客户端交互:Anchor 会自动生成 IDL (接口描述语言) 文件,前端可以使用它配合 TypeScript 客户端类型安全地调用合约。
🛡️ 安全最佳实践
- 账户验证:始终验证传入的账户是否符合预期(如所有者、是否可写、是否是 PDA),推荐使用 Anchor 的账户约束自动完成。
- 所有权与权限:严格遵循账户模型,确保只有账户的
owner程序才能修改其数据。 - PDA 签名:使用 PDA 时,必须验证
seeds和bump,确保程序有权限代表 PDA 进行操作。 - 重入防护:虽然 Solana 的并行模型降低了风险,但在跨程序调用 (CPI) 时仍需注意重入攻击。
- 关闭账户:提供关闭账户的指令,并将剩余的 lamports 退还给用户,避免存储浪费。
- 代码审计:在主网部署前,务必进行专业的安全审计。
🧪 开发环境准备
- 安装 Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - 安装 Solana CLI:
sh -c "$(curl -sSfL https://release.solana.com/stable/install)" - 安装 Anchor CLI:
cargo install avm --git https://github.com/solana-foundation/anchor --locked && avm install 1.0.0 && avm use 1.0.0 - 验证安装:
anchor --version solana --version rustc --version
💎 总结
- 无状态程序:Solana 程序的代码与状态(数据账户)是分离的。
- 核心语言:主要使用 Rust 开发,编译为 eBPF 字节码。
- 官方推荐框架:使用 Anchor 可以大幅简化开发、测试和部署流程。
- 开发流程:通过 Solana CLI 和 Anchor CLI 实现从编译、部署到测试的全流程管理。
- 前端交互:Anchor 生成的 IDL 可实现类型安全的前端调用。
如果想深入了解某个部分,比如 Anchor 的 PDA 账户管理或如何进行跨程序调用(CPI),可以随时再问我。