Solana Playground | 18 小时最全 Solana 教程 - 2024 训练营

  • Alan
  • 更新于 3天前
  • 阅读 203

学习Solana,https://github.com/solana-developers/developer-bootcamp-2024 https://space.bilibili.com/581611011/channel/collectiondetail?sid=4304339

// Our program's address!
// This matches the key in the target/deploy directory
declare_id!("ww9C83noARSQVBnqmCUmaVdbJjmiwcV9j2LkXYMoUCV");

// Anchor programs always use 8 bits for the discriminator
pub const ANCHOR_DISCRIMINATOR_SIZE: usize = 8;

// Our Solana program! 
#[program]
pub mod favorites {
    use super::*;

    // Our instruction handler! It sets the user's favorite number and color
    pub fn set_favorites(context: Context<SetFavorites>, number: u64, color: String, hobbies: Vec<String>) -> Result<()> {
        let user_public_key = context.accounts.user.key();
        msg!("Greetings from {}", context.program_id);
        msg!(
            "User {user_public_key}'s favorite number is {number}, favorite color is: {color}",
        );

        msg!(
            "User's hobbies are: {:?}",
            hobbies
        ); 

        context.accounts.favorites.set_inner(Favorites {
            number,
            color,
            hobbies
        });
        Ok(())
    }

    // We can also add a get_favorites instruction handler to return the user's favorite number and color
}

// What we will put inside the Favorites PDA
#[account]
#[derive(InitSpace)]
pub struct Favorites {
    pub number: u64,

    #[max_len(50)]
    pub color: String,

    #[max_len(5, 50)]
    pub hobbies: Vec<String>
}
// When people call the set_favorites instruction, they will need to provide the accounts that will be modifed. This keeps Solana fast!
#[derive(Accounts)]
pub struct SetFavorites<'info> {
    #[account(mut)]
    pub user: Signer<'info>,

    #[account(
        init_if_needed, 
        payer = user, 
        space = ANCHOR_DISCRIMINATOR_SIZE + Favorites::INIT_SPACE, 
        seeds=[b"favorites", user.key().as_ref()],
    bump)]
    pub favorites: Account<'info, Favorites>,

    pub system_program: Program<'info, System>,
}

<!--StartFragment-->

1. 程序定义和程序 ID

declare_id!("ww9C83noARSQVBnqmCUmaVdbJjmiwcV9j2LkXYMoUCV");
  • 这一行声明了 Solana 程序的唯一标识符(程序 ID)。该程序 ID 应该匹配部署时生成的公钥。
  • 该 ID 用于区分不同的智能合约和确保与其他程序的交互。

2. 常量定义:ANCHOR_DISCRIMINATOR_SIZE

pub const ANCHOR_DISCRIMINATOR_SIZE: usize = 8;
  • ANCHOR_DISCRIMINATOR_SIZE 定义了 Anchor 框架所使用的区分符(discriminator)的大小。在 Solana 中,所有账户都有一个区分符,用于确保账户类型的一致性。Anchor 使用 8 字节的区分符来区分不同类型的账户。

3. 主程序结构:#[program]

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

    pub fn set_favorites(context: Context&lt;SetFavorites>, number: u64, color: String, hobbies: Vec&lt;String>) -> Result&lt;()> {
        let user_public_key = context.accounts.user.key();
        msg!("Greetings from {}", context.program_id);
        msg!(
            "User {user_public_key}'s favorite number is {number}, favorite color is: {color}",
        );

        msg!(
            "User's hobbies are: {:?}",
            hobbies
        ); 

        context.accounts.favorites.set_inner(Favorites {
            number,
            color,
            hobbies
        });
        Ok(())
    }
}

学习重点:

  • #[program] 宏标记了一个 Solana 程序。
  • set_favorites 函数是主处理逻辑,接收三个参数:用户的数字、颜色和爱好。该函数会将这些信息存储在一个名为 favorites 的账户中。
  • msg! 用于输出日志信息,这在调试时非常有用,可以显示交易的相关信息。
  • context.accounts.favorites.set_inner() 是一个 Anchor 提供的功能,用于将数据写入指定的账户,确保这些账户的状态得到更新。

4. 账户定义:#[account]

#[account]
#[derive(InitSpace)]
pub struct Favorites {
    pub number: u64,
    #[max_len(50)]
    pub color: String,
    #[max_len(5, 50)]
    pub hobbies: Vec&lt;String>
}

学习重点:

  • #[account] 宏标记了一个账户结构体,定义了程序需要用到的账户类型。
  • Favorites 结构体包含三个字段:numbercolorhobbies。这些字段代表用户的最爱信息。
  • #[max_len] 宏限制了 color 字符串的最大长度为 50,hobbies 向量的每个元素的最大长度为 50,并且最多包含 5 个元素。这些限制用于优化存储,避免不必要的数据浪费。
  • #[derive(InitSpace)] 用于为该账户提供空间计算功能,确保初始化时分配足够的空间。

5. 账户处理:SetFavorites

#[derive(Accounts)]
pub struct SetFavorites&lt;'info> {
    #[account(mut)]
    pub user: Signer&lt;'info>,

    #[account(
        init_if_needed, 
        payer = user, 
        space = ANCHOR_DISCRIMINATOR_SIZE + Favorites::INIT_SPACE, 
        seeds=[b"favorites", user.key().as_ref()],
        bump
    )]
    pub favorites: Account&lt;'info, Favorites>,

    pub system_program: Program&lt;'info, System>,
}

学习重点:

  • #[derive(Accounts)] 宏用来定义与该指令相关的账户结构体。

  • user 是一个签名账户,表示执行该操作的用户。Signer 类型的账户代表一个可以签署交易的用户。

  • favorites 是存储用户最爱信息的账户。如果该账户还不存在,程序会通过 init_if_needed 创建它。这里使用了 PDA(Program Derived Address) 作为账户的地址,seedsbump 用于计算 PDA。

    • seeds=[b"favorites", user.key().as_ref()] 生成一个基于 user 公钥的派生地址,用作存储最爱信息的账户地址。
    • bump 是一种确保 PDA 地址唯一的机制,避免发生冲突。
  • system_program 是系统程序,用于处理基本的账户操作,如创建和初始化账户。

6. 总结与学习重点

  • Anchor框架的结构与功能: 通过 #[program]#[account]#[derive(Accounts)] 宏,Anchor 框架简化了 Solana 程序的开发,使账户和指令处理变得更易于理解和实现。
  • 账户与数据存储: 在 Solana 上存储数据通常使用账户,本例中的 Favorites 账户存储用户的最爱信息。#[account] 宏使得账户结构体可以直接用于程序中,并自动处理数据存储。
  • PDA(Program Derived Address): 使用 seedsbump 来生成派生地址,可以确保每个用户的数据存储在唯一的账户中。PDA 是 Solana 程序中一个重要的概念,通常用于创建无权签署的账户。
  • 程序日志与调试: msg! 宏可以在调试时输出程序的状态信息,这有助于理解程序执行的过程和验证数据是否正确。
  • 初始化空间: 使用 Favorites::INIT_SPACEANCHOR_DISCRIMINATOR_SIZE 来计算所需的空间大小,这是 Solana 中一个重要的概念,用于确保程序分配足够的空间来存储账户数据。

<!--EndFragment-->

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

0 条评论

请先 登录 后评论
Alan
Alan
0x9cAD...0097
区块链BTC、ETH、BNB