PDA-accounts

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.

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,
}

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.

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>,

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.

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));
});
});

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?

Inhoudsopgave

Pagina Bewerken

Beheerd door

© 2026 Solana Foundation.
Alle rechten voorbehouden.
Blijf Verbonden