166 lines
5.8 KiB
Rust
166 lines
5.8 KiB
Rust
use solana_bpf_loader_program::{
|
|
create_vm,
|
|
serialization::{deserialize_parameters, serialize_parameters},
|
|
};
|
|
use solana_rbpf::vm::EbpfVm;
|
|
use solana_sdk::{
|
|
account::{create_account, Account as SolanaAccount},
|
|
bpf_loader,
|
|
entrypoint::SUCCESS,
|
|
keyed_account::KeyedAccount,
|
|
process_instruction::MockInvokeContext,
|
|
program_option::COption,
|
|
program_pack::Pack,
|
|
pubkey::Pubkey,
|
|
sysvar::rent::{self, Rent},
|
|
};
|
|
use spl_token::{
|
|
instruction::TokenInstruction,
|
|
state::{Account, Mint},
|
|
};
|
|
use std::{cell::RefCell, fs::File, io::Read};
|
|
|
|
fn load_program(name: &str) -> Vec<u8> {
|
|
let mut file = File::open(name).unwrap();
|
|
|
|
let mut program = Vec::new();
|
|
file.read_to_end(&mut program).unwrap();
|
|
program
|
|
}
|
|
|
|
fn run_program(
|
|
program_id: &Pubkey,
|
|
parameter_accounts: &[KeyedAccount],
|
|
instruction_data: &[u8],
|
|
) -> u64 {
|
|
let program_account = SolanaAccount {
|
|
data: load_program("../../target/deploy/spl_token.so"),
|
|
..SolanaAccount::default()
|
|
};
|
|
let loader_id = bpf_loader::id();
|
|
let mut invoke_context = MockInvokeContext::default();
|
|
|
|
let executable = EbpfVm::<solana_bpf_loader_program::BPFError>::create_executable_from_elf(
|
|
&&program_account.data,
|
|
None,
|
|
)
|
|
.unwrap();
|
|
let (mut vm, heap_region) = create_vm(
|
|
&loader_id,
|
|
executable.as_ref(),
|
|
parameter_accounts,
|
|
&mut invoke_context,
|
|
)
|
|
.unwrap();
|
|
let mut parameter_bytes = serialize_parameters(
|
|
&loader_id,
|
|
program_id,
|
|
parameter_accounts,
|
|
&instruction_data,
|
|
)
|
|
.unwrap();
|
|
assert_eq!(
|
|
Ok(SUCCESS),
|
|
vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region])
|
|
);
|
|
deserialize_parameters(&loader_id, parameter_accounts, ¶meter_bytes).unwrap();
|
|
vm.get_total_instruction_count()
|
|
}
|
|
|
|
#[test]
|
|
fn assert_instruction_count() {
|
|
let program_id = Pubkey::new_unique();
|
|
let source_key = Pubkey::new_unique();
|
|
let source_account = SolanaAccount::new_ref(u64::MAX, Account::get_packed_len(), &program_id);
|
|
let destination_key = Pubkey::new_unique();
|
|
let destination_account =
|
|
SolanaAccount::new_ref(u64::MAX, Account::get_packed_len(), &program_id);
|
|
let owner_key = Pubkey::new_unique();
|
|
let owner_account = RefCell::new(SolanaAccount::default());
|
|
let mint_key = Pubkey::new_unique();
|
|
let mint_account = SolanaAccount::new_ref(0, Mint::get_packed_len(), &program_id);
|
|
let rent_key = rent::id();
|
|
let rent_account = RefCell::new(create_account(&Rent::free(), 42));
|
|
|
|
// Create new mint
|
|
let instruction_data = TokenInstruction::InitializeMint {
|
|
decimals: 9,
|
|
mint_authority: owner_key,
|
|
freeze_authority: COption::None,
|
|
}
|
|
.pack();
|
|
let parameter_accounts = vec![
|
|
KeyedAccount::new(&mint_key, false, &mint_account),
|
|
KeyedAccount::new(&rent_key, false, &rent_account),
|
|
];
|
|
let initialize_mint_count =
|
|
run_program(&program_id, ¶meter_accounts[..], &instruction_data);
|
|
|
|
// Create source account
|
|
let instruction_data = TokenInstruction::InitializeAccount.pack();
|
|
let parameter_accounts = vec![
|
|
KeyedAccount::new(&source_key, false, &source_account),
|
|
KeyedAccount::new(&mint_key, false, &mint_account),
|
|
KeyedAccount::new(&owner_key, false, &owner_account),
|
|
KeyedAccount::new(&rent_key, false, &rent_account),
|
|
];
|
|
let mintto_count = run_program(&program_id, ¶meter_accounts[..], &instruction_data);
|
|
|
|
// Create destination account
|
|
let instruction_data = TokenInstruction::InitializeAccount.pack();
|
|
let parameter_accounts = vec![
|
|
KeyedAccount::new(&destination_key, false, &destination_account),
|
|
KeyedAccount::new(&mint_key, false, &mint_account),
|
|
KeyedAccount::new(&owner_key, false, &owner_account),
|
|
KeyedAccount::new(&rent_key, false, &rent_account),
|
|
];
|
|
let _ = run_program(&program_id, ¶meter_accounts[..], &instruction_data);
|
|
|
|
// MintTo source account
|
|
let instruction_data = TokenInstruction::MintTo { amount: 100 }.pack();
|
|
let parameter_accounts = vec![
|
|
KeyedAccount::new(&mint_key, false, &mint_account),
|
|
KeyedAccount::new(&source_key, false, &source_account),
|
|
KeyedAccount::new(&owner_key, true, &owner_account),
|
|
];
|
|
let initialize_account_count =
|
|
run_program(&program_id, ¶meter_accounts[..], &instruction_data);
|
|
|
|
// Transfer from source to destination
|
|
let instruction = TokenInstruction::Transfer { amount: 100 };
|
|
let instruction_data = instruction.pack();
|
|
let parameter_accounts = vec![
|
|
KeyedAccount::new(&source_key, false, &source_account),
|
|
KeyedAccount::new(&destination_key, false, &destination_account),
|
|
KeyedAccount::new(&owner_key, true, &owner_account),
|
|
];
|
|
let transfer_count = run_program(&program_id, ¶meter_accounts[..], &instruction_data);
|
|
|
|
const BASELINE_NEW_MINT_COUNT: u64 = 4000; // last known 3802
|
|
const BASELINE_INITIALIZE_ACCOUNT_COUNT: u64 = 6500; // last known 6445
|
|
const BASELINE_MINTTO_COUNT: u64 = 6500; // last known 6194
|
|
const BASELINE_TRANSFER_COUNT: u64 = 8000; // last known 7609
|
|
|
|
println!("BPF instructions executed");
|
|
println!(
|
|
" InitializeMint : {:?} ({:?})",
|
|
initialize_mint_count, BASELINE_NEW_MINT_COUNT
|
|
);
|
|
println!(
|
|
" InitializeAccount: {:?} ({:?})",
|
|
initialize_account_count, BASELINE_INITIALIZE_ACCOUNT_COUNT
|
|
);
|
|
println!(
|
|
" MintTo : {:?} ({:?})",
|
|
mintto_count, BASELINE_MINTTO_COUNT
|
|
);
|
|
println!(
|
|
" Transfer : {:?} ({:?})",
|
|
transfer_count, BASELINE_TRANSFER_COUNT,
|
|
);
|
|
|
|
assert!(initialize_account_count <= BASELINE_INITIALIZE_ACCOUNT_COUNT);
|
|
assert!(initialize_mint_count <= BASELINE_NEW_MINT_COUNT);
|
|
assert!(transfer_count <= BASELINE_TRANSFER_COUNT);
|
|
}
|