Program Derived Address

In deze sectie leer je hoe je een basis Create, Read, Update, Delete (CRUD) programma bouwt.

Deze handleiding demonstreert een eenvoudig programma waarmee gebruikers een bericht kunnen maken, bijwerken en verwijderen. Elk bericht bestaat in een account met een deterministische adres 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, update, en delete instructies om toe te voegen in de volgende stappen.

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

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

Terminal
$
build

Definieer 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, werk de MessageAccount struct bij 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 op het berichtaccount worden opgeslagen. Vervolgens ga je de programma-instructies toevoegen.

Create-instructie toevoegen

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 startercode 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 in de Playground terminal uit te voeren 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