如何在solana pdas中使用零_copy与锚

发布于 2025-02-10 05:18:24 字数 3192 浏览 2 评论 0原文

我是在Solana的基础上,需要一些PDA来存储我的程序状态。

即使仅将地址传达到指令中,带有锚定的默认值也会不断地序列化/应对帐户进行序列化/估算,这确实很快就会粉碎BPM的4K堆栈限制限制我的应用程序。

因此,我找到了我需要的Zero_copy功能,请参见 https ://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html

锚文档中显示的示例以及我通过Web搜索发现的一些代码示例,都涉及钱包拥有的帐户,而不是PDA。从字面上看,没有PDA的关于Zero_copy的网上可以找到,所以我想知道是否有可能吗?

无论如何 - 我觉得我真的非常需要它,否则我的PDA帐户将仅限于400个字节左右。

所以我尝试了一下:

#[program]
mod myapp {

    use super::*;

    pub fn create_aff(ctx: Context<CreateAff>, _i: u8) -> Result<()> {
        let acc = &mut ctx.accounts.aff_account.load_init()?;
        acc.aff_account = ctx.accounts.user.key();
        acc.bump = *ctx.bumps.get("aff_account").unwrap();
        Ok(())
    }
}

#[account(zero_copy)]
pub struct Aff {
    aff_account: Pubkey,
    bump: u8,
}

#[derive(Accounts)]
#[instruction(i: u8)]
pub struct CreateAff<'info> {
    #[account(init, space = 41, payer = user, seeds = [AFFSEED], bump)]
    aff_account: AccountInfor<'info, Aff>,
    #[account(mut)]
    user: Signer<'info>,
    /// CHECK: This is not dangerous because we don't read or write from this account
    system_program: AccountInfo<'info>,
}

到目前为止,一切都很好。它编译。运行一个简单的测试:

  it("Creates the aff account if doesn't exist", async () => {
    const [affPDA, bump] = await PublicKey.findProgramAddress([anchor.utils.bytes.utf8.encode(AFFSEED)],program.programId);
    console.log("CreateAff: affPDA is [", affPDA.toString(), "], bump is", bump);
    const contents = await program.account.aff.fetchNullable(affPDA);
    if (contents == null) {
      await program.rpc.createAff({
        accounts: {
          affAccount: affPDA,
          user: usr,
          systemProgram: SystemProgram.programId,
        },
        signers: [],
      });
      const affe = await program.account.counts.fetch(affPDA);
      console.log("affe: ", affe);
      assert.ok(true);
    } else {
      assert.ok(true);
    }
  });

使我有一个错误:

       Creates the aff account if doesn't exist:
     Error: Invalid arguments: affAccount not provided.
      at /Users/bb/app/nodestore/node_modules/@project-serum/anchor/dist/cjs/program/common.js:39:23
      at Array.forEach (<anonymous>)
      at validateAccounts (node_modules/@project-serum/anchor/dist/cjs/program/common.js:33:16)
      at ix (node_modules/@project-serum/anchor/dist/cjs/program/namespace/instruction.js:38:46)
      at txFn (node_modules/@project-serum/anchor/dist/cjs/program/namespace/transaction.js:16:20)
      at Object.rpc [as createAff] (node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:9:24)
      at Context.<anonymous> (tests/nodeshop.js:63:25)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)

即使我显然将其传递给了,也没有提供affaccount

因此,问题似乎是运行时的某些部分无法处理affaccountaccountloader(对于Zero_copy),而不是标准AccountInfo

任何有助于我如何解决或至少进一步调试的任何帮助,都将受到高度赞赏。

I'm building on Solana and need some PDAs to store my program state.

The default with anchor is constantly serialize/deserialize the accounts, even when just passing the address into instructions, which crushes BPM's 4k stack limit REALLY soon for my app.

So I found the zero_copy feature, which is exactly what I need, see https://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html.

The examples shown in the anchor docs, as well as some code samples I found through web search, all refer to wallet-owned accounts, not to PDAs. There is literally NOTHING to find online about zero_copy with PDAs, so I'm wondering if it's possible at all?!

Anyway - I feel I really, really need it, otherwise my PDA accounts will be limited to something around 400 bytes or so.

So I gave it a try:

#[program]
mod myapp {

    use super::*;

    pub fn create_aff(ctx: Context<CreateAff>, _i: u8) -> Result<()> {
        let acc = &mut ctx.accounts.aff_account.load_init()?;
        acc.aff_account = ctx.accounts.user.key();
        acc.bump = *ctx.bumps.get("aff_account").unwrap();
        Ok(())
    }
}

#[account(zero_copy)]
pub struct Aff {
    aff_account: Pubkey,
    bump: u8,
}

#[derive(Accounts)]
#[instruction(i: u8)]
pub struct CreateAff<'info> {
    #[account(init, space = 41, payer = user, seeds = [AFFSEED], bump)]
    aff_account: AccountInfor<'info, Aff>,
    #[account(mut)]
    user: Signer<'info>,
    /// CHECK: This is not dangerous because we don't read or write from this account
    system_program: AccountInfo<'info>,
}

So far, so good. It compiles. Running a simple test:

  it("Creates the aff account if doesn't exist", async () => {
    const [affPDA, bump] = await PublicKey.findProgramAddress([anchor.utils.bytes.utf8.encode(AFFSEED)],program.programId);
    console.log("CreateAff: affPDA is [", affPDA.toString(), "], bump is", bump);
    const contents = await program.account.aff.fetchNullable(affPDA);
    if (contents == null) {
      await program.rpc.createAff({
        accounts: {
          affAccount: affPDA,
          user: usr,
          systemProgram: SystemProgram.programId,
        },
        signers: [],
      });
      const affe = await program.account.counts.fetch(affPDA);
      console.log("affe: ", affe);
      assert.ok(true);
    } else {
      assert.ok(true);
    }
  });

renders me an error:

       Creates the aff account if doesn't exist:
     Error: Invalid arguments: affAccount not provided.
      at /Users/bb/app/nodestore/node_modules/@project-serum/anchor/dist/cjs/program/common.js:39:23
      at Array.forEach (<anonymous>)
      at validateAccounts (node_modules/@project-serum/anchor/dist/cjs/program/common.js:33:16)
      at ix (node_modules/@project-serum/anchor/dist/cjs/program/namespace/instruction.js:38:46)
      at txFn (node_modules/@project-serum/anchor/dist/cjs/program/namespace/transaction.js:16:20)
      at Object.rpc [as createAff] (node_modules/@project-serum/anchor/dist/cjs/program/namespace/rpc.js:9:24)
      at Context.<anonymous> (tests/nodeshop.js:63:25)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)

It's complaining affAccount is not provided, even though I'm clearly passing it in.

So the problem seems to be some part of the runtime cannot handle affAccount being AccountLoader (for zero_copy) rather than the standard AccountInfo.

Any help how I can fix or at least further debug this are highly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱桃奶球 2025-02-17 05:18:24

我让它起作用。有时,它有助于仅发布一个问题,它可以帮助您思考的事情... ;-)

好消息:Zero_copy与PDA是可能的! :-)

这就是:

我最初给出了create_aff函数(和相应的帐户结构)i参数,即使我不使用并附加i在PDA帐户种子中。这只是我一直在研究的PDA的复制/粘贴错误: - /

由于我与i一致,因此编译器没有抱怨。

我从create_aff的参数列表以及###[consition>#[coce(i:u8)]中删除了i参数。 > createaff 帐户结构声明,并且afivalà现在正在工作。

万能的索拉纳和锚。哦,并向锚点的建造者提供建议:只需将Zero_copy置于默认设置,而冗长的borsh例外!

I got it working. Sometimes it helps just posting a question, it helps thinking things through... ;-)

So great news: zero_copy with PDAs is possible! :-)

Here's what it was:

I originally gave the create_aff function (and the corresponding accounts struct) an i argument, even though I'm not using and additional i in the PDA account seeds. This was just a copy/paste error from a previous PDA I had been working on :-/

Since I was consistent with the i, the compiler didn't complain.

I removed the i parameter from the create_aff's parameter list as well as the #[instruction(i: u8)] from the CreateAff accounts struct declaration and, violà, it's working now.

Long live Solana and anchor. Oh, and a recommendation to the builders of anchor: Just make zero_copy the default, and lengthy borsh the exception!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文