Account PDA

Riepilogo

Crea account PDA tramite invoke_signed con i seed del PDA. Solo il programma proprietario può firmare per un PDA. Il constraint init di Anchor automatizza la creazione di account PDA.

Firma PDA tramite invoke_signed

Quando un programma deve firmare per conto di un PDA durante un CPI, utilizza invoke_signed con i seed del PDA. Il runtime verifica che i seed derivino il PDA atteso usando l'ID del programma chiamante, garantendo che solo il programma proprietario possa firmare. Per il flusso di verifica completo, vedi firma PDA.

Crea un account PDA

Derivare un PDA e creare un account a un PDA sono operazioni separate. Devi creare esplicitamente l'account dopo aver derivato l'indirizzo.

Per creare un account a un PDA, il programma derivante invoca l'istruzione create_account del System Program tramite invoke_signed, passando i seed del PDA in modo che il runtime possa verificare l'autorità del programma su quell'indirizzo.

L'esempio seguente utilizza il framework Anchor per creare un nuovo account con un indirizzo derivato dal programma. Il programma include una singola istruzione initialize per creare il nuovo account, che memorizzerà l'indirizzo utente e il bump seed utilizzati per derivare il 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,
}

Il constraint init indica ad Anchor di invocare il System Program per creare un nuovo account usando il PDA come indirizzo. I seed utilizzati per creare il PDA sono:

  • La stringa fissa: "data"
  • L'indirizzo dell'account utente fornito nell'istruzione
  • Il bump seed canonico

In questo esempio, il vincolo bump non ha un valore assegnato, quindi Anchor userà find_program_address per derivare il PDA e trovare il 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>,

Il file di test qui sotto contiene una transazione che invoca l'istruzione initialize per creare un nuovo account con un indirizzo derivato dal programma. Il file contiene il codice per derivare il PDA.

L'esempio mostra anche come recuperare il nuovo account che verrà creato.

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

Se invochi nuovamente l'istruzione initialize con lo stesso seed di indirizzo user, la transazione fallirà. Questo accade perché esiste già un account all'indirizzo derivato.

Is this page helpful?

Indice dei contenuti

Modifica pagina

Gestito da

© 2026 Solana Foundation.
Tutti i diritti riservati.
Resta connesso