Solana 60 天课程

2025年02月27日更新 92 人订阅
原价: ¥ 66 限时优惠
专栏简介

原生 Solana :读取账户数据

  • RareSkills
  • 发布于 2026-02-28 09:38
  • 阅读 736

本文详细介绍了如何在Solana原生Rust程序中读取和检查传递给入口点的账户数据。它通过提供Rust程序代码和TypeScript客户端测试代码,演示了如何迭代访问账户的公钥、Lamports余额、所有者、数据长度等关键元数据,并解释了AccountInfo结构体的作用。

原生 Solana:读取账户数据

正如我们在上一个教程中讨论的,入口点是你的 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 计数器程序

构建 Rust 程序

让我们构建一个程序,该程序读取并记录传递给指令处理器函数的账户。

首先,设置项目:

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_instructionaccounts 参数访问这些账户,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(())
}

在我们之前的基于...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论