Zusammenfassung
Erstellen Sie PDA-Konten über invoke_signed mit den Seeds der PDA. Nur
das besitzende Programm kann für eine PDA signieren. Anchors
init-Constraint automatisiert die PDA-Konten-Erstellung.
PDA-Signierung über invoke_signed
Wenn ein Programm im Namen einer PDA während eines CPI signieren muss, verwendet
es invoke_signed mit den Seeds der PDA. Die Runtime verifiziert, dass die
Seeds die erwartete PDA unter Verwendung der ID des aufrufenden Programms
ableiten, wodurch sichergestellt wird, dass nur das besitzende Programm
signieren kann. Für den vollständigen Verifizierungsablauf siehe
PDA-Signierung.
Ein PDA-Konto erstellen
Das Ableiten einer PDA und das Erstellen eines Kontos an einer PDA sind separate Vorgänge. Sie müssen das Konto explizit erstellen, nachdem Sie die Adresse abgeleitet haben.
Um ein Konto an einer PDA zu erstellen, ruft das ableitende Programm die
create_account-Anweisung des System Program über
invoke_signed auf und übergibt die Seeds der PDA, damit die
Runtime die Berechtigung des Programms über diese Adresse verifizieren kann.
Das folgende Beispiel verwendet das
Anchor-Framework, um ein neues Konto mit
einer programmabgeleiteten Adresse zu erstellen. Das Programm enthält eine
einzige initialize-Anweisung zum Erstellen des neuen
Kontos, welches die Benutzeradresse und den
bump seed speichert, die zur Ableitung der PDA verwendet wurden.
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,}
Das init-Constraint weist Anchor an,
das System Program aufzurufen,
um ein neues Konto mit der PDA als Adresse zu erstellen. Die
Seeds, die zur Erstellung der PDA verwendet werden, sind:
- Die feste Zeichenkette: "data"
- Die Adresse des Benutzerkontos, die in der Anweisung bereitgestellt wurde
- Der kanonische bump seed
In diesem Beispiel wird der bump-Constraint keinem Wert zugewiesen, sodass
Anchor find_program_address verwendet, um die PDA abzuleiten und den bump
zu finden.
#[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>,
Die untenstehende Testdatei enthält eine Transaktion, die die
initialize-Anweisung aufruft, um ein neues Konto mit
einer programmabgeleiteten Adresse zu erstellen. Die Datei enthält Code zum
Ableiten der PDA.
Das Beispiel zeigt auch, wie das neue Konto, das erstellt wird, abgerufen werden kann.
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));});});
Wenn Sie die initialize-Anweisung erneut mit demselben user-Adress-Seed
aufrufen, schlägt die Transaktion fehl. Dies geschieht, weil bereits ein Konto
unter der abgeleiteten Adresse existiert.
Is this page helpful?