Introspeksi Instruksi dengan Anchor
Anchor tidak memiliki helper bawaan untuk sysvar Instruction, tetapi semua tipe dan fungsi dari crate solana_program secara inheren didukung di Anchor.
Untuk menggunakan Introspeksi Instruksi di Anchor, Anda perlu menambahkan crate solana_program ke proyek Anda:
cargo add solana-programSetelah menambahkan crate, Anda dapat mengakses fungsi-fungsi yang diperlukan dengan mengimpornya:
use solana_program::sysvar::instructions::{
self,
load_current_index_checked,
load_instruction_at_checked
}; Cara menggunakan Introspeksi
Seperti yang disebutkan dalam pendahuluan, Introspeksi Instruksi bekerja dengan mendeserialkan data dari akun sysvar Instruction untuk memberikan detail tentang instruksi dalam sebuah transaksi.
Meskipun fungsi load_instruction_at_checked memverifikasi bahwa akun yang dideserialkan adalah yang benar, adalah praktik yang baik untuk menambahkan pemeriksaan tambahan ke struct akun Anda:
#[account(address = instructions::ID)]
/// CHECK: InstructionsSysvar account
instructions: UncheckedAccount<'info>,Sekarang Anda dapat mulai bekerja dengan Introspeksi Instruksi.
Pertama, periksa indeks instruksi saat ini menggunakan fungsi load_current_index_checked:
// Check the index of the currently executing instruction. This could be in a different position than [0]).
let index = load_current_index_checked(&ctx.accounts.instructions.to_account_info())?;Selanjutnya, Anda dapat memeriksa instruksi pada indeks relatif menggunakan load_instruction_at_checked. Di sini, kita akan memeriksa instruksi yang langsung mengikuti instruksi saat ini:
// Load the next instruction to check its input.
let ix = load_instruction_at_checked(index as usize + 1, &ctx.accounts.instructions.to_account_info())?;Sebelum melanjutkan ke langkah berikutnya, penting untuk mempertimbangkan informasi apa yang penting untuk mencegah serangan berbahaya.
Biasanya kita mulai dengan memeriksa apakah program yang dipanggil adalah yang diharapkan. Dalam contoh ini, kita melakukan introspeksi instruksi lain dari program yang sama:
require_keys_eq!(ix.program_id, ID, EscrowError::InvalidProgram);Selanjutnya, periksa apakah instruksi tersebut adalah yang Anda harapkan. Untuk melakukannya, bandingkan diskriminator instruksi dengan yang diharapkan. Dalam kasus ini, karena ini adalah instruksi Anchor lainnya, Anda dapat melakukannya seperti ini:
require!(ix.data[0..8].eq(instruction::TakeEnd::DISCRIMINATOR.as_slice()), EscrowError::InvalidIx);Anda kemudian dapat melakukan pemeriksaan yang lebih spesifik berdasarkan logika instruksi yang sedang diperiksa.
Dalam contoh ini, kita memeriksa bahwa data instruksi (jumlah) sudah benar. Data instruksi selalu di-deserialisasi setelah diskriminator, jadi Anda dapat melakukannya seperti ini:
require!(ix.data[8..16].eq(&escrow.take_amount.to_le_bytes()), EscrowError::InvalidAmount);Terakhir, periksa akun yang ada dalam instruksi yang diintrospeksi. Langkah ini mengharuskan Anda mengetahui struktur pasti dari struct Account, karena Anda akan meminta data atau kunci publik dari akun pada indeks tertentu:
let maker_ata = get_associated_token_address(&ctx.accounts.maker.key(), &escrow.mint_b);
require_keys_eq!(ix.accounts.get(3).unwrap().pubkey, maker_ata, EscrowError::InvalidMakerATA);