|
1 |
| -use solana_bpf_loader_program::serialization::serialize_parameters; |
2 |
| -use solana_program::{ |
3 |
| - bpf_loader, entrypoint::SUCCESS, program_error::ProgramError, pubkey::Pubkey, |
4 |
| -}; |
5 |
| -use solana_sdk::{account::AccountSharedData, keyed_account::KeyedAccount}; |
6 |
| -use spl_shared_memory::entrypoint; |
7 |
| - |
8 |
| -// TODO: Rework `assert_instruction_count` test to use solana-program-test, avoiding the need to |
9 |
| -// link directly with the BPF VM |
10 |
| -/* |
11 |
| -fn load_program(name: &str) -> Vec<u8> { |
12 |
| - let mut file = |
13 |
| - File::open(&name).unwrap_or_else(|err| panic!("Unable to open {}: {}", name, err)); |
| 1 | +// Program test does not support calling a raw program entrypoint, only `process_instruction` |
| 2 | +#![cfg(feature = "test-bpf")] |
14 | 3 |
|
15 |
| - let mut program = Vec::new(); |
16 |
| - file.read_to_end(&mut program).unwrap(); |
17 |
| - program |
18 |
| -} |
19 |
| -
|
20 |
| -fn run_program( |
21 |
| - program_id: &Pubkey, |
22 |
| - parameter_accounts: &[KeyedAccount], |
23 |
| - instruction_data: &[u8], |
24 |
| -) -> u64 { |
25 |
| - let program_account = Account { |
26 |
| - data: load_program("../../target/deploy/spl_shared_memory.so"), |
27 |
| - ..Account::default() |
28 |
| - }; |
29 |
| - let loader_id = bpf_loader::id(); |
30 |
| - let mut invoke_context = MockInvokeContext::default(); |
31 |
| - let executable = EbpfVm::<solana_bpf_loader_program::BPFError>::create_executable_from_elf( |
32 |
| - &&program_account.data, |
33 |
| - None, |
34 |
| - ) |
35 |
| - .unwrap(); |
36 |
| - let (mut vm, heap_region) = create_vm( |
37 |
| - &loader_id, |
38 |
| - executable.as_ref(), |
39 |
| - parameter_accounts, |
40 |
| - &mut invoke_context, |
41 |
| - ) |
42 |
| - .unwrap(); |
43 |
| - let mut parameter_bytes = serialize_parameters( |
44 |
| - &loader_id, |
45 |
| - program_id, |
46 |
| - parameter_accounts, |
47 |
| - &instruction_data, |
48 |
| - ) |
49 |
| - .unwrap(); |
50 |
| - assert_eq!( |
51 |
| - SUCCESS, |
52 |
| - vm.execute_program(parameter_bytes.as_mut_slice(), &[], &[heap_region]) |
53 |
| - .unwrap() |
54 |
| - ); |
55 |
| - deserialize_parameters(&loader_id, parameter_accounts, ¶meter_bytes).unwrap(); |
56 |
| - vm.get_total_instruction_count() |
57 |
| -} |
| 4 | +use solana_program_test::*; |
| 5 | +use solana_sdk::{ |
| 6 | + account::Account, |
| 7 | + instruction::InstructionError, |
| 8 | + instruction::{AccountMeta, Instruction}, |
| 9 | + pubkey::Pubkey, |
| 10 | + signature::Signer, |
| 11 | + transaction::{Transaction, TransactionError}, |
| 12 | +}; |
58 | 13 |
|
59 |
| -#[test] |
60 |
| -fn assert_instruction_count() { |
| 14 | +#[tokio::test] |
| 15 | +async fn assert_instruction_count() { |
61 | 16 | const OFFSET: usize = 51;
|
62 | 17 | const NUM_TO_SHARE: usize = 500;
|
63 | 18 | let program_id = Pubkey::new_unique();
|
64 | 19 | let shared_key = Pubkey::new_unique();
|
65 |
| - let shared_account = Account::new_ref(u64::MAX, OFFSET + NUM_TO_SHARE * 2, &program_id); |
66 | 20 |
|
67 |
| - // Send some data to share |
68 |
| - let parameter_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; |
| 21 | + let mut program_test = ProgramTest::new( |
| 22 | + "spl_shared_memory", // Run the BPF version with `cargo test-bpf` |
| 23 | + program_id, |
| 24 | + None, |
| 25 | + ); |
| 26 | + program_test.add_account( |
| 27 | + shared_key, |
| 28 | + Account { |
| 29 | + lamports: 5000000000000, |
| 30 | + data: vec![0_u8; NUM_TO_SHARE * 2], |
| 31 | + owner: program_id, |
| 32 | + ..Account::default() |
| 33 | + }, |
| 34 | + ); |
| 35 | + program_test.set_bpf_compute_max_units(480); |
| 36 | + let (mut banks_client, payer, recent_blockhash) = program_test.start().await; |
| 37 | + |
| 38 | + // success |
69 | 39 | let content = vec![42; NUM_TO_SHARE];
|
70 | 40 | let mut instruction_data = OFFSET.to_le_bytes().to_vec();
|
71 | 41 | instruction_data.extend_from_slice(&content);
|
72 |
| - let share_count = run_program(&program_id, ¶meter_accounts[..], &instruction_data); |
73 |
| - const BASELINE_COUNT: u64 = 1474; // 113 if NUM_TO_SHARE is 8 |
74 |
| - println!( |
75 |
| - "BPF instructions executed {:?} (expected {:?})", |
76 |
| - share_count, BASELINE_COUNT |
77 |
| - ); |
78 |
| - assert_eq!( |
79 |
| - &shared_account.borrow().data[OFFSET..OFFSET + NUM_TO_SHARE], |
80 |
| - content |
| 42 | + let mut transaction = Transaction::new_with_payer( |
| 43 | + &[Instruction::new_with_bytes( |
| 44 | + program_id, |
| 45 | + &instruction_data, |
| 46 | + vec![AccountMeta::new(shared_key, false)], |
| 47 | + )], |
| 48 | + Some(&payer.pubkey()), |
81 | 49 | );
|
82 |
| - assert!(share_count <= BASELINE_COUNT); |
| 50 | + transaction.sign(&[&payer], recent_blockhash); |
| 51 | + banks_client.process_transaction(transaction).await.unwrap(); |
83 | 52 | }
|
84 |
| -*/ |
85 | 53 |
|
86 |
| -#[test] |
87 |
| -fn test_share_data() { |
| 54 | +#[tokio::test] |
| 55 | +async fn test_helloworld() { |
88 | 56 | const OFFSET: usize = 51;
|
89 | 57 | const NUM_TO_SHARE: usize = 500;
|
90 |
| - let program_id = Pubkey::new(&[0; 32]); |
| 58 | + let program_id = Pubkey::new_unique(); |
91 | 59 | let shared_key = Pubkey::new_unique();
|
92 |
| - let shared_account = AccountSharedData::new_ref(u64::MAX, NUM_TO_SHARE * 2, &program_id); |
| 60 | + |
| 61 | + let mut program_test = ProgramTest::new( |
| 62 | + "spl_shared_memory", // Run the BPF version with `cargo test-bpf` |
| 63 | + program_id, |
| 64 | + None, |
| 65 | + ); |
| 66 | + program_test.add_account( |
| 67 | + shared_key, |
| 68 | + Account { |
| 69 | + lamports: 5000000000000, |
| 70 | + data: vec![0_u8; NUM_TO_SHARE * 2], |
| 71 | + owner: program_id, |
| 72 | + ..Account::default() |
| 73 | + }, |
| 74 | + ); |
| 75 | + let (mut banks_client, payer, recent_blockhash) = program_test.start().await; |
93 | 76 |
|
94 | 77 | // success
|
95 | 78 | let content = vec![42; NUM_TO_SHARE];
|
96 | 79 | let mut instruction_data = OFFSET.to_le_bytes().to_vec();
|
97 | 80 | instruction_data.extend_from_slice(&content);
|
98 |
| - let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; |
99 |
| - let mut input = serialize_parameters( |
100 |
| - &bpf_loader::id(), |
101 |
| - &program_id, |
102 |
| - &keyed_accounts, |
103 |
| - &instruction_data, |
104 |
| - ) |
105 |
| - .unwrap(); |
106 |
| - assert_eq!(unsafe { entrypoint(input.as_mut_ptr()) }, SUCCESS); |
| 81 | + let mut transaction = Transaction::new_with_payer( |
| 82 | + &[Instruction::new_with_bytes( |
| 83 | + program_id, |
| 84 | + &instruction_data, |
| 85 | + vec![AccountMeta::new(shared_key, false)], |
| 86 | + )], |
| 87 | + Some(&payer.pubkey()), |
| 88 | + ); |
| 89 | + transaction.sign(&[&payer], recent_blockhash); |
| 90 | + banks_client.process_transaction(transaction).await.unwrap(); |
107 | 91 |
|
108 | 92 | // success zero offset
|
109 | 93 | let content = vec![42; NUM_TO_SHARE];
|
110 | 94 | let mut instruction_data = 0_usize.to_le_bytes().to_vec();
|
111 | 95 | instruction_data.extend_from_slice(&content);
|
112 |
| - let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; |
113 |
| - let mut input = serialize_parameters( |
114 |
| - &bpf_loader::id(), |
115 |
| - &program_id, |
116 |
| - &keyed_accounts, |
117 |
| - &instruction_data, |
118 |
| - ) |
119 |
| - .unwrap(); |
120 |
| - assert_eq!(unsafe { entrypoint(input.as_mut_ptr()) }, SUCCESS); |
| 96 | + let mut transaction = Transaction::new_with_payer( |
| 97 | + &[Instruction::new_with_bytes( |
| 98 | + program_id, |
| 99 | + &instruction_data, |
| 100 | + vec![AccountMeta::new(shared_key, false)], |
| 101 | + )], |
| 102 | + Some(&payer.pubkey()), |
| 103 | + ); |
| 104 | + transaction.sign(&[&payer], recent_blockhash); |
| 105 | + banks_client.process_transaction(transaction).await.unwrap(); |
121 | 106 |
|
122 | 107 | // too few accounts
|
123 |
| - let mut input = |
124 |
| - serialize_parameters(&bpf_loader::id(), &program_id, &[], &instruction_data).unwrap(); |
| 108 | + let content = vec![42; NUM_TO_SHARE]; |
| 109 | + let mut instruction_data = OFFSET.to_le_bytes().to_vec(); |
| 110 | + instruction_data.extend_from_slice(&content); |
| 111 | + let mut transaction = Transaction::new_with_payer( |
| 112 | + &[Instruction::new_with_bytes( |
| 113 | + program_id, |
| 114 | + &instruction_data, |
| 115 | + vec![], |
| 116 | + )], |
| 117 | + Some(&payer.pubkey()), |
| 118 | + ); |
| 119 | + transaction.sign(&[&payer], recent_blockhash); |
| 120 | + let result = banks_client.process_transaction(transaction).await; |
125 | 121 | assert_eq!(
|
126 |
| - unsafe { entrypoint(input.as_mut_ptr()) }, |
127 |
| - u64::from(ProgramError::NotEnoughAccountKeys) |
| 122 | + result.unwrap_err().unwrap(), |
| 123 | + TransactionError::InstructionError(0, InstructionError::NotEnoughAccountKeys) |
128 | 124 | );
|
129 | 125 |
|
130 | 126 | // too many accounts
|
131 |
| - let keyed_accounts = vec![ |
132 |
| - KeyedAccount::new(&shared_key, true, &shared_account), |
133 |
| - KeyedAccount::new(&shared_key, true, &shared_account), |
134 |
| - ]; |
135 |
| - let mut input = serialize_parameters( |
136 |
| - &bpf_loader::id(), |
137 |
| - &program_id, |
138 |
| - &keyed_accounts, |
139 |
| - &instruction_data, |
140 |
| - ) |
141 |
| - .unwrap(); |
| 127 | + let content = vec![42; NUM_TO_SHARE]; |
| 128 | + let mut instruction_data = OFFSET.to_le_bytes().to_vec(); |
| 129 | + instruction_data.extend_from_slice(&content); |
| 130 | + let mut transaction = Transaction::new_with_payer( |
| 131 | + &[Instruction::new_with_bytes( |
| 132 | + program_id, |
| 133 | + &instruction_data, |
| 134 | + vec![ |
| 135 | + AccountMeta::new(shared_key, false), |
| 136 | + AccountMeta::new(shared_key, false), |
| 137 | + ], |
| 138 | + )], |
| 139 | + Some(&payer.pubkey()), |
| 140 | + ); |
| 141 | + transaction.sign(&[&payer], recent_blockhash); |
| 142 | + let result = banks_client.process_transaction(transaction).await; |
142 | 143 | assert_eq!(
|
143 |
| - unsafe { entrypoint(input.as_mut_ptr()) }, |
144 |
| - u64::from(ProgramError::InvalidArgument) |
| 144 | + result.unwrap_err().unwrap(), |
| 145 | + TransactionError::InstructionError(0, InstructionError::InvalidArgument) |
145 | 146 | );
|
146 | 147 |
|
147 | 148 | // account data too small
|
148 |
| - let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; |
149 | 149 | let content = vec![42; NUM_TO_SHARE * 10];
|
150 | 150 | let mut instruction_data = OFFSET.to_le_bytes().to_vec();
|
151 | 151 | instruction_data.extend_from_slice(&content);
|
152 |
| - let mut input = serialize_parameters( |
153 |
| - &bpf_loader::id(), |
154 |
| - &program_id, |
155 |
| - &keyed_accounts, |
156 |
| - &instruction_data, |
157 |
| - ) |
158 |
| - .unwrap(); |
| 152 | + let mut transaction = Transaction::new_with_payer( |
| 153 | + &[Instruction::new_with_bytes( |
| 154 | + program_id, |
| 155 | + &instruction_data, |
| 156 | + vec![AccountMeta::new(shared_key, false)], |
| 157 | + )], |
| 158 | + Some(&payer.pubkey()), |
| 159 | + ); |
| 160 | + transaction.sign(&[&payer], recent_blockhash); |
| 161 | + let result = banks_client.process_transaction(transaction).await; |
159 | 162 | assert_eq!(
|
160 |
| - unsafe { entrypoint(input.as_mut_ptr()) }, |
161 |
| - u64::from(ProgramError::AccountDataTooSmall) |
| 163 | + result.unwrap_err().unwrap(), |
| 164 | + TransactionError::InstructionError(0, InstructionError::AccountDataTooSmall) |
162 | 165 | );
|
163 | 166 |
|
164 | 167 | // offset too large
|
165 |
| - let keyed_accounts = vec![KeyedAccount::new(&shared_key, true, &shared_account)]; |
166 | 168 | let content = vec![42; NUM_TO_SHARE];
|
167 | 169 | let mut instruction_data = (OFFSET * 10).to_le_bytes().to_vec();
|
168 | 170 | instruction_data.extend_from_slice(&content);
|
169 |
| - let mut input = serialize_parameters( |
170 |
| - &bpf_loader::id(), |
171 |
| - &program_id, |
172 |
| - &keyed_accounts, |
173 |
| - &instruction_data, |
174 |
| - ) |
175 |
| - .unwrap(); |
| 171 | + let mut transaction = Transaction::new_with_payer( |
| 172 | + &[Instruction::new_with_bytes( |
| 173 | + program_id, |
| 174 | + &instruction_data, |
| 175 | + vec![AccountMeta::new(shared_key, false)], |
| 176 | + )], |
| 177 | + Some(&payer.pubkey()), |
| 178 | + ); |
| 179 | + transaction.sign(&[&payer], recent_blockhash); |
| 180 | + let result = banks_client.process_transaction(transaction).await; |
176 | 181 | assert_eq!(
|
177 |
| - unsafe { entrypoint(input.as_mut_ptr()) }, |
178 |
| - u64::from(ProgramError::AccountDataTooSmall) |
| 182 | + result.unwrap_err().unwrap(), |
| 183 | + TransactionError::InstructionError(0, InstructionError::AccountDataTooSmall) |
179 | 184 | );
|
180 | 185 | }
|
0 commit comments