From 66fa8f966753b732facbbd66ff5b549be796ae3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 17 Dec 2021 14:01:12 +0100 Subject: [PATCH] Refactor: Removes `Rc` from `Refcell` in the program-runtime (#21927) * Removes Rc from Rc> in the program-runtime. * Adjusts tests in bpf_loader, system_instruction_processor, config_processor, vote_instruction and stake_instruction --- program-runtime/src/invoke_context.rs | 156 +- programs/bpf_loader/src/lib.rs | 1808 ++++++++++--------- programs/bpf_loader/src/serialization.rs | 205 ++- programs/bpf_loader/src/syscalls.rs | 17 +- programs/config/src/config_processor.rs | 521 ++++-- programs/stake/src/stake_instruction.rs | 1053 ++++++----- programs/vote/src/vote_instruction.rs | 241 +-- rbpf-cli/src/main.rs | 60 +- runtime/src/bank.rs | 25 +- runtime/src/message_processor.rs | 36 +- runtime/src/system_instruction_processor.rs | 1127 +++++++----- 11 files changed, 2907 insertions(+), 2342 deletions(-) diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index 32674da18..d6d128ed4 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -24,7 +24,7 @@ use { std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc, sync::Arc}, }; -pub type TransactionAccountRefCell = (Pubkey, Rc>); +pub type TransactionAccountRefCell = (Pubkey, RefCell); pub type TransactionAccountRefCells = Vec; pub type ProcessInstructionWithContext = @@ -841,35 +841,23 @@ pub struct MockInvokeContextPreparation { pub fn prepare_mock_invoke_context( program_indices: &[usize], instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, ) -> MockInvokeContextPreparation { - #[allow(clippy::type_complexity)] - let (accounts, mut metas): (TransactionAccountRefCells, Vec) = keyed_accounts - .iter() - .map(|(is_signer, is_writable, pubkey, account)| { - ( - (*pubkey, account.clone()), - AccountMeta { - pubkey: *pubkey, - is_signer: *is_signer, - is_writable: *is_writable, - }, - ) - }) - .unzip(); + let transaction_accounts: TransactionAccountRefCells = transaction_accounts + .into_iter() + .map(|(pubkey, account)| (pubkey, RefCell::new(account))) + .collect(); let program_id = if let Some(program_index) = program_indices.last() { - accounts[*program_index].0 + transaction_accounts[*program_index].0 } else { Pubkey::default() }; - for program_index in program_indices.iter().rev() { - metas.remove(*program_index); - } let message = Message::new( &[Instruction::new_with_bytes( program_id, instruction_data, - metas, + instruction_accounts, )], None, ); @@ -877,14 +865,14 @@ pub fn prepare_mock_invoke_context( .account_keys .iter() .map(|search_key| { - accounts + transaction_accounts .iter() .position(|(key, _account)| key == search_key) - .unwrap_or(accounts.len()) + .unwrap_or(transaction_accounts.len()) }) .collect(); MockInvokeContextPreparation { - accounts, + accounts: transaction_accounts, message, account_indices, } @@ -896,27 +884,31 @@ pub fn with_mock_invoke_context R>( mut callback: F, ) -> R { let program_indices = vec![0, 1]; - let keyed_accounts = [ + let transaction_accounts = vec![ ( - false, - false, loader_id, - AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id()), + AccountSharedData::new(0, 0, &solana_sdk::native_loader::id()), ), ( - false, - false, Pubkey::new_unique(), - AccountSharedData::new_ref(1, 0, &loader_id), + AccountSharedData::new(1, 0, &loader_id), ), ( - false, - false, Pubkey::new_unique(), - AccountSharedData::new_ref(2, account_size, &Pubkey::new_unique()), + AccountSharedData::new(2, account_size, &Pubkey::new_unique()), ), ]; - let preparation = prepare_mock_invoke_context(&program_indices, &[], &keyed_accounts); + let instruction_accounts = vec![AccountMeta { + pubkey: transaction_accounts[2].0, + is_signer: false, + is_writable: false, + }]; + let preparation = prepare_mock_invoke_context( + &program_indices, + &[], + transaction_accounts, + instruction_accounts, + ); let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]); invoke_context .push( @@ -933,38 +925,60 @@ pub fn mock_process_instruction_with_sysvars( loader_id: &Pubkey, mut program_indices: Vec, instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, sysvars: &[(Pubkey, Vec)], process_instruction: ProcessInstructionWithContext, -) -> Result<(), InstructionError> { - let mut preparation = - prepare_mock_invoke_context(&program_indices, instruction_data, keyed_accounts); - let processor_account = AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id()); +) -> Vec { + let mut preparation = prepare_mock_invoke_context( + &program_indices, + instruction_data, + transaction_accounts, + instruction_accounts, + ); + let processor_account = RefCell::new(AccountSharedData::new( + 0, + 0, + &solana_sdk::native_loader::id(), + )); program_indices.insert(0, preparation.accounts.len()); preparation.accounts.push((*loader_id, processor_account)); let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]); invoke_context.sysvars = sysvars; - invoke_context.push( - &preparation.message, - &preparation.message.instructions[0], - &program_indices, - &preparation.account_indices, - )?; - process_instruction(1, instruction_data, &mut invoke_context) + let result = invoke_context + .push( + &preparation.message, + &preparation.message.instructions[0], + &program_indices, + &preparation.account_indices, + ) + .and_then(|_| process_instruction(1, instruction_data, &mut invoke_context)); + preparation.accounts.pop(); + assert_eq!(result, expected_result); + preparation + .accounts + .into_iter() + .map(|(_key, account)| account.into_inner()) + .collect() } pub fn mock_process_instruction( loader_id: &Pubkey, program_indices: Vec, instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, process_instruction: ProcessInstructionWithContext, -) -> Result<(), InstructionError> { +) -> Vec { mock_process_instruction_with_sysvars( loader_id, program_indices, instruction_data, - keyed_accounts, + transaction_accounts, + instruction_accounts, + expected_result, &[], process_instruction, ) @@ -1076,22 +1090,18 @@ mod tests { invoke_stack.push(solana_sdk::pubkey::new_rand()); accounts.push(( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::new( - i as u64, - 1, - &invoke_stack[i], - ))), + RefCell::new(AccountSharedData::new(i as u64, 1, &invoke_stack[i])), )); metas.push(AccountMeta::new(accounts[i].0, false)); } for program_id in invoke_stack.iter() { accounts.push(( *program_id, - Rc::new(RefCell::new(AccountSharedData::new( + RefCell::new(AccountSharedData::new( 1, 1, &solana_sdk::pubkey::Pubkey::default(), - ))), + )), )); metas.push(AccountMeta::new(*program_id, false)); } @@ -1178,7 +1188,7 @@ mod tests { fn test_invoke_context_verify() { let accounts = vec![( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::default())), + RefCell::new(AccountSharedData::default()), )]; let message = Message::new( &[Instruction::new_with_bincode( @@ -1216,20 +1226,17 @@ mod tests { program_account.set_executable(true); let accounts = vec![ + (solana_sdk::pubkey::new_rand(), RefCell::new(owned_account)), ( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(owned_account)), + RefCell::new(not_owned_account), ), ( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(not_owned_account)), + RefCell::new(readonly_account), ), - ( - solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(readonly_account)), - ), - (caller_program_id, Rc::new(RefCell::new(loader_account))), - (callee_program_id, Rc::new(RefCell::new(program_account))), + (caller_program_id, RefCell::new(loader_account)), + (callee_program_id, RefCell::new(program_account)), ]; let account_indices = [0, 1, 2]; let program_indices = [3, 4]; @@ -1346,20 +1353,17 @@ mod tests { program_account.set_executable(true); let accounts = vec![ + (solana_sdk::pubkey::new_rand(), RefCell::new(owned_account)), ( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(owned_account)), + RefCell::new(not_owned_account), ), ( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(not_owned_account)), + RefCell::new(readonly_account), ), - ( - solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(readonly_account)), - ), - (caller_program_id, Rc::new(RefCell::new(loader_account))), - (callee_program_id, Rc::new(RefCell::new(program_account))), + (caller_program_id, RefCell::new(loader_account)), + (callee_program_id, RefCell::new(program_account)), ]; let program_indices = [3]; let metas = vec![ @@ -1441,11 +1445,11 @@ mod tests { let accounts = vec![ ( solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::default())), + RefCell::new(AccountSharedData::default()), ), ( crate::neon_evm_program::id(), - Rc::new(RefCell::new(AccountSharedData::default())), + RefCell::new(AccountSharedData::default()), ), ]; diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index f33ab43e2..2ab48e249 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1113,7 +1113,7 @@ mod tests { system_program, sysvar, transaction::TransactionError, }, - std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc, sync::Arc}, + std::{fs::File, io::Read, ops::Range, sync::Arc}, }; struct TestInstructionMeter { @@ -1132,29 +1132,30 @@ mod tests { loader_id: &Pubkey, program_indices: &[usize], instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], - ) -> Result<(), InstructionError> { + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, + ) -> Vec { mock_process_instruction( loader_id, program_indices.to_vec(), instruction_data, - keyed_accounts, + transaction_accounts, + instruction_accounts, + expected_result, super::process_instruction, ) } - fn load_program_account_from_elf( - loader_id: &Pubkey, - path: &str, - ) -> Rc> { + fn load_program_account_from_elf(loader_id: &Pubkey, path: &str) -> AccountSharedData { let mut file = File::open(path).expect("file open failed"); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); let rent = Rent::default(); - let program_account = - AccountSharedData::new_ref(rent.minimum_balance(elf.len()), 0, loader_id); - program_account.borrow_mut().set_data(elf); - program_account.borrow_mut().set_executable(true); + let mut program_account = + AccountSharedData::new(rent.minimum_balance(elf.len()), 0, loader_id); + program_account.set_data(elf); + program_account.set_executable(true); program_account } @@ -1199,8 +1200,7 @@ mod tests { fn test_bpf_loader_write() { let loader_id = bpf_loader::id(); let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(1, 0, &loader_id); - let mut keyed_accounts = vec![]; + let mut program_account = AccountSharedData::new(1, 0, &loader_id); let instruction_data = bincode::serialize(&LoaderInstruction::Write { offset: 3, bytes: vec![1, 2, 3], @@ -1208,32 +1208,58 @@ mod tests { .unwrap(); // Case: No program account - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction_data, + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); // Case: Not signed - keyed_accounts.push((false, false, program_id, program_account)); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction_data, + vec![(program_id, program_account.clone())], + vec![AccountMeta { + pubkey: program_id, + is_signer: false, + is_writable: false, + }], Err(InstructionError::MissingRequiredSignature), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); // Case: Write bytes to an offset - keyed_accounts[0].0 = true; - keyed_accounts[0].3.borrow_mut().set_data(vec![0; 6]); - assert_eq!( + program_account.set_data(vec![0; 6]); + let accounts = process_instruction( + &loader_id, + &[], + &instruction_data, + vec![(program_id, program_account.clone())], + vec![AccountMeta { + pubkey: program_id, + is_signer: true, + is_writable: false, + }], Ok(()), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); - assert_eq!(&vec![0, 0, 0, 1, 2, 3], keyed_accounts[0].3.borrow().data()); + assert_eq!(&vec![0, 0, 0, 1, 2, 3], accounts[0].data()); // Case: Overflow - keyed_accounts[0].3.borrow_mut().set_data(vec![0; 5]); - assert_eq!( + program_account.set_data(vec![0; 5]); + process_instruction( + &loader_id, + &[], + &instruction_data, + vec![(program_id, program_account)], + vec![AccountMeta { + pubkey: program_id, + is_signer: true, + is_writable: false, + }], Err(InstructionError::AccountDataTooSmall), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); } @@ -1241,40 +1267,63 @@ mod tests { fn test_bpf_loader_finalize() { let loader_id = bpf_loader::id(); let program_id = Pubkey::new_unique(); - let program_account = + let mut program_account = load_program_account_from_elf(&loader_id, "test_elfs/noop_aligned.so"); - program_account.borrow_mut().set_executable(false); + program_account.set_executable(false); + let instruction_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap(); // Case: No program account - let instruction_data = bincode::serialize(&LoaderInstruction::Finalize).unwrap(); - let mut keyed_accounts = vec![]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction_data, + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); // Case: Not signed - keyed_accounts.push((false, false, program_id, program_account.clone())); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction_data, + vec![(program_id, program_account.clone())], + vec![AccountMeta { + pubkey: program_id, + is_signer: false, + is_writable: false, + }], Err(InstructionError::MissingRequiredSignature), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); // Case: Finalize - keyed_accounts[0] = (true, false, program_id, program_account.clone()); - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction_data, + vec![(program_id, program_account.clone())], + vec![AccountMeta { + pubkey: program_id, + is_signer: true, + is_writable: false, + }], Ok(()), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); - assert!(keyed_accounts[0].3.borrow().executable()); + assert!(accounts[0].executable()); - program_account.borrow_mut().set_executable(false); // Un-finalize the account - - // Case: Finalize - program_account.borrow_mut().data_as_mut_slice()[0] = 0; // bad elf - assert_eq!( + // Case: Finalize bad ELF + program_account.data_as_mut_slice()[0] = 0; + process_instruction( + &loader_id, + &[], + &instruction_data, + vec![(program_id, program_account)], + vec![AccountMeta { + pubkey: program_id, + is_signer: true, + is_writable: false, + }], Err(InstructionError::InvalidAccountData), - process_instruction(&loader_id, &[], &instruction_data, &keyed_accounts), ); } @@ -1282,159 +1331,222 @@ mod tests { fn test_bpf_loader_invoke_main() { let loader_id = bpf_loader::id(); let program_id = Pubkey::new_unique(); - let program_account = + let mut program_account = load_program_account_from_elf(&loader_id, "test_elfs/noop_aligned.so"); + let parameter_id = Pubkey::new_unique(); + let parameter_account = AccountSharedData::new(1, 0, &loader_id); + let parameter_meta = AccountMeta { + pubkey: parameter_id, + is_signer: false, + is_writable: false, + }; // Case: No program account - let mut keyed_accounts = vec![]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &[], + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), - process_instruction(&loader_id, &[], &[], &keyed_accounts), ); // Case: Only a program account - keyed_accounts.push((false, false, program_id, program_account)); - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![(program_id, program_account.clone())], + Vec::new(), Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); - // Case: Account not a program - keyed_accounts[0].3.borrow_mut().set_executable(false); - assert_eq!( - Err(InstructionError::IncorrectProgramId), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), - ); - keyed_accounts[0].3.borrow_mut().set_executable(true); - // Case: With program and parameter account - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - keyed_accounts.push((false, false, program_id, parameter_account)); - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![ + (program_id, program_account.clone()), + (parameter_id, parameter_account.clone()), + ], + vec![parameter_meta.clone()], Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); // Case: With duplicate accounts - let duplicate_key = Pubkey::new_unique(); - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - keyed_accounts[1] = (false, false, duplicate_key, parameter_account.clone()); - keyed_accounts.push((false, false, duplicate_key, parameter_account)); - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![ + (program_id, program_account.clone()), + (parameter_id, parameter_account), + ], + vec![parameter_meta.clone(), parameter_meta], Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); // Case: limited budget - assert_eq!( + mock_process_instruction( + &loader_id, + vec![0], + &[], + vec![(program_id, program_account.clone())], + Vec::new(), Err(InstructionError::ProgramFailedToComplete), - mock_process_instruction( - &loader_id, - vec![0], - &[], - &keyed_accounts, - |first_instruction_account: usize, - instruction_data: &[u8], - invoke_context: &mut InvokeContext| { - let compute_meter = invoke_context.get_compute_meter(); - let remaining = compute_meter.borrow_mut().get_remaining(); - compute_meter.borrow_mut().consume(remaining).unwrap(); - super::process_instruction( - first_instruction_account, - instruction_data, - invoke_context, - ) - }, - ), + |first_instruction_account: usize, + instruction_data: &[u8], + invoke_context: &mut InvokeContext| { + invoke_context + .get_compute_meter() + .borrow_mut() + .mock_set_remaining(0); + super::process_instruction( + first_instruction_account, + instruction_data, + invoke_context, + ) + }, + ); + + // Case: Account not a program + program_account.set_executable(false); + process_instruction( + &loader_id, + &[0], + &[], + vec![(program_id, program_account)], + Vec::new(), + Err(InstructionError::IncorrectProgramId), ); } #[test] fn test_bpf_loader_serialize_unaligned() { let loader_id = bpf_loader_deprecated::id(); - let program_key = Pubkey::new_unique(); + let program_id = Pubkey::new_unique(); let program_account = load_program_account_from_elf(&loader_id, "test_elfs/noop_unaligned.so"); + let parameter_id = Pubkey::new_unique(); + let parameter_account = AccountSharedData::new(1, 0, &loader_id); + let parameter_meta = AccountMeta { + pubkey: parameter_id, + is_signer: false, + is_writable: false, + }; // Case: With program and parameter account - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - let mut keyed_accounts = vec![ - (false, false, program_key, program_account), - (false, false, program_key, parameter_account), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![ + (program_id, program_account.clone()), + (parameter_id, parameter_account.clone()), + ], + vec![parameter_meta.clone()], Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); // Case: With duplicate accounts - let duplicate_key = Pubkey::new_unique(); - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - keyed_accounts[1] = (false, false, duplicate_key, parameter_account.clone()); - keyed_accounts.push((false, false, duplicate_key, parameter_account)); - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![ + (program_id, program_account), + (parameter_id, parameter_account), + ], + vec![parameter_meta.clone(), parameter_meta], Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); } #[test] fn test_bpf_loader_serialize_aligned() { let loader_id = bpf_loader::id(); - let program_key = Pubkey::new_unique(); + let program_id = Pubkey::new_unique(); let program_account = load_program_account_from_elf(&loader_id, "test_elfs/noop_aligned.so"); + let parameter_id = Pubkey::new_unique(); + let parameter_account = AccountSharedData::new(1, 0, &loader_id); + let parameter_meta = AccountMeta { + pubkey: parameter_id, + is_signer: false, + is_writable: false, + }; // Case: With program and parameter account - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - let mut keyed_accounts = vec![ - (false, false, program_key, program_account), - (false, false, program_key, parameter_account), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![ + (program_id, program_account.clone()), + (parameter_id, parameter_account.clone()), + ], + vec![parameter_meta.clone()], Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); // Case: With duplicate accounts - let duplicate_key = Pubkey::new_unique(); - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - keyed_accounts[1] = (false, false, duplicate_key, parameter_account.clone()); - keyed_accounts.push((false, false, duplicate_key, parameter_account)); - assert_eq!( + process_instruction( + &loader_id, + &[0], + &[], + vec![ + (program_id, program_account), + (parameter_id, parameter_account), + ], + vec![parameter_meta.clone(), parameter_meta], Ok(()), - process_instruction(&loader_id, &[0], &[], &keyed_accounts), ); } #[test] fn test_bpf_loader_upgradeable_initialize_buffer() { - let instruction = - bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap(); let loader_id = bpf_loader_upgradeable::id(); let buffer_address = Pubkey::new_unique(); - let buffer_account = AccountSharedData::new_ref( + let buffer_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(9).unwrap(), &loader_id, ); let authority_address = Pubkey::new_unique(); - let authority_account = AccountSharedData::new_ref( + let authority_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(9).unwrap(), &loader_id, ); + let instruction_data = + bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap(); + let instruction_accounts = vec![ + AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: authority_address, + is_signer: false, + is_writable: false, + }, + ]; // Case: Success - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (false, false, authority_address, authority_account), - ]; - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction_data, + vec![ + (buffer_address, buffer_account), + (authority_address, authority_account), + ], + instruction_accounts.clone(), Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::Buffer { @@ -1443,11 +1555,18 @@ mod tests { ); // Case: Already initialized - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction_data, + vec![ + (buffer_address, accounts[0].clone()), + (authority_address, accounts[1].clone()), + ], + instruction_accounts, Err(InstructionError::AccountAlreadyInitialized), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::Buffer { @@ -1460,11 +1579,23 @@ mod tests { fn test_bpf_loader_upgradeable_write() { let loader_id = bpf_loader_upgradeable::id(); let buffer_address = Pubkey::new_unique(); - let buffer_account = AccountSharedData::new_ref( + let mut buffer_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(9).unwrap(), &loader_id, ); + let instruction_accounts = vec![ + AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: buffer_address, + is_signer: true, + is_writable: false, + }, + ]; // Case: Not initialized let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write { @@ -1472,13 +1603,13 @@ mod tests { bytes: vec![42; 9], }) .unwrap(); - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (true, false, buffer_address, buffer_account.clone()), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + instruction_accounts.clone(), Err(InstructionError::InvalidAccountData), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Write entire buffer @@ -1488,16 +1619,19 @@ mod tests { }) .unwrap(); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(buffer_address), }) .unwrap(); - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + instruction_accounts.clone(), Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::Buffer { @@ -1505,8 +1639,7 @@ mod tests { } ); assert_eq!( - &buffer_account.borrow().data() - [UpgradeableLoaderState::buffer_data_offset().unwrap()..], + &accounts[0].data()[UpgradeableLoaderState::buffer_data_offset().unwrap()..], &[42; 9] ); @@ -1516,26 +1649,25 @@ mod tests { bytes: vec![42; 6], }) .unwrap(); - let buffer_account = AccountSharedData::new_ref( + let mut buffer_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(9).unwrap(), &loader_id, ); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(buffer_address), }) .unwrap(); - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (true, false, buffer_address, buffer_account.clone()), - ]; - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + instruction_accounts.clone(), Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::Buffer { @@ -1543,8 +1675,7 @@ mod tests { } ); assert_eq!( - &buffer_account.borrow().data() - [UpgradeableLoaderState::buffer_data_offset().unwrap()..], + &accounts[0].data()[UpgradeableLoaderState::buffer_data_offset().unwrap()..], &[0, 0, 0, 42, 42, 42, 42, 42, 42] ); @@ -1555,14 +1686,17 @@ mod tests { }) .unwrap(); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(buffer_address), }) .unwrap(); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + instruction_accounts.clone(), Err(InstructionError::AccountDataTooSmall), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: overflow offset @@ -1572,14 +1706,17 @@ mod tests { }) .unwrap(); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(buffer_address), }) .unwrap(); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + instruction_accounts.clone(), Err(InstructionError::AccountDataTooSmall), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Not signed @@ -1589,18 +1726,28 @@ mod tests { }) .unwrap(); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(buffer_address), }) .unwrap(); - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (false, false, buffer_address, buffer_account.clone()), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + vec![ + AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::MissingRequiredSignature), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: wrong authority @@ -1611,18 +1758,31 @@ mod tests { }) .unwrap(); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(buffer_address), }) .unwrap(); - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (true, false, authority_address, buffer_account.clone()), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (buffer_address, buffer_account.clone()), + (authority_address, buffer_account.clone()), + ], + vec![ + AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: authority_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: None authority @@ -1632,14 +1792,17 @@ mod tests { }) .unwrap(); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: None, }) .unwrap(); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![(buffer_address, buffer_account.clone())], + instruction_accounts, Err(InstructionError::Immutable), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); } @@ -1795,26 +1958,17 @@ mod tests { } // Invoke deployed program - { - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - Rc::new(RefCell::new(post_programdata_account)), - ), - ( - false, - false, - program_keypair.pubkey(), - Rc::new(RefCell::new(post_program_account)), - ), - ]; - assert_eq!( - Ok(()), - process_instruction(&bpf_loader_upgradeable::id(), &[0, 1], &[], &keyed_accounts), - ); - } + process_instruction( + &bpf_loader_upgradeable::id(), + &[0, 1], + &[], + vec![ + (programdata_address, post_programdata_account), + (program_keypair.pubkey(), post_program_account), + ], + Vec::new(), + Ok(()), + ); // Test initialized program account bank.clear_signatures(); @@ -2344,8 +2498,6 @@ mod tests { #[test] fn test_bpf_loader_upgradeable_upgrade() { - let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap(); - let loader_id = bpf_loader_upgradeable::id(); let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed"); let mut elf_orig = Vec::new(); file.read_to_end(&mut elf_orig).unwrap(); @@ -2353,133 +2505,155 @@ mod tests { let mut elf_new = Vec::new(); file.read_to_end(&mut elf_new).unwrap(); assert_ne!(elf_orig.len(), elf_new.len()); - let rent = Rent::default(); - let rent_account = Rc::new(RefCell::new(create_account_for_test(&Rent::default()))); let slot = 42; - let clock_account = Rc::new(RefCell::new(create_account_for_test(&Clock { - slot, - ..Clock::default() - }))); - let min_program_balance = - 1.max(rent.minimum_balance(UpgradeableLoaderState::program_len().unwrap())); - let min_programdata_balance = 1.max(rent.minimum_balance( - UpgradeableLoaderState::programdata_len(elf_orig.len().max(elf_new.len())).unwrap(), - )); - let upgrade_authority_address = Pubkey::new_unique(); let buffer_address = Pubkey::new_unique(); - let program_address = Pubkey::new_unique(); - let (programdata_address, _) = - Pubkey::find_program_address(&[program_address.as_ref()], &loader_id); - let spill_address = Pubkey::new_unique(); - let upgrade_authority_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); - let rent_id = sysvar::rent::id(); - let clock_id = sysvar::clock::id(); + let upgrade_authority_address = Pubkey::new_unique(); - #[allow(clippy::type_complexity)] fn get_accounts( + buffer_address: &Pubkey, buffer_authority: &Pubkey, - programdata_address: &Pubkey, upgrade_authority_address: &Pubkey, slot: u64, elf_orig: &[u8], elf_new: &[u8], - min_program_balance: u64, - min_programdata_balance: u64, - ) -> ( - Rc>, - Rc>, - Rc>, - Rc>, - ) { - let buffer_account = AccountSharedData::new_ref( + ) -> (Vec<(Pubkey, AccountSharedData)>, Vec) { + let loader_id = bpf_loader_upgradeable::id(); + let program_address = Pubkey::new_unique(); + let spill_address = Pubkey::new_unique(); + let rent = Rent::default(); + let min_program_balance = + 1.max(rent.minimum_balance(UpgradeableLoaderState::program_len().unwrap())); + let min_programdata_balance = 1.max(rent.minimum_balance( + UpgradeableLoaderState::programdata_len(elf_orig.len().max(elf_new.len())).unwrap(), + )); + let (programdata_address, _) = + Pubkey::find_program_address(&[program_address.as_ref()], &loader_id); + let mut buffer_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(elf_new.len()).unwrap(), &bpf_loader_upgradeable::id(), ); buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(*buffer_authority), }) .unwrap(); - buffer_account.borrow_mut().data_as_mut_slice() + buffer_account.data_as_mut_slice() [UpgradeableLoaderState::buffer_data_offset().unwrap()..] .copy_from_slice(elf_new); - let programdata_account = AccountSharedData::new_ref( + let mut programdata_account = AccountSharedData::new( min_programdata_balance, UpgradeableLoaderState::programdata_len(elf_orig.len().max(elf_new.len())).unwrap(), &bpf_loader_upgradeable::id(), ); programdata_account - .borrow_mut() .set_state(&UpgradeableLoaderState::ProgramData { slot, upgrade_authority_address: Some(*upgrade_authority_address), }) .unwrap(); - let program_account = AccountSharedData::new_ref( + let mut program_account = AccountSharedData::new( min_program_balance, UpgradeableLoaderState::program_len().unwrap(), &bpf_loader_upgradeable::id(), ); - program_account.borrow_mut().set_executable(true); + program_account.set_executable(true); program_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Program { - programdata_address: *programdata_address, + programdata_address, }) .unwrap(); - let spill_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let spill_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let rent_account = create_account_for_test(&rent); + let clock_account = create_account_for_test(&Clock { + slot, + ..Clock::default() + }); + let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); + let transaction_accounts = vec![ + (programdata_address, programdata_account), + (program_address, program_account), + (*buffer_address, buffer_account), + (spill_address, spill_account), + (sysvar::rent::id(), rent_account), + (sysvar::clock::id(), clock_account), + (*upgrade_authority_address, upgrade_authority_account), + ]; + let instruction_accounts = vec![ + AccountMeta { + pubkey: programdata_address, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: program_address, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: *buffer_address, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: spill_address, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::clock::id(), + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: *upgrade_authority_address, + is_signer: true, + is_writable: false, + }, + ]; + (transaction_accounts, instruction_accounts) + } - ( - buffer_account, - program_account, - programdata_account, - spill_account, + fn process_instruction( + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, + ) -> Vec { + let instruction_data = + bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap(); + mock_process_instruction( + &bpf_loader_upgradeable::id(), + Vec::new(), + &instruction_data, + transaction_accounts, + instruction_accounts, + expected_result, + super::process_instruction, ) } // Case: Success - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - let keyed_accounts = vec![ - ( - false, - true, - programdata_address, - programdata_account.clone(), - ), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account.clone()), - (false, true, spill_address, spill_account.clone()), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( - Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), + let accounts = process_instruction(transaction_accounts, instruction_accounts, Ok(())); + let min_programdata_balance = Rent::default().minimum_balance( + UpgradeableLoaderState::programdata_len(elf_orig.len().max(elf_new.len())).unwrap(), ); - assert_eq!(0, buffer_account.borrow().lamports()); - assert_eq!( - min_programdata_balance, - programdata_account.borrow().lamports() - ); - assert_eq!(1, spill_account.borrow().lamports()); - let state: UpgradeableLoaderState = programdata_account.borrow().state().unwrap(); + assert_eq!(min_programdata_balance, accounts[0].lamports()); + assert_eq!(0, accounts[2].lamports()); + assert_eq!(1, accounts[3].lamports()); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::ProgramData { @@ -2487,9 +2661,9 @@ mod tests { upgrade_authority_address: Some(upgrade_authority_address) } ); - for (i, byte) in programdata_account.borrow().data() - [UpgradeableLoaderState::programdata_data_offset().unwrap() - ..UpgradeableLoaderState::programdata_data_offset().unwrap() + elf_new.len()] + for (i, byte) in accounts[0].data()[UpgradeableLoaderState::programdata_data_offset() + .unwrap() + ..UpgradeableLoaderState::programdata_data_offset().unwrap() + elf_new.len()] .iter() .enumerate() { @@ -2497,484 +2671,275 @@ mod tests { } // Case: not upgradable - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - programdata_account - .borrow_mut() + transaction_accounts[0] + .1 .set_state(&UpgradeableLoaderState::ProgramData { slot, upgrade_authority_address: None, }) .unwrap(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::Immutable), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: wrong authority - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, mut instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); let invalid_upgrade_authority_address = Pubkey::new_unique(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - invalid_upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + transaction_accounts[6].0 = invalid_upgrade_authority_address; + instruction_accounts[6].pubkey = invalid_upgrade_authority_address; + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: authority did not sign - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (transaction_accounts, mut instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - false, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + instruction_accounts[6].is_signer = false; + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::MissingRequiredSignature), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Program account not executable - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - program_account.borrow_mut().set_executable(false); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + transaction_accounts[1].1.set_executable(false); + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::AccountNotExecutable), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Program account now owned by loader - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - program_account.borrow_mut().set_owner(Pubkey::new_unique()); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + transaction_accounts[1].1.set_owner(Pubkey::new_unique()); + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::IncorrectProgramId), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Program account not writable - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (transaction_accounts, mut instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, false, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + instruction_accounts[1].is_writable = false; + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::InvalidArgument), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Program account not initialized - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - program_account - .borrow_mut() + transaction_accounts[1] + .1 .set_state(&UpgradeableLoaderState::Uninitialized) .unwrap(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::InvalidAccountData), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Program ProgramData account mismatch - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, mut instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); let invalid_programdata_address = Pubkey::new_unique(); - let keyed_accounts = vec![ - ( - false, - true, - invalid_programdata_address, - programdata_account, - ), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + transaction_accounts[0].0 = invalid_programdata_address; + instruction_accounts[0].pubkey = invalid_programdata_address; + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::InvalidArgument), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Buffer account not initialized - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - buffer_account - .borrow_mut() + transaction_accounts[2] + .1 .set_state(&UpgradeableLoaderState::Uninitialized) .unwrap(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::InvalidArgument), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Buffer account too big - let (_, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - let buffer_account = AccountSharedData::new_ref( + transaction_accounts[2].1 = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(elf_orig.len().max(elf_new.len()) + 1).unwrap(), - &loader_id, + &bpf_loader_upgradeable::id(), ); - buffer_account - .borrow_mut() + transaction_accounts[2] + .1 .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(upgrade_authority_address), }) .unwrap(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::AccountDataTooSmall), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Test small buffer account - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &upgrade_authority_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - buffer_account - .borrow_mut() + transaction_accounts[2] + .1 .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(upgrade_authority_address), }) .unwrap(); - truncate_data(&mut buffer_account.borrow_mut(), 5); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + truncate_data(&mut transaction_accounts[2].1, 5); + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::InvalidAccountData), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Mismatched buffer and program authority - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &buffer_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: None buffer authority - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &buffer_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - buffer_account - .borrow_mut() + transaction_accounts[2] + .1 .set_state(&UpgradeableLoaderState::Buffer { authority_address: None, }) .unwrap(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account.clone()), - (false, false, clock_id, clock_account.clone()), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: None buffer and program authority - let (buffer_account, program_account, programdata_account, spill_account) = get_accounts( + let (mut transaction_accounts, instruction_accounts) = get_accounts( + &buffer_address, &buffer_address, - &programdata_address, &upgrade_authority_address, slot, &elf_orig, &elf_new, - min_program_balance, - min_programdata_balance, ); - buffer_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: None, - }) - .unwrap(); - programdata_account - .borrow_mut() + transaction_accounts[0] + .1 .set_state(&UpgradeableLoaderState::ProgramData { slot, upgrade_authority_address: None, }) .unwrap(); - let keyed_accounts = vec![ - (false, true, programdata_address, programdata_account), - (false, true, program_address, program_account), - (false, true, buffer_address, buffer_account), - (false, true, spill_address, spill_account), - (false, false, rent_id, rent_account), - (false, false, clock_id, clock_account), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account, - ), - ]; - assert_eq!( + transaction_accounts[2] + .1 + .set_state(&UpgradeableLoaderState::Buffer { + authority_address: None, + }) + .unwrap(); + process_instruction( + transaction_accounts, + instruction_accounts, Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); } @@ -2984,53 +2949,62 @@ mod tests { let loader_id = bpf_loader_upgradeable::id(); let slot = 0; let upgrade_authority_address = Pubkey::new_unique(); - let upgrade_authority_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); + let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); let new_upgrade_authority_address = Pubkey::new_unique(); - let new_upgrade_authority_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); + let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); let program_address = Pubkey::new_unique(); let (programdata_address, _) = Pubkey::find_program_address( &[program_address.as_ref()], &bpf_loader_upgradeable::id(), ); - let programdata_account = AccountSharedData::new_ref( + let mut programdata_account = AccountSharedData::new( 1, UpgradeableLoaderState::programdata_len(0).unwrap(), &bpf_loader_upgradeable::id(), ); - - // Case: Set to new authority programdata_account - .borrow_mut() .set_state(&UpgradeableLoaderState::ProgramData { slot, upgrade_authority_address: Some(upgrade_authority_address), }) .unwrap(); - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - programdata_account.clone(), - ), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ( - true, - false, - new_upgrade_authority_address, - new_upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + let programdata_meta = AccountMeta { + pubkey: programdata_address, + is_signer: false, + is_writable: false, + }; + let upgrade_authority_meta = AccountMeta { + pubkey: upgrade_authority_address, + is_signer: true, + is_writable: false, + }; + let new_upgrade_authority_meta = AccountMeta { + pubkey: new_upgrade_authority_address, + is_signer: false, + is_writable: false, + }; + + // Case: Set to new authority + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + (upgrade_authority_address, upgrade_authority_account.clone()), + ( + new_upgrade_authority_address, + new_upgrade_authority_account.clone(), + ), + ], + vec![ + programdata_meta.clone(), + upgrade_authority_meta.clone(), + new_upgrade_authority_meta.clone(), + ], Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = programdata_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::ProgramData { @@ -3040,32 +3014,18 @@ mod tests { ); // Case: Not upgradeable - programdata_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::ProgramData { - slot, - upgrade_authority_address: Some(upgrade_authority_address), - }) - .unwrap(); - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - programdata_account.clone(), - ), - ( - true, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + (upgrade_authority_address, upgrade_authority_account.clone()), + ], + vec![programdata_meta.clone(), upgrade_authority_meta.clone()], Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = programdata_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::ProgramData { @@ -3075,114 +3035,86 @@ mod tests { ); // Case: Authority did not sign - programdata_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::ProgramData { - slot, - upgrade_authority_address: Some(upgrade_authority_address), - }) - .unwrap(); - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - programdata_account.clone(), - ), - ( - false, - false, - upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + (upgrade_authority_address, upgrade_authority_account.clone()), + ], + vec![ + programdata_meta.clone(), + AccountMeta { + pubkey: upgrade_authority_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::MissingRequiredSignature), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: wrong authority - programdata_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::ProgramData { - slot, - upgrade_authority_address: Some(upgrade_authority_address), - }) - .unwrap(); let invalid_upgrade_authority_address = Pubkey::new_unique(); - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - programdata_account.clone(), - ), - ( - true, - false, - invalid_upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ( - false, - false, - new_upgrade_authority_address, - new_upgrade_authority_account, - ), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + ( + invalid_upgrade_authority_address, + upgrade_authority_account.clone(), + ), + (new_upgrade_authority_address, new_upgrade_authority_account), + ], + vec![ + programdata_meta.clone(), + AccountMeta { + pubkey: invalid_upgrade_authority_address, + is_signer: true, + is_writable: false, + }, + new_upgrade_authority_meta, + ], Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: No authority programdata_account - .borrow_mut() .set_state(&UpgradeableLoaderState::ProgramData { slot, upgrade_authority_address: None, }) .unwrap(); - let invalid_upgrade_authority_address = Pubkey::new_unique(); - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - programdata_account.clone(), - ), - ( - true, - false, - invalid_upgrade_authority_address, - upgrade_authority_account.clone(), - ), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + (upgrade_authority_address, upgrade_authority_account.clone()), + ], + vec![programdata_meta.clone(), upgrade_authority_meta.clone()], Err(InstructionError::Immutable), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Not a ProgramData account programdata_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Program { programdata_address: Pubkey::new_unique(), }) .unwrap(); - let invalid_upgrade_authority_address = Pubkey::new_unique(); - let keyed_accounts = vec![ - (false, false, programdata_address, programdata_account), - ( - true, - false, - invalid_upgrade_authority_address, - upgrade_authority_account, - ), - ]; - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + (upgrade_authority_address, upgrade_authority_account), + ], + vec![programdata_meta, upgrade_authority_meta], Err(InstructionError::InvalidArgument), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); } @@ -3190,33 +3122,53 @@ mod tests { fn test_bpf_loader_upgradeable_set_buffer_authority() { let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap(); let loader_id = bpf_loader_upgradeable::id(); + let invalid_authority_address = Pubkey::new_unique(); let authority_address = Pubkey::new_unique(); - let authority_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); + let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); let new_authority_address = Pubkey::new_unique(); - let new_authority_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); + let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); let buffer_address = Pubkey::new_unique(); - let buffer_account = AccountSharedData::new_ref( + let mut buffer_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(0).unwrap(), &loader_id, ); - - // Case: New authority required buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(authority_address), }) .unwrap(); - let mut keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (true, false, authority_address, authority_account.clone()), + let mut transaction_accounts = vec![ + (buffer_address, buffer_account.clone()), + (authority_address, authority_account.clone()), + (new_authority_address, new_authority_account.clone()), ]; - assert_eq!( + let buffer_meta = AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }; + let authority_meta = AccountMeta { + pubkey: authority_address, + is_signer: true, + is_writable: false, + }; + let new_authority_meta = AccountMeta { + pubkey: new_authority_address, + is_signer: false, + is_writable: false, + }; + + // Case: New authority required + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts.clone(), + vec![buffer_meta.clone(), authority_meta.clone()], Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::Buffer { @@ -3226,17 +3178,23 @@ mod tests { // Case: Set to new authority buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(authority_address), }) .unwrap(); - keyed_accounts.push((false, false, new_authority_address, new_authority_account)); - assert_eq!( + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts.clone(), + vec![ + buffer_meta.clone(), + authority_meta.clone(), + new_authority_meta.clone(), + ], Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!( state, UpgradeableLoaderState::Buffer { @@ -3245,73 +3203,89 @@ mod tests { ); // Case: Authority did not sign - buffer_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(authority_address), - }) - .unwrap(); - keyed_accounts[1] = (false, false, authority_address, authority_account.clone()); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts.clone(), + vec![ + buffer_meta.clone(), + AccountMeta { + pubkey: authority_address, + is_signer: false, + is_writable: false, + }, + new_authority_meta.clone(), + ], Err(InstructionError::MissingRequiredSignature), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: wrong authority - buffer_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(authority_address), - }) - .unwrap(); - let invalid_authority_address = Pubkey::new_unique(); - keyed_accounts[1] = ( - true, - false, - invalid_authority_address, - authority_account.clone(), - ); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (buffer_address, buffer_account.clone()), + (invalid_authority_address, authority_account), + (new_authority_address, new_authority_account), + ], + vec![ + buffer_meta.clone(), + AccountMeta { + pubkey: invalid_authority_address, + is_signer: true, + is_writable: false, + }, + new_authority_meta.clone(), + ], Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: No authority - buffer_account - .borrow_mut() + process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts.clone(), + vec![buffer_meta.clone(), authority_meta.clone()], + Err(InstructionError::IncorrectAuthority), + ); + + // Case: Set to no authority + transaction_accounts[0] + .1 .set_state(&UpgradeableLoaderState::Buffer { authority_address: None, }) .unwrap(); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts.clone(), + vec![ + buffer_meta.clone(), + authority_meta.clone(), + new_authority_meta.clone(), + ], Err(InstructionError::Immutable), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); // Case: Not a Buffer account - buffer_account - .borrow_mut() + transaction_accounts[0] + .1 .set_state(&UpgradeableLoaderState::Program { programdata_address: Pubkey::new_unique(), }) .unwrap(); - keyed_accounts.pop(); - assert_eq!( + process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts.clone(), + vec![buffer_meta, authority_meta, new_authority_meta], Err(InstructionError::InvalidArgument), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), - ); - - // Case: Set to no authority - buffer_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(authority_address), - }) - .unwrap(); - keyed_accounts[1] = (true, false, authority_address, authority_account); - assert_eq!( - Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); } @@ -3319,147 +3293,185 @@ mod tests { fn test_bpf_loader_upgradeable_close() { let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap(); let loader_id = bpf_loader_upgradeable::id(); + let invalid_authority_address = Pubkey::new_unique(); let authority_address = Pubkey::new_unique(); - let authority_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); + let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); let recipient_address = Pubkey::new_unique(); - let recipient_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); + let recipient_account = AccountSharedData::new(1, 0, &Pubkey::new_unique()); let buffer_address = Pubkey::new_unique(); - let buffer_account = AccountSharedData::new_ref( + let mut buffer_account = AccountSharedData::new( 1, UpgradeableLoaderState::buffer_len(0).unwrap(), - &bpf_loader_upgradeable::id(), + &loader_id, ); - - // Case: close a buffer account buffer_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Buffer { authority_address: Some(authority_address), }) .unwrap(); - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account.clone()), - (false, false, recipient_address, recipient_account.clone()), - (true, false, authority_address, authority_account.clone()), - ]; - assert_eq!( - Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), - ); - assert_eq!(0, buffer_account.borrow().lamports()); - assert_eq!(2, recipient_account.borrow().lamports()); - let state: UpgradeableLoaderState = buffer_account.borrow().state().unwrap(); - assert_eq!(state, UpgradeableLoaderState::Uninitialized); - - // Case: close with wrong authority - buffer_account - .borrow_mut() - .set_state(&UpgradeableLoaderState::Buffer { - authority_address: Some(authority_address), - }) - .unwrap(); - let incorrect_authority_address = Pubkey::new_unique(); - let keyed_accounts = vec![ - (false, false, buffer_address, buffer_account), - (false, false, recipient_address, recipient_account), - ( - true, - false, - incorrect_authority_address, - authority_account.clone(), - ), - ]; - assert_eq!( - Err(InstructionError::IncorrectAuthority), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), - ); - - // Case: close an uninitialized account let uninitialized_address = Pubkey::new_unique(); - let uninitialized_account = AccountSharedData::new_ref( + let mut uninitialized_account = AccountSharedData::new( 1, UpgradeableLoaderState::programdata_len(0).unwrap(), - &bpf_loader_upgradeable::id(), + &loader_id, ); uninitialized_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Uninitialized) .unwrap(); - let recipient_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); - let keyed_accounts = vec![ - ( - false, - false, - uninitialized_address, - uninitialized_account.clone(), - ), - (false, false, recipient_address, recipient_account.clone()), - ]; - assert_eq!( - Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), - ); - assert_eq!(0, uninitialized_account.borrow().lamports()); - assert_eq!(2, recipient_account.borrow().lamports()); - let state: UpgradeableLoaderState = uninitialized_account.borrow().state().unwrap(); - assert_eq!(state, UpgradeableLoaderState::Uninitialized); - - // Case: close a program account let programdata_address = Pubkey::new_unique(); - let programdata_account = AccountSharedData::new_ref( + let mut programdata_account = AccountSharedData::new( 1, UpgradeableLoaderState::programdata_len(0).unwrap(), - &bpf_loader_upgradeable::id(), + &loader_id, ); programdata_account - .borrow_mut() .set_state(&UpgradeableLoaderState::ProgramData { slot: 0, upgrade_authority_address: Some(authority_address), }) .unwrap(); let program_address = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref( + let mut program_account = AccountSharedData::new( 1, UpgradeableLoaderState::program_len().unwrap(), - &bpf_loader_upgradeable::id(), + &loader_id, ); - program_account.borrow_mut().set_executable(true); + program_account.set_executable(true); program_account - .borrow_mut() .set_state(&UpgradeableLoaderState::Program { programdata_address, }) .unwrap(); - let recipient_account = AccountSharedData::new_ref(1, 0, &Pubkey::new_unique()); - let keyed_accounts = vec![ - ( - false, - false, - programdata_address, - programdata_account.clone(), - ), - (false, false, recipient_address, recipient_account.clone()), - (true, false, authority_address, authority_account), - (false, true, program_address, program_account.clone()), + let transaction_accounts = vec![ + (buffer_address, buffer_account.clone()), + (recipient_address, recipient_account.clone()), + (authority_address, authority_account.clone()), ]; - assert_eq!( + let buffer_meta = AccountMeta { + pubkey: buffer_address, + is_signer: false, + is_writable: false, + }; + let recipient_meta = AccountMeta { + pubkey: recipient_address, + is_signer: false, + is_writable: false, + }; + let authority_meta = AccountMeta { + pubkey: authority_address, + is_signer: true, + is_writable: false, + }; + + // Case: close a buffer account + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + transaction_accounts, + vec![ + buffer_meta.clone(), + recipient_meta.clone(), + authority_meta.clone(), + ], Ok(()), - process_instruction(&loader_id, &[], &instruction, &keyed_accounts), ); - assert_eq!(0, programdata_account.borrow().lamports()); - assert_eq!(2, recipient_account.borrow().lamports()); - let state: UpgradeableLoaderState = programdata_account.borrow().state().unwrap(); + assert_eq!(0, accounts[0].lamports()); + assert_eq!(2, accounts[1].lamports()); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); + assert_eq!(state, UpgradeableLoaderState::Uninitialized); + + // Case: close with wrong authority + process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (buffer_address, buffer_account.clone()), + (recipient_address, recipient_account.clone()), + (invalid_authority_address, authority_account.clone()), + ], + vec![ + buffer_meta, + recipient_meta.clone(), + AccountMeta { + pubkey: invalid_authority_address, + is_signer: true, + is_writable: false, + }, + ], + Err(InstructionError::IncorrectAuthority), + ); + + // Case: close an uninitialized account + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (uninitialized_address, uninitialized_account.clone()), + (recipient_address, recipient_account.clone()), + (invalid_authority_address, authority_account.clone()), + ], + vec![ + AccountMeta { + pubkey: uninitialized_address, + is_signer: false, + is_writable: false, + }, + recipient_meta.clone(), + authority_meta.clone(), + ], + Ok(()), + ); + assert_eq!(0, accounts[0].lamports()); + assert_eq!(2, accounts[1].lamports()); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); + assert_eq!(state, UpgradeableLoaderState::Uninitialized); + + // Case: close a program account + let accounts = process_instruction( + &loader_id, + &[], + &instruction, + vec![ + (programdata_address, programdata_account.clone()), + (recipient_address, recipient_account), + (authority_address, authority_account), + (program_address, program_account.clone()), + ], + vec![ + AccountMeta { + pubkey: programdata_address, + is_signer: false, + is_writable: false, + }, + recipient_meta, + authority_meta, + AccountMeta { + pubkey: program_address, + is_signer: false, + is_writable: true, + }, + ], + Ok(()), + ); + assert_eq!(0, accounts[0].lamports()); + assert_eq!(2, accounts[1].lamports()); + let state: UpgradeableLoaderState = accounts[0].state().unwrap(); assert_eq!(state, UpgradeableLoaderState::Uninitialized); // Try to invoke closed account - let keyed_accounts = vec![ - (false, false, programdata_address, programdata_account), - (false, false, program_address, program_account), - ]; - assert_eq!( + process_instruction( + &program_address, + &[0, 1], + &[], + vec![ + (programdata_address, programdata_account.clone()), + (program_address, program_account.clone()), + ], + Vec::new(), Err(InstructionError::InvalidAccountData), - process_instruction(&program_address, &[0, 1], &[], &keyed_accounts), ); } @@ -3505,17 +3517,17 @@ mod tests { 0..elf.len(), 0..255, |bytes: &mut [u8]| { - let program_account = AccountSharedData::new_ref(1, 0, &loader_id); - program_account.borrow_mut().set_data(bytes.to_vec()); - program_account.borrow_mut().set_executable(true); - - let parameter_account = AccountSharedData::new_ref(1, 0, &loader_id); - let keyed_accounts = vec![ - (false, false, program_id, program_account), - (false, false, program_id, parameter_account), - ]; - - let _result = process_instruction(&loader_id, &[], &[], &keyed_accounts); + let mut program_account = AccountSharedData::new(1, 0, &loader_id); + program_account.set_data(bytes.to_vec()); + program_account.set_executable(true); + process_instruction( + &loader_id, + &[], + &[], + vec![(program_id, program_account)], + Vec::new(), + Ok(()), + ); }, ); } diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index 4ae530e21..2b924498e 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -322,6 +322,7 @@ mod tests { account_info::AccountInfo, bpf_loader, entrypoint::deserialize, + instruction::AccountMeta, }, std::{ cell::RefCell, @@ -333,122 +334,128 @@ mod tests { #[test] fn test_serialize_parameters() { let program_id = solana_sdk::pubkey::new_rand(); - let dup_key = solana_sdk::pubkey::new_rand(); - let dup_key2 = solana_sdk::pubkey::new_rand(); - let keyed_accounts = [ + let transaction_accounts = vec![ ( - false, - false, program_id, - Rc::new(RefCell::new(AccountSharedData::from(Account { + AccountSharedData::from(Account { lamports: 0, data: vec![], owner: bpf_loader::id(), executable: true, rent_epoch: 0, - }))), + }), ), ( - false, - false, - dup_key, - Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: 1, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }))), - ), - ( - false, - false, - dup_key, - Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: 1, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }))), - ), - ( - false, - false, solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::from(Account { + AccountSharedData::from(Account { + lamports: 1, + data: vec![1u8, 2, 3, 4, 5], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 100, + }), + ), + ( + solana_sdk::pubkey::new_rand(), + AccountSharedData::from(Account { lamports: 2, data: vec![11u8, 12, 13, 14, 15, 16, 17, 18, 19], owner: bpf_loader::id(), executable: true, rent_epoch: 200, - }))), + }), ), ( - false, - false, solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::from(Account { + AccountSharedData::from(Account { lamports: 3, data: vec![], owner: bpf_loader::id(), executable: false, rent_epoch: 3100, - }))), + }), ), ( - false, - true, - dup_key2, - Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: 4, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }))), - ), - ( - false, - true, - dup_key2, - Rc::new(RefCell::new(AccountSharedData::from(Account { - lamports: 4, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }))), - ), - ( - false, - true, solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::from(Account { + AccountSharedData::from(Account { + lamports: 4, + data: vec![1u8, 2, 3, 4, 5], + owner: bpf_loader::id(), + executable: false, + rent_epoch: 100, + }), + ), + ( + solana_sdk::pubkey::new_rand(), + AccountSharedData::from(Account { lamports: 5, data: vec![11u8, 12, 13, 14, 15, 16, 17, 18, 19], owner: bpf_loader::id(), executable: true, rent_epoch: 200, - }))), + }), ), ( - false, - true, solana_sdk::pubkey::new_rand(), - Rc::new(RefCell::new(AccountSharedData::from(Account { + AccountSharedData::from(Account { lamports: 6, data: vec![], owner: bpf_loader::id(), executable: false, rent_epoch: 3100, - }))), + }), ), ]; + let instruction_accounts = vec![ + AccountMeta { + pubkey: transaction_accounts[1].0, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: transaction_accounts[1].0, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: transaction_accounts[2].0, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: transaction_accounts[3].0, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: transaction_accounts[4].0, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: transaction_accounts[4].0, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: transaction_accounts[5].0, + is_signer: false, + is_writable: true, + }, + AccountMeta { + pubkey: transaction_accounts[6].0, + is_signer: false, + is_writable: true, + }, + ]; let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; let program_indices = [0]; - let preparation = - prepare_mock_invoke_context(&program_indices, &instruction_data, &keyed_accounts); + let preparation = prepare_mock_invoke_context( + &program_indices, + &instruction_data, + transaction_accounts.clone(), + instruction_accounts, + ); let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]); invoke_context .push( @@ -479,9 +486,12 @@ mod tests { (&de_instruction_data[0] as *const u8).align_offset(BPF_ALIGN_OF_U128), 0 ); - for ((_, _, key, account), account_info) in keyed_accounts.iter().skip(1).zip(de_accounts) { - assert_eq!(key, account_info.key); - let account = account.borrow(); + for account_info in de_accounts { + let account = &transaction_accounts + .iter() + .find(|(key, _account)| key == account_info.key) + .unwrap() + .1; assert_eq!(account.lamports(), account_info.lamports()); assert_eq!(account.data(), &account_info.data.borrow()[..]); assert_eq!(account.owner(), account_info.owner); @@ -511,12 +521,14 @@ mod tests { true, ) .unwrap(); - for ((_, _, key, account), de_keyed_account) in keyed_accounts.iter().zip(de_keyed_accounts) - { - assert_eq!(key, de_keyed_account.unsigned_key()); - let account = account.borrow(); - assert_eq!(account.executable(), de_keyed_account.executable().unwrap()); - assert_eq!(account.rent_epoch(), de_keyed_account.rent_epoch().unwrap()); + for keyed_account in de_keyed_accounts { + let account = &transaction_accounts + .iter() + .find(|(key, _account)| key == keyed_account.unsigned_key()) + .unwrap() + .1; + assert_eq!(account.executable(), keyed_account.executable().unwrap()); + assert_eq!(account.rent_epoch(), keyed_account.rent_epoch().unwrap()); } // check serialize_parameters_unaligned @@ -534,9 +546,12 @@ mod tests { unsafe { deserialize_unaligned(&mut serialized.as_slice_mut()[0] as *mut u8) }; assert_eq!(&program_id, de_program_id); assert_eq!(instruction_data, de_instruction_data); - for ((_, _, key, account), account_info) in keyed_accounts.iter().skip(1).zip(de_accounts) { - assert_eq!(key, account_info.key); - let account = account.borrow(); + for account_info in de_accounts { + let account = &transaction_accounts + .iter() + .find(|(key, _account)| key == account_info.key) + .unwrap() + .1; assert_eq!(account.lamports(), account_info.lamports()); assert_eq!(account.data(), &account_info.data.borrow()[..]); assert_eq!(account.owner(), account_info.owner); @@ -553,18 +568,20 @@ mod tests { true, ) .unwrap(); - for ((_, _, key, account), de_keyed_account) in keyed_accounts.iter().zip(de_keyed_accounts) - { - assert_eq!(key, de_keyed_account.unsigned_key()); - let account = account.borrow(); - assert_eq!(account.lamports(), de_keyed_account.lamports().unwrap()); + for keyed_account in de_keyed_accounts { + let account = &transaction_accounts + .iter() + .find(|(key, _account)| key == keyed_account.unsigned_key()) + .unwrap() + .1; + assert_eq!(account.lamports(), keyed_account.lamports().unwrap()); assert_eq!( account.data(), - de_keyed_account.try_account_ref().unwrap().data() + keyed_account.try_account_ref().unwrap().data() ); - assert_eq!(*account.owner(), de_keyed_account.owner().unwrap()); - assert_eq!(account.executable(), de_keyed_account.executable().unwrap()); - assert_eq!(account.rent_epoch(), de_keyed_account.rent_epoch().unwrap()); + assert_eq!(*account.owner(), keyed_account.owner().unwrap()); + assert_eq!(account.executable(), keyed_account.executable().unwrap()); + assert_eq!(account.rent_epoch(), keyed_account.rent_epoch().unwrap()); } } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index b9f3f3504..978dd2842 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -2980,7 +2980,7 @@ mod tests { #[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")] fn test_syscall_sol_panic() { let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3057,7 +3057,7 @@ mod tests { #[test] fn test_syscall_sol_log() { let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3161,7 +3161,7 @@ mod tests { #[test] fn test_syscall_sol_log_u64() { let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3203,7 +3203,7 @@ mod tests { #[test] fn test_syscall_sol_pubkey() { let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3415,7 +3415,8 @@ mod tests { fn test_syscall_sha256() { let config = Config::default(); let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader_deprecated::id()); + let program_account = + RefCell::new(AccountSharedData::new(0, 0, &bpf_loader_deprecated::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3544,7 +3545,7 @@ mod tests { fn test_syscall_get_sysvar() { let config = Config::default(); let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3854,7 +3855,7 @@ mod tests { // These tests duplicate the direct tests in solana_program::pubkey let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], @@ -3970,7 +3971,7 @@ mod tests { #[test] fn test_find_program_address() { let program_id = Pubkey::new_unique(); - let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id()); + let program_account = RefCell::new(AccountSharedData::new(0, 0, &bpf_loader::id())); let accounts = [(program_id, program_account)]; let message = Message::new( &[Instruction::new_with_bytes(program_id, &[], vec![])], diff --git a/programs/config/src/config_processor.rs b/programs/config/src/config_processor.rs index bac1f5d40..05accbf99 100644 --- a/programs/config/src/config_processor.rs +++ b/programs/config/src/config_processor.rs @@ -147,22 +147,26 @@ mod tests { solana_program_runtime::invoke_context::mock_process_instruction, solana_sdk::{ account::AccountSharedData, + instruction::AccountMeta, pubkey::Pubkey, signature::{Keypair, Signer}, system_instruction::SystemInstruction, }, - std::{cell::RefCell, rc::Rc}, }; fn process_instruction( instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], - ) -> Result<(), InstructionError> { + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, + ) -> Vec { mock_process_instruction( &id(), Vec::new(), instruction_data, - keyed_accounts, + transaction_accounts, + instruction_accounts, + expected_result, super::process_instruction, ) } @@ -191,16 +195,12 @@ mod tests { } } - fn create_config_account( - keys: Vec<(Pubkey, bool)>, - ) -> (Keypair, Rc>) { + fn create_config_account(keys: Vec<(Pubkey, bool)>) -> (Keypair, AccountSharedData) { let from_pubkey = Pubkey::new_unique(); let config_keypair = Keypair::new(); let config_pubkey = config_keypair.pubkey(); - let instructions = config_instruction::create_account::(&from_pubkey, &config_pubkey, 1, keys); - let system_instruction = limited_deserialize(&instructions[0].data).unwrap(); let space = match system_instruction { SystemInstruction::CreateAccount { @@ -210,14 +210,18 @@ mod tests { } => space, _ => panic!("Not a CreateAccount system instruction"), }; - let config_account = AccountSharedData::new_ref(0, space as usize, &id()); - let keyed_accounts = [(true, false, config_pubkey, config_account.clone())]; - assert_eq!( - process_instruction(&instructions[1].data, &keyed_accounts), - Ok(()) + let config_account = AccountSharedData::new(0, space as usize, &id()); + let accounts = process_instruction( + &instructions[1].data, + vec![(config_pubkey, config_account)], + vec![AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }], + Ok(()), ); - - (config_keypair, config_account) + (config_keypair, accounts[0].clone()) } #[test] @@ -226,7 +230,7 @@ mod tests { let (_, config_account) = create_config_account(vec![]); assert_eq!( Some(MyConfig::default()), - deserialize(get_config_data(config_account.borrow().data()).unwrap()).ok() + deserialize(get_config_data(config_account.data()).unwrap()).ok() ); } @@ -239,14 +243,19 @@ mod tests { let my_config = MyConfig::new(42); let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); - let keyed_accounts = [(true, false, config_pubkey, config_account.clone())]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Ok(()) + let accounts = process_instruction( + &instruction.data, + vec![(config_pubkey, config_account)], + vec![AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }], + Ok(()), ); assert_eq!( Some(my_config), - deserialize(get_config_data(config_account.borrow().data()).unwrap()).ok() + deserialize(get_config_data(accounts[0].data()).unwrap()).ok() ); } @@ -260,10 +269,15 @@ mod tests { let mut instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); instruction.data = vec![0; 123]; // <-- Replace data with a vector that's too large - let keyed_accounts = [(true, false, config_pubkey, config_account)]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::InvalidInstructionData) + process_instruction( + &instruction.data, + vec![(config_pubkey, config_account)], + vec![AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }], + Err(InstructionError::InvalidInstructionData), ); } @@ -277,10 +291,15 @@ mod tests { let mut instruction = config_instruction::store(&config_pubkey, true, vec![], &my_config); instruction.accounts[0].is_signer = false; // <----- not a signer - let keyed_accounts = [(false, false, config_pubkey, config_account)]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::MissingRequiredSignature) + process_instruction( + &instruction.data, + vec![(config_pubkey, config_account)], + vec![AccountMeta { + pubkey: config_pubkey, + is_signer: false, + is_writable: false, + }], + Err(InstructionError::MissingRequiredSignature), ); } @@ -298,24 +317,41 @@ mod tests { let (config_keypair, config_account) = create_config_account(keys.clone()); let config_pubkey = config_keypair.pubkey(); let my_config = MyConfig::new(42); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let signer1_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let keyed_accounts = [ - (true, false, config_pubkey, config_account.clone()), - (true, false, signer0_pubkey, signer0_account), - (true, false, signer1_pubkey, signer1_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Ok(()) + let accounts = process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account), + (signer1_pubkey, signer1_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer1_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); - let meta_data: ConfigKeys = deserialize(config_account.borrow().data()).unwrap(); + let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap(); assert_eq!(meta_data.keys, keys); assert_eq!( Some(my_config), - deserialize(get_config_data(config_account.borrow().data()).unwrap()).ok() + deserialize(get_config_data(accounts[0].data()).unwrap()).ok() ); } @@ -328,13 +364,18 @@ mod tests { let (config_keypair, _) = create_config_account(keys.clone()); let config_pubkey = config_keypair.pubkey(); let my_config = MyConfig::new(42); + let signer0_account = AccountSharedData::new(0, 0, &id()); let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config); - let signer0_account = AccountSharedData::new_ref(0, 0, &id()); - let keyed_accounts = [(true, false, signer0_pubkey, signer0_account)]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::InvalidAccountData) + process_instruction( + &instruction.data, + vec![(signer0_pubkey, signer0_account)], + vec![AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }], + Err(InstructionError::InvalidAccountData), ); } @@ -343,30 +384,56 @@ mod tests { solana_logger::setup(); let signer0_pubkey = Pubkey::new_unique(); let signer1_pubkey = Pubkey::new_unique(); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let signer1_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let keys = vec![(signer0_pubkey, true)]; let (config_keypair, config_account) = create_config_account(keys.clone()); let config_pubkey = config_keypair.pubkey(); let my_config = MyConfig::new(42); - let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); - // Config-data pubkey doesn't match signer - let mut keyed_accounts = [ - (true, false, config_pubkey, config_account), - (true, false, signer1_pubkey, signer1_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::MissingRequiredSignature) + let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); + process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account.clone()), + (signer1_pubkey, signer1_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer1_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Err(InstructionError::MissingRequiredSignature), ); // Config-data pubkey not a signer - keyed_accounts[1] = (false, false, signer0_pubkey, signer0_account); - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::MissingRequiredSignature) + process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: false, + is_writable: false, + }, + ], + Err(InstructionError::MissingRequiredSignature), ); } @@ -377,9 +444,9 @@ mod tests { let signer0_pubkey = Pubkey::new_unique(); let signer1_pubkey = Pubkey::new_unique(); let signer2_pubkey = Pubkey::new_unique(); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let signer1_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let signer2_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let signer2_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let keys = vec![ (pubkey, false), (signer0_pubkey, true), @@ -390,40 +457,98 @@ mod tests { let my_config = MyConfig::new(42); let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config); - let mut keyed_accounts = [ - (true, false, config_pubkey, config_account.clone()), - (true, false, signer0_pubkey, signer0_account), - (true, false, signer1_pubkey, signer1_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Ok(()) + let accounts = process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account.clone()), + (signer1_pubkey, signer1_account.clone()), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer1_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); // Update with expected signatures let new_config = MyConfig::new(84); let instruction = config_instruction::store(&config_pubkey, false, keys.clone(), &new_config); - keyed_accounts[0].0 = false; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Ok(()) + let accounts = process_instruction( + &instruction.data, + vec![ + (config_pubkey, accounts[0].clone()), + (signer0_pubkey, signer0_account.clone()), + (signer1_pubkey, signer1_account.clone()), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer1_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); - let meta_data: ConfigKeys = deserialize(config_account.borrow().data()).unwrap(); + let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap(); assert_eq!(meta_data.keys, keys); assert_eq!( new_config, - MyConfig::deserialize(get_config_data(config_account.borrow().data()).unwrap()) - .unwrap() + MyConfig::deserialize(get_config_data(accounts[0].data()).unwrap()).unwrap() ); // Attempt update with incomplete signatures let keys = vec![(pubkey, false), (signer0_pubkey, true)]; let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config); - keyed_accounts[2].0 = false; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::MissingRequiredSignature) + process_instruction( + &instruction.data, + vec![ + (config_pubkey, accounts[0].clone()), + (signer0_pubkey, signer0_account.clone()), + (signer1_pubkey, signer1_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer1_pubkey, + is_signer: false, + is_writable: false, + }, + ], + Err(InstructionError::MissingRequiredSignature), ); // Attempt update with incorrect signatures @@ -433,10 +558,31 @@ mod tests { (signer2_pubkey, true), ]; let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config); - keyed_accounts[2] = (true, false, signer2_pubkey, signer2_account); - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::MissingRequiredSignature) + process_instruction( + &instruction.data, + vec![ + (config_pubkey, accounts[0].clone()), + (signer0_pubkey, signer0_account), + (signer2_pubkey, signer2_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer2_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Err(InstructionError::MissingRequiredSignature), ); } @@ -445,7 +591,7 @@ mod tests { solana_logger::setup(); let config_address = Pubkey::new_unique(); let signer0_pubkey = Pubkey::new_unique(); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let keys = vec![ (config_address, false), (signer0_pubkey, true), @@ -457,13 +603,29 @@ mod tests { // Attempt initialization with duplicate signer inputs let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); - let keyed_accounts = [ - (true, false, config_pubkey, config_account), - (true, false, signer0_pubkey, signer0_account.clone()), - (true, false, signer0_pubkey, signer0_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), + process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } @@ -474,8 +636,8 @@ mod tests { let config_address = Pubkey::new_unique(); let signer0_pubkey = Pubkey::new_unique(); let signer1_pubkey = Pubkey::new_unique(); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let signer1_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let keys = vec![ (config_address, false), (signer0_pubkey, true), @@ -486,13 +648,30 @@ mod tests { let my_config = MyConfig::new(42); let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); - let mut keyed_accounts = [ - (true, false, config_pubkey, config_account), - (true, false, signer0_pubkey, signer0_account), - (true, false, signer1_pubkey, signer1_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), + let accounts = process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account.clone()), + (signer1_pubkey, signer1_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer1_pubkey, + is_signer: true, + is_writable: false, + }, + ], Ok(()), ); @@ -504,9 +683,29 @@ mod tests { (signer0_pubkey, true), ]; let instruction = config_instruction::store(&config_pubkey, false, dupe_keys, &new_config); - keyed_accounts[2] = keyed_accounts[1].clone(); - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), + process_instruction( + &instruction.data, + vec![ + (config_pubkey, accounts[0].clone()), + (signer0_pubkey, signer0_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } @@ -516,7 +715,7 @@ mod tests { solana_logger::setup(); let pubkey = Pubkey::new_unique(); let signer0_pubkey = Pubkey::new_unique(); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let keys = vec![ (pubkey, false), (signer0_pubkey, true), @@ -525,7 +724,6 @@ mod tests { let (config_keypair, config_account) = create_config_account(keys); let config_pubkey = config_keypair.pubkey(); let my_config = MyConfig::new(42); - let keys = vec![ (pubkey, false), (signer0_pubkey, true), @@ -533,37 +731,70 @@ mod tests { ]; let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config); - let keyed_accounts = [ - (true, false, config_pubkey, config_account.clone()), - (true, false, signer0_pubkey, signer0_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Ok(()) + let accounts = process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account.clone()), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); // Update with expected signatures let new_config = MyConfig::new(84); let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &new_config); - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Ok(()) + let accounts = process_instruction( + &instruction.data, + vec![ + (config_pubkey, accounts[0].clone()), + (signer0_pubkey, signer0_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); - let meta_data: ConfigKeys = deserialize(config_account.borrow().data()).unwrap(); + let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap(); assert_eq!(meta_data.keys, keys); assert_eq!( new_config, - MyConfig::deserialize(get_config_data(config_account.borrow().data()).unwrap()) - .unwrap() + MyConfig::deserialize(get_config_data(accounts[0].data()).unwrap()).unwrap() ); // Attempt update with incomplete signatures let keys = vec![(pubkey, false), (config_keypair.pubkey(), true)]; let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config); - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts[0..1]), - Err(InstructionError::MissingRequiredSignature) + process_instruction( + &instruction.data, + vec![(config_pubkey, accounts[0].clone())], + vec![AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }], + Err(InstructionError::MissingRequiredSignature), ); } @@ -574,9 +805,11 @@ mod tests { let (_, _config_account) = create_config_account(vec![]); let instructions = config_instruction::create_account::(&from_pubkey, &config_pubkey, 1, vec![]); - assert_eq!( - process_instruction(&instructions[1].data, &[]), - Err(InstructionError::NotEnoughAccountKeys) + process_instruction( + &instructions[1].data, + Vec::new(), + Vec::new(), + Err(InstructionError::NotEnoughAccountKeys), ); } @@ -586,8 +819,8 @@ mod tests { let config_pubkey = Pubkey::new_unique(); let new_config = MyConfig::new(84); let signer0_pubkey = Pubkey::new_unique(); - let signer0_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); - let config_account = AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()); + let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); + let config_account = AccountSharedData::new(0, 0, &Pubkey::new_unique()); let (_, _config_account) = create_config_account(vec![]); let keys = vec![ (from_pubkey, false), @@ -596,13 +829,25 @@ mod tests { ]; let instruction = config_instruction::store(&config_pubkey, true, keys, &new_config); - let keyed_accounts = [ - (true, false, config_pubkey, config_account), - (true, false, signer0_pubkey, signer0_account), - ]; - assert_eq!( - process_instruction(&instruction.data, &keyed_accounts), - Err(InstructionError::InvalidAccountOwner) + process_instruction( + &instruction.data, + vec![ + (config_pubkey, config_account), + (signer0_pubkey, signer0_account), + ], + vec![ + AccountMeta { + pubkey: config_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: signer0_pubkey, + is_signer: true, + is_writable: false, + }, + ], + Err(InstructionError::InvalidAccountOwner), ); } } diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index e9fee4939..63bfa229c 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -342,7 +342,7 @@ mod tests { crate::stake_state::{Meta, StakeState}, bincode::serialize, solana_program_runtime::invoke_context::{ - mock_process_instruction, prepare_mock_invoke_context, InvokeContext, + mock_process_instruction, mock_process_instruction_with_sysvars, }, solana_sdk::{ account::{self, AccountSharedData}, @@ -356,15 +356,15 @@ mod tests { }, sysvar::{stake_history::StakeHistory, Sysvar}, }, - std::{cell::RefCell, rc::Rc, str::FromStr}, + std::str::FromStr, }; - fn create_default_account() -> Rc> { - AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()) + fn create_default_account() -> AccountSharedData { + AccountSharedData::new(0, 0, &Pubkey::new_unique()) } - fn create_default_stake_account() -> Rc> { - AccountSharedData::new_ref(0, 0, &id()) + fn create_default_stake_account() -> AccountSharedData { + AccountSharedData::new(0, 0, &id()) } fn invalid_stake_state_pubkey() -> Pubkey { @@ -385,258 +385,244 @@ mod tests { fn process_instruction( instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], - ) -> Result<(), InstructionError> { + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, + ) -> Vec { mock_process_instruction( &id(), Vec::new(), instruction_data, - keyed_accounts, + transaction_accounts, + instruction_accounts, + expected_result, super::process_instruction, ) } - fn process_instruction_as_one_arg(instruction: &Instruction) -> Result<(), InstructionError> { - let accounts = instruction.accounts.iter().map(|meta| { - Rc::new(RefCell::new(if sysvar::clock::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&sysvar::clock::Clock::default()) - } else if sysvar::rewards::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&sysvar::rewards::Rewards::new(0.0)) - } else if sysvar::stake_history::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&StakeHistory::default()) - } else if stake_config::check_id(&meta.pubkey) { - config::create_account(0, &stake_config::Config::default()) - } else if sysvar::rent::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&Rent::default()) - } else if meta.pubkey == invalid_stake_state_pubkey() { - AccountSharedData::new(0, 0, &id()) - } else if meta.pubkey == invalid_vote_state_pubkey() { - AccountSharedData::new(0, 0, &solana_vote_program::id()) - } else if meta.pubkey == spoofed_stake_state_pubkey() { - AccountSharedData::new(0, 0, &spoofed_stake_program_id()) - } else { - AccountSharedData::new(0, 0, &id()) - })) - }); - let keyed_accounts: Vec<_> = instruction + fn process_instruction_as_one_arg( + instruction: &Instruction, + expected_result: Result<(), InstructionError>, + ) -> Vec { + let transaction_accounts = instruction .accounts .iter() - .zip(accounts) - .map(|(meta, account)| (meta.is_signer, meta.is_writable, meta.pubkey, account)) + .map(|meta| { + ( + meta.pubkey, + if sysvar::clock::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test( + &sysvar::clock::Clock::default(), + ) + } else if sysvar::rewards::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test( + &sysvar::rewards::Rewards::new(0.0), + ) + } else if sysvar::stake_history::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test(&StakeHistory::default()) + } else if stake_config::check_id(&meta.pubkey) { + config::create_account(0, &stake_config::Config::default()) + } else if sysvar::rent::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test(&Rent::default()) + } else if meta.pubkey == invalid_stake_state_pubkey() { + AccountSharedData::new(0, 0, &id()) + } else if meta.pubkey == invalid_vote_state_pubkey() { + AccountSharedData::new(0, 0, &solana_vote_program::id()) + } else if meta.pubkey == spoofed_stake_state_pubkey() { + AccountSharedData::new(0, 0, &spoofed_stake_program_id()) + } else { + AccountSharedData::new(0, 0, &id()) + }, + ) + }) .collect(); - let mut preparation = prepare_mock_invoke_context(&[], &instruction.data, &keyed_accounts); - let processor_account = AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id()); - let program_indices = vec![preparation.accounts.len()]; - preparation.accounts.push((id(), processor_account)); let mut data = Vec::with_capacity(sysvar::clock::Clock::size_of()); bincode::serialize_into(&mut data, &sysvar::clock::Clock::default()).unwrap(); - let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]); - let sysvars = [(sysvar::clock::id(), data)]; - invoke_context.sysvars = &sysvars; - invoke_context.push( - &preparation.message, - &preparation.message.instructions[0], - &program_indices, - &preparation.account_indices, - )?; - super::process_instruction(1, &instruction.data, &mut invoke_context) + mock_process_instruction_with_sysvars( + &id(), + Vec::new(), + &instruction.data, + transaction_accounts, + instruction.accounts.clone(), + expected_result, + &[(sysvar::clock::id(), data)], + super::process_instruction, + ) } #[test] fn test_stake_process_instruction() { - assert_eq!( - process_instruction_as_one_arg(&instruction::initialize( + process_instruction_as_one_arg( + &instruction::initialize( &Pubkey::new_unique(), &Authorized::default(), - &Lockup::default() - )), + &Lockup::default(), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::authorize( + process_instruction_as_one_arg( + &instruction::authorize( &Pubkey::new_unique(), &Pubkey::new_unique(), &Pubkey::new_unique(), StakeAuthorize::Staker, None, - )), - Err(InstructionError::InvalidAccountData), - ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::split( - &Pubkey::new_unique(), - &Pubkey::new_unique(), - 100, - &invalid_stake_state_pubkey(), - )[2] ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::merge( - &Pubkey::new_unique(), - &invalid_stake_state_pubkey(), - &Pubkey::new_unique(), - )[0] - ), + process_instruction_as_one_arg( + &instruction::split( + &Pubkey::new_unique(), + &Pubkey::new_unique(), + 100, + &invalid_stake_state_pubkey(), + )[2], Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::split_with_seed( - &Pubkey::new_unique(), - &Pubkey::new_unique(), - 100, - &invalid_stake_state_pubkey(), - &Pubkey::new_unique(), - "seed" - )[1] - ), + process_instruction_as_one_arg( + &instruction::merge( + &Pubkey::new_unique(), + &invalid_stake_state_pubkey(), + &Pubkey::new_unique(), + )[0], Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::delegate_stake( + process_instruction_as_one_arg( + &instruction::split_with_seed( + &Pubkey::new_unique(), + &Pubkey::new_unique(), + 100, + &invalid_stake_state_pubkey(), + &Pubkey::new_unique(), + "seed", + )[1], + Err(InstructionError::InvalidAccountData), + ); + process_instruction_as_one_arg( + &instruction::delegate_stake( &Pubkey::new_unique(), &Pubkey::new_unique(), &invalid_vote_state_pubkey(), - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::withdraw( + process_instruction_as_one_arg( + &instruction::withdraw( &Pubkey::new_unique(), &Pubkey::new_unique(), &Pubkey::new_unique(), 100, None, - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::deactivate_stake( - &Pubkey::new_unique(), - &Pubkey::new_unique() - )), + process_instruction_as_one_arg( + &instruction::deactivate_stake(&Pubkey::new_unique(), &Pubkey::new_unique()), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::set_lockup( + process_instruction_as_one_arg( + &instruction::set_lockup( &Pubkey::new_unique(), &LockupArgs::default(), - &Pubkey::new_unique() - )), + &Pubkey::new_unique(), + ), Err(InstructionError::InvalidAccountData), ); } #[test] fn test_spoofed_stake_accounts() { - assert_eq!( - process_instruction_as_one_arg(&instruction::initialize( + process_instruction_as_one_arg( + &instruction::initialize( &spoofed_stake_state_pubkey(), &Authorized::default(), - &Lockup::default() - )), + &Lockup::default(), + ), Err(InstructionError::InvalidAccountOwner), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::authorize( + process_instruction_as_one_arg( + &instruction::authorize( &spoofed_stake_state_pubkey(), &Pubkey::new_unique(), &Pubkey::new_unique(), StakeAuthorize::Staker, None, - )), - Err(InstructionError::InvalidAccountOwner), - ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::split( - &spoofed_stake_state_pubkey(), - &Pubkey::new_unique(), - 100, - &Pubkey::new_unique(), - )[2] ), Err(InstructionError::InvalidAccountOwner), ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::split( - &Pubkey::new_unique(), - &Pubkey::new_unique(), - 100, - &spoofed_stake_state_pubkey(), - )[2] - ), + process_instruction_as_one_arg( + &instruction::split( + &spoofed_stake_state_pubkey(), + &Pubkey::new_unique(), + 100, + &Pubkey::new_unique(), + )[2], + Err(InstructionError::InvalidAccountOwner), + ); + process_instruction_as_one_arg( + &instruction::split( + &Pubkey::new_unique(), + &Pubkey::new_unique(), + 100, + &spoofed_stake_state_pubkey(), + )[2], Err(InstructionError::IncorrectProgramId), ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::merge( - &spoofed_stake_state_pubkey(), - &Pubkey::new_unique(), - &Pubkey::new_unique(), - )[0] - ), - Err(InstructionError::InvalidAccountOwner), - ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::merge( - &Pubkey::new_unique(), - &spoofed_stake_state_pubkey(), - &Pubkey::new_unique(), - )[0] - ), - Err(InstructionError::IncorrectProgramId), - ); - assert_eq!( - process_instruction_as_one_arg( - &instruction::split_with_seed( - &spoofed_stake_state_pubkey(), - &Pubkey::new_unique(), - 100, - &Pubkey::new_unique(), - &Pubkey::new_unique(), - "seed" - )[1] - ), - Err(InstructionError::InvalidAccountOwner), - ); - assert_eq!( - process_instruction_as_one_arg(&instruction::delegate_stake( + process_instruction_as_one_arg( + &instruction::merge( &spoofed_stake_state_pubkey(), &Pubkey::new_unique(), &Pubkey::new_unique(), - )), + )[0], Err(InstructionError::InvalidAccountOwner), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::withdraw( + process_instruction_as_one_arg( + &instruction::merge( + &Pubkey::new_unique(), + &spoofed_stake_state_pubkey(), + &Pubkey::new_unique(), + )[0], + Err(InstructionError::IncorrectProgramId), + ); + process_instruction_as_one_arg( + &instruction::split_with_seed( + &spoofed_stake_state_pubkey(), + &Pubkey::new_unique(), + 100, + &Pubkey::new_unique(), + &Pubkey::new_unique(), + "seed", + )[1], + Err(InstructionError::InvalidAccountOwner), + ); + process_instruction_as_one_arg( + &instruction::delegate_stake( + &spoofed_stake_state_pubkey(), + &Pubkey::new_unique(), + &Pubkey::new_unique(), + ), + Err(InstructionError::InvalidAccountOwner), + ); + process_instruction_as_one_arg( + &instruction::withdraw( &spoofed_stake_state_pubkey(), &Pubkey::new_unique(), &Pubkey::new_unique(), 100, None, - )), + ), Err(InstructionError::InvalidAccountOwner), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::deactivate_stake( - &spoofed_stake_state_pubkey(), - &Pubkey::new_unique() - )), + process_instruction_as_one_arg( + &instruction::deactivate_stake(&spoofed_stake_state_pubkey(), &Pubkey::new_unique()), Err(InstructionError::InvalidAccountOwner), ); - assert_eq!( - process_instruction_as_one_arg(&instruction::set_lockup( + process_instruction_as_one_arg( + &instruction::set_lockup( &spoofed_stake_state_pubkey(), &LockupArgs::default(), - &Pubkey::new_unique() - )), + &Pubkey::new_unique(), + ), Err(InstructionError::InvalidAccountOwner), ); } @@ -644,199 +630,241 @@ mod tests { #[test] fn test_stake_process_instruction_decode_bail() { // these will not call stake_state, have bogus contents + let stake_address = Pubkey::new_unique(); + let stake_account = create_default_stake_account(); + let rent_address = sysvar::rent::id(); + let rent_account = account::create_account_shared_data_for_test(&Rent::default()); + let rewards_address = sysvar::rewards::id(); + let rewards_account = + account::create_account_shared_data_for_test(&sysvar::rewards::Rewards::new(0.0)); + let stake_history_address = sysvar::stake_history::id(); + let stake_history_account = + account::create_account_shared_data_for_test(&StakeHistory::default()); + let vote_address = Pubkey::new_unique(); + let vote_account = AccountSharedData::new(0, 0, &solana_vote_program::id()); + let clock_address = sysvar::clock::id(); + let clock_account = + account::create_account_shared_data_for_test(&sysvar::clock::Clock::default()); + let config_address = stake_config::id(); + let config_account = config::create_account(0, &stake_config::Config::default()); // gets the "is_empty()" check - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Initialize( - Authorized::default(), - Lockup::default() - )) - .unwrap(), - &[], - ), + process_instruction( + &serialize(&StakeInstruction::Initialize( + Authorized::default(), + Lockup::default(), + )) + .unwrap(), + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), ); // no account for rent - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let keyed_accounts = [(false, false, stake_address, stake_account)]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Initialize( - Authorized::default(), - Lockup::default() - )) - .unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::Initialize( + Authorized::default(), + Lockup::default(), + )) + .unwrap(), + vec![(stake_address, stake_account.clone())], + vec![AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }], Err(InstructionError::NotEnoughAccountKeys), ); // rent fails to deserialize - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let rent_address = sysvar::rent::id(); - let rent_account = create_default_account(); - let keyed_accounts = [ - (false, false, stake_address, stake_account), - (false, false, rent_address, rent_account), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Initialize( - Authorized::default(), - Lockup::default() - )) - .unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::Initialize( + Authorized::default(), + Lockup::default(), + )) + .unwrap(), + vec![ + (stake_address, stake_account.clone()), + (rent_address, create_default_account()), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: rent_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); // fails to deserialize stake state - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let rent_address = sysvar::rent::id(); - let rent_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &Rent::default(), - ))); - let keyed_accounts = [ - (false, false, stake_address, stake_account), - (false, false, rent_address, rent_account), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Initialize( - Authorized::default(), - Lockup::default() - )) - .unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::Initialize( + Authorized::default(), + Lockup::default(), + )) + .unwrap(), + vec![ + (stake_address, stake_account.clone()), + (rent_address, rent_account), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: rent_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidAccountData), ); // gets the first check in delegate, wrong number of accounts - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let keyed_accounts = [(false, false, stake_address, stake_account)]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::DelegateStake).unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::DelegateStake).unwrap(), + vec![(stake_address, stake_account.clone())], + vec![AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }], Err(InstructionError::NotEnoughAccountKeys), ); // gets the sub-check for number of args - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let keyed_accounts = [(false, false, stake_address, stake_account)]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::DelegateStake).unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::DelegateStake).unwrap(), + vec![(stake_address, stake_account.clone())], + vec![AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }], Err(InstructionError::NotEnoughAccountKeys), ); // gets the check non-deserialize-able account in delegate_stake - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let vote_address = Pubkey::new_unique(); - let vote_account = AccountSharedData::new_ref(0, 0, &solana_vote_program::id()); - let clock_address = sysvar::clock::id(); - let clock_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &sysvar::clock::Clock::default(), - ))); - let stake_history_address = sysvar::stake_history::id(); - let stake_history_account = - Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &sysvar::stake_history::StakeHistory::default(), - ))); - let config_address = stake_config::id(); - let config_account = Rc::new(RefCell::new(config::create_account( - 0, - &stake_config::Config::default(), - ))); - let keyed_accounts = [ - (true, false, stake_address, stake_account), - (false, false, vote_address, vote_account), - (false, false, clock_address, clock_account), - (false, false, stake_history_address, stake_history_account), - (false, false, config_address, config_account), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::DelegateStake).unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::DelegateStake).unwrap(), + vec![ + (stake_address, stake_account.clone()), + (vote_address, vote_account.clone()), + (clock_address, clock_account), + (stake_history_address, stake_history_account.clone()), + (config_address, config_account), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: vote_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: clock_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: stake_history_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: config_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidAccountData), ); // Tests 3rd keyed account is of correct type (Clock instead of rewards) in withdraw - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let vote_address = Pubkey::new_unique(); - let vote_account = create_default_account(); - let rewards_address = sysvar::rewards::id(); - let rewards_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &sysvar::rewards::Rewards::new(0.0), - ))); - let stake_history_address = sysvar::stake_history::id(); - let stake_history_account = Rc::new(RefCell::new( - account::create_account_shared_data_for_test(&StakeHistory::default()), - )); - let keyed_accounts = [ - (false, false, stake_address, stake_account), - (false, false, vote_address, vote_account), - (false, false, rewards_address, rewards_account), - (false, false, stake_history_address, stake_history_account), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Withdraw(42)).unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::Withdraw(42)).unwrap(), + vec![ + (stake_address, stake_account.clone()), + (vote_address, vote_account), + (rewards_address, rewards_account.clone()), + (stake_history_address, stake_history_account), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: vote_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: rewards_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: stake_history_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); // Tests correct number of accounts are provided in withdraw - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let keyed_accounts = [(false, false, stake_address, stake_account)]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Withdraw(42)).unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::Withdraw(42)).unwrap(), + vec![(stake_address, stake_account.clone())], + vec![AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }], Err(InstructionError::NotEnoughAccountKeys), ); // Tests 2nd keyed account is of correct type (Clock instead of rewards) in deactivate - let stake_address = Pubkey::new_unique(); - let stake_account = create_default_stake_account(); - let rewards_address = sysvar::rewards::id(); - let rewards_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &sysvar::rewards::Rewards::new(0.0), - ))); - let keyed_accounts = [ - (false, false, stake_address, stake_account), - (false, false, rewards_address, rewards_account), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::Deactivate).unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::Deactivate).unwrap(), + vec![ + (stake_address, stake_account), + (rewards_address, rewards_account), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: rewards_address, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); // Tests correct number of accounts are provided in deactivate - assert_eq!( - process_instruction(&serialize(&StakeInstruction::Deactivate).unwrap(), &[]), + process_instruction( + &serialize(&StakeInstruction::Deactivate).unwrap(), + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), ); } @@ -845,46 +873,68 @@ mod tests { fn test_stake_checked_instructions() { let stake_address = Pubkey::new_unique(); let staker = Pubkey::new_unique(); + let staker_account = create_default_account(); let withdrawer = Pubkey::new_unique(); + let withdrawer_account = create_default_account(); + let authorized_address = Pubkey::new_unique(); + let authorized_account = create_default_account(); + let new_authorized_account = create_default_account(); + let clock_address = sysvar::clock::id(); + let clock_account = account::create_account_shared_data_for_test(&Clock::default()); + let custodian = Pubkey::new_unique(); + let custodian_account = create_default_account(); // Test InitializeChecked with non-signing withdrawer let mut instruction = initialize_checked(&stake_address, &Authorized { staker, withdrawer }); instruction.accounts[3] = AccountMeta::new_readonly(withdrawer, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); // Test InitializeChecked with withdrawer signer - let stake_account = AccountSharedData::new_ref( + let stake_account = AccountSharedData::new( 1_000_000_000, std::mem::size_of::(), &id(), ); let rent_address = sysvar::rent::id(); - let rent_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &Rent::default(), - ))); - let staker_account = create_default_account(); - let withdrawer_account = create_default_account(); - - let keyed_accounts = [ - (false, false, stake_address, stake_account), - (false, false, rent_address, rent_account), - (false, false, staker, staker_account), - (true, false, withdrawer, withdrawer_account.clone()), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::InitializeChecked).unwrap(), - &keyed_accounts, - ), + let rent_account = account::create_account_shared_data_for_test(&Rent::default()); + process_instruction( + &serialize(&StakeInstruction::InitializeChecked).unwrap(), + vec![ + (stake_address, stake_account), + (rent_address, rent_account), + (staker, staker_account), + (withdrawer, withdrawer_account.clone()), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: rent_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: staker, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: withdrawer, + is_signer: true, + is_writable: false, + }, + ], Ok(()), ); // Test AuthorizeChecked with non-signing authority - let authorized_address = Pubkey::new_unique(); let mut instruction = authorize_checked( &stake_address, &authorized_address, @@ -893,8 +943,8 @@ mod tests { None, ); instruction.accounts[3] = AccountMeta::new_readonly(staker, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); @@ -906,51 +956,85 @@ mod tests { None, ); instruction.accounts[3] = AccountMeta::new_readonly(withdrawer, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); // Test AuthorizeChecked with authority signer - let stake_account = Rc::new( - AccountSharedData::new_ref_data_with_space( - 42, - &StakeState::Initialized(Meta::auto(&authorized_address)), - std::mem::size_of::(), - &id(), - ) - .unwrap(), - ); - let clock_address = sysvar::clock::id(); - let clock_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &Clock::default(), - ))); - let authorized_account = create_default_account(); - let new_authorized_account = create_default_account(); - - let mut keyed_accounts = [ - (false, false, stake_address, stake_account), - (false, false, clock_address, clock_account.clone()), - (true, false, authorized_address, authorized_account.clone()), - (true, false, staker, new_authorized_account.clone()), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::AuthorizeChecked(StakeAuthorize::Staker)).unwrap(), - &keyed_accounts, - ), + let stake_account = AccountSharedData::new_data_with_space( + 42, + &StakeState::Initialized(Meta::auto(&authorized_address)), + std::mem::size_of::(), + &id(), + ) + .unwrap(); + process_instruction( + &serialize(&StakeInstruction::AuthorizeChecked(StakeAuthorize::Staker)).unwrap(), + vec![ + (stake_address, stake_account.clone()), + (clock_address, clock_account.clone()), + (authorized_address, authorized_account.clone()), + (staker, new_authorized_account.clone()), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: clock_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: authorized_address, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: staker, + is_signer: true, + is_writable: false, + }, + ], Ok(()), ); - keyed_accounts[3] = (true, false, withdrawer, new_authorized_account.clone()); - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::AuthorizeChecked( - StakeAuthorize::Withdrawer - )) - .unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::AuthorizeChecked( + StakeAuthorize::Withdrawer, + )) + .unwrap(), + vec![ + (stake_address, stake_account), + (clock_address, clock_account.clone()), + (authorized_address, authorized_account.clone()), + (withdrawer, new_authorized_account.clone()), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: clock_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: authorized_address, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: withdrawer, + is_signer: true, + is_writable: false, + }, + ], Ok(()), ); @@ -969,8 +1053,8 @@ mod tests { None, ); instruction.accounts[3] = AccountMeta::new_readonly(staker, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); @@ -984,60 +1068,100 @@ mod tests { None, ); instruction.accounts[3] = AccountMeta::new_readonly(staker, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); // Test AuthorizeCheckedWithSeed with authority signer - let stake_account = Rc::new( - AccountSharedData::new_ref_data_with_space( - 42, - &StakeState::Initialized(Meta::auto(&address_with_seed)), - std::mem::size_of::(), - &id(), - ) + let stake_account = AccountSharedData::new_data_with_space( + 42, + &StakeState::Initialized(Meta::auto(&address_with_seed)), + std::mem::size_of::(), + &id(), + ) + .unwrap(); + process_instruction( + &serialize(&StakeInstruction::AuthorizeCheckedWithSeed( + AuthorizeCheckedWithSeedArgs { + stake_authorize: StakeAuthorize::Staker, + authority_seed: seed.to_string(), + authority_owner: authorized_owner, + }, + )) .unwrap(), - ); - let mut keyed_accounts = [ - (false, false, address_with_seed, stake_account), - (true, false, authorized_owner, authorized_account), - (false, false, clock_address, clock_account), - (true, false, staker, new_authorized_account.clone()), - ]; - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::AuthorizeCheckedWithSeed( - AuthorizeCheckedWithSeedArgs { - stake_authorize: StakeAuthorize::Staker, - authority_seed: seed.to_string(), - authority_owner: authorized_owner, - } - )) - .unwrap(), - &keyed_accounts, - ), + vec![ + (address_with_seed, stake_account.clone()), + (authorized_owner, authorized_account.clone()), + (clock_address, clock_account.clone()), + (staker, new_authorized_account.clone()), + ], + vec![ + AccountMeta { + pubkey: address_with_seed, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: authorized_owner, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: clock_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: staker, + is_signer: true, + is_writable: false, + }, + ], Ok(()), ); - keyed_accounts[3] = (true, false, withdrawer, new_authorized_account); - assert_eq!( - process_instruction( - &serialize(&StakeInstruction::AuthorizeCheckedWithSeed( - AuthorizeCheckedWithSeedArgs { - stake_authorize: StakeAuthorize::Withdrawer, - authority_seed: seed.to_string(), - authority_owner: authorized_owner, - } - )) - .unwrap(), - &keyed_accounts, - ), + process_instruction( + &serialize(&StakeInstruction::AuthorizeCheckedWithSeed( + AuthorizeCheckedWithSeedArgs { + stake_authorize: StakeAuthorize::Withdrawer, + authority_seed: seed.to_string(), + authority_owner: authorized_owner, + }, + )) + .unwrap(), + vec![ + (address_with_seed, stake_account), + (authorized_owner, authorized_account), + (clock_address, clock_account), + (withdrawer, new_authorized_account), + ], + vec![ + AccountMeta { + pubkey: address_with_seed, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: authorized_owner, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: clock_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: withdrawer, + is_signer: true, + is_writable: false, + }, + ], Ok(()), ); // Test SetLockupChecked with non-signing lockup custodian - let custodian = Pubkey::new_unique(); let mut instruction = set_lockup_checked( &stake_address, &LockupArgs { @@ -1048,48 +1172,51 @@ mod tests { &withdrawer, ); instruction.accounts[2] = AccountMeta::new_readonly(custodian, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); // Test SetLockupChecked with lockup custodian signer - let stake_account = Rc::new( - AccountSharedData::new_ref_data_with_space( - 42, - &StakeState::Initialized(Meta::auto(&withdrawer)), - std::mem::size_of::(), - &id(), - ) - .unwrap(), - ); - let custodian_account = create_default_account(); + let stake_account = AccountSharedData::new_data_with_space( + 42, + &StakeState::Initialized(Meta::auto(&withdrawer)), + std::mem::size_of::(), + &id(), + ) + .unwrap(); - let keyed_accounts = [ - (false, false, stake_address, stake_account), - (true, false, withdrawer, withdrawer_account), - (true, false, custodian, custodian_account), - ]; - let mut preparation = prepare_mock_invoke_context(&[], &instruction.data, &keyed_accounts); - let processor_account = AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id()); - let program_indices = vec![preparation.accounts.len()]; - preparation.accounts.push((id(), processor_account)); let mut data = Vec::with_capacity(sysvar::clock::Clock::size_of()); bincode::serialize_into(&mut data, &sysvar::clock::Clock::default()).unwrap(); - let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]); - let sysvars = [(sysvar::clock::id(), data)]; - invoke_context.sysvars = &sysvars; - invoke_context - .push( - &preparation.message, - &preparation.message.instructions[0], - &program_indices, - &preparation.account_indices, - ) - .unwrap(); - assert_eq!( - super::process_instruction(1, &instruction.data, &mut invoke_context), + mock_process_instruction_with_sysvars( + &id(), + Vec::new(), + &instruction.data, + vec![ + (stake_address, stake_account), + (withdrawer, withdrawer_account), + (custodian, custodian_account), + ], + vec![ + AccountMeta { + pubkey: stake_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: withdrawer, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: custodian, + is_signer: true, + is_writable: false, + }, + ], Ok(()), + &[(sysvar::clock::id(), data)], + super::process_instruction, ); } } diff --git a/programs/vote/src/vote_instruction.rs b/programs/vote/src/vote_instruction.rs index 2e114cbfa..817d2a54e 100644 --- a/programs/vote/src/vote_instruction.rs +++ b/programs/vote/src/vote_instruction.rs @@ -518,66 +518,67 @@ mod tests { use { super::*, bincode::serialize, - solana_program_runtime::invoke_context::mock_process_instruction, + solana_program_runtime::invoke_context::{ + mock_process_instruction, mock_process_instruction_with_sysvars, + }, solana_sdk::{ account::{self, Account, AccountSharedData}, rent::Rent, }, - std::{cell::RefCell, rc::Rc, str::FromStr}, + std::str::FromStr, }; - fn create_default_account() -> Rc> { - AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()) + fn create_default_account() -> AccountSharedData { + AccountSharedData::new(0, 0, &Pubkey::new_unique()) } fn process_instruction( instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], - ) -> Result<(), InstructionError> { + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, + ) -> Vec { mock_process_instruction( &id(), Vec::new(), instruction_data, - keyed_accounts, + transaction_accounts, + instruction_accounts, + expected_result, super::process_instruction, ) } - fn process_instruction_as_one_arg(instruction: &Instruction) -> Result<(), InstructionError> { - let mut accounts: Vec<_> = instruction + fn process_instruction_as_one_arg( + instruction: &Instruction, + expected_result: Result<(), InstructionError>, + ) -> Vec { + let transaction_accounts: Vec<_> = instruction .accounts .iter() .map(|meta| { - Rc::new(RefCell::new(if sysvar::clock::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&Clock::default()) - } else if sysvar::slot_hashes::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&SlotHashes::default()) - } else if sysvar::rent::check_id(&meta.pubkey) { - account::create_account_shared_data_for_test(&Rent::free()) - } else if meta.pubkey == invalid_vote_state_pubkey() { - AccountSharedData::from(Account { - owner: invalid_vote_state_pubkey(), - ..Account::default() - }) - } else { - AccountSharedData::from(Account { - owner: id(), - ..Account::default() - }) - })) + ( + meta.pubkey, + if sysvar::clock::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test(&Clock::default()) + } else if sysvar::slot_hashes::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test(&SlotHashes::default()) + } else if sysvar::rent::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test(&Rent::free()) + } else if meta.pubkey == invalid_vote_state_pubkey() { + AccountSharedData::from(Account { + owner: invalid_vote_state_pubkey(), + ..Account::default() + }) + } else { + AccountSharedData::from(Account { + owner: id(), + ..Account::default() + }) + }, + ) }) .collect(); - #[allow(clippy::same_item_push)] - for _ in 0..instruction.accounts.len() { - accounts.push(AccountSharedData::new_ref(0, 0, &Pubkey::new_unique())); - } - let keyed_accounts: Vec<_> = instruction - .accounts - .iter() - .zip(accounts.into_iter()) - .map(|(meta, account)| (meta.is_signer, meta.is_writable, meta.pubkey, account)) - .collect(); - let rent = Rent::default(); let rent_sysvar = (sysvar::rent::id(), bincode::serialize(&rent).unwrap()); let clock = Clock::default(); @@ -587,11 +588,13 @@ mod tests { sysvar::slot_hashes::id(), bincode::serialize(&slot_hashes).unwrap(), ); - solana_program_runtime::invoke_context::mock_process_instruction_with_sysvars( + mock_process_instruction_with_sysvars( &id(), Vec::new(), &instruction.data, - &keyed_accounts, + transaction_accounts, + instruction.accounts.clone(), + expected_result, &[rent_sysvar, clock_sysvar, slot_hashes_sysvar], super::process_instruction, ) @@ -604,28 +607,30 @@ mod tests { // these are for 100% coverage in this file #[test] fn test_vote_process_instruction_decode_bail() { - assert_eq!( - process_instruction(&[], &[]), + process_instruction( + &[], + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_spoofed_vote() { - assert_eq!( - process_instruction_as_one_arg(&vote( + process_instruction_as_one_arg( + &vote( &invalid_vote_state_pubkey(), &Pubkey::new_unique(), Vote::default(), - )), + ), Err(InstructionError::InvalidAccountOwner), ); - assert_eq!( - process_instruction_as_one_arg(&update_vote_state( + process_instruction_as_one_arg( + &update_vote_state( &invalid_vote_state_pubkey(), &Pubkey::default(), VoteStateUpdate::default(), - )), + ), Err(InstructionError::InvalidAccountOwner), ); } @@ -639,79 +644,72 @@ mod tests { &VoteInit::default(), 101, ); - assert_eq!( - process_instruction_as_one_arg(&instructions[1]), - Err(InstructionError::InvalidAccountData), - ); - assert_eq!( - process_instruction_as_one_arg(&vote( + process_instruction_as_one_arg(&instructions[1], Err(InstructionError::InvalidAccountData)); + process_instruction_as_one_arg( + &vote( &Pubkey::new_unique(), &Pubkey::new_unique(), Vote::default(), - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&vote_switch( + process_instruction_as_one_arg( + &vote_switch( &Pubkey::new_unique(), &Pubkey::new_unique(), Vote::default(), Hash::default(), - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&authorize( + process_instruction_as_one_arg( + &authorize( &Pubkey::new_unique(), &Pubkey::new_unique(), &Pubkey::new_unique(), VoteAuthorize::Voter, - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&update_vote_state( + process_instruction_as_one_arg( + &update_vote_state( &Pubkey::default(), &Pubkey::default(), VoteStateUpdate::default(), - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&update_vote_state_switch( + process_instruction_as_one_arg( + &update_vote_state_switch( &Pubkey::default(), &Pubkey::default(), VoteStateUpdate::default(), Hash::default(), - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&update_validator_identity( + process_instruction_as_one_arg( + &update_validator_identity( &Pubkey::new_unique(), &Pubkey::new_unique(), &Pubkey::new_unique(), - )), + ), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&update_commission( - &Pubkey::new_unique(), - &Pubkey::new_unique(), - 0, - )), + process_instruction_as_one_arg( + &update_commission(&Pubkey::new_unique(), &Pubkey::new_unique(), 0), Err(InstructionError::InvalidAccountData), ); - assert_eq!( - process_instruction_as_one_arg(&withdraw( + process_instruction_as_one_arg( + &withdraw( &Pubkey::new_unique(), &Pubkey::new_unique(), 0, - &Pubkey::new_unique() - )), + &Pubkey::new_unique(), + ), Err(InstructionError::InvalidAccountData), ); } @@ -730,10 +728,7 @@ mod tests { VoteAuthorize::Voter, ); instruction.accounts = instruction.accounts[0..2].to_vec(); - assert_eq!( - process_instruction_as_one_arg(&instruction), - Err(InstructionError::NotEnoughAccountKeys), - ); + process_instruction_as_one_arg(&instruction, Err(InstructionError::NotEnoughAccountKeys)); let mut instruction = authorize_checked( &vote_pubkey, @@ -742,10 +737,7 @@ mod tests { VoteAuthorize::Withdrawer, ); instruction.accounts = instruction.accounts[0..2].to_vec(); - assert_eq!( - process_instruction_as_one_arg(&instruction), - Err(InstructionError::NotEnoughAccountKeys), - ); + process_instruction_as_one_arg(&instruction, Err(InstructionError::NotEnoughAccountKeys)); // Test with non-signing new_authorized_pubkey let mut instruction = authorize_checked( @@ -755,8 +747,8 @@ mod tests { VoteAuthorize::Voter, ); instruction.accounts[3] = AccountMeta::new_readonly(new_authorized_pubkey, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); @@ -767,43 +759,60 @@ mod tests { VoteAuthorize::Withdrawer, ); instruction.accounts[3] = AccountMeta::new_readonly(new_authorized_pubkey, false); - assert_eq!( - process_instruction_as_one_arg(&instruction), + process_instruction_as_one_arg( + &instruction, Err(InstructionError::MissingRequiredSignature), ); // Test with new_authorized_pubkey signer - let vote_account = AccountSharedData::new_ref(100, VoteState::size_of(), &id()); + let vote_account = AccountSharedData::new(100, VoteState::size_of(), &id()); let clock_address = sysvar::clock::id(); - let clock_account = Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &Clock::default(), - ))); + let clock_account = account::create_account_shared_data_for_test(&Clock::default()); let default_authorized_pubkey = Pubkey::default(); let authorized_account = create_default_account(); let new_authorized_account = create_default_account(); - let keyed_accounts = [ - (false, false, vote_pubkey, vote_account), - (false, false, clock_address, clock_account), - (true, false, default_authorized_pubkey, authorized_account), - (true, false, new_authorized_pubkey, new_authorized_account), + let transaction_accounts = vec![ + (vote_pubkey, vote_account), + (clock_address, clock_account), + (default_authorized_pubkey, authorized_account), + (new_authorized_pubkey, new_authorized_account), ]; - assert_eq!( - process_instruction( - &serialize(&VoteInstruction::AuthorizeChecked(VoteAuthorize::Voter)).unwrap(), - &keyed_accounts, - ), - Ok(()) + let instruction_accounts = vec![ + AccountMeta { + pubkey: vote_pubkey, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: clock_address, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: default_authorized_pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: new_authorized_pubkey, + is_signer: true, + is_writable: false, + }, + ]; + process_instruction( + &serialize(&VoteInstruction::AuthorizeChecked(VoteAuthorize::Voter)).unwrap(), + transaction_accounts.clone(), + instruction_accounts.clone(), + Ok(()), ); - - assert_eq!( - process_instruction( - &serialize(&VoteInstruction::AuthorizeChecked( - VoteAuthorize::Withdrawer - )) - .unwrap(), - &keyed_accounts, - ), - Ok(()) + process_instruction( + &serialize(&VoteInstruction::AuthorizeChecked( + VoteAuthorize::Withdrawer, + )) + .unwrap(), + transaction_accounts, + instruction_accounts, + Ok(()), ); } diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index ee40c6e5b..47af3bfbe 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -14,7 +14,9 @@ use { verifier::check, vm::{Config, DynamicAnalysis}, }, - solana_sdk::{account::AccountSharedData, bpf_loader, pubkey::Pubkey}, + solana_sdk::{ + account::AccountSharedData, bpf_loader, instruction::AccountMeta, pubkey::Pubkey, + }, std::{ fs::File, io::{Read, Seek, SeekFrom}, @@ -162,51 +164,57 @@ native machine code before execting it in the virtual machine.", ..Config::default() }; let loader_id = bpf_loader::id(); - let mut keyed_accounts = vec![ + let mut transaction_accounts = vec![ ( - false, - false, loader_id, - AccountSharedData::new_ref(0, 0, &solana_sdk::native_loader::id()), + AccountSharedData::new(0, 0, &solana_sdk::native_loader::id()), ), ( - false, - false, Pubkey::new_unique(), - AccountSharedData::new_ref(0, 0, &loader_id), + AccountSharedData::new(0, 0, &loader_id), ), ]; + let mut instruction_accounts = Vec::new(); let instruction_data = match matches.value_of("input").unwrap().parse::() { Ok(allocation_size) => { - keyed_accounts.push(( - false, - true, - Pubkey::new_unique(), - AccountSharedData::new_ref(0, allocation_size, &Pubkey::new_unique()), + let pubkey = Pubkey::new_unique(); + transaction_accounts.push(( + pubkey, + AccountSharedData::new(0, allocation_size, &Pubkey::new_unique()), )); + instruction_accounts.push(AccountMeta { + pubkey, + is_signer: false, + is_writable: true, + }); vec![] } Err(_) => { let input = load_accounts(Path::new(matches.value_of("input").unwrap())).unwrap(); - for account in input.accounts { - let account_refcell = AccountSharedData::new_ref( - account.lamports, - account.data.len(), - &account.owner, + for account_info in input.accounts { + let mut account = AccountSharedData::new( + account_info.lamports, + account_info.data.len(), + &account_info.owner, ); - account_refcell.borrow_mut().set_data(account.data); - keyed_accounts.push(( - account.is_signer, - account.is_writable, - account.key, - account_refcell, - )); + account.set_data(account_info.data); + instruction_accounts.push(AccountMeta { + pubkey: account_info.key, + is_signer: account_info.is_signer, + is_writable: account_info.is_writable, + }); + transaction_accounts.push((account_info.key, account)); } input.instruction_data } }; let program_indices = [0, 1]; - let preparation = prepare_mock_invoke_context(&program_indices, &[], &keyed_accounts); + let preparation = prepare_mock_invoke_context( + &program_indices, + &[], + transaction_accounts, + instruction_accounts, + ); let mut invoke_context = InvokeContext::new_mock(&preparation.accounts, &[]); invoke_context .push( diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 4b783ce99..a3bcdf7a5 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -3403,11 +3403,10 @@ impl Bank { /// Converts Accounts into RefCell, this involves moving /// ownership by draining the source fn accounts_to_refcells(accounts: &mut TransactionAccounts) -> TransactionAccountRefCells { - let account_refcells: Vec<_> = accounts + accounts .drain(..) - .map(|(pubkey, account)| (pubkey, Rc::new(RefCell::new(account)))) - .collect(); - account_refcells + .map(|(pubkey, account)| (pubkey, RefCell::new(account))) + .collect() } /// Converts back from RefCell to AccountSharedData, this involves moving @@ -3415,17 +3414,10 @@ impl Bank { fn refcells_to_accounts( accounts: &mut TransactionAccounts, mut account_refcells: TransactionAccountRefCells, - ) -> std::result::Result<(), TransactionError> { + ) { for (pubkey, account_refcell) in account_refcells.drain(..) { - accounts.push(( - pubkey, - Rc::try_unwrap(account_refcell) - .map_err(|_| TransactionError::AccountBorrowOutstanding)? - .into_inner(), - )) + accounts.push((pubkey, account_refcell.into_inner())) } - - Ok(()) } /// Get any cached executors needed by the transaction @@ -3641,13 +3633,10 @@ impl Bank { }); inner_instructions.push(inner_instruction_list); - if let Err(e) = Self::refcells_to_accounts( + Self::refcells_to_accounts( &mut loaded_transaction.accounts, account_refcells, - ) { - warn!("Account lifetime mismanagement"); - process_result = Err(e); - } + ); if process_result.is_ok() { self.update_executors(executors); diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index b249b09c8..1009e66ed 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -202,19 +202,19 @@ mod tests { process_instruction: mock_system_process_instruction, }]; - let program_account = Rc::new(RefCell::new(create_loadable_account_for_test( - "mock_system_program", - ))); let accounts = vec![ ( solana_sdk::pubkey::new_rand(), - AccountSharedData::new_ref(100, 1, &mock_system_program_id), + RefCell::new(AccountSharedData::new(100, 1, &mock_system_program_id)), ), ( solana_sdk::pubkey::new_rand(), - AccountSharedData::new_ref(0, 1, &mock_system_program_id), + RefCell::new(AccountSharedData::new(0, 1, &mock_system_program_id)), + ), + ( + mock_system_program_id, + RefCell::new(create_loadable_account_for_test("mock_system_program")), ), - (mock_system_program_id, program_account), ]; let program_indices = vec![vec![2]]; @@ -406,19 +406,19 @@ mod tests { process_instruction: mock_system_process_instruction, }]; - let program_account = Rc::new(RefCell::new(create_loadable_account_for_test( - "mock_system_program", - ))); let accounts = vec![ ( solana_sdk::pubkey::new_rand(), - AccountSharedData::new_ref(100, 1, &mock_program_id), + RefCell::new(AccountSharedData::new(100, 1, &mock_program_id)), ), ( solana_sdk::pubkey::new_rand(), - AccountSharedData::new_ref(0, 1, &mock_program_id), + RefCell::new(AccountSharedData::new(0, 1, &mock_program_id)), + ), + ( + mock_program_id, + RefCell::new(create_loadable_account_for_test("mock_system_program")), ), - (mock_program_id, program_account), ]; let program_indices = vec![vec![2]]; @@ -539,13 +539,13 @@ mod tests { process_instruction: mock_process_instruction, }]; - let secp256k1_account = AccountSharedData::new_ref(1, 0, &native_loader::id()); - secp256k1_account.borrow_mut().set_executable(true); - let mock_program_account = AccountSharedData::new_ref(1, 0, &native_loader::id()); - mock_program_account.borrow_mut().set_executable(true); + let mut secp256k1_account = AccountSharedData::new(1, 0, &native_loader::id()); + secp256k1_account.set_executable(true); + let mut mock_program_account = AccountSharedData::new(1, 0, &native_loader::id()); + mock_program_account.set_executable(true); let accounts = vec![ - (secp256k1_program::id(), secp256k1_account), - (mock_program_id, mock_program_account), + (secp256k1_program::id(), RefCell::new(secp256k1_account)), + (mock_program_id, RefCell::new(mock_program_account)), ]; let message = Message::new( diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index 5161af784..c1de986fd 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -508,7 +508,7 @@ mod tests { crate::{bank::Bank, bank_client::BankClient}, bincode::serialize, solana_program_runtime::invoke_context::{mock_process_instruction, InvokeContext}, - std::{cell::RefCell, rc::Rc, sync::Arc}, + std::{cell::RefCell, sync::Arc}, }; impl From for Address { @@ -522,33 +522,33 @@ mod tests { fn process_instruction( instruction_data: &[u8], - keyed_accounts: &[(bool, bool, Pubkey, Rc>)], - ) -> Result<(), InstructionError> { + transaction_accounts: Vec<(Pubkey, AccountSharedData)>, + instruction_accounts: Vec, + expected_result: Result<(), InstructionError>, + ) -> Vec { mock_process_instruction( &system_program::id(), Vec::new(), instruction_data, - keyed_accounts, + transaction_accounts, + instruction_accounts, + expected_result, super::process_instruction, ) } - fn create_default_account() -> Rc> { - AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()) + fn create_default_account() -> AccountSharedData { + AccountSharedData::new(0, 0, &Pubkey::new_unique()) } - fn create_default_recent_blockhashes_account() -> Rc> { - Rc::new(RefCell::new( - #[allow(deprecated)] - recent_blockhashes_account::create_account_with_data_for_test( - vec![IterItem(0u64, &Hash::default(), 0); sysvar::recent_blockhashes::MAX_ENTRIES] - .into_iter(), - ), - )) + fn create_default_recent_blockhashes_account() -> AccountSharedData { + #[allow(deprecated)] + recent_blockhashes_account::create_account_with_data_for_test( + vec![IterItem(0u64, &Hash::default(), 0); sysvar::recent_blockhashes::MAX_ENTRIES] + .into_iter(), + ) } - fn create_default_rent_account() -> Rc> { - Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &Rent::free(), - ))) + fn create_default_rent_account() -> AccountSharedData { + account::create_account_shared_data_for_test(&Rent::free()) } #[test] @@ -556,28 +556,35 @@ mod tests { let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); let to = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); - let to_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let from_account = AccountSharedData::new(100, 0, &system_program::id()); + let to_account = AccountSharedData::new(0, 0, &Pubkey::default()); - assert_eq!( - process_instruction( - &bincode::serialize(&SystemInstruction::CreateAccount { - lamports: 50, - space: 2, - owner: new_owner - }) - .unwrap(), - &[ - (true, false, from, from_account.clone()), - (true, false, to, to_account.clone()), - ], - ), - Ok(()) + let accounts = process_instruction( + &bincode::serialize(&SystemInstruction::CreateAccount { + lamports: 50, + space: 2, + owner: new_owner, + }) + .unwrap(), + vec![(from, from_account), (to, to_account)], + vec![ + AccountMeta { + pubkey: from, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: to, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); - assert_eq!(from_account.borrow().lamports(), 50); - assert_eq!(to_account.borrow().lamports(), 50); - assert_eq!(to_account.borrow().owner(), &new_owner); - assert_eq!(to_account.borrow().data(), &[0, 0]); + assert_eq!(accounts[0].lamports(), 50); + assert_eq!(accounts[1].lamports(), 50); + assert_eq!(accounts[1].owner(), &new_owner); + assert_eq!(accounts[1].data(), &[0, 0]); } #[test] @@ -586,30 +593,37 @@ mod tests { let from = Pubkey::new_unique(); let seed = "shiny pepper"; let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); - let to_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let from_account = AccountSharedData::new(100, 0, &system_program::id()); + let to_account = AccountSharedData::new(0, 0, &Pubkey::default()); - assert_eq!( - process_instruction( - &bincode::serialize(&SystemInstruction::CreateAccountWithSeed { - base: from, - seed: seed.to_string(), - lamports: 50, - space: 2, - owner: new_owner - }) - .unwrap(), - &[ - (true, false, from, from_account.clone()), - (false, false, to, to_account.clone()), - ], - ), - Ok(()) + let accounts = process_instruction( + &bincode::serialize(&SystemInstruction::CreateAccountWithSeed { + base: from, + seed: seed.to_string(), + lamports: 50, + space: 2, + owner: new_owner, + }) + .unwrap(), + vec![(from, from_account), (to, to_account)], + vec![ + AccountMeta { + pubkey: from, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: to, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); - assert_eq!(from_account.borrow().lamports(), 50); - assert_eq!(to_account.borrow().lamports(), 50); - assert_eq!(to_account.borrow().owner(), &new_owner); - assert_eq!(to_account.borrow().data(), &[0, 0]); + assert_eq!(accounts[0].lamports(), 50); + assert_eq!(accounts[1].lamports(), 50); + assert_eq!(accounts[1].owner(), &new_owner); + assert_eq!(accounts[1].data(), &[0, 0]); } #[test] @@ -619,32 +633,43 @@ mod tests { let base = Pubkey::new_unique(); let seed = "shiny pepper"; let to = Pubkey::create_with_seed(&base, seed, &new_owner).unwrap(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); - let to_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); - let base_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let from_account = AccountSharedData::new(100, 0, &system_program::id()); + let to_account = AccountSharedData::new(0, 0, &Pubkey::default()); + let base_account = AccountSharedData::new(0, 0, &Pubkey::default()); - assert_eq!( - process_instruction( - &bincode::serialize(&SystemInstruction::CreateAccountWithSeed { - base, - seed: seed.to_string(), - lamports: 50, - space: 2, - owner: new_owner - }) - .unwrap(), - &[ - (true, false, from, from_account.clone()), - (false, false, to, to_account.clone()), - (true, false, base, base_account), - ], - ), - Ok(()) + let accounts = process_instruction( + &bincode::serialize(&SystemInstruction::CreateAccountWithSeed { + base, + seed: seed.to_string(), + lamports: 50, + space: 2, + owner: new_owner, + }) + .unwrap(), + vec![(from, from_account), (to, to_account), (base, base_account)], + vec![ + AccountMeta { + pubkey: from, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: to, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: base, + is_signer: true, + is_writable: false, + }, + ], + Ok(()), ); - assert_eq!(from_account.borrow().lamports(), 50); - assert_eq!(to_account.borrow().lamports(), 50); - assert_eq!(to_account.borrow().owner(), &new_owner); - assert_eq!(to_account.borrow().data(), &[0, 0]); + assert_eq!(accounts[0].lamports(), 50); + assert_eq!(accounts[1].lamports(), 50); + assert_eq!(accounts[1].owner(), &new_owner); + assert_eq!(accounts[1].data(), &[0, 0]); } #[test] @@ -669,8 +694,8 @@ mod tests { let seed = "dull boy"; let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); - let to_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); + let to_account = RefCell::new(AccountSharedData::new(0, 0, &Pubkey::default())); let to_address = Address::create(&to, Some((&from, seed, &new_owner)), &invoke_context).unwrap(); @@ -697,10 +722,10 @@ mod tests { // create account with zero lamports transferred let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &Pubkey::new_unique()); // not from system account + let from_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new_unique())); // not from system account let to = Pubkey::new_unique(); - let to_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let to_account = RefCell::new(AccountSharedData::new(0, 0, &Pubkey::default())); assert_eq!( create_account( @@ -731,10 +756,10 @@ mod tests { // Attempt to create account with more lamports than remaining in from_account let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let to = Pubkey::new_unique(); - let to_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let to_account = RefCell::new(AccountSharedData::new(0, 0, &Pubkey::default())); let result = create_account( &KeyedAccount::new(&from, true, &from_account), @@ -752,9 +777,9 @@ mod tests { #[test] fn test_request_more_than_allowed_data_length() { let invoke_context = InvokeContext::new_mock(&[], &[]); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let from = Pubkey::new_unique(); - let to_account = AccountSharedData::new_ref(0, 0, &system_program::id()); + let to_account = RefCell::new(AccountSharedData::new(0, 0, &system_program::id())); let to = Pubkey::new_unique(); let signers = &[from, to].iter().cloned().collect::>(); @@ -802,11 +827,11 @@ mod tests { // Attempt to create system account in account already owned by another program let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let original_program_owner = Pubkey::new(&[5; 32]); let owned_key = Pubkey::new_unique(); - let owned_account = AccountSharedData::new_ref(0, 0, &original_program_owner); + let owned_account = RefCell::new(AccountSharedData::new(0, 0, &original_program_owner)); let unchanged_account = owned_account.clone(); let signers = &[from, owned_key].iter().cloned().collect::>(); @@ -829,7 +854,7 @@ mod tests { assert_eq!(owned_account, unchanged_account); // Attempt to create system account in account that already has data - let owned_account = AccountSharedData::new_ref(0, 1, &Pubkey::default()); + let owned_account = RefCell::new(AccountSharedData::new(0, 1, &Pubkey::default())); let unchanged_account = owned_account.borrow().clone(); let result = create_account( &KeyedAccount::new(&from, true, &from_account), @@ -847,7 +872,7 @@ mod tests { assert_eq!(*owned_account.borrow(), unchanged_account); // Attempt to create an account that already has lamports - let owned_account = AccountSharedData::new_ref(1, 0, &Pubkey::default()); + let owned_account = RefCell::new(AccountSharedData::new(1, 0, &Pubkey::default())); let unchanged_account = owned_account.borrow().clone(); let result = create_account( &KeyedAccount::new(&from, true, &from_account), @@ -870,10 +895,10 @@ mod tests { // Attempt to create an account without signing the transfer let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let owned_key = Pubkey::new_unique(); - let owned_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let owned_account = RefCell::new(AccountSharedData::new(0, 0, &Pubkey::default())); let owned_address = owned_key.into(); @@ -891,7 +916,7 @@ mod tests { assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); // Haven't signed to account - let owned_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let owned_account = RefCell::new(AccountSharedData::new(0, 0, &Pubkey::default())); let result = create_account( &KeyedAccount::new(&from, true, &from_account), &KeyedAccount::new(&owned_key, true, &owned_account), @@ -905,7 +930,7 @@ mod tests { assert_eq!(result, Err(InstructionError::MissingRequiredSignature)); // Don't support unsigned creation with zero lamports (ephemeral account) - let owned_account = AccountSharedData::new_ref(0, 0, &Pubkey::default()); + let owned_account = RefCell::new(AccountSharedData::new(0, 0, &Pubkey::default())); let result = create_account( &KeyedAccount::new(&from, false, &from_account), &KeyedAccount::new(&owned_key, true, &owned_account), @@ -924,10 +949,10 @@ mod tests { let invoke_context = InvokeContext::new_mock(&[], &[]); // Attempt to create system account in account already owned by another program let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let to = Pubkey::new_unique(); - let to_account = AccountSharedData::new_ref(0, 0, &system_program::id()); + let to_account = RefCell::new(AccountSharedData::new(0, 0, &system_program::id())); let signers = [from, to].iter().cloned().collect::>(); let to_address = to.into(); @@ -959,10 +984,10 @@ mod tests { invoke_context.feature_set = Arc::new(feature_set); // Attempt to create system account in account already owned by another program let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let to = Pubkey::new_unique(); - let to_account = AccountSharedData::new_ref(0, 0, &system_program::id()); + let to_account = RefCell::new(AccountSharedData::new(0, 0, &system_program::id())); let signers = [from, to].iter().cloned().collect::>(); let to_address = to.into(); @@ -986,14 +1011,13 @@ mod tests { // Attempt to create system account in account with populated data let new_owner = Pubkey::new(&[9; 32]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id())); let populated_key = Pubkey::new_unique(); - let populated_account = AccountSharedData::from(Account { + let populated_account = RefCell::new(AccountSharedData::from(Account { data: vec![0, 1, 2, 3], ..Account::default() - }) - .into(); + })); let signers = [from, populated_key] .iter() @@ -1018,18 +1042,20 @@ mod tests { fn test_create_from_account_is_nonce_fail() { let invoke_context = InvokeContext::new_mock(&[], &[]); let nonce = Pubkey::new_unique(); - let nonce_account = AccountSharedData::new_ref_data( - 42, - &nonce::state::Versions::new_current(nonce::State::Initialized( - nonce::state::Data::default(), - )), - &system_program::id(), - ) - .unwrap(); + let nonce_account = RefCell::new( + AccountSharedData::new_data( + 42, + &nonce::state::Versions::new_current(nonce::State::Initialized( + nonce::state::Data::default(), + )), + &system_program::id(), + ) + .unwrap(), + ); let from = KeyedAccount::new(&nonce, true, &nonce_account); let new = Pubkey::new_unique(); - let new_account = AccountSharedData::new_ref(0, 0, &system_program::id()); + let new_account = RefCell::new(AccountSharedData::new(0, 0, &system_program::id())); let signers = [nonce, new].iter().cloned().collect::>(); let new_address = new.into(); @@ -1080,13 +1106,15 @@ mod tests { Ok(()) ); - let account = Rc::new(RefCell::new(account)); - assert_eq!( - process_instruction( - &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(), - &[(true, false, pubkey, account)], - ), - Ok(()) + process_instruction( + &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(), + vec![(pubkey, account)], + vec![AccountMeta { + pubkey, + is_signer: true, + is_writable: false, + }], + Ok(()), ); } @@ -1143,25 +1171,37 @@ mod tests { owner: Pubkey::new_unique(), }; let data = serialize(&instruction).unwrap(); - let result = process_instruction(&data, &[]); - assert_eq!(result, Err(InstructionError::NotEnoughAccountKeys)); + process_instruction( + &data, + Vec::new(), + Vec::new(), + Err(InstructionError::NotEnoughAccountKeys), + ); // Attempt to transfer with no destination let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &system_program::id()); + let from_account = AccountSharedData::new(100, 0, &system_program::id()); let instruction = SystemInstruction::Transfer { lamports: 0 }; let data = serialize(&instruction).unwrap(); - let result = process_instruction(&data, &[(true, false, from, from_account)]); - assert_eq!(result, Err(InstructionError::NotEnoughAccountKeys)); + process_instruction( + &data, + vec![(from, from_account)], + vec![AccountMeta { + pubkey: from, + is_signer: true, + is_writable: false, + }], + Err(InstructionError::NotEnoughAccountKeys), + ); } #[test] fn test_transfer_lamports() { let invoke_context = InvokeContext::new_mock(&[], &[]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter + let from_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter let to = Pubkey::new(&[3; 32]); - let to_account = AccountSharedData::new_ref(1, 0, &to); // account owner should not matter + let to_account = RefCell::new(AccountSharedData::new(1, 0, &to)); // account owner should not matter let from_keyed_account = KeyedAccount::new(&from, true, &from_account); let to_keyed_account = KeyedAccount::new(&to, false, &to_account); transfer(&from_keyed_account, &to_keyed_account, 50, &invoke_context).unwrap(); @@ -1197,14 +1237,14 @@ mod tests { fn test_transfer_with_seed() { let invoke_context = InvokeContext::new_mock(&[], &[]); let base = Pubkey::new_unique(); - let base_account = AccountSharedData::new_ref(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter + let base_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter let from_base_keyed_account = KeyedAccount::new(&base, true, &base_account); let from_seed = "42"; let from_owner = system_program::id(); let from = Pubkey::create_with_seed(&base, from_seed, &from_owner).unwrap(); - let from_account = AccountSharedData::new_ref(100, 0, &Pubkey::new(&[2; 32])); // account owner should not matter + let from_account = RefCell::new(AccountSharedData::new(100, 0, &Pubkey::new(&[2; 32]))); // account owner should not matter let to = Pubkey::new(&[3; 32]); - let to_account = AccountSharedData::new_ref(1, 0, &to); // account owner should not matter + let to_account = RefCell::new(AccountSharedData::new(1, 0, &to)); // account owner should not matter let from_keyed_account = KeyedAccount::new(&from, true, &from_account); let to_keyed_account = KeyedAccount::new(&to, false, &to_account); transfer_with_seed( @@ -1257,22 +1297,26 @@ mod tests { fn test_transfer_lamports_from_nonce_account_fail() { let invoke_context = InvokeContext::new_mock(&[], &[]); let from = Pubkey::new_unique(); - let from_account = AccountSharedData::new_ref_data( - 100, - &nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { - authority: from, - ..nonce::state::Data::default() - })), - &system_program::id(), - ) - .unwrap(); + let from_account = RefCell::new( + AccountSharedData::new_data( + 100, + &nonce::state::Versions::new_current(nonce::State::Initialized( + nonce::state::Data { + authority: from, + ..nonce::state::Data::default() + }, + )), + &system_program::id(), + ) + .unwrap(), + ); assert_eq!( get_system_account_kind(&from_account.borrow()), Some(SystemAccountKind::Nonce) ); let to = Pubkey::new(&[3; 32]); - let to_account = AccountSharedData::new_ref(1, 0, &to); // account owner should not matter + let to_account = RefCell::new(AccountSharedData::new(1, 0, &to)); // account owner should not matter assert_eq!( transfer( &KeyedAccount::new(&from, true, &from_account), @@ -1463,78 +1507,92 @@ mod tests { assert_eq!(bank_client.get_balance(&mallory_pubkey).unwrap(), 50); } - fn process_nonce_instruction(instruction: &Instruction) -> Result<(), InstructionError> { - let accounts = instruction.accounts.iter().map(|meta| { - #[allow(deprecated)] - if sysvar::recent_blockhashes::check_id(&meta.pubkey) { - create_default_recent_blockhashes_account() - } else if sysvar::rent::check_id(&meta.pubkey) { - Rc::new(RefCell::new(account::create_account_shared_data_for_test( - &Rent::free(), - ))) - } else { - AccountSharedData::new_ref(0, 0, &Pubkey::new_unique()) - } - }); - let keyed_accounts: Vec<_> = instruction + fn process_nonce_instruction( + instruction: Instruction, + expected_result: Result<(), InstructionError>, + ) -> Vec { + let transaction_accounts = instruction .accounts .iter() - .zip(accounts) - .map(|(meta, account)| (meta.is_signer, meta.is_writable, meta.pubkey, account)) + .map(|meta| { + #[allow(deprecated)] + ( + meta.pubkey, + if sysvar::recent_blockhashes::check_id(&meta.pubkey) { + create_default_recent_blockhashes_account() + } else if sysvar::rent::check_id(&meta.pubkey) { + account::create_account_shared_data_for_test(&Rent::free()) + } else { + AccountSharedData::new(0, 0, &Pubkey::new_unique()) + }, + ) + }) .collect(); - process_instruction(&instruction.data, &keyed_accounts) + process_instruction( + &instruction.data, + transaction_accounts, + instruction.accounts, + expected_result, + ) } #[test] fn test_process_nonce_ix_no_acc_data_fail() { let none_address = Pubkey::new_unique(); - assert_eq!( - process_nonce_instruction(&system_instruction::advance_nonce_account( - &none_address, - &none_address - )), + process_nonce_instruction( + system_instruction::advance_nonce_account(&none_address, &none_address), Err(InstructionError::InvalidAccountData), ); } #[test] fn test_process_nonce_ix_no_keyed_accs_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), - &[], - ), + process_instruction( + &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_process_nonce_ix_only_nonce_acc_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), - &[(true, true, Pubkey::new_unique(), create_default_account())], - ), + let pubkey = Pubkey::new_unique(); + process_instruction( + &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), + vec![(pubkey, create_default_account())], + vec![AccountMeta { + pubkey, + is_signer: true, + is_writable: true, + }], Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_process_nonce_ix_bad_recent_blockhash_state_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), - &[ - (true, true, Pubkey::new_unique(), create_default_account()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_account(), - ), - ], - ), + let pubkey = Pubkey::new_unique(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), + vec![ + (pubkey, create_default_account()), + (blockhash_id, create_default_account()), + ], + vec![ + AccountMeta { + pubkey, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } @@ -1542,252 +1600,315 @@ mod tests { #[test] fn test_process_nonce_ix_ok() { let nonce_address = Pubkey::new_unique(); - let nonce_account = Rc::new(nonce_account::create_account(1_000_000)); - process_instruction( + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + let accounts = process_instruction( &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), - &[ - (true, true, nonce_address, nonce_account.clone()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - ( - false, - false, - sysvar::rent::id(), - create_default_rent_account(), - ), + vec![ + (nonce_address, nonce_account), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_rent_account()), ], - ) - .unwrap(); + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], + Ok(()), + ); let blockhash = hash(&serialize(&0).unwrap()); #[allow(deprecated)] - let new_recent_blockhashes_account = Rc::new(RefCell::new( + let new_recent_blockhashes_account = solana_sdk::recent_blockhashes_account::create_account_with_data_for_test( vec![IterItem(0u64, &blockhash, 0); sysvar::recent_blockhashes::MAX_ENTRIES] .into_iter(), - ), - )); - #[allow(deprecated)] - let blockhash_id = sysvar::recent_blockhashes::id(); - let keyed_accounts = [ - (true, true, nonce_address, nonce_account), - (false, false, blockhash_id, new_recent_blockhashes_account), - ]; - assert_eq!( - mock_process_instruction( - &system_program::id(), - Vec::new(), - &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), - &keyed_accounts, - |first_instruction_account: usize, - instruction_data: &[u8], - invoke_context: &mut InvokeContext| { - invoke_context.blockhash = hash(&serialize(&0).unwrap()); - super::process_instruction( - first_instruction_account, - instruction_data, - invoke_context, - ) + ); + mock_process_instruction( + &system_program::id(), + Vec::new(), + &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), + vec![ + (nonce_address, accounts[0].clone()), + (blockhash_id, new_recent_blockhashes_account), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, }, - ), + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + ], Ok(()), + |first_instruction_account: usize, + instruction_data: &[u8], + invoke_context: &mut InvokeContext| { + invoke_context.blockhash = hash(&serialize(&0).unwrap()); + super::process_instruction( + first_instruction_account, + instruction_data, + invoke_context, + ) + }, ); } #[test] fn test_process_withdraw_ix_no_acc_data_fail() { let nonce_address = Pubkey::new_unique(); - assert_eq!( - process_nonce_instruction(&system_instruction::withdraw_nonce_account( + process_nonce_instruction( + system_instruction::withdraw_nonce_account( &nonce_address, &Pubkey::new_unique(), &nonce_address, 1, - )), + ), Err(InstructionError::InvalidAccountData), ); } #[test] fn test_process_withdraw_ix_no_keyed_accs_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), - &[], - ), + process_instruction( + &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_process_withdraw_ix_only_nonce_acc_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), - &[(true, false, Pubkey::default(), create_default_account())], - ), + let nonce_address = Pubkey::new_unique(); + process_instruction( + &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), + vec![(nonce_address, create_default_account())], + vec![AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }], Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_process_withdraw_ix_bad_recent_blockhash_state_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), - &[ - (true, false, Pubkey::default(), create_default_account()), - (false, false, Pubkey::default(), create_default_account()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_account() - ), - ], - ), + let nonce_address = Pubkey::new_unique(); + let pubkey = Pubkey::new_unique(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), + vec![ + (nonce_address, create_default_account()), + (pubkey, create_default_account()), + (blockhash_id, create_default_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } #[test] fn test_process_withdraw_ix_bad_rent_state_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), - &[ - ( - true, - false, - Pubkey::default(), - Rc::new(nonce_account::create_account(1_000_000)), - ), - (true, false, Pubkey::default(), create_default_account()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - (false, false, sysvar::rent::id(), create_default_account()), - ], - ), + let nonce_address = Pubkey::new_unique(); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + let pubkey = Pubkey::new_unique(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), + vec![ + (nonce_address, nonce_account), + (pubkey, create_default_account()), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } #[test] fn test_process_withdraw_ix_ok() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), - &[ - ( - true, - true, - Pubkey::new_unique(), - Rc::new(nonce_account::create_account(1_000_000)), - ), - (true, false, Pubkey::default(), create_default_account()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - ( - false, - false, - sysvar::rent::id(), - create_default_rent_account() - ), - ], - ), + let nonce_address = Pubkey::new_unique(); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + let pubkey = Pubkey::new_unique(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(), + vec![ + (nonce_address, nonce_account), + (pubkey, create_default_account()), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_rent_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey, + is_signer: true, + is_writable: false, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], Ok(()), ); } #[test] fn test_process_initialize_ix_no_keyed_accs_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), - &[], - ), + process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), + Vec::new(), + Vec::new(), Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_process_initialize_ix_only_nonce_acc_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), - &[( - true, - false, - Pubkey::default(), - Rc::new(nonce_account::create_account(1_000_000)), - )], - ), + let nonce_address = Pubkey::new_unique(); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), + vec![(nonce_address, nonce_account)], + vec![AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }], Err(InstructionError::NotEnoughAccountKeys), ); } #[test] fn test_process_initialize_bad_recent_blockhash_state_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), - &[ - ( - true, - false, - Pubkey::default(), - Rc::new(nonce_account::create_account(1_000_000)), - ), - ( - true, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_account() - ), - ], - ), + let nonce_address = Pubkey::new_unique(); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), + vec![ + (nonce_address, nonce_account), + (blockhash_id, create_default_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } #[test] fn test_process_initialize_ix_bad_rent_state_fail() { - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(), - &[ - ( - true, - false, - Pubkey::default(), - Rc::new(nonce_account::create_account(1_000_000)), - ), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - (false, false, sysvar::rent::id(), create_default_account()), - ], - ), + let nonce_address = Pubkey::new_unique(); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), + vec![ + (nonce_address, nonce_account), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], Err(InstructionError::InvalidArgument), ); } @@ -1795,31 +1916,33 @@ mod tests { #[test] fn test_process_initialize_ix_ok() { let nonce_address = Pubkey::new_unique(); - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), - &[ - ( - true, - true, - nonce_address, - Rc::new(nonce_account::create_account(1_000_000)), - ), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - ( - false, - false, - sysvar::rent::id(), - create_default_rent_account() - ), - ], - ), + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), + vec![ + (nonce_address, nonce_account), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_rent_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], Ok(()), ); } @@ -1827,32 +1950,43 @@ mod tests { #[test] fn test_process_authorize_ix_ok() { let nonce_address = Pubkey::new_unique(); - let nonce_account = Rc::new(nonce_account::create_account(1_000_000)); - process_instruction( + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); + #[allow(deprecated)] + let blockhash_id = sysvar::recent_blockhashes::id(); + let accounts = process_instruction( &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), - &[ - (true, true, nonce_address, nonce_account.clone()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - ( - false, - false, - sysvar::rent::id(), - create_default_rent_account(), - ), + vec![ + (nonce_address, nonce_account), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_rent_account()), ], - ) - .unwrap(); - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::AuthorizeNonceAccount(nonce_address)).unwrap(), - &[(true, true, nonce_address, nonce_account)], - ), + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], + Ok(()), + ); + process_instruction( + &serialize(&SystemInstruction::AuthorizeNonceAccount(nonce_address)).unwrap(), + vec![(nonce_address, accounts[0].clone())], + vec![AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }], Ok(()), ); } @@ -1860,12 +1994,12 @@ mod tests { #[test] fn test_process_authorize_bad_account_data_fail() { let nonce_address = Pubkey::new_unique(); - assert_eq!( - process_nonce_instruction(&system_instruction::authorize_nonce_account( + process_nonce_instruction( + system_instruction::authorize_nonce_account( &nonce_address, &Pubkey::new_unique(), &nonce_address, - )), + ), Err(InstructionError::InvalidAccountData), ); } @@ -1926,91 +2060,110 @@ mod tests { #[test] fn test_nonce_initialize_with_empty_recent_blockhashes_fail() { let nonce_address = Pubkey::new_unique(); - let nonce_account = Rc::new(nonce_account::create_account(1_000_000)); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); #[allow(deprecated)] - let new_recent_blockhashes_account = Rc::new(RefCell::new( + let blockhash_id = sysvar::recent_blockhashes::id(); + #[allow(deprecated)] + let new_recent_blockhashes_account = solana_sdk::recent_blockhashes_account::create_account_with_data_for_test( vec![].into_iter(), - ), - )); - assert_eq!( - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), - &[ - (true, true, nonce_address, nonce_account), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - new_recent_blockhashes_account, - ), - ( - false, - false, - sysvar::rent::id(), - create_default_rent_account() - ), - ], - ), - Err(NonceError::NoRecentBlockhashes.into()) + ); + process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), + vec![ + (nonce_address, nonce_account), + (blockhash_id, new_recent_blockhashes_account), + (sysvar::rent::id(), create_default_rent_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], + Err(NonceError::NoRecentBlockhashes.into()), ); } #[test] fn test_nonce_advance_with_empty_recent_blockhashes_fail() { let nonce_address = Pubkey::new_unique(); - let nonce_account = Rc::new(nonce_account::create_account(1_000_000)); - process_instruction( - &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), - &[ - (true, true, nonce_address, nonce_account.clone()), - ( - false, - false, - #[allow(deprecated)] - sysvar::recent_blockhashes::id(), - create_default_recent_blockhashes_account(), - ), - ( - false, - false, - sysvar::rent::id(), - create_default_rent_account(), - ), - ], - ) - .unwrap(); - #[allow(deprecated)] - let new_recent_blockhashes_account = Rc::new(RefCell::new( - solana_sdk::recent_blockhashes_account::create_account_with_data_for_test( - vec![].into_iter(), - ), - )); + let nonce_account = nonce_account::create_account(1_000_000).into_inner(); #[allow(deprecated)] let blockhash_id = sysvar::recent_blockhashes::id(); - let keyed_accounts = [ - (true, false, nonce_address, nonce_account), - (false, false, blockhash_id, new_recent_blockhashes_account), - ]; - assert_eq!( - mock_process_instruction( - &system_program::id(), - Vec::new(), - &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), - &keyed_accounts, - |first_instruction_account: usize, - instruction_data: &[u8], - invoke_context: &mut InvokeContext| { - invoke_context.blockhash = hash(&serialize(&0).unwrap()); - super::process_instruction( - first_instruction_account, - instruction_data, - invoke_context, - ) + let accounts = process_instruction( + &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(), + vec![ + (nonce_address, nonce_account), + (blockhash_id, create_default_recent_blockhashes_account()), + (sysvar::rent::id(), create_default_rent_account()), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, }, - ), + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + AccountMeta { + pubkey: sysvar::rent::id(), + is_signer: false, + is_writable: false, + }, + ], + Ok(()), + ); + #[allow(deprecated)] + let new_recent_blockhashes_account = + solana_sdk::recent_blockhashes_account::create_account_with_data_for_test( + vec![].into_iter(), + ); + mock_process_instruction( + &system_program::id(), + Vec::new(), + &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(), + vec![ + (nonce_address, accounts[0].clone()), + (blockhash_id, new_recent_blockhashes_account), + ], + vec![ + AccountMeta { + pubkey: nonce_address, + is_signer: true, + is_writable: true, + }, + AccountMeta { + pubkey: blockhash_id, + is_signer: false, + is_writable: false, + }, + ], Err(NonceError::NoRecentBlockhashes.into()), + |first_instruction_account: usize, + instruction_data: &[u8], + invoke_context: &mut InvokeContext| { + invoke_context.blockhash = hash(&serialize(&0).unwrap()); + super::process_instruction( + first_instruction_account, + instruction_data, + invoke_context, + ) + }, ); } }