在 Anchor 中:不同类型的账户

  • RareSkills
  • 发布于 2024-03-17 14:21
  • 阅读 178

本文详细介绍了 Solana Anchor 框架中的 [derive(Accounts)] 宏,解释了 Solana 并行交易处理机制及其账户访问控制的重要性,并深入探讨了 AccountUncheckedAccountSignerProgram 四种账户类型的使用场景和实现细节。

Anchor中的#[derive(Accounts)]:不同类型的账户

#[derive(Accounts)]在Solana Anchor中是一个类似属性的宏,用于包含所有在执行期间将被函数访问的账户的引用。

在Solana中,交易将要访问的每个账户必须提前指定

Solana之所以如此快速的一个原因是它以并行的方式执行交易。也就是说,如果Alice和Bob都想进行一笔交易,Solana将尝试同时处理他们的交易。然而,如果他们的交易因访问同一存储而发生冲突,就会出现问题。例如,假设Alice和Bob都在尝试写入同一账户。显然,他们的交易不能并行执行。

为了让Solana知道Alice和Bob的交易不能并行处理,Alice和Bob都必须提前指定所有他们的交易将更新的账户。

由于Alice和Bob都指定了一个(存储)账户,Solana运行时可以推断出两个交易之间存在冲突。必须选择一个(推测是支付了更高优先级费用的那个),另一个最终将失败。

这就是为什么每个函数都有自己单独的#[derive(Accounts)]结构体。结构体中的每个字段都是程序在执行期间打算(但并不要求)访问的账户。

一些以太坊开发者可能会注意到这一要求与EIP 2930访问列表交易的相似性。

账户的类型向Anchor信号你打算如何与该账户交互。

最常用的账户类型:Account、Unchecked Account、System Program和Signer

在我们初始化存储的代码中,我们看到了三种不同的“类型”账户:

  • Account
  • Signer
  • Program

这里是代码片段:

账户类型代码片段

当我们读取账户余额时,我们看到了第四种类型:

  • UncheckedAccount

这里是我们使用的代码:未检查账户的代码

我们用绿色框标出的每个项目都是通过文件顶部的anchor_lang::prelude::*;引入的。

AccountUncheckedAccountSignerProgram的目的是在继续之前对传入的账户进行某种检查,并且还提供与这些账户交互的函数。

我们将在接下来的部分进一步解释这四种类型。

Account

Account类型会检查被加载的账户的所有者是否确实被程序拥有。如果所有者不匹配,则不会加载。这作为一种重要的安全措施,以防止意外读取程序未创建的数据。

在以下示例中,我们创建了一个密钥对账户,并尝试将其传递给foo。因为该账户不属于程序,所以交易失败。

Rust:

use anchor_lang::prelude::*;

declare_id!("ETnqC8mvPRyUVXyXoph22EQ1GS5sTs1zndkn5eGMYWfs");

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

    pub fn foo(ctx: Context<Foo>) -> Result<()> {        
        // 我们不对账户SomeAccount做任何操作        
        Ok(())    
    }
}

##[derive(Accounts)]
pub struct Foo<'info> {    
    some_account: Account<'info, SomeAccount>,
}

##[account]
pub struct SomeAccount {}

Typescript:


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

describe("account_types", () => {
    async function airdropSol(publicKey, amount) {    
        let airdropTx = await anchor
            .getProvider()
            .connection.requestAirdrop(
                publicKey, 
                amount * anchor.web3.LAMPORTS_PER_SOL
            );  

        await confirmTransaction(airdropTx);  
    }  

    async function confirmTransaction(tx) {    
        const latestBlockHash = await anchor
            .getProvider()
            .connection.getLatestBlockhash();

        await anchor
            .getProvider()
            .connection.confirmTransaction({      
                blockhash: latestBlockHash.blockhash,       
                lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,      
                signature: tx,    
        });  
    }  

    // 配置客户端以使用本地区块链  
    anchor.setProvider(anchor.AnchorProvider.env());  

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

    it("账户拥有者错误", async () => {    
        const newKeypair = anchor.web3.Keypair.generate();    
        await airdropSol(newKeypair.publicKey, 10);    

        await program.methods
        .foo()
        .accounts({someAccount: newKeypair
        .publicKey}).rpc();  
    });
});

这是执行测试后的输出:

测试执行输出

如果我们向Account添加一个init宏,那么它将尝试将所有权从系统程序转...

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

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

0 条评论

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