Konta PDA

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.

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

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.

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

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.

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

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?

Spis treści

Edytuj stronę

Zarządzane przez

© 2026 Solana Foundation.
Wszelkie prawa zastrzeżone.
Bądź na bieżąco