Share RO and Executable accounts within invocations (#15799)
This commit is contained in:
parent
ac8ccee6b8
commit
478518308d
|
@ -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![];
|
||||||
|
|
|
@ -1089,6 +1089,7 @@ mod tests {
|
||||||
vec![],
|
vec![],
|
||||||
&[],
|
&[],
|
||||||
&[],
|
&[],
|
||||||
|
&[],
|
||||||
None,
|
None,
|
||||||
BpfComputeBudget {
|
BpfComputeBudget {
|
||||||
max_units: 1,
|
max_units: 1,
|
||||||
|
|
|
@ -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,10 +1610,12 @@ 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)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ic_msg!(invoke_context, "Unknown program {}", callee_program_id,);
|
||||||
SyscallError::InstructionError(InstructionError::MissingAccount)
|
SyscallError::InstructionError(InstructionError::MissingAccount)
|
||||||
})?)
|
})?
|
||||||
.clone();
|
.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)?;
|
||||||
|
@ -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(()) => (),
|
||||||
|
|
|
@ -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()))
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,7 +371,20 @@ 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 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
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if let Some(account) = self.pre_accounts.iter().find_map(|pre| {
|
if let Some(account) = self.pre_accounts.iter().find_map(|pre| {
|
||||||
if pre.key == *pubkey {
|
if pre.key == *pubkey {
|
||||||
Some(pre.account.clone())
|
Some(pre.account.clone())
|
||||||
|
@ -386,6 +402,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn update_timing(
|
fn update_timing(
|
||||||
&mut self,
|
&mut self,
|
||||||
serialize_us: u64,
|
serialize_us: u64,
|
||||||
|
@ -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
|
||||||
|
let _ = accounts[account_index]
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
.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
|
||||||
|
let _ = account
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.map_err(|_| InstructionError::AccountBorrowOutstanding)?;
|
.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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue