Skip to content

Commit

Permalink
Switch shared-mem tests to programtest (solana-labs#1611)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmay authored Apr 19, 2021
1 parent 589da55 commit a5c4b1e
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 137 deletions.
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions shared-memory/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ repository = "https://github.com/solana-labs/solana-program-library"
license = "Apache-2.0"
edition = "2018"

[features]
test-bpf = []

[dependencies]
arrayref = "0.3.6"
solana-program = "1.6.2"
solana-program = "=1.6.2"

[dev-dependencies]
solana-bpf-loader-program = "1.6.2"
solana-sdk = "1.6.2"
solana_rbpf = "0.2"
solana-program-test = "=1.6.2"
solana-sdk = "=1.6.2"

[lib]
crate-type = ["cdylib", "lib"]
267 changes: 136 additions & 131 deletions shared-memory/program/tests/shared-memory.rs
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, &parameter_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, &parameter_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)
);
}

0 comments on commit a5c4b1e

Please sign in to comment.