Підсумок
Створюйте облікові записи 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.
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 bumpaccount_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 PDAseeds = [b"data", user.key().as_ref()],// use the canonical bumpbump,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.
#[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.
Приклад також показує, як отримати новий обліковий запис, який буде створено.
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 programconst [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?