Program Derived Address
Dalam bagian ini, Anda akan belajar cara membangun program Create, Read, Update, Delete (CRUD) dasar.
Panduan ini mendemonstrasikan program sederhana di mana pengguna dapat membuat, memperbarui, dan menghapus pesan. Setiap pesan ada dalam akun dengan alamat deterministik yang diturunkan dari program itu sendiri (Program Derived Address atau PDA).
Panduan ini memandu Anda dalam membangun dan menguji program Solana menggunakan framework Anchor sambil mendemonstrasikan Program Derived Addresses (PDAs). Untuk detail lebih lanjut, lihat halaman Program Derived Addresses.
Sebagai referensi, Anda dapat melihat kode final setelah menyelesaikan kedua bagian PDA dan Cross Program Invocation (CPI).
Kode Awal
Mulailah dengan membuka tautan Solana Playground dengan kode awal. Kemudian klik tombol "Import" untuk menambahkan program ke proyek Solana Playground Anda.
Import
Dalam file lib.rs
, Anda akan menemukan program dengan instruksi
create
, update
, dan delete
untuk ditambahkan dalam langkah-langkah berikut.
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 {}
Sebelum memulai, jalankan build
di terminal Playground untuk memeriksa
apakah program awal berhasil dibangun.
$build
Mendefinisikan Tipe Akun Pesan
Pertama, definisikan struktur untuk akun pesan yang akan dibuat oleh program. Struktur ini mendefinisikan data yang akan disimpan dalam akun yang dibuat oleh program.
Di lib.rs
, perbarui struct MessageAccount
dengan yang berikut:
#[account]pub struct MessageAccount {pub user: Pubkey,pub message: String,pub bump: u8,}
Bangun program lagi dengan menjalankan build
di terminal.
$build
Kode ini mendefinisikan data apa yang akan disimpan pada akun pesan. Selanjutnya, Anda akan menambahkan instruksi program.
Tambahkan instruksi create
Sekarang, tambahkan instruksi create
yang membuat dan menginisialisasi
MessageAccount
.
Mulailah dengan mendefinisikan akun yang diperlukan untuk instruksi dengan
memperbarui struct Create
dengan yang berikut:
#[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>,}
Selanjutnya, tambahkan logika bisnis untuk instruksi create
dengan
memperbarui fungsi create
dengan yang berikut:
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(())}
Bangun ulang program.
$build
Tambahkan Instruksi Pembaruan
Selanjutnya, tambahkan instruksi update
untuk mengubah MessageAccount
dengan
pesan baru.
Seperti langkah sebelumnya, pertama tentukan akun yang diperlukan oleh instruksi
update
.
Perbarui struktur Update
dengan yang berikut:
#[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>,}
Selanjutnya, tambahkan logika untuk instruksi update
.
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(())}
Bangun kembali program
$build
Tambahkan Instruksi Delete
Selanjutnya, tambahkan instruksi delete
untuk menutup
MessageAccount
.
Perbarui struct Delete
dengan yang berikut:
#[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>,}
Selanjutnya, tambahkan logika untuk instruksi delete
.
pub fn delete(_ctx: Context<Delete>) -> Result<()> {msg!("Delete Message");Ok(())}
Bangun kembali program.
$build
Deploy Program
Anda sekarang telah menyelesaikan program CRUD dasar. Deploy program dengan
menjalankan deploy
di terminal Playground.
Dalam contoh ini, Anda akan men-deploy program ke devnet, sebuah cluster Solana untuk pengujian pengembangan.
Dompet Playground terhubung ke devnet secara default. Pastikan dompet Playground Anda memiliki SOL devnet untuk membayar deployment program. Dapatkan SOL devnet dari Solana Faucet.
$deploy
Siapkan File Pengujian
Kode awal juga menyertakan file pengujian di 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 () => {});});
Tambahkan kode di bawah ini ke dalam describe()
, tetapi sebelum bagian
it()
.
const program = pg.program;const wallet = pg.wallet;const [messagePda, messageBump] = PublicKey.findProgramAddressSync([Buffer.from("message"), wallet.publicKey.toBuffer()],program.programId);
Jalankan file pengujian dengan menjalankan test
di terminal Playground
untuk memeriksa bahwa file berjalan sesuai harapan. Langkah-langkah berikutnya
menambahkan pengujian yang sebenarnya.
$test
Memanggil Instruksi Create
Perbarui pengujian pertama dengan yang berikut:
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`);});
Memanggil Instruksi Update
Perbarui pengujian kedua dengan yang berikut:
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`);});
Memanggil Instruksi Delete
Perbarui pengujian ketiga dengan yang berikut:
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`);});
Jalankan Pengujian
Setelah menyiapkan pengujian, jalankan file pengujian dengan test
di
terminal Playground. Perintah ini menjalankan pengujian terhadap program yang
di-deploy pada devnet dan mencatat tautan ke SolanaFM untuk melihat detail
transaksi.
$test
Periksa tautan SolanaFM untuk melihat detail transaksi.
Perhatikan bahwa dalam contoh ini, jika Anda menjalankan pengujian lagi,
instruksi create
akan gagal karena messageAccount
sudah ada sebagai akun.
Hanya satu akun yang dapat ada untuk PDA tertentu.
Is this page helpful?