General
Introspeksi Instruksi

Introspeksi Instruksi

Introspeksi Instruksi

Introspeksi Instruksi

Introspeksi instruksi adalah kemampuan yang sangat kuat di Solana yang memungkinkan program untuk menganalisis instruksi lain dalam transaksi yang sama, termasuk yang belum dieksekusi. Ini memungkinkan Anda untuk merespons atau menambah instruksi tersebut secara dinamis — misalnya, dengan menambahkan pengamanan, memvalidasi perilaku, atau mengintegrasikan instruksi dari program eksternal ke dalam logika Anda sendiri.

Hal ini dimungkinkan oleh akun sistem khusus yang disebut sysvar Instructions. Sysvar adalah akun hanya-baca yang dikelola oleh runtime Solana yang mengekspos status internal ke program (misalnya, jam, sewa, jadwal epoch, dll.). Sysvar Instructions secara khusus mengekspos daftar lengkap instruksi dalam transaksi saat ini, beserta metadata dan data yang diserialisasi.

Berikut cara Solana melakukan serialisasi informasi ini pada saat runtime:

rust
// First encode the number of instructions:
//  0..2 - num_instructions
//
// Then a table of offsets of where to find them in the data
//  3..2 * num_instructions table of instruction offsets
//
// Each instruction is then encoded as:
//   0..2 - num_accounts
//   2 - meta_byte -> (bit 0 signer, bit 1 is_writable)
//   3..35 - pubkey - 32 bytes
//   35..67 - program_id
//   67..69 - data len - u16
//   69..data_len - data
#[cfg(not(target_os = "solana"))]
fn serialize_instructions(instructions: &[BorrowedInstruction]) -> Vec<u8> {
    // 64 bytes is a reasonable guess, calculating exactly is slower in benchmarks
    let mut data = Vec::with_capacity(instructions.len() * (32 * 2));
    append_u16(&mut data, instructions.len() as u16);
    for _ in 0..instructions.len() {
        append_u16(&mut data, 0);
    }

    for (i, instruction) in instructions.iter().enumerate() {
        let start_instruction_offset = data.len() as u16;
        let start = 2 + (2 * i);
        data[start..start + 2].copy_from_slice(&start_instruction_offset.to_le_bytes());
        append_u16(&mut data, instruction.accounts.len() as u16);
        for account_meta in &instruction.accounts {
            let mut account_meta_flags = InstructionsSysvarAccountMeta::empty();
            if account_meta.is_signer {
                account_meta_flags |= InstructionsSysvarAccountMeta::IS_SIGNER;
            }
            if account_meta.is_writable {
                account_meta_flags |= InstructionsSysvarAccountMeta::IS_WRITABLE;
            }
            append_u8(&mut data, account_meta_flags.bits());
            append_slice(&mut data, account_meta.pubkey.as_ref());
        }

        append_slice(&mut data, instruction.program_id.as_ref());
        append_u16(&mut data, instruction.data.len() as u16);
        append_slice(&mut data, instruction.data);
    }
    data
}

Ini berarti dengan membaca akun sysvar Instructions di dalam program Anda, Anda dapat mengakses semua instruksi yang termasuk dalam transaksi saat ini.

Anda tidak perlu mengurai byte mentah secara manual. Solana menyediakan fungsi pembantu:

  • load_current_index_checked: mengembalikan indeks dari instruksi yang sedang dieksekusi.

  • load_instruction_at_checked: memungkinkan Anda memuat instruksi tertentu berdasarkan indeksnya dalam format yang sudah diurai dan dideserialkan.

Bagaimana cara kerjanya?

Setiap instruksi Solana berisi:

  • ID program yang ditargetkan,

  • akun yang berinteraksi dengannya (termasuk metadata seperti penandatangan/dapat ditulis),

  • dan muatan data (biasanya diskriminator + argumen).

Dan inilah yang diberikan oleh fungsi load_instruction_at_checked dari sysvar Instructions:

  • program_id: program yang dipanggil oleh instruksi ini.

  • accounts: daftar akun yang terlibat dengan metadata.

  • data: muatan input mentah (jika kita melakukan introspeksi instruksi anchor, sering dimulai dengan diskriminator 8-byte diikuti oleh parameter).

Untuk melakukan introspeksi instruksi lain dengan aman dan efisien, ikuti langkah-langkah berikut:

  • Tentukan Indeks Instruksi Saat Ini: Gunakan load_current_index_checked untuk menemukan indeks dari instruksi yang sedang dijalankan.

Perlu diingat: instruksi Anda mungkin bukan yang pertama (indeks 0) dalam transaksi.

  • Muat Instruksi Target untuk Dianalisis: Dengan indeks yang sudah didapat, gunakan load_instruction_at_checked(index) untuk memuat instruksi lain dalam transaksi yang sama—baik yang sebelumnya, sesudahnya, atau pada posisi tertentu.

Ini berguna untuk memvalidasi perilaku, memastikan input yang diharapkan, atau menyusun program secara aman.

  • Bangun Batasan untuk Mencegah Perilaku Berbahaya: Introspeksi instruksi sangat kuat, tetapi juga memperkenalkan permukaan serangan baru. Pastikan untuk: memvalidasi bahwa instruksi yang diintrospeksi menargetkan program yang diharapkan, konfirmasi bahwa alamat akun dan data sesuai dengan pola yang diharapkan, dan hindari asumsi tentang urutan instruksi kecuali secara eksplisit ditegakkan.

Dengan mengambil tindakan pencegahan ini, Anda dapat memanfaatkan introspeksi instruksi dengan aman untuk membangun program Solana yang kuat, dapat dikomposisi, dan aman.

Batasan Umum untuk Introspeksi

Saat menggunakan introspeksi instruksi, penting untuk menerapkan batasan ketat untuk mencegah perilaku berbahaya atau tidak terduga. Perlindungan yang paling umum meliputi:

  • Verifikasi Instruksi: Validasi ID program instruksi dan diskriminator untuk memastikan itu adalah yang benar. Diskriminator (biasanya 1, 4, atau 8 byte pertama dari data instruksi) secara unik mengidentifikasi fungsi mana yang dipanggil.

Langkah ini memastikan Anda memeriksa instruksi yang dimaksud dan bukan yang palsu atau cacat.

  • Validasi Variabel: Setelah diskriminator, parse dan periksa variabel penting yang digunakan oleh instruksi. Ini mungkin termasuk jumlah, arah (misalnya, long/short), atau ID, dan Anda harus selalu mengonfirmasi bahwa bidang-bidang ini selaras dengan logika yang diharapkan dari integrasi atau perlindungan Anda.

  • Verifikasi Akun: Validasi struktur dan identitas akun instruksi. Periksa bahwa akun yang diharapkan muncul pada posisi tertentu (misalnya, penandatangan, vault, jaminan) dan pastikan bahwa peran seperti status penandatangan/dapat ditulis sesuai dengan asumsi Anda.

Dengan menerapkan batasan-batasan ini, Anda memastikan bahwa program Anda hanya merespons instruksi yang valid dan terpercaya, membuat logika Anda lebih kuat, dapat dikomposisi, dan aman.

Bersama dengan atomisitas transaksi, pemeriksaan ini memungkinkan Anda membangun logika yang kuat dan dapat dikomposisi yang dapat berinteraksi dengan aman dengan program dan instruksi lain dalam transaksi yang sama.

Ingat, transaksi di Solana bersifat atomik. Jika ada instruksi yang gagal, seluruh transaksi akan dibatalkan.

Daftar Isi
Lihat Sumber
Blueshift © 2025Commit: e573eab