Περίληψη
Δημιουργήστε λογαριασμούς 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.
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,}
Ο περιορισμός init υποδεικνύει στο Anchor να
καλέσει το System Program
για να δημιουργήσει έναν νέο λογαριασμό χρησιμοποιώντας το PDA ως διεύθυνση. Τα
seeds που χρησιμοποιούνται για τη δημιουργία του PDA είναι:
- Η σταθερή συμβολοσειρά: "data"
- Η διεύθυνση του λογαριασμού χρήστη που παρέχεται στην εντολή
- Το κανονικό bump seed
Σε αυτό το παράδειγμα, ο περιορισμός bump δεν έχει εκχωρηθεί τιμή, επομένως το
Anchor θα χρησιμοποιήσει το find_program_address για να παράγει το PDA και
να βρει το bump.
#[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.
Το παράδειγμα δείχνει επίσης πώς να ανακτήσετε τον νέο λογαριασμό που θα δημιουργηθεί.
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));});});
Εάν καλέσετε την εντολή initialize ξανά με το ίδιο seed διεύθυνσης user, η
συναλλαγή θα αποτύχει. Αυτό συμβαίνει επειδή υπάρχει ήδη λογαριασμός στην
παραγόμενη διεύθυνση.
Is this page helpful?