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.
Akun
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 Akun
Sebagian besar akun Solana menggunakan kunci publik Ed25519 sebagai alamat mereka.
import { generateKeyPairSigner } from "@solana/kit";// Kit does not enable extractable private keysconst keypairSigner = await generateKeyPairSigner();console.log(keypairSigner);
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}`);
Tipe Akun
Akun memiliki ukuran maksimal 10MiB dan setiap akun di Solana berbagi tipe dasar Account yang sama.
Tipe 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.
pub struct Account {/// lamports in the accountpub 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 rentpub rent_epoch: Epoch,}
import {airdropFactory,createSolanaRpc,createSolanaRpcSubscriptions,generateKeyPairSigner,lamports} from "@solana/kit";// Create a connection to Solana clusterconst rpc = createSolanaRpc("http://localhost:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate a new keypairconst keypair = await generateKeyPairSigner();console.log(`Public Key: ${keypair.address}`);// Funding an address with SOL automatically creates an accountconst 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);
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 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);
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 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);
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 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 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:
- Memanggil Program Sistem untuk membuat akun, kemudian mentransfer kepemilikan ke program kustom
- 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 exampleconst rpc = createSolanaRpc("http://127.0.0.1:8899");const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");// Generate keypairs for fee payerconst feePayer = await generateKeyPairSigner();// Fund fee payerawait airdropFactory({ rpc, rpcSubscriptions })({recipientAddress: feePayer.address,lamports: lamports(1_000_000_000n),commitment: "confirmed"});// Generate keypair to use as address of mintconst mint = await generateKeyPairSigner();// Get default mint account size (in bytes), no extensions enabledconst space = BigInt(getMintSize());// Get minimum balance for rent exemptionconst rent = await rpc.getMinimumBalanceForRentExemption(space).send();// Instruction to create new account for mint (token 2022 program)// Invokes the system programconst createAccountInstruction = getCreateAccountInstruction({payer: feePayer,newAccount: mint,lamports: rent,space,programAddress: TOKEN_2022_PROGRAM_ADDRESS});// Instruction to initialize mint account data// Invokes the token 2022 programconst initializeMintInstruction = getInitializeMintInstruction({mint: mint.address,decimals: 9,mintAuthority: feePayer.address});const instructions = [createAccountInstruction, initializeMintInstruction];// Get latest blockhash to include in transactionconst { value: latestBlockhash } = await rpc.getLatestBlockhash().send();// Create transaction messageconst 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 transactionawait sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction,{ commitment: "confirmed" });// Get transaction signatureconst 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);
Is this page helpful?