Share RO and Executable accounts within invocations (#15799)

This commit is contained in:
Jack May 2021-03-10 23:04:00 -08:00 committed by GitHub
parent ac8ccee6b8
commit 478518308d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 145 additions and 85 deletions

View File

@ -247,7 +247,10 @@ impl program_stubs::SyscallStubs for SyscallStubs {
rent_epoch: ai.rent_epoch, 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 // Convert AccountInfos into Accounts
let mut accounts = vec![]; let mut accounts = vec![];

View File

@ -1089,6 +1089,7 @@ mod tests {
vec![], vec![],
&[], &[],
&[], &[],
&[],
None, None,
BpfComputeBudget { BpfComputeBudget {
max_units: 1, max_units: 1,

View File

@ -16,7 +16,7 @@ use solana_sdk::{
bpf_loader, bpf_loader_deprecated, bpf_loader, bpf_loader_deprecated,
bpf_loader_upgradeable::{self, UpgradeableLoaderState}, bpf_loader_upgradeable::{self, UpgradeableLoaderState},
entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, 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}, hash::{Hasher, HASH_BYTES},
ic_msg, ic_msg,
instruction::{AccountMeta, Instruction, InstructionError}, instruction::{AccountMeta, Instruction, InstructionError},
@ -859,6 +859,7 @@ trait SyscallInvokeSigned<'a> {
fn translate_accounts( fn translate_accounts(
&self, &self,
account_keys: &[Pubkey], account_keys: &[Pubkey],
caller_write_privileges: &[bool],
program_account_index: usize, program_account_index: usize,
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
@ -930,6 +931,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
fn translate_accounts( fn translate_accounts(
&self, &self,
account_keys: &[Pubkey], account_keys: &[Pubkey],
caller_write_privileges: &[bool],
program_account_index: usize, program_account_index: usize,
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
@ -1027,6 +1029,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> {
get_translated_accounts( get_translated_accounts(
account_keys, account_keys,
caller_write_privileges,
program_account_index, program_account_index,
&account_info_keys, &account_info_keys,
account_infos, account_infos,
@ -1228,6 +1231,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
fn translate_accounts( fn translate_accounts(
&self, &self,
account_keys: &[Pubkey], account_keys: &[Pubkey],
caller_write_privileges: &[bool],
program_account_index: usize, program_account_index: usize,
account_infos_addr: u64, account_infos_addr: u64,
account_infos_len: u64, account_infos_len: u64,
@ -1310,6 +1314,7 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> {
get_translated_accounts( get_translated_accounts(
account_keys, account_keys,
caller_write_privileges,
program_account_index, program_account_index,
&account_info_keys, &account_info_keys,
account_infos, account_infos,
@ -1395,6 +1400,7 @@ impl<'a> SyscallObject<BpfError> for SyscallInvokeSignedC<'a> {
fn get_translated_accounts<'a, T, F>( fn get_translated_accounts<'a, T, F>(
account_keys: &[Pubkey], account_keys: &[Pubkey],
caller_write_privileges: &[bool],
program_account_index: usize, program_account_index: usize,
account_info_keys: &[&Pubkey], account_info_keys: &[&Pubkey],
account_infos: &[T], account_infos: &[T],
@ -1416,9 +1422,13 @@ where
SyscallError::InstructionError(InstructionError::MissingAccount) SyscallError::InstructionError(InstructionError::MissingAccount)
})?; })?;
if i == program_account_index || account.borrow().executable { if i == program_account_index
// Use the known executable || account.borrow().executable
accounts.push(Rc::new(account)); || (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); refs.push(None);
} else if let Some(account_info) = } else if let Some(account_info) =
account_info_keys account_info_keys
@ -1496,11 +1506,12 @@ fn check_authorized_program(
Ok(()) Ok(())
} }
#[allow(clippy::type_complexity)]
fn get_upgradeable_executable( fn get_upgradeable_executable(
callee_program_id: &Pubkey, callee_program_id: &Pubkey,
program_account: &RefCell<AccountSharedData>, program_account: &Rc<RefCell<AccountSharedData>>,
invoke_context: &Ref<&mut dyn InvokeContext>, invoke_context: &Ref<&mut dyn InvokeContext>,
) -> Result<Option<(Pubkey, RefCell<AccountSharedData>)>, EbpfError<BpfError>> { ) -> Result<Option<(Pubkey, Rc<RefCell<AccountSharedData>>)>, EbpfError<BpfError>> {
if program_account.borrow().owner == bpf_loader_upgradeable::id() { if program_account.borrow().owner == bpf_loader_upgradeable::id() {
match program_account.borrow().state() { match program_account.borrow().state() {
Ok(UpgradeableLoaderState::Program { Ok(UpgradeableLoaderState::Program {
@ -1541,7 +1552,7 @@ fn call<'a>(
signers_seeds_len: u64, signers_seeds_len: u64,
memory_mapping: &MemoryMapping, memory_mapping: &MemoryMapping,
) -> Result<u64, EbpfError<BpfError>> { ) -> Result<u64, EbpfError<BpfError>> {
let (message, executables, accounts, account_refs, caller_privileges) = { let (message, executables, accounts, account_refs, caller_write_privileges) = {
let invoke_context = syscall.get_context()?; let invoke_context = syscall.get_context()?;
invoke_context invoke_context
@ -1573,7 +1584,7 @@ fn call<'a>(
&invoke_context, &invoke_context,
) )
.map_err(SyscallError::InstructionError)?; .map_err(SyscallError::InstructionError)?;
let caller_privileges = message let caller_write_privileges = message
.account_keys .account_keys
.iter() .iter()
.map(|key| { .map(|key| {
@ -1590,6 +1601,7 @@ fn call<'a>(
check_authorized_program(&callee_program_id, &instruction.data)?; check_authorized_program(&callee_program_id, &instruction.data)?;
let (accounts, account_refs) = syscall.translate_accounts( let (accounts, account_refs) = syscall.translate_accounts(
&message.account_keys, &message.account_keys,
&caller_write_privileges,
callee_program_id_index, callee_program_id_index,
account_infos_addr, account_infos_addr,
account_infos_len, account_infos_len,
@ -1598,11 +1610,13 @@ fn call<'a>(
// Construct executables // Construct executables
let program_account = (**accounts.get(callee_program_id_index).ok_or_else(|| { let program_account = accounts
ic_msg!(invoke_context, "Unknown program {}", callee_program_id); .get(callee_program_id_index)
SyscallError::InstructionError(InstructionError::MissingAccount) .ok_or_else(|| {
})?) ic_msg!(invoke_context, "Unknown program {}", callee_program_id,);
.clone(); SyscallError::InstructionError(InstructionError::MissingAccount)
})?
.clone();
let programdata_executable = let programdata_executable =
get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?; get_upgradeable_executable(&callee_program_id, &program_account, &invoke_context)?;
let mut executables = vec![(callee_program_id, program_account)]; let mut executables = vec![(callee_program_id, program_account)];
@ -1619,7 +1633,7 @@ fn call<'a>(
executables, executables,
accounts, accounts,
account_refs, account_refs,
caller_privileges, caller_write_privileges,
) )
}; };
@ -1630,7 +1644,7 @@ fn call<'a>(
&message, &message,
&executables, &executables,
&accounts, &accounts,
&caller_privileges, &caller_write_privileges,
*(&mut *(syscall.get_context_mut()?)), *(&mut *(syscall.get_context_mut()?)),
) { ) {
Ok(()) => (), Ok(()) => (),

View File

@ -117,8 +117,8 @@ type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "EcB9J7sm37t1R47vLcvGuNeiRciB4Efq1EDWDWL6Bp5h")] #[frozen_abi(digest = "EcB9J7sm37t1R47vLcvGuNeiRciB4Efq1EDWDWL6Bp5h")]
pub type BankSlotDelta = SlotDelta<Result<()>>; pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<Rc<RefCell<AccountSharedData>>>; type TransactionAccountRefCells = Vec<Rc<RefCell<AccountSharedData>>>;
type TransactionAccountDepRefCells = Vec<(Pubkey, RefCell<AccountSharedData>)>; type TransactionAccountDepRefCells = Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>;
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<AccountSharedData>)>>; type TransactionLoaderRefCells = Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>>;
// Eager rent collection repeats in cyclic manner. // Eager rent collection repeats in cyclic manner.
// Each cycle is composed of <partition_count> number of tiny pubkey subranges // Each cycle is composed of <partition_count> number of tiny pubkey subranges
@ -2727,13 +2727,13 @@ impl Bank {
.collect(); .collect();
let account_dep_refcells: Vec<_> = account_deps let account_dep_refcells: Vec<_> = account_deps
.drain(..) .drain(..)
.map(|(pubkey, account_dep)| (pubkey, RefCell::new(account_dep))) .map(|(pubkey, account_dep)| (pubkey, Rc::new(RefCell::new(account_dep))))
.collect(); .collect();
let loader_refcells: Vec<Vec<_>> = loaders let loader_refcells: Vec<Vec<_>> = loaders
.iter_mut() .iter_mut()
.map(|v| { .map(|v| {
v.drain(..) v.drain(..)
.map(|(pubkey, account)| (pubkey, RefCell::new(account))) .map(|(pubkey, account)| (pubkey, Rc::new(RefCell::new(account))))
.collect() .collect()
}) })
.collect(); .collect();
@ -2755,8 +2755,9 @@ impl Bank {
.iter_mut() .iter_mut()
.zip(loader_refcells) .zip(loader_refcells)
.for_each(|(ls, mut lrcs)| { .for_each(|(ls, mut lrcs)| {
lrcs.drain(..) lrcs.drain(..).for_each(|(pubkey, lrc)| {
.for_each(|(pubkey, lrc)| ls.push((pubkey, lrc.into_inner()))) ls.push((pubkey, Rc::try_unwrap(lrc).unwrap().into_inner()))
})
}); });
} }

View File

@ -8,7 +8,7 @@ use solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount}, account::{AccountSharedData, ReadableAccount, WritableAccount},
account_utils::StateMut, account_utils::StateMut,
bpf_loader_upgradeable::{self, UpgradeableLoaderState}, 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, ic_msg,
instruction::{CompiledInstruction, Instruction, InstructionError}, instruction::{CompiledInstruction, Instruction, InstructionError},
keyed_account::{create_keyed_readonly_accounts, KeyedAccount}, keyed_account::{create_keyed_readonly_accounts, KeyedAccount},
@ -82,14 +82,14 @@ impl ExecuteDetailsTimings {
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct PreAccount { pub struct PreAccount {
key: Pubkey, key: Pubkey,
account: RefCell<AccountSharedData>, account: Rc<RefCell<AccountSharedData>>,
changed: bool, changed: bool,
} }
impl PreAccount { impl PreAccount {
pub fn new(key: &Pubkey, account: &AccountSharedData) -> Self { pub fn new(key: &Pubkey, account: &AccountSharedData) -> Self {
Self { Self {
key: *key, key: *key,
account: RefCell::new(account.clone()), account: Rc::new(RefCell::new(account.clone())),
changed: false, changed: false,
} }
} }
@ -254,7 +254,8 @@ pub struct ThisInvokeContext<'a> {
program_ids: Vec<Pubkey>, program_ids: Vec<Pubkey>,
rent: Rent, rent: Rent,
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
account_deps: &'a [(Pubkey, RefCell<AccountSharedData>)], executables: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
account_deps: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
programs: &'a [(Pubkey, ProcessInstructionWithContext)], programs: &'a [(Pubkey, ProcessInstructionWithContext)],
logger: Rc<RefCell<dyn Logger>>, logger: Rc<RefCell<dyn Logger>>,
bpf_compute_budget: BpfComputeBudget, bpf_compute_budget: BpfComputeBudget,
@ -270,7 +271,8 @@ impl<'a> ThisInvokeContext<'a> {
program_id: &Pubkey, program_id: &Pubkey,
rent: Rent, rent: Rent,
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
account_deps: &'a [(Pubkey, RefCell<AccountSharedData>)], executables: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
account_deps: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
programs: &'a [(Pubkey, ProcessInstructionWithContext)], programs: &'a [(Pubkey, ProcessInstructionWithContext)],
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
bpf_compute_budget: BpfComputeBudget, bpf_compute_budget: BpfComputeBudget,
@ -284,6 +286,7 @@ impl<'a> ThisInvokeContext<'a> {
program_ids, program_ids,
rent, rent,
pre_accounts, pre_accounts,
executables,
account_deps, account_deps,
programs, programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })), logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
@ -321,7 +324,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[Rc<RefCell<AccountSharedData>>],
caller_privileges: Option<&[bool]>, caller_write_privileges: Option<&[bool]>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
match self.program_ids.last() { match self.program_ids.last() {
Some(program_id) => MessageProcessor::verify_and_update( Some(program_id) => MessageProcessor::verify_and_update(
@ -331,7 +334,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
accounts, accounts,
program_id, program_id,
&self.rent, &self.rent,
caller_privileges, caller_write_privileges,
&mut self.timings, &mut self.timings,
), ),
None => Err(InstructionError::GenericError), // Should never happen 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 { fn is_feature_active(&self, feature_id: &Pubkey) -> bool {
self.feature_set.is_active(feature_id) self.feature_set.is_active(feature_id)
} }
fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<AccountSharedData>> { fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> {
if let Some(account) = self.pre_accounts.iter().find_map(|pre| { if self.is_feature_active(&cpi_share_ro_and_exec_accounts::id()) {
if pre.key == *pubkey { 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()) Some(pre.account.clone())
} else { } else {
None None
} }
}) { } else {
return Some(account); if let Some(account) = self.pre_accounts.iter().find_map(|pre| {
} if pre.key == *pubkey {
self.account_deps.iter().find_map(|(key, account)| { Some(pre.account.clone())
if key == pubkey { } else {
Some(account.clone()) None
} else { }
None }) {
return Some(account);
} }
}) self.account_deps.iter().find_map(|(key, account)| {
if key == pubkey {
Some(account.clone())
} else {
None
}
})
}
} }
fn update_timing( fn update_timing(
&mut self, &mut self,
@ -508,7 +525,7 @@ impl MessageProcessor {
fn create_keyed_accounts<'a>( fn create_keyed_accounts<'a>(
message: &'a Message, message: &'a Message,
instruction: &'a CompiledInstruction, instruction: &'a CompiledInstruction,
executable_accounts: &'a [(Pubkey, RefCell<AccountSharedData>)], executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &'a [Rc<RefCell<AccountSharedData>>], accounts: &'a [Rc<RefCell<AccountSharedData>>],
) -> Vec<KeyedAccount<'a>> { ) -> Vec<KeyedAccount<'a>> {
let mut keyed_accounts = create_keyed_readonly_accounts(&executable_accounts); let mut keyed_accounts = create_keyed_readonly_accounts(&executable_accounts);
@ -665,7 +682,7 @@ impl MessageProcessor {
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let invoke_context = RefCell::new(invoke_context); 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 invoke_context = invoke_context.borrow();
let caller_program_id = invoke_context.get_caller()?; let caller_program_id = invoke_context.get_caller()?;
@ -676,11 +693,11 @@ impl MessageProcessor {
.iter() .iter()
.map(|seeds| Pubkey::create_program_address(&seeds, caller_program_id)) .map(|seeds| Pubkey::create_program_address(&seeds, caller_program_id))
.collect::<Result<Vec<_>, solana_sdk::pubkey::PubkeyError>>()?; .collect::<Result<Vec<_>, solana_sdk::pubkey::PubkeyError>>()?;
let mut caller_privileges = keyed_accounts let mut caller_write_privileges = keyed_accounts
.iter() .iter()
.map(|keyed_account| keyed_account.is_writable()) .map(|keyed_account| keyed_account.is_writable())
.collect::<Vec<bool>>(); .collect::<Vec<bool>>();
caller_privileges.insert(0, false); caller_write_privileges.insert(0, false);
let (message, callee_program_id, _) = let (message, callee_program_id, _) =
Self::create_message(&instruction, &keyed_accounts, &signers, &invoke_context)?; Self::create_message(&instruction, &keyed_accounts, &signers, &invoke_context)?;
let mut accounts = vec![]; let mut accounts = vec![];
@ -756,7 +773,7 @@ impl MessageProcessor {
executables, executables,
accounts, accounts,
account_refs, account_refs,
caller_privileges, caller_write_privileges,
) )
}; };
@ -765,7 +782,7 @@ impl MessageProcessor {
&message, &message,
&executables, &executables,
&accounts, &accounts,
&caller_privileges, &caller_write_privileges,
*(&mut *(invoke_context.borrow_mut())), *(&mut *(invoke_context.borrow_mut())),
)?; )?;
@ -801,9 +818,9 @@ impl MessageProcessor {
/// This method calls the instruction's program entrypoint function /// This method calls the instruction's program entrypoint function
pub fn process_cross_program_instruction( pub fn process_cross_program_instruction(
message: &Message, message: &Message,
executable_accounts: &[(Pubkey, RefCell<AccountSharedData>)], executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[Rc<RefCell<AccountSharedData>>],
caller_privileges: &[bool], caller_write_privileges: &[bool],
invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
if let Some(instruction) = message.instructions.get(0) { if let Some(instruction) = message.instructions.get(0) {
@ -814,7 +831,7 @@ impl MessageProcessor {
message, message,
instruction, instruction,
accounts, accounts,
Some(caller_privileges), Some(caller_write_privileges),
)?; )?;
// Construct keyed accounts // Construct keyed accounts
@ -870,7 +887,7 @@ impl MessageProcessor {
/// Verify there are no outstanding borrows /// Verify there are no outstanding borrows
pub fn verify_account_references( pub fn verify_account_references(
accounts: &[(Pubkey, RefCell<AccountSharedData>)], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
for (_, account) in accounts.iter() { for (_, account) in accounts.iter() {
account account
@ -885,7 +902,7 @@ impl MessageProcessor {
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
pre_accounts: &[PreAccount], pre_accounts: &[PreAccount],
executable_accounts: &[(Pubkey, RefCell<AccountSharedData>)], executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[Rc<RefCell<AccountSharedData>>],
rent: &Rent, rent: &Rent,
timings: &mut ExecuteDetailsTimings, timings: &mut ExecuteDetailsTimings,
@ -898,10 +915,13 @@ impl MessageProcessor {
{ {
let program_id = instruction.program_id(&message.account_keys); let program_id = instruction.program_id(&message.account_keys);
let mut work = |unique_index: usize, account_index: usize| { let mut work = |unique_index: usize, account_index: usize| {
// Verify account has no outstanding references and take one {
let account = accounts[account_index] // Verify account has no outstanding references
.try_borrow_mut() let _ = accounts[account_index]
.map_err(|_| InstructionError::AccountBorrowOutstanding)?; .try_borrow_mut()
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
}
let account = accounts[account_index].borrow();
pre_accounts[unique_index].verify( pre_accounts[unique_index].verify(
&program_id, &program_id,
message.is_writable(account_index), message.is_writable(account_index),
@ -931,7 +951,7 @@ impl MessageProcessor {
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[Rc<RefCell<AccountSharedData>>],
program_id: &Pubkey, program_id: &Pubkey,
rent: &Rent, rent: &Rent,
caller_privileges: Option<&[bool]>, caller_write_privileges: Option<&[bool]>,
timings: &mut ExecuteDetailsTimings, timings: &mut ExecuteDetailsTimings,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
// Verify the per-account instruction results // Verify the per-account instruction results
@ -940,25 +960,27 @@ impl MessageProcessor {
if account_index < message.account_keys.len() && account_index < accounts.len() { if account_index < message.account_keys.len() && account_index < accounts.len() {
let key = &message.account_keys[account_index]; let key = &message.account_keys[account_index];
let account = &accounts[account_index]; let account = &accounts[account_index];
let is_writable = if let Some(caller_privileges) = caller_privileges { let is_writable = if let Some(caller_write_privileges) = caller_write_privileges {
caller_privileges[account_index] caller_write_privileges[account_index]
} else { } else {
message.is_writable(account_index) message.is_writable(account_index)
}; };
// Find the matching PreAccount // Find the matching PreAccount
for pre_account in pre_accounts.iter_mut() { for pre_account in pre_accounts.iter_mut() {
if *key == pre_account.key() { if *key == pre_account.key() {
// Verify account has no outstanding references and take one {
let account = account // Verify account has no outstanding references
.try_borrow_mut() let _ = account
.map_err(|_| InstructionError::AccountBorrowOutstanding)?; .try_borrow_mut()
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
}
let account = account.borrow();
pre_account.verify(&program_id, is_writable, &rent, &account, timings)?; pre_account.verify(&program_id, is_writable, &rent, &account, timings)?;
pre_sum += u128::from(pre_account.lamports()); pre_sum += u128::from(pre_account.lamports());
post_sum += u128::from(account.lamports); post_sum += u128::from(account.lamports);
if is_writable && !account.executable {
pre_account.update(&account); pre_account.update(&account);
}
return Ok(()); return Ok(());
} }
} }
@ -984,9 +1006,9 @@ impl MessageProcessor {
&self, &self,
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
executable_accounts: &[(Pubkey, RefCell<AccountSharedData>)], executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[Rc<RefCell<AccountSharedData>>],
account_deps: &[(Pubkey, RefCell<AccountSharedData>)], account_deps: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
rent_collector: &RentCollector, rent_collector: &RentCollector,
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
@ -1017,6 +1039,7 @@ impl MessageProcessor {
program_id, program_id,
rent_collector.rent, rent_collector.rent,
pre_accounts, pre_accounts,
executable_accounts,
account_deps, account_deps,
&self.programs, &self.programs,
log_collector, log_collector,
@ -1052,12 +1075,13 @@ impl MessageProcessor {
/// This method calls each instruction in the message over the set of loaded Accounts /// 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 /// The accounts are committed back to the bank only if every instruction succeeds
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
pub fn process_message( pub fn process_message(
&self, &self,
message: &Message, message: &Message,
loaders: &[Vec<(Pubkey, RefCell<AccountSharedData>)>], loaders: &[Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[Rc<RefCell<AccountSharedData>>],
account_deps: &[(Pubkey, RefCell<AccountSharedData>)], account_deps: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
rent_collector: &RentCollector, rent_collector: &RentCollector,
log_collector: Option<Rc<LogCollector>>, log_collector: Option<Rc<LogCollector>>,
executors: Rc<RefCell<Executors>>, executors: Rc<RefCell<Executors>>,
@ -1128,6 +1152,7 @@ mod tests {
pre_accounts, pre_accounts,
&[], &[],
&[], &[],
&[],
None, None,
BpfComputeBudget::default(), BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
@ -1234,7 +1259,7 @@ mod tests {
fn test_verify_account_references() { fn test_verify_account_references() {
let accounts = vec![( let accounts = vec![(
solana_sdk::pubkey::new_rand(), solana_sdk::pubkey::new_rand(),
RefCell::new(AccountSharedData::default()), Rc::new(RefCell::new(AccountSharedData::default())),
)]; )];
assert!(MessageProcessor::verify_account_references(&accounts).is_ok()); 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); let account = AccountSharedData::new_ref(0, 1, &mock_system_program_id);
accounts.push(account); accounts.push(account);
let mut loaders: Vec<Vec<(Pubkey, RefCell<AccountSharedData>)>> = Vec::new(); let mut loaders: Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>> = Vec::new();
let account = RefCell::new(create_loadable_account("mock_system_program", 1)); let account = Rc::new(RefCell::new(create_loadable_account(
"mock_system_program",
1,
)));
loaders.push(vec![(mock_system_program_id, account)]); loaders.push(vec![(mock_system_program_id, account)]);
let executors = Rc::new(RefCell::new(Executors::default())); let executors = Rc::new(RefCell::new(Executors::default()));
@ -1844,8 +1872,11 @@ mod tests {
let account = AccountSharedData::new_ref(0, 1, &mock_program_id); let account = AccountSharedData::new_ref(0, 1, &mock_program_id);
accounts.push(account); accounts.push(account);
let mut loaders: Vec<Vec<(Pubkey, RefCell<AccountSharedData>)>> = Vec::new(); let mut loaders: Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>> = Vec::new();
let account = RefCell::new(create_loadable_account("mock_system_program", 1)); let account = Rc::new(RefCell::new(create_loadable_account(
"mock_system_program",
1,
)));
loaders.push(vec![(mock_program_id, account)]); loaders.push(vec![(mock_program_id, account)]);
let executors = Rc::new(RefCell::new(Executors::default())); 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()); let mut program_account = AccountSharedData::new(1, 0, &native_loader::id());
program_account.executable = true; program_account.executable = true;
let executable_preaccount = PreAccount::new(&callee_program_id, &program_account); 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_key = solana_sdk::pubkey::new_rand();
let owned_account = AccountSharedData::new(42, 1, &callee_program_id); let owned_account = AccountSharedData::new(42, 1, &callee_program_id);
@ -2016,6 +2050,7 @@ mod tests {
executable_preaccount, executable_preaccount,
], ],
&[], &[],
&[],
programs.as_slice(), programs.as_slice(),
None, None,
BpfComputeBudget::default(), BpfComputeBudget::default(),
@ -2036,7 +2071,7 @@ mod tests {
metas.clone(), metas.clone(),
); );
let message = Message::new(&[instruction], None); let message = Message::new(&[instruction], None);
let caller_privileges = message let caller_write_privileges = message
.account_keys .account_keys
.iter() .iter()
.enumerate() .enumerate()
@ -2047,7 +2082,7 @@ mod tests {
&message, &message,
&executable_accounts, &executable_accounts,
&accounts, &accounts,
&caller_privileges, &caller_write_privileges,
&mut invoke_context, &mut invoke_context,
), ),
Err(InstructionError::ExternalAccountDataModified) Err(InstructionError::ExternalAccountDataModified)
@ -2071,7 +2106,7 @@ mod tests {
let instruction = let instruction =
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone()); Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
let message = Message::new(&[instruction], None); let message = Message::new(&[instruction], None);
let caller_privileges = message let caller_write_privileges = message
.account_keys .account_keys
.iter() .iter()
.enumerate() .enumerate()
@ -2082,7 +2117,7 @@ mod tests {
&message, &message,
&executable_accounts, &executable_accounts,
&accounts, &accounts,
&caller_privileges, &caller_write_privileges,
&mut invoke_context, &mut invoke_context,
), ),
case.1 case.1

View File

@ -107,6 +107,10 @@ pub mod check_program_owner {
solana_sdk::declare_id!("5XnbR5Es9YXEARRuP6mdvoxiW3hx5atNNeBmwVd8P3QD"); solana_sdk::declare_id!("5XnbR5Es9YXEARRuP6mdvoxiW3hx5atNNeBmwVd8P3QD");
} }
pub mod cpi_share_ro_and_exec_accounts {
solana_sdk::declare_id!("6VgVBi3uRVqp56TtEwNou8idgdmhCD1aYqX8FaJ1fnJb");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -133,7 +137,8 @@ lazy_static! {
(full_inflation::mainnet::certusone::vote::id(), "Community vote allowing Certus One to enable full inflation"), (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"), (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_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 ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()

View File

@ -6,6 +6,7 @@ use solana_program::{clock::Epoch, instruction::InstructionError, pubkey::Pubkey
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, cell::{Ref, RefCell, RefMut},
iter::FromIterator, iter::FromIterator,
rc::Rc,
}; };
#[repr(C)] #[repr(C)]
@ -160,7 +161,7 @@ pub fn create_keyed_is_signer_accounts<'a>(
} }
pub fn create_keyed_readonly_accounts( pub fn create_keyed_readonly_accounts(
accounts: &[(Pubkey, RefCell<AccountSharedData>)], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
) -> Vec<KeyedAccount> { ) -> Vec<KeyedAccount> {
accounts accounts
.iter() .iter()

View File

@ -59,7 +59,7 @@ pub trait InvokeContext {
/// Get the bank's active feature set /// Get the bank's active feature set
fn is_feature_active(&self, feature_id: &Pubkey) -> bool; fn is_feature_active(&self, feature_id: &Pubkey) -> bool;
/// Get an account from a pre-account /// Get an account from a pre-account
fn get_account(&self, pubkey: &Pubkey) -> Option<RefCell<AccountSharedData>>; fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>>;
/// Update timing /// Update timing
fn update_timing( fn update_timing(
&mut self, &mut self,
@ -333,7 +333,7 @@ impl InvokeContext for MockInvokeContext {
fn is_feature_active(&self, _feature_id: &Pubkey) -> bool { fn is_feature_active(&self, _feature_id: &Pubkey) -> bool {
true true
} }
fn get_account(&self, _pubkey: &Pubkey) -> Option<RefCell<AccountSharedData>> { fn get_account(&self, _pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> {
None None
} }
fn update_timing( fn update_timing(