Program Derived Address
Σε αυτή την ενότητα, θα μάθετε πώς να δημιουργήσετε ένα βασικό πρόγραμμα Δημιουργίας, Ανάγνωσης, Ενημέρωσης, Διαγραφής (CRUD).
Αυτός ο οδηγός παρουσιάζει ένα απλό πρόγραμμα όπου οι χρήστες μπορούν να δημιουργούν, να ενημερώνουν και να διαγράφουν ένα μήνυμα. Κάθε μήνυμα υπάρχει σε έναν λογαριασμό με προκαθορισμένη διεύθυνση που προέρχεται από το ίδιο το πρόγραμμα (Program Derived Address ή PDA).
Αυτός ο οδηγός σας καθοδηγεί στη δημιουργία και τον έλεγχο ενός προγράμματος Solana χρησιμοποιώντας το πλαίσιο Anchor, ενώ παράλληλα επιδεικνύει τα Program Derived Addresses (PDAs). Για περισσότερες λεπτομέρειες, ανατρέξτε στη σελίδα Program Derived Addresses.
Για αναφορά, μπορείτε να δείτε τον τελικό κώδικα αφού ολοκληρώσετε τόσο τις ενότητες PDA όσο και Cross-Program Invocation (CPI).
Αρχικός κώδικας
Ξεκινήστε ανοίγοντας αυτόν τον σύνδεσμο Solana Playground με τον αρχικό κώδικα. Στη συνέχεια, κάντε κλικ στο κουμπί "Import" για να προσθέσετε το πρόγραμμα στα έργα σας στο Solana Playground.
Εισαγωγή
Στο αρχείο lib.rs
, θα βρείτε ένα πρόγραμμα με τις εντολές
create
, update
και delete
που θα προσθέσετε στα επόμενα βήματα.
use anchor_lang::prelude::*;declare_id!("8KPzbM2Cwn4Yjak7QYAEH9wyoQh86NcBicaLuzPaejdw");#[program]pub mod pda {use super::*;pub fn create(_ctx: Context<Create>) -> Result<()> {Ok(())}pub fn update(_ctx: Context<Update>) -> Result<()> {Ok(())}pub fn delete(_ctx: Context<Delete>) -> Result<()> {Ok(())}}#[derive(Accounts)]pub struct Create {}#[derive(Accounts)]pub struct Update {}#[derive(Accounts)]pub struct Delete {}#[account]pub struct MessageAccount {}
Πριν ξεκινήσετε, εκτελέστε build
στο τερματικό του Playground για να
ελέγξετε ότι το αρχικό πρόγραμμα μεταγλωττίζεται επιτυχώς.
$build
Ορισμός τύπου λογαριασμού μηνύματος
Πρώτα, ορίστε τη δομή για τον λογαριασμό μηνύματος που δημιουργεί το πρόγραμμα. Αυτή η δομή καθορίζει τα δεδομένα που θα αποθηκευτούν στον λογαριασμό που δημιουργείται από το πρόγραμμα.
Στο lib.rs
, ενημερώστε τη δομή MessageAccount
με τα εξής:
#[account]pub struct MessageAccount {pub user: Pubkey,pub message: String,pub bump: u8,}
Δημιουργήστε ξανά το πρόγραμμα εκτελώντας build
στο τερματικό.
$build
Αυτός ο κώδικας καθορίζει ποια δεδομένα θα αποθηκευτούν στον λογαριασμό μηνύματος. Στη συνέχεια, θα προσθέσετε τις οδηγίες του προγράμματος.
Προσθήκη οδηγίας δημιουργίας
Τώρα, προσθέστε την οδηγία create
που δημιουργεί και αρχικοποιεί το
MessageAccount
.
Ξεκινήστε καθορίζοντας τους λογαριασμούς που απαιτούνται για την οδηγία,
ενημερώνοντας τη δομή Create
με τα εξής:
#[derive(Accounts)]#[instruction(message: String)]pub struct Create<'info> {#[account(mut)]pub user: Signer<'info>,#[account(init,seeds = [b"message", user.key().as_ref()],bump,payer = user,space = 8 + 32 + 4 + message.len() + 1)]pub message_account: Account<'info, MessageAccount>,pub system_program: Program<'info, System>,}
Στη συνέχεια, προσθέστε την επιχειρηματική λογική για την εντολή create
ενημερώνοντας τη συνάρτηση create
με τα ακόλουθα:
pub fn create(ctx: Context<Create>, message: String) -> Result<()> {msg!("Create Message: {}", message);let account_data = &mut ctx.accounts.message_account;account_data.user = ctx.accounts.user.key();account_data.message = message;account_data.bump = ctx.bumps.message_account;Ok(())}
Επαναδημιουργήστε το πρόγραμμα.
$build
Προσθήκη εντολής ενημέρωσης
Στη συνέχεια, προσθέστε την εντολή update
για να αλλάξετε το MessageAccount
με ένα νέο μήνυμα.
Όπως και στο προηγούμενο βήμα, πρώτα καθορίστε τους λογαριασμούς που απαιτούνται
από την εντολή update
.
Ενημερώστε τη δομή Update
με τα ακόλουθα:
#[derive(Accounts)]#[instruction(message: String)]pub struct Update<'info> {#[account(mut)]pub user: Signer<'info>,#[account(mut,seeds = [b"message", user.key().as_ref()],bump = message_account.bump,realloc = 8 + 32 + 4 + message.len() + 1,realloc::payer = user,realloc::zero = true,)]pub message_account: Account<'info, MessageAccount>,pub system_program: Program<'info, System>,}
Στη συνέχεια, προσθέστε τη λογική για την εντολή update
.
pub fn update(ctx: Context<Update>, message: String) -> Result<()> {msg!("Update Message: {}", message);let account_data = &mut ctx.accounts.message_account;account_data.message = message;Ok(())}
Επαναδημιουργήστε το πρόγραμμα
$build
Προσθήκη εντολής διαγραφής
Στη συνέχεια, προσθέστε την εντολή delete
για να κλείσετε το
MessageAccount
.
Ενημερώστε τη δομή Delete
με τα ακόλουθα:
#[derive(Accounts)]pub struct Delete<'info> {#[account(mut)]pub user: Signer<'info>,#[account(mut,seeds = [b"message", user.key().as_ref()],bump = message_account.bump,close = user,)]pub message_account: Account<'info, MessageAccount>,}
Στη συνέχεια, προσθέστε τη λογική για την εντολή delete
.
pub fn delete(_ctx: Context<Delete>) -> Result<()> {msg!("Delete Message");Ok(())}
Επαναδημιουργήστε το πρόγραμμα.
$build
Ανάπτυξη προγράμματος
Έχετε πλέον ολοκληρώσει το βασικό πρόγραμμα CRUD. Αναπτύξτε το πρόγραμμα
εκτελώντας deploy
στο τερματικό του Playground.
Σε αυτό το παράδειγμα, θα αναπτύξετε το πρόγραμμα στο devnet, ένα Solana cluster για δοκιμές ανάπτυξης.
Το πορτοφόλι του Playground συνδέεται στο devnet από προεπιλογή. Βεβαιωθείτε ότι το πορτοφόλι του Playground έχει devnet SOL για να πληρώσει για την ανάπτυξη του προγράμματος. Αποκτήστε devnet SOL από το Solana Faucet.
$deploy
Ρύθμιση αρχείου δοκιμής
Ο αρχικός κώδικας περιλαμβάνει επίσης ένα αρχείο δοκιμών στο anchor.test.ts
.
import { PublicKey } from "@solana/web3.js";describe("pda", () => {it("Create Message Account", async () => {});it("Update Message Account", async () => {});it("Delete Message Account", async () => {});});
Προσθέστε τον παρακάτω κώδικα μέσα στο describe()
, αλλά πριν από τις
ενότητες it()
.
const program = pg.program;const wallet = pg.wallet;const [messagePda, messageBump] = PublicKey.findProgramAddressSync([Buffer.from("message"), wallet.publicKey.toBuffer()],program.programId);
Εκτελέστε το αρχείο δοκιμών τρέχοντας test
στο τερματικό του Playground
για να ελέγξετε ότι εκτελείται όπως αναμένεται. Τα επόμενα βήματα προσθέτουν τις
πραγματικές δοκιμές.
$test
Κλήση της εντολής Create
Ενημερώστε την πρώτη δοκιμή με τα ακόλουθα:
it("Create Message Account", async () => {const message = "Hello, World!";const transactionSignature = await program.methods.create(message).accounts({messageAccount: messagePda}).rpc({ commitment: "confirmed" });const messageAccount = await program.account.messageAccount.fetch(messagePda,"confirmed");console.log(JSON.stringify(messageAccount, null, 2));console.log("Transaction Signature:",`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`);});
Επίκληση εντολής ενημέρωσης
Ενημερώστε τη δεύτερη δοκιμή με τα ακόλουθα:
it("Update Message Account", async () => {const message = "Hello, Solana!";const transactionSignature = await program.methods.update(message).accounts({messageAccount: messagePda}).rpc({ commitment: "confirmed" });const messageAccount = await program.account.messageAccount.fetch(messagePda,"confirmed");console.log(JSON.stringify(messageAccount, null, 2));console.log("Transaction Signature:",`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`);});
Επίκληση εντολής διαγραφής
Ενημερώστε την τρίτη δοκιμή με τα ακόλουθα:
it("Delete Message Account", async () => {const transactionSignature = await program.methods.delete().accounts({messageAccount: messagePda}).rpc({ commitment: "confirmed" });const messageAccount = await program.account.messageAccount.fetchNullable(messagePda,"confirmed");console.log("Expect Null:", JSON.stringify(messageAccount, null, 2));console.log("Transaction Signature:",`https://solana.fm/tx/${transactionSignature}?cluster=devnet-solana`);});
Εκτέλεση δοκιμής
Αφού προετοιμάσετε τις δοκιμές σας, εκτελέστε το αρχείο δοκιμής με test
στο τερματικό του Playground. Αυτή η εντολή εκτελεί τις δοκιμές στο πρόγραμμα
που έχει αναπτυχθεί στο devnet και καταγράφει συνδέσμους προς το SolanaFM για να
δείτε τις λεπτομέρειες της συναλλαγής.
$test
Εξετάστε τους συνδέσμους SolanaFM για να δείτε τις λεπτομέρειες της συναλλαγής.
Σημειώστε ότι σε αυτό το παράδειγμα, αν εκτελέσετε ξανά τη δοκιμή, η εντολή
create
αποτυγχάνει επειδή ο λογαριασμός messageAccount
υπάρχει ήδη. Μόνο
ένας λογαριασμός μπορεί να υπάρχει για ένα συγκεκριμένο PDA.
Is this page helpful?