Created
May 9, 2025 08:36
-
-
Save buffalojoec/ed431922000992f24985b13cde1e68df to your computer and use it in GitHub Desktop.
Interpreting account data with bytemuck is cheap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use { | |
bytemuck::{Pod, Zeroable}, | |
pinocchio::{ | |
account_info::AccountInfo, program_entrypoint, | |
pubkey::Pubkey, ProgramResult, program_error::ProgramError, | |
}, | |
}; | |
#[derive(Clone, Copy, Pod, Zeroable)] | |
#[repr(C)] | |
struct SmallData { | |
payload: [Pubkey; 2], | |
} | |
#[derive(Clone, Copy, Pod, Zeroable)] | |
#[repr(C)] | |
struct MediumData { | |
payload: [Pubkey; 16], | |
} | |
#[derive(Clone, Copy, Pod, Zeroable)] | |
#[repr(C)] | |
struct LargeData { | |
payload: [Pubkey; 32], | |
} | |
program_entrypoint!(process_instruction); | |
#[inline(always)] | |
fn process_instruction( | |
_program_id: &Pubkey, | |
accounts: &[AccountInfo], | |
input: &[u8], | |
) -> ProgramResult { | |
let info = &accounts[0]; | |
match input.first() { | |
Some(&0) => { | |
// No-op (base) | |
() | |
} | |
Some(&1) => { | |
// Account data borrow | |
let _ = info.try_borrow_data()?; | |
} | |
Some(&2) => { | |
// bytemuck cast small | |
let data = info.try_borrow_data()?; | |
let _ = bytemuck::from_bytes::<SmallData>(&data); | |
} | |
Some(&3) => { | |
// bytemuck cast medium | |
let data = info.try_borrow_data()?; | |
let _ = bytemuck::from_bytes::<MediumData>(&data); | |
} | |
Some(&4) => { | |
// bytemuck cast large | |
let data = info.try_borrow_data()?; | |
let _ = bytemuck::from_bytes::<LargeData>(&data); | |
} | |
_ => Err(ProgramError::InvalidInstructionData)?, | |
} | |
Ok(()) | |
} | |
#[cfg(all(test, feature = "test-sbf"))] | |
mod tests { | |
use { | |
super::*, | |
mollusk_svm::{result::Check, Mollusk}, | |
solana_account::Account, | |
solana_instruction::{AccountMeta, Instruction}, | |
solana_pubkey::Pubkey, | |
}; | |
fn run_test( | |
ix_dscr: u8, | |
acct_data: &[u8], | |
cus: u64, | |
) { | |
let program_id = Pubkey::new_unique(); | |
let key = Pubkey::new_unique(); | |
Mollusk::new(&program_id, "tests").process_and_validate_instruction( | |
&Instruction::new_with_bytes(program_id, &[ix_dscr], vec![AccountMeta::new(key, false)]), | |
&[(key, Account { data: acct_data.to_vec(), ..Default::default() })], | |
&[Check::success(), Check::compute_units(cus)], | |
); | |
} | |
#[test] | |
fn test_base() { | |
run_test( | |
0, | |
&[], | |
/* CUs: */ 39, | |
); | |
} | |
#[test] | |
fn test_account_borrow() { | |
run_test( | |
1, | |
&[], | |
/* CUs: */ 49, | |
); | |
} | |
#[test] | |
fn test_bytemuck_small() { | |
run_test( | |
2, | |
bytemuck::bytes_of(&SmallData { | |
payload: [[4; 32]; 2], | |
}), | |
/* CUs: */ 55, | |
); | |
} | |
#[test] | |
fn test_bytemuck_medium() { | |
run_test( | |
3, | |
bytemuck::bytes_of(&MediumData { | |
payload: [[4; 32]; 16], | |
}), | |
/* CUs: */ 56, | |
); | |
} | |
#[test] | |
fn test_bytemuck_large() { | |
run_test( | |
4, | |
bytemuck::bytes_of(&LargeData { | |
payload: [[4; 32]; 32], | |
}), | |
/* CUs: */ 56, | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment