Model Akun Solana

Di Solana, semua data disimpan dalam apa yang disebut "akun." Anda dapat menganggap data di Solana sebagai database publik dengan satu tabel "Akun", di mana setiap entri dalam tabel ini adalah "akun." Setiap akun Solana berbagi tipe Akun dasar yang sama.

AkunAkun

Poin Penting

  • Akun dapat menyimpan hingga 10MiB data, yang berisi kode program yang dapat dieksekusi atau status program.
  • Akun memerlukan deposit rent dalam lamport (SOL) yang sebanding dengan jumlah data yang disimpan, dan Anda dapat sepenuhnya memulihkannya saat menutup akun.
  • Setiap akun memiliki pemilik program. Hanya program yang memiliki akun yang dapat mengubah datanya atau mengurangi saldo lamport-nya. Tetapi siapa pun dapat menambah saldo.
  • Akun sysvar adalah akun khusus yang menyimpan status cluster jaringan.
  • Akun program menyimpan kode yang dapat dieksekusi dari kontrak pintar.
  • Akun data dibuat oleh program untuk menyimpan dan mengelola status program.

Akun

Setiap akun di Solana memiliki alamat unik 32 byte, sering ditampilkan sebagai string yang dikodekan base58 (misalnya 14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5).

Hubungan antara akun dan alamatnya bekerja seperti pasangan key-value, di mana alamat adalah kunci untuk menemukan data on-chain yang sesuai dari akun tersebut. Alamat akun bertindak sebagai "ID unik" untuk setiap entri dalam tabel "Akun".

Alamat AkunAlamat Akun

Sebagian besar akun Solana menggunakan kunci publik Ed25519 sebagai alamat mereka.

import { generateKeyPairSigner } from "@solana/kit";
// Kit does not enable extractable private keys
const keypairSigner = await generateKeyPairSigner();
console.log(keypairSigner);
Console
Click to execute the code.

Meskipun kunci publik umumnya digunakan sebagai alamat akun, Solana juga mendukung fitur yang disebut Program Derived Addresses (PDA). PDA adalah alamat khusus yang dapat Anda turunkan secara deterministik dari ID program dan input opsional (seed).

import { Address, getProgramDerivedAddress } from "@solana/kit";
const programAddress = "11111111111111111111111111111111" as Address;
const seeds = ["helloWorld"];
const [pda, bump] = await getProgramDerivedAddress({
programAddress,
seeds
});
console.log(`PDA: ${pda}`);
console.log(`Bump: ${bump}`);
Console
Click to execute the code.

Tipe Akun

Akun memiliki ukuran maksimal 10MiB dan setiap akun di Solana berbagi tipe dasar Account yang sama.

Tipe AkunTipe Akun

Setiap Akun di Solana memiliki bidang-bidang berikut.

Base Account Type
pub struct Account {
/// lamports in the account
pub lamports: u64,
/// data held in this account
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
pub data: Vec<u8>,
/// the program that owns this account. If executable, the program that loads this account.
pub owner: Pubkey,
/// this account's data contains a loaded program (and is now read-only)
pub executable: bool,
/// the epoch at which this account will next owe rent
pub rent_epoch: Epoch,
}

Bidang Lamports

Saldo akun dalam lamport, unit terkecil dari SOL (1 SOL = 1 miliar lamport). Saldo SOL sebuah akun adalah jumlah dalam bidang lamports yang dikonversi ke SOL.

Akun Solana harus memiliki saldo lamport minimum yang sebanding dengan jumlah data yang disimpan pada akun (dalam byte). Saldo minimum ini disebut "rent."

Saldo lamport yang disimpan dalam akun dapat sepenuhnya dipulihkan ketika akun ditutup.

Bidang Data

Array byte yang menyimpan data arbitrer untuk sebuah akun. Bidang data ini umumnya disebut "data akun."

  • Untuk akun program (kontrak pintar), bidang ini berisi kode program yang dapat dieksekusi atau alamat akun lain yang menyimpan kode program yang dapat dieksekusi.
  • Untuk akun yang tidak dapat dieksekusi, ini umumnya menyimpan status yang dimaksudkan untuk dibaca.

Membaca data dari akun Solana melibatkan dua langkah:

  1. Ambil akun menggunakan alamatnya (kunci publik)
  2. Deserialisasi bidang data akun dari byte mentah ke dalam struktur data yang sesuai, yang ditentukan oleh program yang memiliki akun tersebut

Bidang Pemilik

ID program (kunci publik) dari program yang memiliki akun ini.

Setiap akun Solana memiliki program yang ditunjuk sebagai pemiliknya. Hanya program yang memiliki akun yang dapat mengubah data akun atau mengurangi saldo lamport-nya.

Instruksi yang didefinisikan dalam program menentukan bagaimana data akun dan saldo lamport dapat diubah.

Kolom Executable

Kolom ini menunjukkan apakah sebuah akun adalah program yang dapat dieksekusi.

  • Jika true, akun tersebut adalah program Solana yang dapat dieksekusi.
  • Jika false, akun tersebut adalah akun data yang menyimpan state.

Untuk akun yang dapat dieksekusi, kolom owner berisi ID program dari program loader. Program loader adalah program bawaan yang bertanggung jawab untuk memuat dan mengelola akun program yang dapat dieksekusi.

Kolom Rent Epoch

Kolom rent_epoch adalah kolom lama yang tidak lagi digunakan.

Awalnya, kolom ini melacak kapan sebuah akun perlu membayar rent (dalam lamport) untuk mempertahankan datanya di jaringan. Namun, mekanisme pengumpulan rent ini sejak itu telah tidak digunakan lagi.

Bidang Lamports

Saldo akun dalam lamport, unit terkecil dari SOL (1 SOL = 1 miliar lamport). Saldo SOL sebuah akun adalah jumlah dalam bidang lamports yang dikonversi ke SOL.

Akun Solana harus memiliki saldo lamport minimum yang sebanding dengan jumlah data yang disimpan pada akun (dalam byte). Saldo minimum ini disebut "rent."

Saldo lamport yang disimpan dalam akun dapat sepenuhnya dipulihkan ketika akun ditutup.

Bidang Data

Array byte yang menyimpan data arbitrer untuk sebuah akun. Bidang data ini umumnya disebut "data akun."

  • Untuk akun program (kontrak pintar), bidang ini berisi kode program yang dapat dieksekusi atau alamat akun lain yang menyimpan kode program yang dapat dieksekusi.
  • Untuk akun yang tidak dapat dieksekusi, ini umumnya menyimpan status yang dimaksudkan untuk dibaca.

Membaca data dari akun Solana melibatkan dua langkah:

  1. Ambil akun menggunakan alamatnya (kunci publik)
  2. Deserialisasi bidang data akun dari byte mentah ke dalam struktur data yang sesuai, yang ditentukan oleh program yang memiliki akun tersebut

Bidang Pemilik

ID program (kunci publik) dari program yang memiliki akun ini.

Setiap akun Solana memiliki program yang ditunjuk sebagai pemiliknya. Hanya program yang memiliki akun yang dapat mengubah data akun atau mengurangi saldo lamport-nya.

Instruksi yang didefinisikan dalam program menentukan bagaimana data akun dan saldo lamport dapat diubah.

Kolom Executable

Kolom ini menunjukkan apakah sebuah akun adalah program yang dapat dieksekusi.

  • Jika true, akun tersebut adalah program Solana yang dapat dieksekusi.
  • Jika false, akun tersebut adalah akun data yang menyimpan state.

Untuk akun yang dapat dieksekusi, kolom owner berisi ID program dari program loader. Program loader adalah program bawaan yang bertanggung jawab untuk memuat dan mengelola akun program yang dapat dieksekusi.

Kolom Rent Epoch

Kolom rent_epoch adalah kolom lama yang tidak lagi digunakan.

Awalnya, kolom ini melacak kapan sebuah akun perlu membayar rent (dalam lamport) untuk mempertahankan datanya di jaringan. Namun, mekanisme pengumpulan rent ini sejak itu telah tidak digunakan lagi.

Base Account Type
pub struct Account {
/// lamports in the account
pub lamports: u64,
}
// Example Token Mint Account
Account {
lamports: 1461600,
}
// Example Token Program Account
Account {
lamports: 4513200894,
}

Rent

Untuk menyimpan data on-chain, akun juga harus mempertahankan saldo lamport (SOL) yang sebanding dengan jumlah data yang disimpan pada akun (dalam byte). Saldo ini disebut "rent", tetapi lebih berfungsi seperti deposit karena Anda dapat mendapatkan kembali jumlah penuh saat Anda menutup akun. Anda dapat menemukan perhitungannya di sini menggunakan konstanta ini.

Istilah "rent" berasal dari mekanisme lama yang secara teratur mengurangi lamport dari akun yang berada di bawah ambang batas rent. Mekanisme ini tidak lagi aktif.

Pemilik Program

Di Solana, "smart contract" disebut program. Kepemilikan program adalah bagian penting dari Model Akun Solana. Setiap akun memiliki program yang ditunjuk sebagai pemiliknya. Hanya program pemilik yang dapat:

  • Mengubah bidang data akun
  • Mengurangi lamport dari saldo akun

Setiap program mendefinisikan struktur data yang disimpan dalam bidang data akun. Instruksi program menentukan bagaimana data ini dan saldo lamports akun dapat diubah.

System Program

Secara default, semua akun baru dimiliki oleh System Program. System Program melakukan fungsi-fungsi utama berikut:

FungsiDeskripsi
Pembuatan Akun BaruHanya System Program yang dapat membuat akun baru.
Alokasi RuangMengatur kapasitas byte untuk bidang data setiap akun.
Menetapkan Kepemilikan ProgramSetelah System Program membuat akun, ia dapat menetapkan kembali pemilik program yang ditunjuk ke program account yang berbeda. Begitulah cara program kustom mengambil kepemilikan akun baru yang dibuat oleh System Program.
Transfer SOLMentransfer lamport (SOL) dari Akun System ke akun lainnya.

Perlu diketahui bahwa semua akun "dompet" di Solana adalah "Akun System" yang dimiliki oleh System Program. Saldo lamport dalam akun ini menunjukkan jumlah SOL yang dimiliki oleh dompet. Hanya Akun System yang dapat membayar biaya transaksi.

Akun SystemAkun System

Ketika SOL dikirim ke alamat baru untuk pertama kalinya, sebuah akun secara otomatis dibuat di alamat tersebut yang dimiliki oleh System Program.

Dalam contoh di bawah ini, sebuah keypair baru dibuat dan didanai dengan SOL. Jalankan kode untuk melihat hasilnya. Perhatikan bahwa bidang owner dari akun tersebut adalah System Program dengan alamat 11111111111111111111111111111111.

import {
airdropFactory,
createSolanaRpc,
createSolanaRpcSubscriptions,
generateKeyPairSigner,
lamports
} from "@solana/kit";
// Create a connection to Solana cluster
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate a new keypair
const keypair = await generateKeyPairSigner();
console.log(`Public Key: ${keypair.address}`);
// Funding an address with SOL automatically creates an account
const signature = await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: keypair.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
const accountInfo = await rpc.getAccountInfo(keypair.address).send();
console.log(accountInfo);
Console
Click to execute the code.

Akun Sysvar

Akun Sysvar adalah akun khusus pada alamat yang telah ditentukan yang menyediakan akses ke data status klaster. Akun-akun ini diperbarui secara dinamis dengan data tentang klaster jaringan. Anda dapat menemukan daftar lengkap Akun Sysvar di sini.

Contoh berikut menunjukkan cara mengambil dan mendeserialkan data dari akun Sysvar Clock.

import { createSolanaRpc } from "@solana/kit";
import { fetchSysvarClock, SYSVAR_CLOCK_ADDRESS } from "@solana/sysvars";
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
const accountInfo = await rpc
.getAccountInfo(SYSVAR_CLOCK_ADDRESS, { encoding: "base64" })
.send();
console.log(accountInfo);
// Automatically fetch and deserialize the account data
const clock = await fetchSysvarClock(rpc);
console.log(clock);
Console
Click to execute the code.

Program Account

Menerapkan program Solana menciptakan program account yang dapat dieksekusi. Program account menyimpan kode yang dapat dieksekusi dari program tersebut. Program account dimiliki oleh Loader Program.

Program AccountProgram Account

Untuk menyederhanakan, Anda dapat memperlakukan program account sebagai program itu sendiri. Ketika Anda memanggil instruksi program, Anda menentukan alamat program account (umumnya disebut "Program ID").

Contoh berikut mengambil Token Program account untuk menunjukkan bahwa program account memiliki tipe dasar Account yang sama, kecuali bidang executable diatur ke true. Karena program account berisi kode yang dapat dieksekusi di bidang data mereka, kita tidak mendeserialkan datanya.

import { Address, createSolanaRpc } from "@solana/kit";
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
const programId = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" as Address;
const accountInfo = await rpc
.getAccountInfo(programId, { encoding: "base64" })
.send();
console.log(accountInfo);
Console
Click to execute the code.

Ketika Anda menerapkan program Solana, program tersebut disimpan dalam program account. Program account dimiliki oleh Loader Program. Ada beberapa versi loader, tetapi semua kecuali loader-v3 menyimpan kode yang dapat dieksekusi langsung di program account. Loader-v3 menyimpan kode yang dapat dieksekusi dalam "program data account" terpisah dan program account hanya menunjuk ke akun tersebut. Ketika Anda menerapkan program baru, Solana CLI menggunakan versi loader terbaru secara default.

Akun Buffer

Loader-v3 memiliki tipe akun khusus untuk sementara menyiapkan unggahan program selama deployment atau upgrade. Di loader-v4, masih ada buffer, tetapi mereka hanyalah program account biasa.

Akun Data Program

Loader-v3 bekerja berbeda dari semua program BPF Loader lainnya. Program account hanya berisi alamat dari program data account, yang menyimpan kode yang dapat dieksekusi:

Akun Data ProgramAkun Data Program

Jangan bingungkan program data account ini dengan data account dari program (lihat di bawah).

Akun Data

Di Solana, kode yang dapat dieksekusi dari program disimpan di akun yang berbeda dari state program. Ini seperti bagaimana sistem operasi biasanya memiliki file terpisah untuk program dan data mereka.

Untuk mempertahankan state, program mendefinisikan instruksi untuk membuat akun terpisah yang mereka miliki. Setiap akun ini memiliki alamat uniknya sendiri dan dapat menyimpan data arbitrer apa pun yang didefinisikan oleh program.

Akun DataAkun Data

Perhatikan bahwa hanya System Program yang dapat membuat akun baru. Setelah System Program membuat akun, kemudian dapat menetapkan kepemilikan akun baru ke program lain.

Dengan kata lain, membuat data account untuk program kustom memerlukan dua langkah:

  1. Memanggil System Program untuk membuat akun, kemudian mentransfer kepemilikan ke program kustom
  2. Memanggil program kustom, yang sekarang memiliki akun tersebut, untuk menginisialisasi data akun seperti yang didefinisikan oleh instruksi program

Proses pembuatan akun ini sering diabstraksikan sebagai satu langkah, tetapi penting untuk memahami proses yang mendasarinya.

Contoh berikut menunjukkan cara membuat dan mengambil akun Token Mint yang dimiliki oleh program Token 2022.

import {
airdropFactory,
appendTransactionMessageInstructions,
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
generateKeyPairSigner,
getSignatureFromTransaction,
lamports,
pipe,
sendAndConfirmTransactionFactory,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners
} from "@solana/kit";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
getInitializeMintInstruction,
getMintSize,
TOKEN_2022_PROGRAM_ADDRESS,
fetchMint
} from "@solana-program/token-2022";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer
const feePayer = await generateKeyPairSigner();
// Fund fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Instruction to create new account for mint (token 2022 program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_2022_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token 2022 program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: feePayer.address
});
const instructions = [createAccountInstruction, initializeMintInstruction];
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }), // Create transaction message
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx), // Set fee payer
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), // Set transaction blockhash
(tx) => appendTransactionMessageInstructions(instructions, tx) // Append instructions
);
// Sign transaction message with required signers (fee payer and mint keypair)
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature = getSignatureFromTransaction(signedTransaction);
console.log("Mint Address:", mint.address);
console.log("Transaction Signature:", transactionSignature);
const accountInfo = await rpc.getAccountInfo(mint.address).send();
console.log(accountInfo);
const mintAccount = await fetchMint(rpc, mint.address);
console.log(mintAccount);
Console
Click to execute the code.

Is this page helpful?

Daftar Isi

Edit Halaman