PDA-Konten

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.

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

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.

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

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.

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

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?

Inhaltsverzeichnis

Seite bearbeiten

Verwaltet von

© 2026 Solana Foundation.
Alle Rechte vorbehalten.
Verbinden Sie sich