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.

ImportImport

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 message
Ok(())
}
pub fn update_message(ctx: Context<UpdateMessage>, content: String) -> Result<()> {
// TODO: Implement update message
Ok(())
}
pub fn delete_message(ctx: Context<DeleteMessage>) -> Result<()> {
// TODO: Implement delete message
Ok(())
}
}

Voordat je begint, voer anchor build uit in de Playground-terminal om te controleren of het starterprogramma succesvol wordt gebouwd.

$ anchor build
BuildOptions {
skip_lint: false,
mode: Release,
features: "",
}
Compiling proc-macro2 v1.0.66
Compiling unicode-ident v1.0.11
Compiling quote v1.0.33
Compiling 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:

lib.rs
#[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.

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:

lib.rs
#[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:

lib.rs
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.

Terminal
$
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:

lib.rs
#[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.

lib.rs
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

Terminal
$
build

Verwijderinstructie toevoegen

Voeg vervolgens de delete instructie toe om de MessageAccount te sluiten.

Werk de Delete struct bij met het volgende:

lib.rs
#[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.

lib.rs
pub fn delete(_ctx: Context<Delete>) -> Result<()> {
msg!("Delete Message");
Ok(())
}

Herbouw het programma.

Terminal
$
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.

Terminal
$
deploy

Testbestand instellen

De starterscode bevat ook een testbestand in anchor.test.ts.

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.

anchor.test.ts
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.

Terminal
$
test

Create-instructie aanroepen

Update de eerste test met het volgende:

anchor.test.ts
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:

anchor.test.ts
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:

anchor.test.ts
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.

Terminal
$
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?

Inhoudsopgave

Pagina Bewerken