账户模型
#![allow(unused)]
fn main() {
pub struct Account{
pub lamports:u64,
pub data:Vec<u8>,
pub owner:Pubkey,
pub executable:bool,
pub rent_epoch:Epoch,
}
}
结构分析:
| 字段 | 类型 | 作用 |
|---|---|---|
| lamports | u64 | 表示账户的 SOL 余额,以 Lamports 为单位。1 SOL = 1,000,000,000 Lamports(10^9)。用于支付交易费用和账户租金。 |
| data | Vec<u8> | 存储账户的实际数据内容。对于数据账户,存储由 owner program 定义和解析的状态数据;对于程序账户,可能存储可执行字节码或指向程序数据账户的地址。 |
| owner | Pubkey | 表示拥有该账户写权限的程序 ID。owner program 可以修改账户数据或扣减账户 lamports,任意程序可以向可写账户增加 lamports。 |
| executable | bool | 标识该账户是否为可执行账户。当为 `true` 时,表示账户存储的是可执行的智能合约;否则,为普通账户。 |
| rent_epoch | Epoch | 历史遗留字段。早期用于记录账户租金周期;当前重点是账户需要满足 rent-exempt minimum,租金周期字段已不再作为定期扣费依据。 |
关键字说明
• lamports (u64):
• 类型:无符号 64 位整数 (u64)。
• 作用:账户的 SOL 余额,以 Lamports 为单位。用于支付交易费用和账户租金,确保账户持有足够的余额以维持其在区块链上的存在。
• data (Vec<u8>):
• 类型:动态字节向量 (Vec<u8>)。
• 作用:存储账户的实际数据。对于数据账户,可以存储代币余额、NFT 元数据等由程序定义的状态;对于程序账户,可能存储可执行字节码或指向程序数据账户的地址。账户数据的格式由 owner program 定义,普通钱包账户通常不用于存储应用状态。
• owner (Pubkey):
• 类型:公钥 (Pubkey) –solana自定义类型,非rust原生。
• 作用:标识拥有该账户写权限的程序 ID。只有 owner program 可以修改账户的 data 字段或扣减账户中的 lamports;任意程序可以向可写账户增加 lamports。这里的 owner 不是“用户所有者”,而是 Solana runtime 用来判断账户修改权限的程序地址。
• executable (bool):
• 类型:布尔值 (bool)。
• 作用:标识账户是否为可执行账户。当设置为 true 时,表示该账户存储的是可执行的智能合约;否则,为普通账户,用于存储数据和资产。
• rent_epoch (Epoch):
• 类型:Epoch 类型,表示区块链的一个时间周期–solana自定义类型,非rust原生。
• 作用:历史上用于管理账户的存储租金周期。当前租金定期扣除机制已废弃,新账户通常需要满足 rent-exempt minimum,即根据账户数据大小存入最低 lamports 余额以保持账户留存在链上。
rent_epoch :这是从 Solana 有定期从账户扣除 lamports 的机制时遗留下来的一个旧字段。虽然这个字段在 Account 类型中仍然存在,但由于租金收集已被弃用,它不再被使用。
示例
Solana 账户的 Account 结构体实例:
#![allow(unused)]
fn main() {
let account = Account {
lamports: 1_000_000_000, // 1 SOL
data: vec![0, 1, 2, 3], // 存储的数据
owner: Pubkey::new_unique(), // owner program 的地址,此处仅作示例
executable: false, // 普通账户
rent_epoch: u64::MAX, // 历史遗留字段,rent-exempt 账户通常为 u64::MAX
};
}
原生程序(Native Programs)
以下大部分为对solana官方文档的翻译,如有谬误请联系指正!
系统程序:
1.创建链上所有的新账户
2.为账户分配数据空间
3.转移账户所有权到自定义程序中
BPF加载器
全称 Berkeley Packet Filter Loader(伯克利包过滤器加载器)。在 Solana 中,程序会被编译为 sBPF 字节码,并由 loader program 负责部署、升级和执行。 1.已部署程序账户的 owner 通常是某个 loader program
2.处理程序部署和升级
-
系统程序(System Program)
所有在 Solana 上的“钱包”账户都只是由系统程序拥有的账户。这些账户中存储的 lamport 余额代表钱包拥有的 SOL 数量。只有由系统程序拥有的账户才能用作交易费用支付者。 -
BPF Loader
BPF Loader 是 Solana 用来管理链上程序的加载器,不包括其他原生程序。它负责部署、升级和执行自定义程序;当前常见的可升级程序通常由 BPF Loader Upgradeable(loader-v3)管理。
系统变量账户(Sysvar Accounts)
Sysvar 账户是位于预定义地址的特殊账户,提供对集群状态数据的访问。这些账户会动态更新关于网络集群的数据。账户类型见 Sysvars。
自定义程序(Custom Programs)
在 Solana 上,“智能合约”被称为程序。程序是包含可执行代码的账户。程序账户的 executable 标志为 true。
程序被部署到网络中,可以被用户和其他程序调用以执行它们的指令。
程序账户(Program Account)
Loader-v3 的可升级程序涉及以下账户;部署阶段的临时缓冲账户与持续存在的程序账户不同:
- Program:程序入口账户,记录 ProgramData 地址。
- ProgramData:保存程序代码、升级权限等信息。
- 缓冲账户:在程序部署或升级期间创建的临时账户,用于存储程序的执行代码。成功部署后,代码将被移动到程序执行数据账户,缓冲账户将被关闭。
例如,以下是 Token Extensions Program Account 及其对应的 Program Executable Data Account 在 Solana Explorer 中的链接。 指令使用程序账户地址作为 Program ID。Loader-v3 的 Program 账户指向 ProgramData,后者保存程序代码与升级权限;账户关系依赖所使用的加载器版本。
数据账户(Data Account)
Solana 上的程序是“无状态的”,这意味着程序账户仅存储可执行代码,不存储用于读取的数据。 为了维护状态,程序定义指令以创建由程序拥有的单独账户。每个账户都有自己的唯一地址,可以存储程序定义的任何任意数据。 注意,只有系统程序可以创建新的账户。一旦系统程序创建了账户,它就可以将新账户的所有权转让给另一个程序。 换句话说,为自定义程序创建数据账户需要两个步骤:
1.调用系统程序创建账户,然后将其所有权转让给自定义程序
2.调用现在拥有账户的自定义程序,然后初始化程序指令定义的账户数据
这个账户创建过程通常被抽象为单一步骤。