Anchor 中 #[program] #[derive(Accounts)] #[account] 这三者之间是怎么样的关系

  • 曲弯
  • 发布于 13小时前
  • 阅读 17

[program][derive(Accounts)][account]这三者之间是怎么样的关系这三个宏是Anchor框架的核心,理清它们的关系是入门的关键。我们可以通过一个生动的比喻来理解:开发一个Anchor程序就像拍摄一部电影。下面我们详细拆解这个“电影剧组”的运

<!--StartFragment-->

[program] #[derive(Accounts)] #[account] 这三者之间是怎么样的关系

这三个宏是 Anchor 框架的核心,理清它们的关系是入门的关键。我们可以通过一个生动的比喻来理解:开发一个 Anchor 程序就像拍摄一部电影

image.png

下面我们详细拆解这个“电影剧组”的运作方式。

🎬 核心成员分工

1. #[program]:剧本和导演

它定义了程序的所有可执行指令,包含了“做什么”的业务逻辑。

  • 作用对象:一个模块(mod)。
  • 核心职责:在这个模块下,每个公共函数(如 initialize, increment)就是一个可以被外部调用的链上指令。它负责处理具体的计算、状态变更等核心逻辑。

2. #[derive(Accounts)]:演员名单和进场规则

它定义了执行某个特定指令时所需的所有账户的集合、验证规则和安全约束,规定了“用谁来做”以及“他们需要满足什么条件”

  • 作用对象:一个结构体(struct)。每个指令都有自己专属的账户结构体,这是因为不同的指令需要操作不同的账户,有着不同的安全要求。
  • 核心职责:自动生成代码来验证传入的账户是否合法。例如,账户是否为签名者、是否可变、是否是程序派生地址(PDA)等。

3. #[account]:角色设定

它用于定义自定义账户的数据结构,即这个账户在链上“存储什么”数据。

  • 作用对象:一个结构体(struct)。

  • 核心职责

    • 自动序列化/反序列化:根据定义的结构,自动将内存中的数据转换为可存储在链上的字节格式,以及反向转换。
    • 设置程序所有者:自动将该账户的所有者设置为当前程序。
    • 添加标识符:自动为账户数据添加一个8字节的discriminator,用于在反序列化时唯一识别账户类型。

💡 结合实例理解互动

让我们用经典的计数器程序片段,具体看它们如何协作:

  1. 定义数据结构(角色设定)

    首先,我们用 #[account]定义计数器账户里要存什么数据。

    #[account]
    pub struct Counter {
       pub count: u64, // 只有一个计数字段
    }
  2. 定义指令的账户上下文(演员名单)

    然后,为“初始化计数器”这个指令定义它需要的账户和规则。

    #[derive(Accounts)]
    pub struct Initialize&lt;'info> {
       #[account(init, payer = user, space = 8 + 8)] // 规则:创建新账户,用户付租金,分配空间
       pub counter: Account&lt;'info, Counter>, // 账户:一个Counter类型的账户
       #[account(mut)]
       pub user: Signer&lt;'info>, // 账户:必须是交易的签名者
       pub system_program: Program&lt;'info, System>, // 账户:必须传入系统程序
    }
  3. 实现指令逻辑(导演说“开机!”)

    最后,在 #[program]下实现指令函数。Anchor会自动将账户验证和业务逻辑绑定。

    #[program]
    pub mod counter_program {
       use super::*;
    
       pub fn initialize(ctx: Context&lt;Initialize>) -> Result&lt;()> {
           // 开拍!这里可以安全地使用已经通过验证的账户
           let counter = &mut ctx.accounts.counter; // 拿到counter账户
           counter.count = 0; // 执行逻辑:设置初始值为0
           Ok(())
       }
    }

⚠️ 关键记忆点

  • 依赖关系#[program]中的指令函数通过 Context&lt;T>依赖​ 特定的 #[derive(Accounts)]结构体(T)。而 #[derive(Accounts)]结构体中的 Account类型,又依赖#[account]定义的数据结构。
  • 职责分离#[account]管数据长什么样#[derive(Accounts)]管需要哪些人(账户)并检查他们的资格#[program]管具体做什么事
  • 编译时魔法:Anchor 在编译时,会利用这些宏生成大量样板代码(如账户验证、序列化等),让我们能专注于核心逻辑。 <!--EndFragment-->
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
曲弯
曲弯
0xb51E...CADb
江湖只有他的大名,没有他的介绍。