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 smart contract.
  • 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 vines1vzrYbzLMRdu58ou5XTby4qAqVRLmqo36NKPTg).

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

  • data: Array byte yang menyimpan data arbitrer untuk sebuah akun. Untuk akun non-executable, ini sering menyimpan state yang dimaksudkan untuk dibaca. Untuk akun program (smart contract), ini berisi kode program yang dapat dieksekusi. Bidang data umumnya disebut "data akun."
  • executable: Flag ini menunjukkan apakah sebuah akun adalah program.
  • lamports: Saldo akun dalam lamport, unit terkecil dari SOL (1 SOL = 1 miliar lamport).
  • owner: ID program (kunci publik) dari program yang memiliki akun ini. Hanya program pemilik yang dapat mengubah data akun atau mengurangi saldo lamport-nya.
  • rent_epoch: Bidang lama dari ketika Solana memiliki mekanisme yang secara berkala mengurangi lamport dari akun. Meskipun bidang ini masih ada dalam tipe Account, bidang ini tidak lagi digunakan sejak pengumpulan rent dihentikan.
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,
}
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);
Click to execute the code.

Rent

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

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

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

Program sistem

Secara default, semua akun baru dimiliki oleh Program Sistem. Program Sistem melakukan beberapa hal penting:

  • Pembuatan Akun Baru: Hanya Program Sistem yang dapat membuat akun baru.
  • Alokasi Ruang: Menetapkan kapasitas byte untuk bidang data setiap akun.
  • Transfer / Penugasan Kepemilikan Program: Setelah Program Sistem membuat akun, ia dapat menetapkan kembali pemilik program yang ditunjuk ke akun program yang berbeda. Begitulah cara program kustom mengambil kepemilikan akun baru yang dibuat oleh Program Sistem.

Semua akun "dompet" di Solana hanyalah akun yang dimiliki oleh Program Sistem. Saldo lamport dalam akun ini menunjukkan jumlah SOL yang dimiliki oleh dompet. Hanya akun yang dimiliki oleh Program Sistem yang dapat membayar biaya transaksi.

Akun SistemAkun Sistem

Akun Sysvar

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

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

Akun Program

Menerapkan program Solana menciptakan akun program yang dapat dieksekusi. Akun program menyimpan kode yang dapat dieksekusi dari program tersebut.

Akun program dimiliki oleh Program Loader.

Akun ProgramAkun Program

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

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);
Click to execute the code.

Ketika Anda menerapkan program Solana, program tersebut disimpan dalam akun program. Akun program dimiliki oleh Program Loader. Ada beberapa versi loader, tetapi semua kecuali loader-v3 menyimpan kode yang dapat dieksekusi langsung di akun program. Loader-v3 menyimpan kode yang dapat dieksekusi dalam "akun data program" terpisah dan akun program 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 menyimpan unggahan program selama penerapan atau penerapan ulang/peningkatan. Di loader-v4, masih ada buffer, tetapi mereka hanya akun program normal.

Akun Data Program

Loader-v3 bekerja secara berbeda dari semua program BPF Loader lainnya. Akun program hanya berisi alamat dari akun data program, yang menyimpan kode yang dapat dieksekusi sebenarnya:

Akun Data ProgramAkun Data Program

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

Akun Data

Di Solana, kode yang dapat dieksekusi dari sebuah program disimpan di akun yang berbeda dari state program tersebut. 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 Program Sistem yang dapat membuat akun baru. Setelah Program Sistem membuat akun, program tersebut kemudian dapat mentransfer atau menetapkan kepemilikan akun baru ke program lain.

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

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

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

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
} from "@solana-program/token-2022";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://127.0.0.1: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);
Click to execute the code.

Is this page helpful?

Daftar Isi

Edit Halaman