Résumé
Créez des comptes PDA via invoke_signed avec les seeds du PDA. Seul le
programme propriétaire peut signer pour un PDA. La contrainte init
d'Anchor automatise la création de comptes PDA.
Signature PDA via invoke_signed
Lorsqu'un programme doit signer au nom d'un PDA lors d'un CPI, il utilise
invoke_signed avec les seeds du PDA. Le runtime vérifie que les seeds
dérivent le PDA attendu en utilisant l'ID du programme appelant,
garantissant que seul le programme propriétaire peut signer. Pour le flux de
vérification complet, voir
Signature PDA.
Créer un compte PDA
Dériver un PDA et créer un compte à une adresse PDA sont des opérations distinctes. Vous devez explicitement créer le compte après avoir dérivé l'adresse.
Pour créer un compte à une adresse PDA, le programme de dérivation invoque
l'instruction create_account du System Program via
invoke_signed, en passant les seeds du PDA afin que le
runtime puisse vérifier l'autorité du programme sur cette adresse.
L'exemple ci-dessous utilise le
framework Anchor pour créer un nouveau
compte avec une adresse dérivée du programme. Le programme inclut une seule
instruction initialize pour créer le nouveau compte, qui
stockera l'adresse utilisateur et le
bump seed utilisés pour dériver le 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,}
La contrainte init indique à Anchor
d'invoquer le System Program
pour créer un nouveau compte en utilisant le PDA comme adresse. Les
seeds utilisés pour créer le PDA sont :
- La chaîne fixe : "data"
- L'adresse du compte utilisateur fournie dans l'instruction
- Le bump seed canonique
Dans cet exemple, la contrainte bump n'a pas de valeur assignée, donc Anchor
utilisera find_program_address pour dériver le PDA et trouver le 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>,
Le fichier de test ci-dessous contient une transaction qui invoque l'instruction
initialize pour créer un nouveau compte avec une adresse
dérivée de programme. Le fichier contient du code pour
dériver le PDA.
L'exemple montre également comment récupérer le nouveau compte qui sera créé.
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));});});
Si vous invoquez l'instruction initialize à nouveau avec la même seed
d'adresse user, la transaction échouera. Cela se produit parce qu'un compte
existe déjà à l'adresse dérivée.
Is this page helpful?