本文详细介绍了如何在Solana原生Rust程序中读取和检查传递给入口点的账户数据。它通过提供Rust程序代码和TypeScript客户端测试代码,演示了如何迭代访问账户的公钥、Lamports余额、所有者、数据长度等关键元数据,并解释了AccountInfo结构体的作用。
正如我们在上一个教程中讨论的,入口点是你的 Solana 程序的“前门”,它处理所有进入程序的指令。
在本教程中,我们将学习如何通过入口点读取传递给我们原生 Rust Solana 程序的账户。
在 Anchor 中,你使用 #[derive(Accounts)] 宏定义你的程序所期望的账户:
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = user, space = 8 + 32)]
pub data_account: Account<'info, MyData>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[account]
pub struct MyData {
pub value: u64,
}
然后,你通过 Context 在指令处理器中访问这些账户:
#[program]
pub mod my_program {
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
// 其他函数逻辑
ctx.accounts.data_account.value = 100;
Ok(())
}
}
Anchor 处理账户验证并提供通过 Context 的类型化访问。在原生 Rust 中,你直接使用传递给指令处理器函数的原始 accounts 切片(我们在上一个教程中看到过)。
如果你需要复习 Solana 账户,请参阅在 Solana 和 Anchor 中初始化账户 和 Solana 计数器程序。
让我们构建一个程序,该程序读取并记录传递给指令处理器函数的账户。
首先,设置项目:
mkdir solana-storage
cd solana-storage
cargo init --lib solana-storage
将你的 Cargo.toml 更新为:
[package]
name = "solana-storage"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
[dependencies]
solana-program = "3.0.0"
borsh = "0.10"
我们添加了 borsh = "0.10" 用于未来的教程,其中我们将序列化账户数据。
将 src/lib.rs 中的代码替换为以下内容。该程序遍历每个提供的账户,并记录其公钥、Lamport 余额、所有者、数据长度,以及账户是否可执行、可写或签名者。它通过传递给 process_instruction 的 accounts 参数访问这些账户,accounts 参数是一个 AccountInfo 结构体数组。AccountInfo 是用于表示链上账户的原生 Solana 类型。为了避免记录大量数据,程序只打印每个账户数据的前 8 字节,作为存储内容的预览。
use solana_program::{
account_info::AccountInfo,
entrypoint,
entrypoint::ProgramResult,
msg,
pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
msg!("Storage Program: Examining {} accounts", accounts.len());
// 创建一个账户迭代器以安全访问每个账户
let accounts_iter = &mut accounts.iter();
// 遍历每个账户并记录其元数据
for (index, account) in accounts_iter.enumerate() {
msg!("Account {}: {}", index, account.key);
msg!("Lamports: {}", account.lamports());
msg!("Owner: {}", account.owner);
msg!("Data length: {} bytes", account.data_len());
msg!("Executable: {}", account.executable);
msg!("Writable: {}", account.is_writable);
msg!("Is signer: {}", account.is_signer);
// 仅记录前 8 字节以避免日志过多
if account.data_len() > 0 {
let data = account.try_borrow_data()?;
// 取 8 和 data.len() 中的较小值,以避免超出缓冲区切片。
// 这将预览限制为最多 8 字节,同时保持在界限内。
let preview_len = std::cmp::min(8, data.len());
msg!("First {} bytes: {:?}", preview_len, &data[..preview_len]);
} else {
msg!("No data stored");
}
msg!(""); // 空行用于提高可读性
}
Ok(())
}
在我们之前的基于...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!