Refactor: Remove Rc from PreAccount and InvokeContext::get_account() (#21882)

* Removes Rc and RefCell from PreAccount

* Splits get_account() into find_index_of_account() and get_account_at_index()
in order to remove Rc from return type.
This commit is contained in:
Alexander Meißner
2021-12-14 15:44:31 +01:00
committed by GitHub
parent c92c09a8be
commit 4adc8b133f
5 changed files with 74 additions and 68 deletions

View File

@ -257,9 +257,9 @@ impl<'a> InvokeContext<'a> {
self.pre_accounts = Vec::with_capacity(instruction.accounts.len());
let mut work = |_unique_index: usize, account_index: usize| {
if account_index < self.accounts.len() {
let account = self.accounts[account_index].1.borrow();
let account = self.accounts[account_index].1.borrow().clone();
self.pre_accounts
.push(PreAccount::new(&self.accounts[account_index].0, &account));
.push(PreAccount::new(&self.accounts[account_index].0, account));
return Ok(());
}
Err(InstructionError::MissingAccount)
@ -461,7 +461,7 @@ impl<'a> InvokeContext<'a> {
.checked_add(u128::from(account.lamports()))
.ok_or(InstructionError::UnbalancedInstruction)?;
if is_writable && !pre_account.executable() {
pre_account.update(&account);
pre_account.update(account.clone());
}
return Ok(());
}
@ -489,12 +489,12 @@ impl<'a> InvokeContext<'a> {
let mut account_indices = Vec::with_capacity(message.account_keys.len());
let mut prev_account_sizes = Vec::with_capacity(message.account_keys.len());
for account_key in message.account_keys.iter() {
let (account_index, account) = self
.get_account(account_key)
let account_index = self
.find_index_of_account(account_key)
.ok_or(InstructionError::MissingAccount)?;
let account_length = account.borrow().data().len();
let account_length = self.accounts[account_index].1.borrow().data().len();
account_indices.push(account_index);
prev_account_sizes.push((account, account_length));
prev_account_sizes.push((account_index, account_length));
}
if let Some(instruction_recorder) = &self.instruction_recorder {
@ -510,8 +510,10 @@ impl<'a> InvokeContext<'a> {
// Verify the called program has not misbehaved
let do_support_realloc = self.feature_set.is_active(&do_support_realloc::id());
for (account, prev_size) in prev_account_sizes.iter() {
if !do_support_realloc && *prev_size != account.borrow().data().len() && *prev_size != 0
for (account_index, prev_size) in prev_account_sizes.into_iter() {
if !do_support_realloc
&& prev_size != self.accounts[account_index].1.borrow().data().len()
&& prev_size != 0
{
// Only support for `CreateAccount` at this time.
// Need a way to limit total realloc size across multiple CPI calls
@ -595,26 +597,27 @@ impl<'a> InvokeContext<'a> {
// Find and validate executables / program accounts
let callee_program_id = instruction.program_id;
let (program_account_index, program_account) = callee_keyed_accounts
let program_account_index = callee_keyed_accounts
.iter()
.find(|keyed_account| &callee_program_id == keyed_account.unsigned_key())
.and_then(|_keyed_account| self.get_account(&callee_program_id))
.and_then(|_keyed_account| self.find_index_of_account(&callee_program_id))
.ok_or_else(|| {
ic_msg!(self, "Unknown program {}", callee_program_id);
InstructionError::MissingAccount
})?;
if !program_account.borrow().executable() {
let program_account = self.accounts[program_account_index].1.borrow();
if !program_account.executable() {
ic_msg!(self, "Account {} is not executable", callee_program_id);
return Err(InstructionError::AccountNotExecutable);
}
let mut program_indices = vec![];
if program_account.borrow().owner() == &bpf_loader_upgradeable::id() {
if program_account.owner() == &bpf_loader_upgradeable::id() {
if let UpgradeableLoaderState::Program {
programdata_address,
} = program_account.borrow().state()?
} = program_account.state()?
{
if let Some((programdata_account_index, _programdata_account)) =
self.get_account(&programdata_address)
if let Some(programdata_account_index) =
self.find_index_of_account(&programdata_address)
{
program_indices.push(programdata_account_index);
} else {
@ -797,16 +800,21 @@ impl<'a> InvokeContext<'a> {
self.executors.borrow().get(pubkey)
}
/// Find an account_index and account by its key
pub fn get_account(&self, pubkey: &Pubkey) -> Option<(usize, Rc<RefCell<AccountSharedData>>)> {
for (index, (key, account)) in self.accounts.iter().enumerate().rev() {
/// Finds an account_index by its key
pub fn find_index_of_account(&self, pubkey: &Pubkey) -> Option<usize> {
for (index, (key, _account)) in self.accounts.iter().enumerate().rev() {
if key == pubkey {
return Some((index, account.clone()));
return Some(index);
}
}
None
}
/// Returns an account by its account_index
pub fn get_account_at_index(&self, account_index: usize) -> &RefCell<AccountSharedData> {
&self.accounts[account_index].1
}
/// Get this invocation's compute budget
pub fn get_compute_budget(&self) -> &ComputeBudget {
&self.current_compute_budget

View File

@ -8,11 +8,7 @@ use {
system_instruction::MAX_PERMITTED_DATA_LENGTH,
system_program,
},
std::{
cell::{Ref, RefCell},
fmt::Debug,
rc::Rc,
},
std::fmt::Debug,
};
// The relevant state of an account before an Instruction executes, used
@ -20,14 +16,14 @@ use {
#[derive(Clone, Debug, Default)]
pub struct PreAccount {
key: Pubkey,
account: Rc<RefCell<AccountSharedData>>,
account: AccountSharedData,
changed: bool,
}
impl PreAccount {
pub fn new(key: &Pubkey, account: &AccountSharedData) -> Self {
pub fn new(key: &Pubkey, account: AccountSharedData) -> Self {
Self {
key: *key,
account: Rc::new(RefCell::new(account.clone())),
account,
changed: false,
}
}
@ -42,7 +38,7 @@ impl PreAccount {
outermost_call: bool,
do_support_realloc: bool,
) -> Result<(), InstructionError> {
let pre = self.account.borrow();
let pre = &self.account;
// Only the owner of the account may change owner and
// only if the account is writable and
@ -157,11 +153,10 @@ impl PreAccount {
Ok(())
}
pub fn update(&mut self, account: &AccountSharedData) {
let mut pre = self.account.borrow_mut();
let rent_epoch = pre.rent_epoch();
*pre = account.clone();
pre.set_rent_epoch(rent_epoch);
pub fn update(&mut self, account: AccountSharedData) {
let rent_epoch = self.account.rent_epoch();
self.account = account;
self.account.set_rent_epoch(rent_epoch);
self.changed = true;
}
@ -170,16 +165,16 @@ impl PreAccount {
&self.key
}
pub fn data(&self) -> Ref<[u8]> {
Ref::map(self.account.borrow(), |account| account.data())
pub fn data(&self) -> &[u8] {
self.account.data()
}
pub fn lamports(&self) -> u64 {
self.account.borrow().lamports()
self.account.lamports()
}
pub fn executable(&self) -> bool {
self.account.borrow().executable()
self.account.executable()
}
pub fn is_zeroed(buf: &[u8]) -> bool {
@ -236,10 +231,9 @@ mod tests {
is_writable: true,
pre: PreAccount::new(
&solana_sdk::pubkey::new_rand(),
&AccountSharedData::from(Account {
AccountSharedData::from(Account {
owner: *owner,
lamports: std::u64::MAX,
data: vec![],
..Account::default()
}),
),
@ -255,12 +249,12 @@ mod tests {
self
}
pub fn executable(mut self, pre: bool, post: bool) -> Self {
self.pre.account.borrow_mut().set_executable(pre);
self.pre.account.set_executable(pre);
self.post.set_executable(post);
self
}
pub fn lamports(mut self, pre: u64, post: u64) -> Self {
self.pre.account.borrow_mut().set_lamports(pre);
self.pre.account.set_lamports(pre);
self.post.set_lamports(post);
self
}
@ -269,12 +263,12 @@ mod tests {
self
}
pub fn data(mut self, pre: Vec<u8>, post: Vec<u8>) -> Self {
self.pre.account.borrow_mut().set_data(pre);
self.pre.account.set_data(pre);
self.post.set_data(post);
self
}
pub fn rent_epoch(mut self, pre: u64, post: u64) -> Self {
self.pre.account.borrow_mut().set_rent_epoch(pre);
self.pre.account.set_rent_epoch(pre);
self.post.set_rent_epoch(post);
self
}