Program Derived Address
In diesem Abschnitt lernen Sie, wie Sie ein grundlegendes Create, Read, Update, Delete (CRUD)-Programm erstellen.
Diese Anleitung demonstriert ein einfaches Programm, bei dem Benutzer eine Nachricht erstellen, aktualisieren und löschen können. Jede Nachricht existiert in einem Konto mit einer deterministischen Adresse, die vom Programm selbst abgeleitet wird (Program Derived Address oder PDA).
Diese Anleitung führt Sie durch die Erstellung und das Testen eines Solana-Programms mit dem Anchor-Framework und demonstriert dabei Program Derived Addresses (PDAs). Weitere Details finden Sie auf der Seite Program Derived Addresses.
Als Referenz können Sie den endgültigen Code nach Abschluss beider Abschnitte zu PDA und Cross-Program Invocation (CPI) einsehen.
Starter-Code
Beginnen Sie, indem Sie diesen Solana Playground-Link mit dem Starter-Code öffnen. Klicken Sie dann auf die Schaltfläche "Import", um das Programm zu Ihren Solana Playground-Projekten hinzuzufügen.
Import
In der lib.rs
Datei finden Sie ein Programm mit den create
,
update
und delete
Anweisungen, die in den
folgenden Schritten hinzugefügt werden sollen.
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 {}
Führen Sie vor Beginn build
im Playground-Terminal aus, um zu
überprüfen, ob das Starter-Programm erfolgreich erstellt wird.
$build
Nachrichtenkonto-Typ definieren
Definieren Sie zunächst die Struktur für das Nachrichtenkonto, das das Programm erstellt. Diese Struktur definiert die Daten, die in dem vom Programm erstellten Konto gespeichert werden sollen.
In lib.rs
, aktualisiere die MessageAccount
Struktur mit folgendem:
#[account]pub struct MessageAccount {pub user: Pubkey,pub message: String,pub bump: u8,}
Baue das Programm erneut, indem du build
im Terminal ausführst.
$build
Dieser Code definiert, welche Daten im Nachrichten-Konto gespeichert werden sollen. Als nächstes fügst du die Programm-Anweisungen hinzu.
Erstellen-Anweisung hinzufügen
Füge nun die create
Anweisung hinzu, die das MessageAccount
erstellt
und initialisiert.
Beginne damit, die für die Anweisung erforderlichen Konten zu definieren, indem
du die Create
Struktur mit folgendem aktualisierst:
#[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>,}
Als nächstes füge die Geschäftslogik für die create
Anweisung hinzu, indem
du die create
Funktion mit folgendem Code aktualisierst:
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(())}
Baue das Programm neu.
$build
Anweisung zum Aktualisieren hinzufügen
Als Nächstes fügen Sie die update
Anweisung hinzu, um das MessageAccount
mit
einer neuen Nachricht zu ändern.
Wie im vorherigen Schritt, geben Sie zuerst die Konten an, die von der update
Anweisung benötigt werden.
Aktualisieren Sie die Update
Struktur mit Folgendem:
#[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>,}
Als Nächstes fügen Sie die Logik für die update
Anweisung hinzu.
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(())}
Baue das Programm neu
$build
Lösch-Anweisung hinzufügen
Als Nächstes füge die Anweisung delete
hinzu, um das MessageAccount
zu schließen.
Aktualisiere die Struktur Delete
mit Folgendem:
#[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>,}
Als Nächstes fügen Sie die Logik für die delete
Anweisung hinzu.
pub fn delete(_ctx: Context<Delete>) -> Result<()> {msg!("Delete Message");Ok(())}
Baue das Programm neu.
$build
Programm deployen
Sie haben jetzt das grundlegende CRUD-Programm fertiggestellt. Deployen Sie das
Programm, indem Sie deploy
im Playground-Terminal ausführen.
In diesem Beispiel werden Sie das Programm auf dem Devnet deployen, einem Solana-Cluster für Entwicklungstests.
Die Playground-Wallet verbindet sich standardmäßig mit dem Devnet. Stellen Sie sicher, dass Ihre Playground- Wallet über Devnet SOL verfügt, um für das Programm-Deployment zu bezahlen. Holen Sie sich Devnet SOL vom Solana Faucet.
$deploy
Testdatei einrichten
Der Startercode enthält auch eine Testdatei in 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 () => {});});
Füge den folgenden Code in describe()
ein, aber vor den it()
Abschnitten.
const program = pg.program;const wallet = pg.wallet;const [messagePda, messageBump] = PublicKey.findProgramAddressSync([Buffer.from("message"), wallet.publicKey.toBuffer()],program.programId);
Führe die Testdatei aus, indem du test
im Playground-Terminal
ausführst, um zu überprüfen, dass sie wie erwartet läuft. Die nächsten Schritte
fügen die eigentlichen Tests hinzu.
$test
Create-Anweisung aufrufen
Aktualisiere den ersten Test mit Folgendem:
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`);});
Update-Anweisung aufrufen
Aktualisieren Sie den zweiten Test mit Folgendem:
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`);});
Löschanweisung aufrufen
Aktualisieren Sie den dritten Test mit folgendem:
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 ausführen
Nachdem du deine Tests vorbereitet hast, führe die Testdatei mit test
im Playground-Terminal aus. Dieser Befehl führt die Tests gegen das auf dem
Devnet bereitgestellte Programm aus und protokolliert Links zu SolanaFM, um die
Transaktionsdetails anzuzeigen.
$test
Überprüfe die SolanaFM-Links, um die Transaktionsdetails anzusehen.
Beachte, dass in diesem Beispiel, wenn du den Test erneut ausführst, die
create
Anweisung fehlschlägt, weil messageAccount
bereits als Konto
existiert. Nur ein Konto kann für eine bestimmte PDA existieren.
Is this page helpful?