Λογαριασμοί PDA

Περίληψη

Δημιουργήστε λογαριασμούς PDA μέσω invoke_signed με τα seeds του PDA. Μόνο το πρόγραμμα-ιδιοκτήτης μπορεί να υπογράψει για ένα PDA. Ο περιορισμός init του Anchor αυτοματοποιεί τη δημιουργία λογαριασμού PDA.

Υπογραφή PDA μέσω invoke_signed

Όταν ένα πρόγραμμα χρειάζεται να υπογράψει εκ μέρους ενός PDA κατά τη διάρκεια ενός CPI, χρησιμοποιεί invoke_signed με τα seeds του PDA. Το runtime επαληθεύει ότι τα seeds παράγουν το αναμενόμενο PDA χρησιμοποιώντας το ID του προγράμματος που καλεί, διασφαλίζοντας ότι μόνο το πρόγραμμα-ιδιοκτήτης μπορεί να υπογράψει. Για την πλήρη ροή επαλήθευσης, δείτε Υπογραφή PDA.

Δημιουργία λογαριασμού PDA

Η παραγωγή ενός PDA και η δημιουργία λογαριασμού σε ένα PDA είναι ξεχωριστές λειτουργίες. Πρέπει να δημιουργήσετε ρητά τον λογαριασμό αφού παράγετε τη διεύθυνση.

Για να δημιουργήσετε έναν λογαριασμό σε ένα PDA, το πρόγραμμα παραγωγής καλεί την εντολή create_account του System Program μέσω invoke_signed, περνώντας τα seeds του PDA ώστε το runtime να μπορεί να επαληθεύσει την εξουσία του προγράμματος πάνω σε αυτή τη διεύθυνση.

Το παρακάτω παράδειγμα χρησιμοποιεί το Anchor framework για να δημιουργήσει έναν νέο λογαριασμό με διεύθυνση που παράγεται από το πρόγραμμα. Το πρόγραμμα περιλαμβάνει μία μόνο εντολή initialize για τη δημιουργία του νέου λογαριασμού, ο οποίος θα αποθηκεύσει τη διεύθυνση χρήστη και το bump seed που χρησιμοποιήθηκε για την παραγωγή του 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,
}

Ο περιορισμός init υποδεικνύει στο Anchor να καλέσει το System Program για να δημιουργήσει έναν νέο λογαριασμό χρησιμοποιώντας το PDA ως διεύθυνση. Τα seeds που χρησιμοποιούνται για τη δημιουργία του PDA είναι:

  • Η σταθερή συμβολοσειρά: "data"
  • Η διεύθυνση του λογαριασμού χρήστη που παρέχεται στην εντολή
  • Το κανονικό bump seed

Σε αυτό το παράδειγμα, ο περιορισμός bump δεν έχει εκχωρηθεί τιμή, επομένως το Anchor θα χρησιμοποιήσει το find_program_address για να παράγει το PDA και να βρει το 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>,

Το αρχείο δοκιμών παρακάτω περιέχει μια συναλλαγή που καλεί την εντολή initialize για να δημιουργήσει έναν νέο λογαριασμό με διεύθυνση που προέρχεται από πρόγραμμα. Το αρχείο περιέχει κώδικα για να παράγει το PDA.

Το παράδειγμα δείχνει επίσης πώς να ανακτήσετε τον νέο λογαριασμό που θα δημιουργηθεί.

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

Εάν καλέσετε την εντολή initialize ξανά με το ίδιο seed διεύθυνσης user, η συναλλαγή θα αποτύχει. Αυτό συμβαίνει επειδή υπάρχει ήδη λογαριασμός στην παραγόμενη διεύθυνση.

Is this page helpful?

Πίνακας Περιεχομένων

Επεξεργασία Σελίδας

Διαχειρίζεται από

© 2026 Ίδρυμα Solana.
Με επιφύλαξη παντός δικαιώματος.
Συνδεθείτε