Samenvatting
Maak PDA-accounts aan via invoke_signed met de seeds van de PDA. Alleen
het eigenaarsprogramma kan namens een PDA ondertekenen. Anchor's init
constraint automatiseert het aanmaken van PDA-accounts.
PDA-ondertekening via invoke_signed
Wanneer een programma namens een PDA moet ondertekenen tijdens een CPI, gebruikt
het invoke_signed met de seeds van de PDA. De runtime verifieert dat de
seeds de verwachte PDA afleiden met behulp van de ID van het aanroepende
programma, waardoor alleen het eigenaarsprogramma kan ondertekenen. Voor het
volledige verificatieproces, zie
PDA-ondertekening.
Een PDA-account aanmaken
Het afleiden van een PDA en het aanmaken van een account op een PDA zijn afzonderlijke bewerkingen. Je moet het account expliciet aanmaken na het afleiden van het adres.
Om een account aan te maken op een PDA, roept het afleidende programma de
create_account instructie van het System Program aan via
invoke_signed, waarbij de seeds van de PDA worden
doorgegeven zodat de runtime de bevoegdheid van het programma over dat adres kan
verifiëren.
Het onderstaande voorbeeld gebruikt het
Anchor framework om een nieuw account aan te
maken met een program-derived address. Het programma bevat een enkele
initialize instructie om het nieuwe account aan te
maken, dat het gebruikersadres en de
bump seed opslaat die gebruikt zijn om de PDA af te leiden.
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,}
De init constraint instrueert Anchor om
het System Program aan te roepen
om een nieuw account aan te maken met de PDA als adres. De
seeds die gebruikt worden om de PDA aan te maken zijn:
- De vaste string: "data"
- Het adres van het gebruikersaccount dat in de instructie is opgegeven
- De canonieke bump seed
In dit voorbeeld krijgt de bump constraint geen waarde toegewezen, dus Anchor
zal find_program_address gebruiken om de PDA af te leiden en de bump te
vinden.
#[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>,
Het testbestand hieronder bevat een transactie die de
initialize instructie aanroept om een nieuw account aan
te maken met een program-derived address. Het bestand bevat code om
de PDA af te leiden.
Het voorbeeld laat ook zien hoe je het nieuwe account dat wordt aangemaakt kunt ophalen.
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));});});
Als je de initialize instructie opnieuw aanroept met dezelfde user adres
seed, zal de transactie mislukken. Dit gebeurt omdat er al een account bestaat
op het afgeleide adres.
Is this page helpful?