Облікові записи PDA

Підсумок

Створюйте облікові записи PDA через invoke_signed з seeds PDA. Тільки програма-власник може підписувати від імені PDA. Обмеження init в Anchor автоматизує створення облікових записів PDA.

Підписання PDA через invoke_signed

Коли програмі потрібно підписати від імені PDA під час CPI, вона використовує invoke_signed з seeds PDA. Runtime верифікує, що seeds виводять очікуваний PDA, використовуючи ID програми, що викликає, гарантуючи, що тільки програма-власник може підписувати. Для повного процесу верифікації дивіться Підписання PDA.

Створення облікового запису PDA

Виведення PDA та створення облікового запису за PDA — це окремі операції. Ви повинні явно створити обліковий запис після виведення адреси.

Щоб створити обліковий запис за PDA, програма, що виводить, викликає інструкцію create_account System Program через invoke_signed, передаючи seeds PDA, щоб runtime міг верифікувати повноваження програми над цією адресою.

Приклад нижче використовує фреймворк Anchor для створення нового облікового запису з адресою, виведеною програмою. Програма включає одну інструкцію initialize для створення нового облікового запису, який зберігатиме адресу користувача та bump seed, використані для виведення PDA.

Program
use anchor_lang::prelude::*;
declare_id!("75GJVCJNhaukaa2vCCqhreY31gaphv7XTScBChmr1ueR");
#[program]
pub mod pda_account {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
let account_data = &mut ctx.accounts.pda_account;
// store the address of the `user`
account_data.user = *ctx.accounts.user.key;
// store the canonical bump
account_data.bump = ctx.bumps.pda_account;
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub user: Signer<'info>,
#[account(
init,
// define the seeds to derive the PDA
seeds = [b"data", user.key().as_ref()],
// use the canonical bump
bump,
payer = user,
space = 8 + DataAccount::INIT_SPACE // 8 bytes for Anchor account discriminator
)]
pub pda_account: Account<'info, DataAccount>,
pub system_program: Program<'info, System>,
}
#[account]
#[derive(InitSpace)]
pub struct DataAccount {
pub user: Pubkey,
pub bump: u8,
}

Обмеження init вказує Anchor викликати System Program для створення нового облікового запису, використовуючи PDA як адресу. Seeds, використані для створення PDA:

  • Фіксований рядок: "data"
  • Адреса облікового запису користувача, надана в інструкції
  • Канонічний bump seed

У цьому прикладі обмеженню bump не присвоєно значення, тому Anchor використає find_program_address для виведення PDA та знаходження bump.

pda_account
#[account(
init,
seeds = [b"data", user.key().as_ref()],
bump,
payer = user,
space = 8 + DataAccount::INIT_SPACE // 8 bytes for Anchor account discriminator
)]
pub pda_account: Account<'info, DataAccount>,

Тестовий файл нижче містить транзакцію, яка викликає інструкцію initialize для створення нового облікового запису з адресою, похідною від програми. Файл містить код для виведення PDA.

Приклад також показує, як отримати новий обліковий запис, який буде створено.

Test
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { PdaAccount } from "../target/types/pda_account";
import { PublicKey } from "@solana/web3.js";
describe("pda-account", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.PdaAccount as Program<PdaAccount>;
const user = provider.wallet as anchor.Wallet;
// Derive the PDA address using the seeds specified on the program
const [PDA] = PublicKey.findProgramAddressSync(
[Buffer.from("data"), user.publicKey.toBuffer()],
program.programId
);
it("Is initialized!", async () => {
const transactionSignature = await program.methods
.initialize()
.accounts({
user: user.publicKey
})
.rpc();
console.log("Transaction Signature:", transactionSignature);
});
it("Fetch Account", async () => {
const pdaAccount = await program.account.dataAccount.fetch(PDA);
console.log(JSON.stringify(pdaAccount, null, 2));
});
});

Якщо ви викличете інструкцію initialize знову з тим самим seed адреси user, транзакція не виконається. Це відбувається тому, що обліковий запис вже існує за похідною адресою.

Is this page helpful?

Зміст

Редагувати сторінку

Керується

© 2026 Фонд Solana.
Всі права захищені.
Залишайтеся на зв'язку