Program Derived Address
In dit gedeelte leer je hoe je een basis Create, Read, Update, Delete (CRUD) programma bouwt.
Deze handleiding demonstreert een eenvoudig programma waarin gebruikers een bericht kunnen maken, bijwerken en verwijderen. Elk bericht bestaat in een account met een deterministisch adres dat is afgeleid van het programma zelf (Program Derived Address of PDA).
Deze handleiding leidt je door het bouwen en testen van een Solana-programma met behulp van het Anchor-framework, terwijl Program Derived Addresses (PDAs) worden gedemonstreerd. Voor meer details, raadpleeg de Program Derived Addresses pagina.
Ter referentie kun je de uiteindelijke code bekijken na het voltooien van zowel de PDA- als Cross-Program Invocation (CPI)-secties.
Starterscode
Begin door deze Solana Playground-link te openen met de starterscode. Klik vervolgens op de knop "Import" om het programma toe te voegen aan je Solana Playground-projecten.
Import
In het lib.rs
bestand vind je een programma met de
create_message
, update_message
, en
delete_message
instructies om toe te voegen in de volgende
stappen.
use anchor_lang::prelude::*;declare_id!("11111111111111111111111111111111");#[program]pub mod message_program {use super::*;pub fn create_message(ctx: Context<CreateMessage>, content: String) -> Result<()> {// TODO: Implement create messageOk(())}pub fn update_message(ctx: Context<UpdateMessage>, content: String) -> Result<()> {// TODO: Implement update messageOk(())}pub fn delete_message(ctx: Context<DeleteMessage>) -> Result<()> {// TODO: Implement delete messageOk(())}}
Voordat je begint, voer anchor build
uit in de Playground-terminal om te
controleren of het starterprogramma succesvol wordt gebouwd.
$ anchor buildBuildOptions {skip_lint: false,mode: Release,features: "",}Compiling proc-macro2 v1.0.66Compiling unicode-ident v1.0.11Compiling quote v1.0.33Compiling syn v1.0.109...Compiling message-program v0.1.0 (/workspace/programs/message-program)Finished release [optimized] target(s) in 13.82s
Definieer het berichtaccounttype
Definieer eerst de structuur voor het berichtaccount dat het programma maakt. Deze structuur definieert de gegevens die worden opgeslagen in het account dat door het programma wordt gemaakt.
In lib.rs
, update de MessageAccount
struct met het volgende:
#[account]pub struct MessageAccount {pub user: Pubkey,pub message: String,pub bump: u8,}
Bouw het programma opnieuw door build
uit te voeren in de terminal.
$build
Deze code definieert welke gegevens moeten worden opgeslagen in het berichtaccount. Vervolgens ga je de programma-instructies toevoegen.
Voeg Create-instructie toe
Voeg nu de create
instructie toe die de MessageAccount
aanmaakt en
initialiseert.
Begin met het definiëren van de accounts die nodig zijn voor de instructie door
de Create
struct bij te werken met het volgende:
#[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>,}
Voeg vervolgens de bedrijfslogica toe voor de create
instructie door de
create
functie bij te werken met het volgende:
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(())}
Herbouw het programma.
$build
Update-instructie toevoegen
Voeg vervolgens de update
instructie toe om de MessageAccount
met een nieuw
bericht te wijzigen.
Net als bij de vorige stap, specificeer eerst de accounts die vereist zijn voor
de update
instructie.
Update de Update
struct met het volgende:
#[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>,}
Voeg vervolgens de logica toe voor de update
instructie.
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(())}
Herbouw het programma
$build
Verwijderinstructie toevoegen
Voeg vervolgens de delete
instructie toe om de MessageAccount
te
sluiten.
Werk de Delete
struct bij met het volgende:
#[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>,}
Voeg vervolgens de logica toe voor de delete
instructie.
pub fn delete(_ctx: Context<Delete>) -> Result<()> {msg!("Delete Message");Ok(())}
Herbouw het programma.
$build
Programma implementeren
Je hebt nu het basis CRUD-programma voltooid. Implementeer het programma door
deploy
uit te voeren in de Playground-terminal.
In dit voorbeeld implementeer je het programma op het devnet, een Solana-cluster voor ontwikkelingstests.
De Playground-wallet maakt standaard verbinding met het devnet. Zorg ervoor dat je Playground- wallet devnet SOL heeft om te betalen voor de programma-implementatie. Verkrijg devnet SOL via de Solana Faucet.
$deploy
Testbestand instellen
De starterscode bevat ook een testbestand 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 () => {});});
Voeg de onderstaande code toe binnen describe()
, maar vóór de it()
secties.
const program = pg.program;const wallet = pg.wallet;const [messagePda, messageBump] = PublicKey.findProgramAddressSync([Buffer.from("message"), wallet.publicKey.toBuffer()],program.programId);
Voer het testbestand uit door test
uit te voeren in de Playground
terminal om te controleren of het naar verwachting werkt. De volgende stappen
voegen de eigenlijke tests toe.
$test
Create-instructie aanroepen
Update de eerste test met het volgende:
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-instructie aanroepen
Werk de tweede test bij met het volgende:
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`);});
Delete-instructie aanroepen
Werk de derde test bij met het volgende:
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 uitvoeren
Na het voorbereiden van je tests, voer je het testbestand uit met test
in de Playground terminal. Dit commando voert de tests uit tegen het programma
dat op de devnet is geïmplementeerd en logt links naar SolanaFM om de
transactiedetails te bekijken.
$test
Bekijk de SolanaFM-links om de transactiedetails te zien.
Merk op dat in dit voorbeeld, als je de test opnieuw uitvoert, de create
instructie mislukt omdat messageAccount
al bestaat als een account. Er kan
slechts één account bestaan voor een gegeven PDA.
Is this page helpful?