General
Pengenalan Blockchain dan Solana

Pengenalan Blockchain dan Solana

Pengenalan Solana

Sebelum membangun di Solana, Anda perlu memahami beberapa konsep fundamental yang membuat Solana unik. Panduan ini mencakup akun, transaksi, program, dan interaksi di antaranya.

Akun di Solana

Arsitektur Solana berpusat pada akun: wadah data yang menyimpan informasi di blockchain. Anggap akun sebagai file individual dalam sistem file, di mana setiap file memiliki properti spesifik dan pemilik yang mengendalikannya.

Setiap akun Solana memiliki struktur dasar yang sama:

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

Setiap akun memiliki alamat unik 32-byte, ditampilkan sebagai string yang dikodekan base58 (misalnya, 14grJpemFaf88c8tiVb77W7TYg2W3ir6pfkKz3YjhhZ5). Alamat ini berfungsi sebagai pengidentifikasi akun di blockchain dan merupakan cara Anda menemukan data tertentu.

Akun dapat menyimpan hingga 10 MiB data, yang dapat berisi kode program yang dapat dieksekusi atau data khusus program.

Semua akun memerlukan deposit lamport yang proporsional dengan ukuran datanya untuk menjadi "rent-exempt". Istilah "rent" bersifat historis, karena lamport awalnya dikurangi dari akun setiap epoch, tetapi fitur ini sekarang dinonaktifkan. Saat ini, deposit bekerja lebih seperti deposit yang dapat dikembalikan. Selama akun Anda mempertahankan saldo minimum untuk ukuran datanya, akun tersebut tetap rent-exempt dan bertahan tanpa batas waktu. Ketika Anda tidak lagi membutuhkan akun, Anda dapat menutupnya dan mendapatkan kembali deposit ini sepenuhnya.

Setiap akun dimiliki oleh program, dan hanya program pemilik yang dapat memodifikasi data akun atau menarik lamport-nya. Namun, siapa pun dapat meningkatkan saldo lamport akun, yang berguna untuk mendanai operasi atau membayar rent tanpa bergantung pada pemanggilan program itu sendiri.

Otoritas penandatanganan bekerja secara berbeda tergantung pada kepemilikan. Akun yang dimiliki oleh Program Sistem dapat menandatangani transaksi untuk memodifikasi data mereka sendiri, mentransfer kepemilikan, atau mengklaim kembali lamport yang tersimpan. Setelah kepemilikan ditransfer ke program lain, program tersebut mendapatkan kendali penuh atas akun terlepas dari apakah Anda masih memiliki kunci privat. Transfer kendali ini bersifat permanen dan tidak dapat dibalik.

Jenis Akun

Jenis akun yang paling umum adalah Akun Sistem, yang menyimpan lamport (unit terkecil dari SOL) dan dimiliki oleh Program Sistem. Akun ini berfungsi sebagai akun dompet dasar yang digunakan pengguna secara langsung untuk mengirim dan menerima SOL.

Akun Token memiliki tujuan khusus, menyimpan informasi token SPL, termasuk kepemilikan dan metadata token. Program Token memiliki akun-akun ini dan mengelola semua operasi terkait token di seluruh ekosistem Solana. Akun Token adalah Akun Data.

Akun Data menyimpan informasi khusus aplikasi dan dimiliki oleh program kustom. Akun ini menyimpan status aplikasi Anda dan dapat distrukturkan sesuai kebutuhan program Anda, mulai dari profil pengguna sederhana hingga data keuangan yang kompleks.

Terakhir, Akun Program berisi kode yang dapat dieksekusi yang berjalan di Solana, di mana smart contract berada. Akun ini ditandai sebagai executable: true dan menyimpan logika program yang memproses instruksi dan mengelola status.

Bekerja dengan Data Akun

Berikut cara program berinteraksi dengan data akun:

rust
#[derive(BorshSerialize, BorshDeserialize)]
pub struct UserAccount {
    pub name: String,
    pub balance: u64,
    pub posts: Vec<u32>,
}
 
pub fn update_user_data(accounts: &[AccountInfo], new_name: String) -> ProgramResult {
    let user_account = &accounts[0];
    
    // Deserialize existing data
    let mut user_data = UserAccount::try_from_slice(&user_account.data.borrow())?;
    
    // Modify the data
    user_data.name = new_name;
    
    // Serialize back to account
    user_data.serialize(&mut &mut user_account.data.borrow_mut()[..])?;
    
    Ok(())
}

Tidak seperti database di mana Anda cukup memasukkan catatan, akun Solana harus secara eksplisit dibuat dan didanai sebelum digunakan.

Transaksi di Solana

Transaksi Solana adalah operasi atomik yang dapat berisi beberapa instruksi. Semua instruksi dalam transaksi berhasil bersama atau gagal bersama: tidak ada eksekusi parsial.

Sebuah transaksi terdiri dari:

  • Instruksi: Operasi individual yang akan dilakukan
  • Akun: Akun spesifik yang akan dibaca atau ditulis oleh setiap instruksi
  • Penandatangan: Akun yang mengotorisasi transaksi
rust
Transaction {
    instructions: [
        // Instruction 1: Transfer SOL
        system_program::transfer(from_wallet, to_wallet, amount),
        
        // Instruction 2: Update user profile  
        my_program::update_profile(user_account, new_name),
        
        // Instruction 3: Log activity
        my_program::log_activity(activity_account, "transfer", amount),
    ],
    accounts: [from_wallet, to_wallet, user_account, activity_account]
    signers: [user_keypair],
}

Persyaratan dan Biaya Transaksi

Transaksi dibatasi hingga total 1.232 byte, yang membatasi berapa banyak instruksi dan akun yang dapat Anda sertakan.

Setiap instruksi dalam transaksi memerlukan tiga komponen penting: alamat program yang akan dipanggil, semua akun yang akan dibaca atau ditulis oleh instruksi, dan data tambahan seperti argumen fungsi.

Instruksi dieksekusi secara berurutan sesuai dengan urutan yang Anda tentukan dalam transaksi.

Setiap transaksi dikenakan biaya dasar sebesar 5.000 lamports per tanda tangan untuk memberi kompensasi kepada validator yang memproses transaksi Anda.

Anda juga dapat membayar biaya prioritas opsional untuk meningkatkan kemungkinan bahwa pemimpin saat ini memproses transaksi Anda dengan cepat. Biaya prioritas ini dihitung sebagai batas unit komputasi Anda dikalikan dengan harga unit komputasi Anda (diukur dalam mikro-lamports).

 
prioritization_fee = compute_unit_limit × compute_unit_price

Akun yang membayar biaya transaksi harus dimiliki oleh System Program, memastikan bahwa akun tersebut dapat mengotorisasi pembayaran dengan benar.

Programs on Solana

Program di Solana pada dasarnya stateless, artinya mereka tidak mempertahankan status internal antara pemanggilan fungsi. Sebagai gantinya, mereka menerima akun sebagai input, memproses data dalam akun tersebut, dan mengembalikan hasil yang telah dimodifikasi.

Desain stateless ini memastikan perilaku yang dapat diprediksi dan memungkinkan pola komposabilitas yang kuat.

Program itu sendiri disimpan dalam akun khusus yang ditandai sebagai executable: true, berisi kode biner terkompilasi yang dieksekusi ketika dipanggil.

Pengguna berinteraksi dengan program-program ini dengan mengirimkan transaksi yang berisi instruksi spesifik, masing-masing menargetkan fungsi program tertentu dengan data akun dan parameter yang diperlukan.

rust
use solana_program::prelude::*;
 
#[derive(BorshSerialize, BorshDeserialize)]
pub struct User {
    pub name: String,
    pub created_at: i64,
}
 
pub fn create_user(
    accounts: &[AccountInfo],
    name: String,
) -> ProgramResult {
    let user_account = &accounts[0];
    
    let user = User {
        name,
        created_at: Clock::get()?.unix_timestamp,
    };
    
    user.serialize(&mut &mut user_account.data.borrow_mut()[..])?;
    Ok(())
}

Program dapat diperbarui oleh otoritas peningkatan yang ditunjuk, memungkinkan pengembang untuk memperbaiki bug dan menambahkan fitur setelah penerapan. Namun, menghapus otoritas peningkatan ini membuat program menjadi permanen tidak dapat diubah, memberikan jaminan kepada pengguna bahwa kode tidak akan pernah berubah.

Untuk transparansi dan keamanan, pengguna dapat memverifikasi bahwa program on-chain sesuai dengan kode sumber publik mereka melalui build yang dapat diverifikasi, memastikan bytecode yang diterapkan sesuai persis dengan sumber yang dipublikasikan.

Program Derived Addresses (PDAs)

PDA adalah alamat yang dihasilkan secara deterministik yang memungkinkan pola pemrograman yang kuat. Alamat ini dibuat menggunakan seed dan ID program, menghasilkan alamat tanpa kunci privat yang sesuai.

PDA menggunakan hashing SHA-256 dengan input tertentu, termasuk seed kustom Anda, nilai bump untuk memastikan hasilnya off-curve, ID program yang akan memiliki PDA, dan penanda konstan.

Ketika hash menghasilkan alamat on-curve (yang terjadi sekitar 50% waktu), sistem akan melakukan iterasi dari bump 255 turun ke 254, 253, dan seterusnya hingga menemukan hasil off-curve.

rust
use solana_nostd_sha256::hashv;
 
const PDA_MARKER: &[u8; 21] = b"ProgramDerivedAddress";
 
let pda = hashv(&[
    seed_data.as_ref(),    // Your custom seeds
    &[bump],               // Bump to ensure off-curve
    program_id.as_ref(),   // Program that owns this PDA
    PDA_MARKER,
]);

Manfaat

Sifat deterministik PDA menghilangkan kebutuhan untuk menyimpan alamat: Anda dapat menghasilkannya kembali dari seed yang sama kapan pun diperlukan.

Ini menciptakan skema pengalamatan yang dapat diprediksi yang berfungsi seperti struktur hashmap on-chain. Yang lebih penting, program dapat menandatangani PDA mereka sendiri, memungkinkan pengelolaan aset secara otonom tanpa mengekspos kunci privat:

rust
let seeds = &[b"vault", user.as_ref(), &[bump]];
 
invoke_signed(
    &transfer_instruction,
    &[from_pda, to_account, token_program],
    &[&seeds[..]], // Program proves PDA control
)?;

Cross Program Invocation (CPI)

CPI memungkinkan program untuk memanggil program lain dalam transaksi yang sama, menciptakan komposabilitas sejati di mana beberapa program dapat berinteraksi secara atomik tanpa koordinasi eksternal.

Ini memungkinkan pengembang untuk membangun aplikasi kompleks dengan menggabungkan program yang sudah ada daripada membangun ulang fungsionalitas dari awal.

CPI mengikuti pola yang sama seperti instruksi biasa, mengharuskan Anda untuk menentukan program target, akun yang dibutuhkan, dan data instruksi, dengan perbedaan utama yaitu CPI dapat dilakukan di dalam program lain.

Program yang memanggil tetap mempertahankan kontrol atas alur sambil mendelegasikan operasi tertentu ke program yang terspesialisasi:

rust
let cpi_accounts = TransferAccounts {
    from: source_account.clone(),
    to: destination_account.clone(), 
    authority: authority_account.clone(),
};
 
let cpi_ctx = CpiContext::new(token_program.clone(), cpi_accounts);
token_program::cpi::transfer(cpi_ctx, amount)?;

Batasan dan Kemampuan

Penandatangan transaksi asli mempertahankan otoritas mereka di seluruh rantai CPI, memungkinkan program untuk bertindak atas nama pengguna dengan mulus.

Namun, program hanya dapat membuat CPI hingga 4 level kedalaman (A → B → C → D) untuk mencegah rekursi tak terbatas. Program juga dapat menandatangani PDA mereka dalam CPI menggunakan CpiContext::new_with_signer, memungkinkan operasi otonom yang canggih.

Komposabilitas ini memungkinkan operasi kompleks di berbagai program dalam satu transaksi atomik, membuat aplikasi Solana sangat modular dan interoperabel.

Daftar Isi
Lihat Sumber
Blueshift © 2025Commit: 96f50c6