Solana 60 天课程

2025年02月27日更新 89 人订阅
原价: ¥ 66 限时优惠
专栏简介 开始 Solana - 安装与故障排除 Solana 和 Rust 中的算术与基本类型 Solana Anchor 程序 IDL Solana中的Require、Revert和自定义错误 Solana程序是可升级的,并且没有构造函数 Solidity开发者的Rust基础 Rust不寻常的语法 Rust 函数式过程宏 Rust 结构体与属性式和自定义派生宏 Rust 和 Solana 中的可见性与“继承” Solana时钟及其他“区块”变量 Solana 系统变量详解 Solana 日志、“事件”与交易历史 Tx.origin、msg.sender 和 onlyOwner 在 Solana 中:识别调用者 Solana 计算单元与交易费用介绍 在 Solana 和 Anchor 中初始化账户 Solana 计数器教程:在账户中读写数据 使用 Solana web3 js 和 Anchor 读取账户数据 在Solana中创建“映射”和“嵌套映射” Solana中的存储成本、最大存储容量和账户调整 在 Solana 中读取账户余额的 Anchor 方法:address(account).balance 功能修饰符(view、pure、payable)和回退函数在 Solana 中不存在的原因 在 Solana 上实现 SOL 转账及构建支付分配器 使用不同签名者修改账户 PDA(程序派生地址)与 Solana 中的密钥对账户 理解 Solana 中的账户所有权:从PDA中转移SOL Anchor 中的 Init if needed 与重初始化攻击 Solana 中的多重调用:批量交易与交易大小限制 Solana 中的所有者与权限 在Solana中删除和关闭账户与程序 在 Anchor 中:不同类型的账户 在链上读取另一个锚点程序账户数据 在 Anchor 中的跨程序调用(CPI) SPL Token 的运作方式 使用 Anchor 和 Web3.js 转移 SPL Token Solana 教程 - 如何实现 Token 出售 基础银行教程 Metaplex Token 元数据工作原理 使用Metaplex实施代币元数据 使用 LiteSVM 进行时间旅行测试 Solana Token-2022 标准规范 生息代币第一部分 计息代币第二部分 Solana 指令自省 Solana 中的 Ed25519 签名验证 Solana - Switchboard 预言机使用 原生Solana:程序入口与执行 原生 Solana :读取账户数据 原生 Solana :Borsh 序列化 原生 Solana:使用 invoke 和 invoke signed 进行跨程序调用 原生 Solana :创建存储账户 (一) 原生 Solana:创建存储账户 二 原生 Solana: 函数分发 原生 Solana:关键安全检查 Rust 程序到 SBF 编译 sBPF 虚拟机和指令集介绍 跟踪 sBPF 指令执行和计算成本 Solana 程序执行与输入序列化 指令处理器和运行时设置 sBPF 内存布局和寄存器约定 使用 sBPF 汇编读取 Solana 指令输入 Solana 系统调用:sBPF 汇编中的日志记录

原生 Solana :读取账户数据

本文详细介绍了如何在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 条评论

请先 登录 后评论