Skip to content

Commit

Permalink
Share RO and Executable accounts within invocations (#15799)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmay authored Mar 11, 2021
1 parent ac8ccee commit 4785183
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 85 deletions.
5 changes: 4 additions & 1 deletion program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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![];
Expand Down
1 change: 1 addition & 0 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,7 @@ mod tests {
vec![],
&[],
&[],
&[],
None,
BpfComputeBudget {
max_units: 1,
Expand Down
44 changes: 29 additions & 15 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1395,6 +1400,7 @@ impl<'a> SyscallObject<BpfError> 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],
Expand All @@ -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
Expand Down Expand Up @@ -1496,11 +1506,12 @@ fn check_authorized_program(
Ok(())
}

#[allow(clippy::type_complexity)]
fn get_upgradeable_executable(
callee_program_id: &Pubkey,
program_account: &RefCell<AccountSharedData>,
program_account: &Rc<RefCell<AccountSharedData>>,
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() {
match program_account.borrow().state() {
Ok(UpgradeableLoaderState::Program {
Expand Down Expand Up @@ -1541,7 +1552,7 @@ fn call<'a>(
signers_seeds_len: u64,
memory_mapping: &MemoryMapping,
) -> 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()?;

invoke_context
Expand Down Expand Up @@ -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| {
Expand All @@ -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,
Expand All @@ -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)];
Expand All @@ -1619,7 +1633,7 @@ fn call<'a>(
executables,
accounts,
account_refs,
caller_privileges,
caller_write_privileges,
)
};

Expand All @@ -1630,7 +1644,7 @@ fn call<'a>(
&message,
&executables,
&accounts,
&caller_privileges,
&caller_write_privileges,
*(&mut *(syscall.get_context_mut()?)),
) {
Ok(()) => (),
Expand Down
13 changes: 7 additions & 6 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "EcB9J7sm37t1R47vLcvGuNeiRciB4Efq1EDWDWL6Bp5h")]
pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<Rc<RefCell<AccountSharedData>>>;
type TransactionAccountDepRefCells = Vec<(Pubkey, RefCell<AccountSharedData>)>;
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, RefCell<AccountSharedData>)>>;
type TransactionAccountDepRefCells = Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>;
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>>;

// Eager rent collection repeats in cyclic manner.
// Each cycle is composed of <partition_count> number of tiny pubkey subranges
Expand Down Expand Up @@ -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<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();
Expand All @@ -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()))
})
});
}

Expand Down
Loading

0 comments on commit 4785183

Please sign in to comment.