Podsumowanie
Twórz konta PDA za pomocą invoke_signed z seedami PDA. Tylko program
będący właścicielem może podpisywać za PDA. Constraint init w Anchorze
automatyzuje tworzenie kont PDA.
Podpisywanie PDA przez invoke_signed
Gdy program musi podpisać się w imieniu PDA podczas CPI, używa
invoke_signed z seedami PDA. Środowisko uruchomieniowe weryfikuje, czy
seedy wyprowadzają oczekiwany PDA, używając ID wywołującego programu,
zapewniając, że tylko program będący właścicielem może podpisać. Pełny przepływ
weryfikacji znajdziesz w
PDA Signing.
Tworzenie konta PDA
Wyprowadzenie PDA i utworzenie konta na PDA to osobne operacje. Po wyprowadzeniu adresu musisz jawnie utworzyć konto.
Aby utworzyć konto na PDA, program wyprowadzający wywołuje instrukcję System
Programu create_account przez invoke_signed,
przekazując seedy PDA, aby środowisko uruchomieniowe mogło zweryfikować
uprawnienia programu do tego adresu.
Poniższy przykład wykorzystuje
framework Anchor do utworzenia nowego konta
z adresem wyprowadzonym przez program. Program zawiera pojedynczą instrukcję
initialize do utworzenia nowego konta, które będzie
przechowywać adres użytkownika oraz
bump seed użyte do wyprowadzenia 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,}
Constraint init informuje Anchor, aby
wywołał System Program
i utworzył nowe konto, używając PDA jako adresu. Użyte do tego seedy
(mention:seeds) to:
- Stały ciąg znaków: "data"
- Adres konta użytkownika podany w instrukcji
- Kanoniczny bump seed
W tym przykładzie ograniczenie bump nie ma przypisanej wartości, więc Anchor
użyje find_program_address, aby wyprowadzić PDA i znaleźć 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>,
Poniższy plik testowy zawiera transakcję, która wywołuje instrukcję
initialize w celu utworzenia nowego konta z adresem
pochodnym programu (PDA). Plik zawiera kod do wyprowadzenia PDA.
Przykład pokazuje również, jak pobrać nowe konto, które zostanie utworzone.
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));});});
Jeśli ponownie wywołasz instrukcję initialize z tym samym adresem seed
user, transakcja zakończy się niepowodzeniem. Dzieje się tak, ponieważ konto
już istnieje pod wyprowadzonym adresem.
Is this page helpful?