From a5c4b1e071dc8c792f855e822ff65a1f3629369e Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 19 Apr 2021 11:14:23 -0700 Subject: [PATCH] Switch shared-mem tests to programtest (#1611) --- Cargo.lock | 3 +- shared-memory/program/Cargo.toml | 10 +- shared-memory/program/tests/shared-memory.rs | 267 ++++++++++--------- 3 files changed, 143 insertions(+), 137 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 48b5c6903e7fba..593e78b32eee7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3816,10 +3816,9 @@ name = "spl-shared-memory" version = "2.0.6" dependencies = [ "arrayref", - "solana-bpf-loader-program", "solana-program", + "solana-program-test", "solana-sdk", - "solana_rbpf", ] [[package]] diff --git a/shared-memory/program/Cargo.toml b/shared-memory/program/Cargo.toml index 619703d7ed2369..26d24da51c7095 100644 --- a/shared-memory/program/Cargo.toml +++ b/shared-memory/program/Cargo.toml @@ -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"] diff --git a/shared-memory/program/tests/shared-memory.rs b/shared-memory/program/tests/shared-memory.rs index b3a6b5eea85568..3db3ce1413eef2 100644 --- a/shared-memory/program/tests/shared-memory.rs +++ b/shared-memory/program/tests/shared-memory.rs @@ -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 { - 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::::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) ); }