From 478518308d2fe08ca33f29d99b4478b3b3c4b1c0 Mon Sep 17 00:00:00 2001 From: Jack May Date: Wed, 10 Mar 2021 23:04:00 -0800 Subject: [PATCH] Share RO and Executable accounts within invocations (#15799) --- program-test/src/lib.rs | 5 +- programs/bpf_loader/src/lib.rs | 1 + programs/bpf_loader/src/syscalls.rs | 44 +++++--- runtime/src/bank.rs | 13 +-- runtime/src/message_processor.rs | 153 +++++++++++++++++----------- sdk/src/feature_set.rs | 7 +- sdk/src/keyed_account.rs | 3 +- sdk/src/process_instruction.rs | 4 +- 8 files changed, 145 insertions(+), 85 deletions(-) diff --git a/program-test/src/lib.rs b/program-test/src/lib.rs index 03fdc3712..59cfd35ba 100644 --- a/program-test/src/lib.rs +++ b/program-test/src/lib.rs @@ -247,7 +247,10 @@ impl program_stubs::SyscallStubs for SyscallStubs { rent_epoch: ai.rent_epoch, } } - let executables = vec![(program_id, RefCell::new(ai_to_a(program_account_info)))]; + let executables = vec![( + program_id, + Rc::new(RefCell::new(ai_to_a(program_account_info))), + )]; // Convert AccountInfos into Accounts let mut accounts = vec![]; diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 5e70d6402..54a28af63 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1089,6 +1089,7 @@ mod tests { vec![], &[], &[], + &[], None, BpfComputeBudget { max_units: 1, diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index f4a87849a..4defbfa72 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -16,7 +16,7 @@ use solana_sdk::{ bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, - feature_set::ristretto_mul_syscall_enabled, + feature_set::{cpi_share_ro_and_exec_accounts, ristretto_mul_syscall_enabled}, hash::{Hasher, HASH_BYTES}, ic_msg, instruction::{AccountMeta, Instruction, InstructionError}, @@ -859,6 +859,7 @@ trait SyscallInvokeSigned<'a> { fn translate_accounts( &self, account_keys: &[Pubkey], + caller_write_privileges: &[bool], program_account_index: usize, account_infos_addr: u64, account_infos_len: u64, @@ -930,6 +931,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { fn translate_accounts( &self, account_keys: &[Pubkey], + caller_write_privileges: &[bool], program_account_index: usize, account_infos_addr: u64, account_infos_len: u64, @@ -1027,6 +1029,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { get_translated_accounts( account_keys, + caller_write_privileges, program_account_index, &account_info_keys, account_infos, @@ -1228,6 +1231,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { fn translate_accounts( &self, account_keys: &[Pubkey], + caller_write_privileges: &[bool], program_account_index: usize, account_infos_addr: u64, account_infos_len: u64, @@ -1310,6 +1314,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { get_translated_accounts( account_keys, + caller_write_privileges, program_account_index, &account_info_keys, account_infos, @@ -1395,6 +1400,7 @@ impl<'a> SyscallObject for SyscallInvokeSignedC<'a> { fn get_translated_accounts<'a, T, F>( account_keys: &[Pubkey], + caller_write_privileges: &[bool], program_account_index: usize, account_info_keys: &[&Pubkey], account_infos: &[T], @@ -1416,9 +1422,13 @@ where SyscallError::InstructionError(InstructionError::MissingAccount) })?; - if i == program_account_index || account.borrow().executable { - // Use the known executable - accounts.push(Rc::new(account)); + if i == program_account_index + || account.borrow().executable + || (invoke_context.is_feature_active(&cpi_share_ro_and_exec_accounts::id()) + && !caller_write_privileges[i]) + { + // Use the known account + accounts.push(account); refs.push(None); } else if let Some(account_info) = account_info_keys @@ -1496,11 +1506,12 @@ fn check_authorized_program( Ok(()) } +#[allow(clippy::type_complexity)] fn get_upgradeable_executable( callee_program_id: &Pubkey, - program_account: &RefCell, + program_account: &Rc>, invoke_context: &Ref<&mut dyn InvokeContext>, -) -> Result)>, EbpfError> { +) -> Result>)>, EbpfError> { if program_account.borrow().owner == bpf_loader_upgradeable::id() { match program_account.borrow().state() { Ok(UpgradeableLoaderState::Program { @@ -1541,7 +1552,7 @@ fn call<'a>( signers_seeds_len: u64, memory_mapping: &MemoryMapping, ) -> Result> { - let (message, executables, accounts, account_refs, caller_privileges) = { + let (message, executables, accounts, account_refs, caller_write_privileges) = { let invoke_context = syscall.get_context()?; invoke_context @@ -1573,7 +1584,7 @@ fn call<'a>( &invoke_context, ) .map_err(SyscallError::InstructionError)?; - let caller_privileges = message + let caller_write_privileges = message .account_keys .iter() .map(|key| { @@ -1590,6 +1601,7 @@ fn call<'a>( check_authorized_program(&callee_program_id, &instruction.data)?; let (accounts, account_refs) = syscall.translate_accounts( &message.account_keys, + &caller_write_privileges, callee_program_id_index, account_infos_addr, account_infos_len, @@ -1598,11 +1610,13 @@ fn call<'a>( // Construct executables - let program_account = (**accounts.get(callee_program_id_index).ok_or_else(|| { - ic_msg!(invoke_context, "Unknown program {}", callee_program_id); - SyscallError::InstructionError(InstructionError::MissingAccount) - })?) - .clone(); + let program_account = accounts + .get(callee_program_id_index) + .ok_or_else(|| { + ic_msg!(invoke_context, "Unknown program {}", callee_program_id,); + SyscallError::InstructionError(InstructionError::MissingAccount) + })? + .clone(); let programdata_executable = get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?; let mut executables = vec![(callee_program_id, program_account)]; @@ -1619,7 +1633,7 @@ fn call<'a>( executables, accounts, account_refs, - caller_privileges, + caller_write_privileges, ) }; @@ -1630,7 +1644,7 @@ fn call<'a>( &message, &executables, &accounts, - &caller_privileges, + &caller_write_privileges, *(&mut *(syscall.get_context_mut()?)), ) { Ok(()) => (), diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 948d8e9ac..8da4c8bb5 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -117,8 +117,8 @@ type BankStatusCache = StatusCache>; #[frozen_abi(digest = "EcB9J7sm37t1R47vLcvGuNeiRciB4Efq1EDWDWL6Bp5h")] pub type BankSlotDelta = SlotDelta>; type TransactionAccountRefCells = Vec>>; -type TransactionAccountDepRefCells = Vec<(Pubkey, RefCell)>; -type TransactionLoaderRefCells = Vec)>>; +type TransactionAccountDepRefCells = Vec<(Pubkey, Rc>)>; +type TransactionLoaderRefCells = Vec>)>>; // Eager rent collection repeats in cyclic manner. // Each cycle is composed of number of tiny pubkey subranges @@ -2727,13 +2727,13 @@ impl Bank { .collect(); let account_dep_refcells: Vec<_> = account_deps .drain(..) - .map(|(pubkey, account_dep)| (pubkey, RefCell::new(account_dep))) + .map(|(pubkey, account_dep)| (pubkey, Rc::new(RefCell::new(account_dep)))) .collect(); let loader_refcells: Vec> = loaders .iter_mut() .map(|v| { v.drain(..) - .map(|(pubkey, account)| (pubkey, RefCell::new(account))) + .map(|(pubkey, account)| (pubkey, Rc::new(RefCell::new(account)))) .collect() }) .collect(); @@ -2755,8 +2755,9 @@ impl Bank { .iter_mut() .zip(loader_refcells) .for_each(|(ls, mut lrcs)| { - lrcs.drain(..) - .for_each(|(pubkey, lrc)| ls.push((pubkey, lrc.into_inner()))) + lrcs.drain(..).for_each(|(pubkey, lrc)| { + ls.push((pubkey, Rc::try_unwrap(lrc).unwrap().into_inner())) + }) }); } diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 098825ceb..e05d5fa4a 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -8,7 +8,7 @@ use solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::StateMut, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - feature_set::{instructions_sysvar_enabled, FeatureSet}, + feature_set::{cpi_share_ro_and_exec_accounts, instructions_sysvar_enabled, FeatureSet}, ic_msg, instruction::{CompiledInstruction, Instruction, InstructionError}, keyed_account::{create_keyed_readonly_accounts, KeyedAccount}, @@ -82,14 +82,14 @@ impl ExecuteDetailsTimings { #[derive(Clone, Debug, Default)] pub struct PreAccount { key: Pubkey, - account: RefCell, + account: Rc>, changed: bool, } impl PreAccount { pub fn new(key: &Pubkey, account: &AccountSharedData) -> Self { Self { key: *key, - account: RefCell::new(account.clone()), + account: Rc::new(RefCell::new(account.clone())), changed: false, } } @@ -254,7 +254,8 @@ pub struct ThisInvokeContext<'a> { program_ids: Vec, rent: Rent, pre_accounts: Vec, - account_deps: &'a [(Pubkey, RefCell)], + executables: &'a [(Pubkey, Rc>)], + account_deps: &'a [(Pubkey, Rc>)], programs: &'a [(Pubkey, ProcessInstructionWithContext)], logger: Rc>, bpf_compute_budget: BpfComputeBudget, @@ -270,7 +271,8 @@ impl<'a> ThisInvokeContext<'a> { program_id: &Pubkey, rent: Rent, pre_accounts: Vec, - account_deps: &'a [(Pubkey, RefCell)], + executables: &'a [(Pubkey, Rc>)], + account_deps: &'a [(Pubkey, Rc>)], programs: &'a [(Pubkey, ProcessInstructionWithContext)], log_collector: Option>, bpf_compute_budget: BpfComputeBudget, @@ -284,6 +286,7 @@ impl<'a> ThisInvokeContext<'a> { program_ids, rent, pre_accounts, + executables, account_deps, programs, logger: Rc::new(RefCell::new(ThisLogger { log_collector })), @@ -321,7 +324,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { message: &Message, instruction: &CompiledInstruction, accounts: &[Rc>], - caller_privileges: Option<&[bool]>, + caller_write_privileges: Option<&[bool]>, ) -> Result<(), InstructionError> { match self.program_ids.last() { Some(program_id) => MessageProcessor::verify_and_update( @@ -331,7 +334,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { accounts, program_id, &self.rent, - caller_privileges, + caller_write_privileges, &mut self.timings, ), None => Err(InstructionError::GenericError), // Should never happen @@ -368,23 +371,37 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> { fn is_feature_active(&self, feature_id: &Pubkey) -> bool { self.feature_set.is_active(feature_id) } - fn get_account(&self, pubkey: &Pubkey) -> Option> { - if let Some(account) = self.pre_accounts.iter().find_map(|pre| { - if pre.key == *pubkey { + fn get_account(&self, pubkey: &Pubkey) -> Option>> { + if self.is_feature_active(&cpi_share_ro_and_exec_accounts::id()) { + if let Some((_, account)) = self.executables.iter().find(|(key, _)| key == pubkey) { + Some(account.clone()) + } else if let Some((_, account)) = + self.account_deps.iter().find(|(key, _)| key == pubkey) + { + Some(account.clone()) + } else if let Some(pre) = self.pre_accounts.iter().find(|pre| pre.key == *pubkey) { Some(pre.account.clone()) } else { None } - }) { - return Some(account); - } - self.account_deps.iter().find_map(|(key, account)| { - if key == pubkey { - Some(account.clone()) - } else { - None + } else { + if let Some(account) = self.pre_accounts.iter().find_map(|pre| { + if pre.key == *pubkey { + Some(pre.account.clone()) + } else { + None + } + }) { + return Some(account); } - }) + self.account_deps.iter().find_map(|(key, account)| { + if key == pubkey { + Some(account.clone()) + } else { + None + } + }) + } } fn update_timing( &mut self, @@ -508,7 +525,7 @@ impl MessageProcessor { fn create_keyed_accounts<'a>( message: &'a Message, instruction: &'a CompiledInstruction, - executable_accounts: &'a [(Pubkey, RefCell)], + executable_accounts: &'a [(Pubkey, Rc>)], accounts: &'a [Rc>], ) -> Vec> { let mut keyed_accounts = create_keyed_readonly_accounts(&executable_accounts); @@ -665,7 +682,7 @@ impl MessageProcessor { ) -> Result<(), InstructionError> { let invoke_context = RefCell::new(invoke_context); - let (message, executables, accounts, account_refs, caller_privileges) = { + let (message, executables, accounts, account_refs, caller_write_privileges) = { let invoke_context = invoke_context.borrow(); let caller_program_id = invoke_context.get_caller()?; @@ -676,11 +693,11 @@ impl MessageProcessor { .iter() .map(|seeds| Pubkey::create_program_address(&seeds, caller_program_id)) .collect::, solana_sdk::pubkey::PubkeyError>>()?; - let mut caller_privileges = keyed_accounts + let mut caller_write_privileges = keyed_accounts .iter() .map(|keyed_account| keyed_account.is_writable()) .collect::>(); - caller_privileges.insert(0, false); + caller_write_privileges.insert(0, false); let (message, callee_program_id, _) = Self::create_message(&instruction, &keyed_accounts, &signers, &invoke_context)?; let mut accounts = vec![]; @@ -756,7 +773,7 @@ impl MessageProcessor { executables, accounts, account_refs, - caller_privileges, + caller_write_privileges, ) }; @@ -765,7 +782,7 @@ impl MessageProcessor { &message, &executables, &accounts, - &caller_privileges, + &caller_write_privileges, *(&mut *(invoke_context.borrow_mut())), )?; @@ -801,9 +818,9 @@ impl MessageProcessor { /// This method calls the instruction's program entrypoint function pub fn process_cross_program_instruction( message: &Message, - executable_accounts: &[(Pubkey, RefCell)], + executable_accounts: &[(Pubkey, Rc>)], accounts: &[Rc>], - caller_privileges: &[bool], + caller_write_privileges: &[bool], invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { if let Some(instruction) = message.instructions.get(0) { @@ -814,7 +831,7 @@ impl MessageProcessor { message, instruction, accounts, - Some(caller_privileges), + Some(caller_write_privileges), )?; // Construct keyed accounts @@ -870,7 +887,7 @@ impl MessageProcessor { /// Verify there are no outstanding borrows pub fn verify_account_references( - accounts: &[(Pubkey, RefCell)], + accounts: &[(Pubkey, Rc>)], ) -> Result<(), InstructionError> { for (_, account) in accounts.iter() { account @@ -885,7 +902,7 @@ impl MessageProcessor { message: &Message, instruction: &CompiledInstruction, pre_accounts: &[PreAccount], - executable_accounts: &[(Pubkey, RefCell)], + executable_accounts: &[(Pubkey, Rc>)], accounts: &[Rc>], rent: &Rent, timings: &mut ExecuteDetailsTimings, @@ -898,10 +915,13 @@ impl MessageProcessor { { let program_id = instruction.program_id(&message.account_keys); let mut work = |unique_index: usize, account_index: usize| { - // Verify account has no outstanding references and take one - let account = accounts[account_index] - .try_borrow_mut() - .map_err(|_| InstructionError::AccountBorrowOutstanding)?; + { + // Verify account has no outstanding references + let _ = accounts[account_index] + .try_borrow_mut() + .map_err(|_| InstructionError::AccountBorrowOutstanding)?; + } + let account = accounts[account_index].borrow(); pre_accounts[unique_index].verify( &program_id, message.is_writable(account_index), @@ -931,7 +951,7 @@ impl MessageProcessor { accounts: &[Rc>], program_id: &Pubkey, rent: &Rent, - caller_privileges: Option<&[bool]>, + caller_write_privileges: Option<&[bool]>, timings: &mut ExecuteDetailsTimings, ) -> Result<(), InstructionError> { // Verify the per-account instruction results @@ -940,25 +960,27 @@ impl MessageProcessor { if account_index < message.account_keys.len() && account_index < accounts.len() { let key = &message.account_keys[account_index]; let account = &accounts[account_index]; - let is_writable = if let Some(caller_privileges) = caller_privileges { - caller_privileges[account_index] + let is_writable = if let Some(caller_write_privileges) = caller_write_privileges { + caller_write_privileges[account_index] } else { message.is_writable(account_index) }; // Find the matching PreAccount for pre_account in pre_accounts.iter_mut() { if *key == pre_account.key() { - // Verify account has no outstanding references and take one - let account = account - .try_borrow_mut() - .map_err(|_| InstructionError::AccountBorrowOutstanding)?; - + { + // Verify account has no outstanding references + let _ = account + .try_borrow_mut() + .map_err(|_| InstructionError::AccountBorrowOutstanding)?; + } + let account = account.borrow(); pre_account.verify(&program_id, is_writable, &rent, &account, timings)?; pre_sum += u128::from(pre_account.lamports()); post_sum += u128::from(account.lamports); - - pre_account.update(&account); - + if is_writable && !account.executable { + pre_account.update(&account); + } return Ok(()); } } @@ -984,9 +1006,9 @@ impl MessageProcessor { &self, message: &Message, instruction: &CompiledInstruction, - executable_accounts: &[(Pubkey, RefCell)], + executable_accounts: &[(Pubkey, Rc>)], accounts: &[Rc>], - account_deps: &[(Pubkey, RefCell)], + account_deps: &[(Pubkey, Rc>)], rent_collector: &RentCollector, log_collector: Option>, executors: Rc>, @@ -1017,6 +1039,7 @@ impl MessageProcessor { program_id, rent_collector.rent, pre_accounts, + executable_accounts, account_deps, &self.programs, log_collector, @@ -1052,12 +1075,13 @@ impl MessageProcessor { /// This method calls each instruction in the message over the set of loaded Accounts /// The accounts are committed back to the bank only if every instruction succeeds #[allow(clippy::too_many_arguments)] + #[allow(clippy::type_complexity)] pub fn process_message( &self, message: &Message, - loaders: &[Vec<(Pubkey, RefCell)>], + loaders: &[Vec<(Pubkey, Rc>)>], accounts: &[Rc>], - account_deps: &[(Pubkey, RefCell)], + account_deps: &[(Pubkey, Rc>)], rent_collector: &RentCollector, log_collector: Option>, executors: Rc>, @@ -1128,6 +1152,7 @@ mod tests { pre_accounts, &[], &[], + &[], None, BpfComputeBudget::default(), Rc::new(RefCell::new(Executors::default())), @@ -1234,7 +1259,7 @@ mod tests { fn test_verify_account_references() { let accounts = vec![( solana_sdk::pubkey::new_rand(), - RefCell::new(AccountSharedData::default()), + Rc::new(RefCell::new(AccountSharedData::default())), )]; assert!(MessageProcessor::verify_account_references(&accounts).is_ok()); @@ -1677,8 +1702,11 @@ mod tests { let account = AccountSharedData::new_ref(0, 1, &mock_system_program_id); accounts.push(account); - let mut loaders: Vec)>> = Vec::new(); - let account = RefCell::new(create_loadable_account("mock_system_program", 1)); + let mut loaders: Vec>)>> = Vec::new(); + let account = Rc::new(RefCell::new(create_loadable_account( + "mock_system_program", + 1, + ))); loaders.push(vec![(mock_system_program_id, account)]); let executors = Rc::new(RefCell::new(Executors::default())); @@ -1844,8 +1872,11 @@ mod tests { let account = AccountSharedData::new_ref(0, 1, &mock_program_id); accounts.push(account); - let mut loaders: Vec)>> = Vec::new(); - let account = RefCell::new(create_loadable_account("mock_system_program", 1)); + let mut loaders: Vec>)>> = Vec::new(); + let account = Rc::new(RefCell::new(create_loadable_account( + "mock_system_program", + 1, + ))); loaders.push(vec![(mock_program_id, account)]); let executors = Rc::new(RefCell::new(Executors::default())); @@ -1989,7 +2020,10 @@ mod tests { let mut program_account = AccountSharedData::new(1, 0, &native_loader::id()); program_account.executable = true; let executable_preaccount = PreAccount::new(&callee_program_id, &program_account); - let executable_accounts = vec![(callee_program_id, RefCell::new(program_account.clone()))]; + let executable_accounts = vec![( + callee_program_id, + Rc::new(RefCell::new(program_account.clone())), + )]; let owned_key = solana_sdk::pubkey::new_rand(); let owned_account = AccountSharedData::new(42, 1, &callee_program_id); @@ -2016,6 +2050,7 @@ mod tests { executable_preaccount, ], &[], + &[], programs.as_slice(), None, BpfComputeBudget::default(), @@ -2036,7 +2071,7 @@ mod tests { metas.clone(), ); let message = Message::new(&[instruction], None); - let caller_privileges = message + let caller_write_privileges = message .account_keys .iter() .enumerate() @@ -2047,7 +2082,7 @@ mod tests { &message, &executable_accounts, &accounts, - &caller_privileges, + &caller_write_privileges, &mut invoke_context, ), Err(InstructionError::ExternalAccountDataModified) @@ -2071,7 +2106,7 @@ mod tests { let instruction = Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone()); let message = Message::new(&[instruction], None); - let caller_privileges = message + let caller_write_privileges = message .account_keys .iter() .enumerate() @@ -2082,7 +2117,7 @@ mod tests { &message, &executable_accounts, &accounts, - &caller_privileges, + &caller_write_privileges, &mut invoke_context, ), case.1 diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 4ba16a863..63bc92793 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -107,6 +107,10 @@ pub mod check_program_owner { solana_sdk::declare_id!("5XnbR5Es9YXEARRuP6mdvoxiW3hx5atNNeBmwVd8P3QD"); } +pub mod cpi_share_ro_and_exec_accounts { + solana_sdk::declare_id!("6VgVBi3uRVqp56TtEwNou8idgdmhCD1aYqX8FaJ1fnJb"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -133,7 +137,8 @@ lazy_static! { (full_inflation::mainnet::certusone::vote::id(), "Community vote allowing Certus One to enable full inflation"), (warp_timestamp_again::id(), "warp timestamp again, adjust bounding to 25% fast 80% slow #15204"), (check_init_vote_data::id(), "check initialized Vote data"), - (check_program_owner::id(), "limit programs to operating on accounts owned by itself") + (check_program_owner::id(), "limit programs to operating on accounts owned by itself"), + (cpi_share_ro_and_exec_accounts::id(), "Share RO and Executable accounts during cross-program invocations"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter() diff --git a/sdk/src/keyed_account.rs b/sdk/src/keyed_account.rs index 63013aadb..bd00c5745 100644 --- a/sdk/src/keyed_account.rs +++ b/sdk/src/keyed_account.rs @@ -6,6 +6,7 @@ use solana_program::{clock::Epoch, instruction::InstructionError, pubkey::Pubkey use std::{ cell::{Ref, RefCell, RefMut}, iter::FromIterator, + rc::Rc, }; #[repr(C)] @@ -160,7 +161,7 @@ pub fn create_keyed_is_signer_accounts<'a>( } pub fn create_keyed_readonly_accounts( - accounts: &[(Pubkey, RefCell)], + accounts: &[(Pubkey, Rc>)], ) -> Vec { accounts .iter() diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs index 34f05eb42..8088f717b 100644 --- a/sdk/src/process_instruction.rs +++ b/sdk/src/process_instruction.rs @@ -59,7 +59,7 @@ pub trait InvokeContext { /// Get the bank's active feature set fn is_feature_active(&self, feature_id: &Pubkey) -> bool; /// Get an account from a pre-account - fn get_account(&self, pubkey: &Pubkey) -> Option>; + fn get_account(&self, pubkey: &Pubkey) -> Option>>; /// Update timing fn update_timing( &mut self, @@ -333,7 +333,7 @@ impl InvokeContext for MockInvokeContext { fn is_feature_active(&self, _feature_id: &Pubkey) -> bool { true } - fn get_account(&self, _pubkey: &Pubkey) -> Option> { + fn get_account(&self, _pubkey: &Pubkey) -> Option>> { None } fn update_timing(