Program Derived Address

Tässä osiossa opit rakentamaan perus Create, Read, Update, Delete (CRUD) -ohjelman.

Tämä opas esittelee yksinkertaisen ohjelman, jossa käyttäjät voivat luoda, päivittää ja poistaa viestin. Jokainen viesti on tallennettu tiliin, jonka osoite on deterministisesti johdettu ohjelmasta itsestään (Program Derived Address eli PDA).

Tämä opas käy läpi Solana-ohjelman rakentamisen ja testaamisen käyttäen Anchor-kehystä ja havainnollistaa Program Derived Addresses (PDA) -osoitteita. Lisätietoja löydät Program Derived Addresses -sivulta.

Voit tarkastella lopullista koodia kun olet suorittanut sekä PDA- että Cross-Program Invocation (CPI) -osiot.

Aloituskoodi

Aloita avaamalla tämä Solana Playground -linkki, joka sisältää aloituskoodin. Napsauta sitten "Import"-painiketta lisätäksesi ohjelman Solana Playground -projekteihisi.

ImportImport

Tiedostossa lib.rs löydät ohjelman, jossa on create, update ja delete -ohjeet lisättäväksi seuraavissa vaiheissa.

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 {}

Ennen aloittamista, suorita build Playground-terminaalissa tarkistaaksesi, että aloitusohjelma kääntyy onnistuneesti.

Terminal
$
build

Määritä viestitityypin rakenne

Ensin määritellään rakenne viestitilille, jonka ohjelma luo. Tämä rakenne määrittelee tiedot, jotka tallennetaan ohjelman luomaan tiliin.

Päivitä lib.rs -tiedostossa MessageAccount -rakenne seuraavasti:

lib.rs
#[account]
pub struct MessageAccount {
pub user: Pubkey,
pub message: String,
pub bump: u8,
}

Rakenna ohjelma uudelleen suorittamalla build terminaalissa.

Terminal
$
build

Tämä koodi määrittelee, mitä tietoja viestiin liittyvään tiliin tallennetaan. Seuraavaksi lisäät ohjelman ohjeet.

Lisää Create-ohje

Lisää nyt create -ohje, joka luo ja alustaa MessageAccount.

Aloita määrittelemällä ohjetta varten tarvittavat tilit päivittämällä Create -rakenne seuraavasti:

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>,
}

Seuraavaksi lisää liiketoimintalogiikka create -ohjeelle päivittämällä create -funktio seuraavasti:

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(())
}

Käännä ohjelma uudelleen.

Terminal
$
build

Lisää päivitysohje

Seuraavaksi lisää update -ohje, jolla voidaan muuttaa MessageAccount uudella viestillä.

Kuten edellisessä vaiheessa, määrittele ensin update -ohjeen vaatimat tilit.

Päivitä Update -rakenne seuraavasti:

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>,
}

Seuraavaksi lisää logiikka update -ohjeelle.

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(())
}

Rakenna ohjelma uudelleen

Terminal
$
build

Lisää poisto-ohje

Seuraavaksi lisää delete ohje sulkeaksesi MessageAccount.

Päivitä Delete rakenne seuraavasti:

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>,
}

Seuraavaksi lisää logiikka delete ohjeelle.

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

Käännä ohjelma uudelleen.

Terminal
$
build

Ohjelman käyttöönotto

Olet nyt saanut valmiiksi perustason CRUD-ohjelman. Ota ohjelma käyttöön suorittamalla deploy Playground-terminaalissa.

Tässä esimerkissä otat ohjelman käyttöön devnetissä, joka on Solanan kehitystestauksen klusteri.

Playground-lompakko yhdistyy oletuksena devnetiin. Varmista, että Playground-lompakossasi on devnet SOLia ohjelman käyttöönoton maksamiseen. Hanki devnet SOLia Solana Faucetista.

Terminal
$
deploy

Testitiedoston määrittäminen

Aloituskoodi sisältää myös testitiedoston kansiossa 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 () => {});
});

Lisää alla oleva koodi describe() -tiedostoon, mutta ennen it() -osioita.

anchor.test.ts
const program = pg.program;
const wallet = pg.wallet;
const [messagePda, messageBump] = PublicKey.findProgramAddressSync(
[Buffer.from("message"), wallet.publicKey.toBuffer()],
program.programId
);

Suorita testitiedosto ajamalla test Playground-terminaalissa tarkistaaksesi, että se toimii odotetusti. Seuraavissa vaiheissa lisätään varsinaiset testit.

Terminal
$
test

Kutsu Create-ohjetta

Päivitä ensimmäinen testi seuraavasti:

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`
);
});

Kutsu Update-ohjetta

Päivitä toinen testi seuraavasti:

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`
);
});

Kutsu Delete-ohjetta

Päivitä kolmas testi seuraavasti:

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`
);
});

Suorita testi

Kun olet valmistellut testisi, suorita testitiedosto komennolla test Playground-terminaalissa. Tämä komento suorittaa testit devnetissä käyttöönotettua ohjelmaa vastaan ja kirjaa linkit SolanaFM:ään, josta voit tarkastella transaktion yksityiskohtia.

Terminal
$
test

Tarkastele SolanaFM-linkkejä nähdäksesi transaktion yksityiskohdat.

Huomaa, että tässä esimerkissä, jos suoritat testin uudelleen, create -ohje epäonnistuu, koska messageAccount on jo olemassa tilinä. Vain yksi tili voi olla olemassa tietylle PDA:lle.

Is this page helpful?

Sisällysluettelo

Muokkaa sivua