如何在solana pdas中使用零_copy与锚
我是在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
。
因此,问题似乎是运行时的某些部分无法处理affaccount
为accountloader
(对于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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我让它起作用。有时,它有助于仅发布一个问题,它可以帮助您思考的事情... ;-)
好消息: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) ani
argument, even though I'm not using and additionali
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 thecreate_aff
's parameter list as well as the#[instruction(i: u8)]
from theCreateAff
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!