forked from solana-labs/solana
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch shared-mem tests to programtest (solana-labs#1611)
- Loading branch information
Showing
3 changed files
with
143 additions
and
137 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,180 +1,185 @@ | ||
use solana_bpf_loader_program::serialization::serialize_parameters; | ||
use solana_program::{ | ||
bpf_loader, entrypoint::SUCCESS, program_error::ProgramError, pubkey::Pubkey, | ||
}; | ||
use solana_sdk::{account::AccountSharedData, keyed_account::KeyedAccount}; | ||
use spl_shared_memory::entrypoint; | ||
|
||
// TODO: Rework `assert_instruction_count` test to use solana-program-test, avoiding the need to | ||
// link directly with the BPF VM | ||
/* | ||
fn load_program(name: &str) -> Vec<u8> { | ||
let mut file = | ||
File::open(&name).unwrap_or_else(|err| panic!("Unable to open {}: {}", name, err)); | ||
// Program test does not support calling a raw program entrypoint, only `process_instruction` | ||
#![cfg(feature = "test-bpf")] | ||
|
||
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 = Account { | ||
data: load_program("../../target/deploy/spl_shared_memory.so"), | ||
..Account::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!( | ||
SUCCESS, | ||
vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region]) | ||
.unwrap() | ||
); | ||
deserialize_parameters(&loader_id, parameter_accounts, ¶meter_bytes).unwrap(); | ||
vm.get_total_instruction_count() | ||
} | ||
use solana_program_test::*; | ||
use solana_sdk::{ | ||
account::Account, | ||
instruction::InstructionError, | ||
instruction::{AccountMeta, Instruction}, | ||
pubkey::Pubkey, | ||
signature::Signer, | ||
transaction::{Transaction, TransactionError}, | ||
}; | ||
|
||
#[test] | ||
fn assert_instruction_count() { | ||
#[tokio::test] | ||
async fn assert_instruction_count() { | ||
const OFFSET: usize = 51; | ||
const NUM_TO_SHARE: usize = 500; | ||
let program_id = Pubkey::new_unique(); | ||
let shared_key = Pubkey::new_unique(); | ||
let shared_account = Account::new_ref(u64::MAX, OFFSET + NUM_TO_SHARE * 2, &program_id); | ||
|
||
// Send some data to share | ||
let parameter_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; | ||
let mut program_test = ProgramTest::new( | ||
"spl_shared_memory", // Run the BPF version with `cargo test-bpf` | ||
program_id, | ||
None, | ||
); | ||
program_test.add_account( | ||
shared_key, | ||
Account { | ||
lamports: 5000000000000, | ||
data: vec![0_u8; NUM_TO_SHARE * 2], | ||
owner: program_id, | ||
..Account::default() | ||
}, | ||
); | ||
program_test.set_bpf_compute_max_units(480); | ||
let (mut banks_client, payer, recent_blockhash) = program_test.start().await; | ||
|
||
// success | ||
let content = vec![42; NUM_TO_SHARE]; | ||
let mut instruction_data = OFFSET.to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let share_count = run_program(&program_id, ¶meter_accounts[..], &instruction_data); | ||
const BASELINE_COUNT: u64 = 1474; // 113 if NUM_TO_SHARE is 8 | ||
println!( | ||
"BPF instructions executed {:?} (expected {:?})", | ||
share_count, BASELINE_COUNT | ||
); | ||
assert_eq!( | ||
&shared_account.borrow().data[OFFSET..OFFSET + NUM_TO_SHARE], | ||
content | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![AccountMeta::new(shared_key, false)], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
assert!(share_count <= BASELINE_COUNT); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
banks_client.process_transaction(transaction).await.unwrap(); | ||
} | ||
*/ | ||
|
||
#[test] | ||
fn test_share_data() { | ||
#[tokio::test] | ||
async fn test_helloworld() { | ||
const OFFSET: usize = 51; | ||
const NUM_TO_SHARE: usize = 500; | ||
let program_id = Pubkey::new(&[0; 32]); | ||
let program_id = Pubkey::new_unique(); | ||
let shared_key = Pubkey::new_unique(); | ||
let shared_account = AccountSharedData::new_ref(u64::MAX, NUM_TO_SHARE * 2, &program_id); | ||
|
||
let mut program_test = ProgramTest::new( | ||
"spl_shared_memory", // Run the BPF version with `cargo test-bpf` | ||
program_id, | ||
None, | ||
); | ||
program_test.add_account( | ||
shared_key, | ||
Account { | ||
lamports: 5000000000000, | ||
data: vec![0_u8; NUM_TO_SHARE * 2], | ||
owner: program_id, | ||
..Account::default() | ||
}, | ||
); | ||
let (mut banks_client, payer, recent_blockhash) = program_test.start().await; | ||
|
||
// success | ||
let content = vec![42; NUM_TO_SHARE]; | ||
let mut instruction_data = OFFSET.to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; | ||
let mut input = serialize_parameters( | ||
&bpf_loader::id(), | ||
&program_id, | ||
&keyed_accounts, | ||
&instruction_data, | ||
) | ||
.unwrap(); | ||
assert_eq!(unsafe { entrypoint(input.as_mut_ptr()) }, SUCCESS); | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![AccountMeta::new(shared_key, false)], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
banks_client.process_transaction(transaction).await.unwrap(); | ||
|
||
// success zero offset | ||
let content = vec![42; NUM_TO_SHARE]; | ||
let mut instruction_data = 0_usize.to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; | ||
let mut input = serialize_parameters( | ||
&bpf_loader::id(), | ||
&program_id, | ||
&keyed_accounts, | ||
&instruction_data, | ||
) | ||
.unwrap(); | ||
assert_eq!(unsafe { entrypoint(input.as_mut_ptr()) }, SUCCESS); | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![AccountMeta::new(shared_key, false)], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
banks_client.process_transaction(transaction).await.unwrap(); | ||
|
||
// too few accounts | ||
let mut input = | ||
serialize_parameters(&bpf_loader::id(), &program_id, &[], &instruction_data).unwrap(); | ||
let content = vec![42; NUM_TO_SHARE]; | ||
let mut instruction_data = OFFSET.to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
let result = banks_client.process_transaction(transaction).await; | ||
assert_eq!( | ||
unsafe { entrypoint(input.as_mut_ptr()) }, | ||
u64::from(ProgramError::NotEnoughAccountKeys) | ||
result.unwrap_err().unwrap(), | ||
TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys) | ||
); | ||
|
||
// too many accounts | ||
let keyed_accounts = vec![ | ||
KeyedAccount::new(&shared_key, true, &shared_account), | ||
KeyedAccount::new(&shared_key, true, &shared_account), | ||
]; | ||
let mut input = serialize_parameters( | ||
&bpf_loader::id(), | ||
&program_id, | ||
&keyed_accounts, | ||
&instruction_data, | ||
) | ||
.unwrap(); | ||
let content = vec![42; NUM_TO_SHARE]; | ||
let mut instruction_data = OFFSET.to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![ | ||
AccountMeta::new(shared_key, false), | ||
AccountMeta::new(shared_key, false), | ||
], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
let result = banks_client.process_transaction(transaction).await; | ||
assert_eq!( | ||
unsafe { entrypoint(input.as_mut_ptr()) }, | ||
u64::from(ProgramError::InvalidArgument) | ||
result.unwrap_err().unwrap(), | ||
TransactionError::InstructionError(0, InstructionError::InvalidArgument) | ||
); | ||
|
||
// account data too small | ||
let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; | ||
let content = vec![42; NUM_TO_SHARE * 10]; | ||
let mut instruction_data = OFFSET.to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let mut input = serialize_parameters( | ||
&bpf_loader::id(), | ||
&program_id, | ||
&keyed_accounts, | ||
&instruction_data, | ||
) | ||
.unwrap(); | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![AccountMeta::new(shared_key, false)], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
let result = banks_client.process_transaction(transaction).await; | ||
assert_eq!( | ||
unsafe { entrypoint(input.as_mut_ptr()) }, | ||
u64::from(ProgramError::AccountDataTooSmall) | ||
result.unwrap_err().unwrap(), | ||
TransactionError::InstructionError(0, InstructionError::AccountDataTooSmall) | ||
); | ||
|
||
// offset too large | ||
let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; | ||
let content = vec![42; NUM_TO_SHARE]; | ||
let mut instruction_data = (OFFSET * 10).to_le_bytes().to_vec(); | ||
instruction_data.extend_from_slice(&content); | ||
let mut input = serialize_parameters( | ||
&bpf_loader::id(), | ||
&program_id, | ||
&keyed_accounts, | ||
&instruction_data, | ||
) | ||
.unwrap(); | ||
let mut transaction = Transaction::new_with_payer( | ||
&[Instruction::new_with_bytes( | ||
program_id, | ||
&instruction_data, | ||
vec![AccountMeta::new(shared_key, false)], | ||
)], | ||
Some(&payer.pubkey()), | ||
); | ||
transaction.sign(&[&payer], recent_blockhash); | ||
let result = banks_client.process_transaction(transaction).await; | ||
assert_eq!( | ||
unsafe { entrypoint(input.as_mut_ptr()) }, | ||
u64::from(ProgramError::AccountDataTooSmall) | ||
result.unwrap_err().unwrap(), | ||
TransactionError::InstructionError(0, InstructionError::AccountDataTooSmall) | ||
); | ||
} |