在 Solana 中读取账户余额的 Anchor 方法:address(account).balance

文章介绍了如何在Solana程序中使用Anchor框架读取账户余额,并详细解释了UncheckedAccount的使用及其安全性考虑。

Solona和Anchor获取账户余额

在Anchor Rust中读取账户余额

要在Solana程序中读取地址的Solana余额,请使用以下代码:

use anchor_lang::prelude::*;

declare_id!("Gnf6u7S7fGJbqEGH9PuDE5Prq6f6ZrDxHY3jNJ4SYySQ");

#[program]
pub mod balance {
    use super::*;

    pub fn read_balance(ctx: Context<ReadBalance>) -> Result<()> {
        let balance = ctx.accounts.acct.to_account_info().lamports();

        msg!("余额以Lamports表示为 {}", balance);
        Ok(())
    }
}

#[derive(Accounts)]
pub struct ReadBalance<'info> {
    /// CHECK: 尽管我们读取这个账户的余额,但我们并没有用到这个信息
    pub acct: UncheckedAccount<'info>,
}

下面是触发它的web3 js代码:

import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { Balance } from "../target/types/balance";

describe("balance", () => {
  // 配置客户端以使用本地集群。
  anchor.setProvider(anchor.AnchorProvider.env());

  const program = anchor.workspace.Balance as Program<Balance>;

  // 以下是我们使用的Solana钱包
  let pubkey = new anchor.web3.PublicKey("5jmigjgt77kAfKsHri3MHpMMFPo6UuiAMF19VdDfrrTj");

  it("测试余额", async () => {
    const tx = await program.methods.readBalance().accounts({ acct: pubkey }).rpc();
  });
});

本示例中的某些项与以前的教程不同,特别是使用UncheckedAccount

在Solana Anchor中什么是UncheckedAccount

UncheckedAccount类型通知Anchor不检查正在读取的账户是否被该程序拥有。

注意,我们通过Context结构传递的账户并不是该程序初始化的账户,因此该程序并不拥有它。

当Anchor读取#[derive(Accounts)]中的Account类型账户时,它会检查(在后台)该账户是否被该程序拥有。如果不拥有,执行将会停止。

这作为一个重要的安全检查。

如果恶意用户构造了一个该程序未创建的账户,并将其传递给Solana程序,而Solana程序盲目信任该账户中的数据,就可能发生严重错误。

例如,如果该程序是一个银行,而该账户存储了用户的余额,那么黑客可以提供一个不同的账户,其人工作高于实际余额。

不过,要实施这个黑客,用户必须在单独的交易中创建虚假账户,然后将其传递给Solana程序。然而,Anchor框架会在后台检查该账户是否不被程序拥有,并拒绝读取该账户。

UncheckedAccount绕过了这个安全检查。

重要AccountInfoUncheckedAccount是彼此的别名,并且AccountInfo具有相同的安全性考虑。

在我们的案例中,我们传递的账户显然不被程序拥有——我们想检查一个任意账户的余额。因此,我们必须确保移除这个安全检查后没有关键逻辑可以被篡改。

在我们的案例中,我们只是将余额记录到控制台,但大多数现实案例会有更复杂的逻辑。

什么是/// CHECK:

由于使用UncheckedAccount的危险性,Anchor强制你包括此注释,以鼓励你不要忽视安全考虑。

练习:删除/// CHECK:注释并运行anchor build,你应该看到构建停止,并要求你添加回注释并解释为什么未经检查的账户是安全的。也就是说,读取不可信的账户可能是危险的,Anchor希望确保你不对账户中的数据执行任何关键操作。

为什么程序中没有#[account]结构?

#[account]结构告诉Anchor如何反序列化持有数据的账户。例如,以下看似的账户结构将通知Anchor将存储在账户中的数据反序列化为一个单一的u64

#[account]
pub struct Counter {
    counter: u64
}

然而,在我们的案例中,我们并不想从账户中读取数据——我们只想读取余额。这类似于我们可以读取以太坊地址的余额,而无法读取其代码。由于我们想反序列化数据,因此我们不提供#[account]结构。

并非所有账户中的SOL都是可支配的

回忆一下我们关于Solana账户租金的讨论,账户必须保持一定的SOL余额以便“免租”,否则运行时将删除该账户。仅仅因为账户中有“1 SOL”并不一定意味着该账户可以支配全部1 SOL。

例如,如果你正在构建一个质押或银行应用程序,其中用户存入的SOL存放在单独的账户中,那么简单地测量这些账户的SOL余额并不准确,因为租金将包含在余额中。

了解更多

请参阅我们的Solana开发者课程以获取更多Solana材料。

最初发布于2024年2月29日

  • 原文链接: rareskills.io/post/solan...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/