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.

ImportImport

Dalam file lib.rs, Anda akan menemukan program dengan instruksi create, update, dan delete untuk ditambahkan dalam langkah-langkah berikut.

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

Sebelum memulai, jalankan build di terminal Playground untuk memeriksa apakah program awal berhasil dibangun.

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

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

Bangun program lagi dengan menjalankan build di terminal.

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:

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

Selanjutnya, tambahkan logika bisnis untuk instruksi create dengan memperbarui fungsi create dengan yang berikut:

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

Bangun ulang program.

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

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

Selanjutnya, tambahkan logika untuk instruksi update.

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

Bangun kembali program

Terminal
$
build

Tambahkan Instruksi Delete

Selanjutnya, tambahkan instruksi delete untuk menutup MessageAccount.

Perbarui struct Delete dengan yang berikut:

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

Selanjutnya, tambahkan logika untuk instruksi delete.

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

Bangun kembali program.

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

Terminal
$
deploy

Siapkan File Pengujian

Kode awal juga menyertakan file pengujian di 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 () => {});
});

Tambahkan kode di bawah ini ke dalam describe(), tetapi sebelum bagian it().

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

Terminal
$
test

Memanggil Instruksi Create

Perbarui pengujian pertama dengan yang berikut:

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

Memanggil Instruksi Update

Perbarui pengujian kedua dengan yang berikut:

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

Memanggil Instruksi Delete

Perbarui pengujian ketiga dengan yang berikut:

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

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.

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

Daftar Isi

Edit Halaman