Refactoring: Unify account_deps and accounts (#17898)

* Changes ThisInvokeContext::get_account() to use accounts instead of pre_accounts.

* Adds explicit keys to accounts to make them symmetric to account_deps.

* Appends account_deps to accounts in transaction loading and removes account_deps everywhere else.
This commit is contained in:
Alexander Meißner 2021-07-05 13:49:37 +02:00 committed by GitHub
parent ffb1f3932a
commit 7462c27d07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 289 additions and 308 deletions

View File

@ -290,7 +290,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
'outer: for key in &message.account_keys { 'outer: for key in &message.account_keys {
for account_info in account_infos { for account_info in account_infos {
if account_info.unsigned_key() == key { if account_info.unsigned_key() == key {
accounts.push(Rc::new(RefCell::new(ai_to_a(account_info)))); accounts.push((*key, Rc::new(RefCell::new(ai_to_a(account_info)))));
continue 'outer; continue 'outer;
} }
} }
@ -336,14 +336,12 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.map_err(|err| ProgramError::try_from(err).unwrap_or_else(|err| panic!("{}", err)))?; .map_err(|err| ProgramError::try_from(err).unwrap_or_else(|err| panic!("{}", err)))?;
// Copy writeable account modifications back into the caller's AccountInfos // Copy writeable account modifications back into the caller's AccountInfos
for (i, account_pubkey) in message.account_keys.iter().enumerate() { for (i, (pubkey, account)) in accounts.iter().enumerate().take(message.account_keys.len()) {
if !message.is_writable(i, true) { if !message.is_writable(i, true) {
continue; continue;
} }
for account_info in account_infos { for account_info in account_infos {
if account_info.unsigned_key() == account_pubkey { if account_info.unsigned_key() == pubkey {
let account = &accounts[i];
**account_info.try_borrow_mut_lamports().unwrap() = account.borrow().lamports(); **account_info.try_borrow_mut_lamports().unwrap() = account.borrow().lamports();
let mut data = account_info.try_borrow_mut_data()?; let mut data = account_info.try_borrow_mut_data()?;

View File

@ -1417,7 +1417,7 @@ type TranslatedAccount<'a> = (
Option<AccountReferences<'a>>, Option<AccountReferences<'a>>,
); );
type TranslatedAccounts<'a> = ( type TranslatedAccounts<'a> = (
Vec<Rc<RefCell<AccountSharedData>>>, Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>,
Vec<Option<AccountReferences<'a>>>, Vec<Option<AccountReferences<'a>>>,
); );
@ -2062,7 +2062,7 @@ where
if i == program_account_index || account.borrow().executable() { if i == program_account_index || account.borrow().executable() {
// Use the known account // Use the known account
accounts.push(account); accounts.push((**account_key, 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
@ -2077,7 +2077,7 @@ where
}) })
{ {
let (account, account_ref) = do_translate(account_info, invoke_context)?; let (account, account_ref) = do_translate(account_info, invoke_context)?;
accounts.push(account); accounts.push((**account_key, account));
refs.push(account_ref); refs.push(account_ref);
} else { } else {
ic_msg!( ic_msg!(
@ -2266,6 +2266,7 @@ fn call<'a>(
ic_msg!(invoke_context, "Unknown program {}", callee_program_id,); ic_msg!(invoke_context, "Unknown program {}", callee_program_id,);
SyscallError::InstructionError(InstructionError::MissingAccount) SyscallError::InstructionError(InstructionError::MissingAccount)
})? })?
.1
.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)?;
@ -2307,7 +2308,7 @@ fn call<'a>(
// Copy results back to caller // Copy results back to caller
{ {
let invoke_context = syscall.get_context()?; let invoke_context = syscall.get_context()?;
for (i, (account, account_ref)) in accounts.iter().zip(account_refs).enumerate() { for (i, ((_key, account), account_ref)) in accounts.iter().zip(account_refs).enumerate() {
let account = account.borrow(); let account = account.borrow();
if let Some(mut account_ref) = account_ref { if let Some(mut account_ref) = account_ref {
if message.is_writable(i, demote_sysvar_write_locks) && !account.executable() { if message.is_writable(i, demote_sysvar_write_locks) && !account.executable() {

View File

@ -3096,15 +3096,21 @@ pub mod rpc_full {
accounts.push(if result.is_err() { accounts.push(if result.is_err() {
None None
} else { } else {
transaction (0..transaction.message.account_keys.len())
.message .position(|i| {
.account_keys post_simulation_accounts
.iter() .get(i)
.position(|pubkey| *pubkey == address) .map(|(key, _account)| *key == address)
.map(|i| post_simulation_accounts.get(i)) .unwrap_or(false)
.flatten() })
.map(|account| { .map(|i| {
UiAccount::encode(&address, account, accounts_encoding, None, None) UiAccount::encode(
&address,
&post_simulation_accounts[i].1,
accounts_encoding,
None,
None,
)
}) })
}); });
} }

View File

@ -97,14 +97,12 @@ pub struct Accounts {
} }
// for the load instructions // for the load instructions
pub type TransactionAccounts = Vec<AccountSharedData>; pub type TransactionAccounts = Vec<(Pubkey, AccountSharedData)>;
pub type TransactionAccountDeps = Vec<(Pubkey, AccountSharedData)>;
pub type TransactionRent = u64; pub type TransactionRent = u64;
pub type TransactionLoaders = Vec<Vec<(Pubkey, AccountSharedData)>>; pub type TransactionLoaders = Vec<Vec<(Pubkey, AccountSharedData)>>;
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub struct LoadedTransaction { pub struct LoadedTransaction {
pub accounts: TransactionAccounts, pub accounts: TransactionAccounts,
pub account_deps: TransactionAccountDeps,
pub loaders: TransactionLoaders, pub loaders: TransactionLoaders,
pub rent: TransactionRent, pub rent: TransactionRent,
pub rent_debits: RentDebits, pub rent_debits: RentDebits,
@ -277,20 +275,27 @@ impl Accounts {
// Fill in an empty account for the program slots. // Fill in an empty account for the program slots.
AccountSharedData::default() AccountSharedData::default()
}; };
accounts.push(account); accounts.push((*key, account));
} }
debug_assert_eq!(accounts.len(), message.account_keys.len()); debug_assert_eq!(accounts.len(), message.account_keys.len());
// Appends the account_deps at the end of the accounts,
// this way they can be accessed in a uniform way.
// At places where only the accounts are needed,
// the account_deps are truncated using e.g:
// accounts.iter().take(message.account_keys.len())
accounts.append(&mut account_deps);
if let Some(payer_index) = payer_index { if let Some(payer_index) = payer_index {
if payer_index != 0 { if payer_index != 0 {
warn!("Payer index should be 0! {:?}", tx); warn!("Payer index should be 0! {:?}", tx);
} }
if accounts[payer_index].lamports() == 0 { let payer_account = &mut accounts[payer_index].1;
if payer_account.lamports() == 0 {
error_counters.account_not_found += 1; error_counters.account_not_found += 1;
Err(TransactionError::AccountNotFound) Err(TransactionError::AccountNotFound)
} else { } else {
let min_balance = match get_system_account_kind(&accounts[payer_index]) let min_balance =
.ok_or_else(|| { match get_system_account_kind(payer_account).ok_or_else(|| {
error_counters.invalid_account_for_fee += 1; error_counters.invalid_account_for_fee += 1;
TransactionError::InvalidAccountForFee TransactionError::InvalidAccountForFee
})? { })? {
@ -302,11 +307,11 @@ impl Accounts {
} }
}; };
if accounts[payer_index].lamports() < fee + min_balance { if payer_account.lamports() < fee + min_balance {
error_counters.insufficient_funds += 1; error_counters.insufficient_funds += 1;
Err(TransactionError::InsufficientFundsForFee) Err(TransactionError::InsufficientFundsForFee)
} else { } else {
accounts[payer_index] payer_account
.checked_sub_lamports(fee) .checked_sub_lamports(fee)
.map_err(|_| TransactionError::InsufficientFundsForFee)?; .map_err(|_| TransactionError::InsufficientFundsForFee)?;
@ -329,7 +334,6 @@ impl Accounts {
.collect::<Result<TransactionLoaders>>()?; .collect::<Result<TransactionLoaders>>()?;
Ok(LoadedTransaction { Ok(LoadedTransaction {
accounts, accounts,
account_deps,
loaders, loaders,
rent: tx_rent, rent: tx_rent,
rent_debits, rent_debits,
@ -992,12 +996,9 @@ impl Accounts {
let message = &tx.message(); let message = &tx.message();
let loaded_transaction = raccs.as_mut().unwrap(); let loaded_transaction = raccs.as_mut().unwrap();
let mut fee_payer_index = None; let mut fee_payer_index = None;
for ((i, key), account) in message for (i, (key, account)) in (0..message.account_keys.len())
.account_keys
.iter()
.enumerate()
.zip(loaded_transaction.accounts.iter_mut()) .zip(loaded_transaction.accounts.iter_mut())
.filter(|((i, key), _account)| message.is_non_loader_key(key, *i)) .filter(|(i, (key, _account))| message.is_non_loader_key(key, *i))
{ {
let is_nonce_account = prepare_if_nonce_account( let is_nonce_account = prepare_if_nonce_account(
account, account,
@ -1035,7 +1036,7 @@ impl Accounts {
.rent_debits .rent_debits
.push(key, rent, account.lamports()); .push(key, rent, account.lamports());
} }
accounts.push((key, &*account)); accounts.push((&*key, &*account));
} }
} }
} }
@ -1377,7 +1378,7 @@ mod tests {
assert_eq!(loaded_accounts.len(), 1); assert_eq!(loaded_accounts.len(), 1);
let (load_res, _nonce_rollback) = &loaded_accounts[0]; let (load_res, _nonce_rollback) = &loaded_accounts[0];
let loaded_transaction = load_res.as_ref().unwrap(); let loaded_transaction = load_res.as_ref().unwrap();
assert_eq!(loaded_transaction.accounts[0].lamports(), min_balance); assert_eq!(loaded_transaction.accounts[0].1.lamports(), min_balance);
// Fee leaves zero balance fails // Fee leaves zero balance fails
accounts[0].1.set_lamports(min_balance); accounts[0].1.set_lamports(min_balance);
@ -1439,7 +1440,7 @@ mod tests {
match &loaded_accounts[0] { match &loaded_accounts[0] {
(Ok(loaded_transaction), _nonce_rollback) => { (Ok(loaded_transaction), _nonce_rollback) => {
assert_eq!(loaded_transaction.accounts.len(), 3); assert_eq!(loaded_transaction.accounts.len(), 3);
assert_eq!(loaded_transaction.accounts[0], accounts[0].1); assert_eq!(loaded_transaction.accounts[0].1, accounts[0].1);
assert_eq!(loaded_transaction.loaders.len(), 1); assert_eq!(loaded_transaction.loaders.len(), 1);
assert_eq!(loaded_transaction.loaders[0].len(), 0); assert_eq!(loaded_transaction.loaders[0].len(), 0);
} }
@ -1662,7 +1663,7 @@ mod tests {
match &loaded_accounts[0] { match &loaded_accounts[0] {
(Ok(loaded_transaction), _nonce_rollback) => { (Ok(loaded_transaction), _nonce_rollback) => {
assert_eq!(loaded_transaction.accounts.len(), 3); assert_eq!(loaded_transaction.accounts.len(), 3);
assert_eq!(loaded_transaction.accounts[0], accounts[0].1); assert_eq!(loaded_transaction.accounts[0].1, accounts[0].1);
assert_eq!(loaded_transaction.loaders.len(), 2); assert_eq!(loaded_transaction.loaders.len(), 2);
assert_eq!(loaded_transaction.loaders[0].len(), 1); assert_eq!(loaded_transaction.loaders[0].len(), 1);
assert_eq!(loaded_transaction.loaders[1].len(), 2); assert_eq!(loaded_transaction.loaders[1].len(), 2);
@ -1970,6 +1971,9 @@ mod tests {
let keypair0 = Keypair::new(); let keypair0 = Keypair::new();
let keypair1 = Keypair::new(); let keypair1 = Keypair::new();
let pubkey = solana_sdk::pubkey::new_rand(); let pubkey = solana_sdk::pubkey::new_rand();
let account0 = AccountSharedData::new(1, 0, &Pubkey::default());
let account1 = AccountSharedData::new(2, 0, &Pubkey::default());
let account2 = AccountSharedData::new(3, 0, &Pubkey::default());
let rent_collector = RentCollector::default(); let rent_collector = RentCollector::default();
@ -1982,6 +1986,10 @@ mod tests {
Hash::default(), Hash::default(),
instructions, instructions,
); );
let transaction_accounts0 = vec![
(message.account_keys[0], account0),
(message.account_keys[1], account2.clone()),
];
let tx0 = Transaction::new(&[&keypair0], message, Hash::default()); let tx0 = Transaction::new(&[&keypair0], message, Hash::default());
let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])]; let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
@ -1993,22 +2001,19 @@ mod tests {
Hash::default(), Hash::default(),
instructions, instructions,
); );
let transaction_accounts1 = vec![
(message.account_keys[0], account1),
(message.account_keys[1], account2),
];
let tx1 = Transaction::new(&[&keypair1], message, Hash::default()); let tx1 = Transaction::new(&[&keypair1], message, Hash::default());
let txs = vec![tx0, tx1];
let loaders = vec![(Ok(()), None), (Ok(()), None)]; let loaders = vec![(Ok(()), None), (Ok(()), None)];
let account0 = AccountSharedData::new(1, 0, &Pubkey::default());
let account1 = AccountSharedData::new(2, 0, &Pubkey::default());
let account2 = AccountSharedData::new(3, 0, &Pubkey::default());
let transaction_accounts0 = vec![account0, account2.clone()];
let transaction_loaders0 = vec![]; let transaction_loaders0 = vec![];
let transaction_rent0 = 0; let transaction_rent0 = 0;
let loaded0 = ( let loaded0 = (
Ok(LoadedTransaction { Ok(LoadedTransaction {
accounts: transaction_accounts0, accounts: transaction_accounts0,
account_deps: vec![],
loaders: transaction_loaders0, loaders: transaction_loaders0,
rent: transaction_rent0, rent: transaction_rent0,
rent_debits: RentDebits::default(), rent_debits: RentDebits::default(),
@ -2016,13 +2021,11 @@ mod tests {
None, None,
); );
let transaction_accounts1 = vec![account1, account2];
let transaction_loaders1 = vec![]; let transaction_loaders1 = vec![];
let transaction_rent1 = 0; let transaction_rent1 = 0;
let loaded1 = ( let loaded1 = (
Ok(LoadedTransaction { Ok(LoadedTransaction {
accounts: transaction_accounts1, accounts: transaction_accounts1,
account_deps: vec![],
loaders: transaction_loaders1, loaders: transaction_loaders1,
rent: transaction_rent1, rent: transaction_rent1,
rent_debits: RentDebits::default(), rent_debits: RentDebits::default(),
@ -2046,6 +2049,7 @@ mod tests {
.unwrap() .unwrap()
.insert_new_readonly(&pubkey); .insert_new_readonly(&pubkey);
} }
let txs = &[tx0, tx1];
let collected_accounts = accounts.collect_accounts_to_store( let collected_accounts = accounts.collect_accounts_to_store(
txs.iter(), txs.iter(),
&loaders, &loaders,
@ -2349,16 +2353,34 @@ mod tests {
let from = keypair_from_seed(&[1; 32]).unwrap(); let from = keypair_from_seed(&[1; 32]).unwrap();
let from_address = from.pubkey(); let from_address = from.pubkey();
let to_address = Pubkey::new_unique(); let to_address = Pubkey::new_unique();
let nonce_state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: nonce_authority.pubkey(),
blockhash: Hash::new_unique(),
fee_calculator: FeeCalculator::default(),
}));
let nonce_account_post =
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
let from_account_post = AccountSharedData::new(4199, 0, &Pubkey::default());
let to_account = AccountSharedData::new(2, 0, &Pubkey::default());
let nonce_authority_account = AccountSharedData::new(3, 0, &Pubkey::default());
let recent_blockhashes_sysvar_account = AccountSharedData::new(4, 0, &Pubkey::default());
let instructions = vec![ let instructions = vec![
system_instruction::advance_nonce_account(&nonce_address, &nonce_authority.pubkey()), system_instruction::advance_nonce_account(&nonce_address, &nonce_authority.pubkey()),
system_instruction::transfer(&from_address, &to_address, 42), system_instruction::transfer(&from_address, &to_address, 42),
]; ];
let message = Message::new(&instructions, Some(&from_address)); let message = Message::new(&instructions, Some(&from_address));
let blockhash = Hash::new_unique(); let blockhash = Hash::new_unique();
let transaction_accounts = vec![
(message.account_keys[0], from_account_post),
(message.account_keys[1], nonce_authority_account),
(message.account_keys[2], nonce_account_post),
(message.account_keys[3], to_account),
(message.account_keys[4], recent_blockhashes_sysvar_account),
];
let tx = Transaction::new(&[&nonce_authority, &from], message, blockhash); let tx = Transaction::new(&[&nonce_authority, &from], message, blockhash);
let txs = vec![tx];
let nonce_state = let nonce_state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: nonce_authority.pubkey(), authority: nonce_authority.pubkey(),
@ -2382,33 +2404,11 @@ mod tests {
nonce_rollback.clone(), nonce_rollback.clone(),
)]; )];
let nonce_state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: nonce_authority.pubkey(),
blockhash: Hash::new_unique(),
fee_calculator: FeeCalculator::default(),
}));
let nonce_account_post =
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
let from_account_post = AccountSharedData::new(4199, 0, &Pubkey::default());
let to_account = AccountSharedData::new(2, 0, &Pubkey::default());
let nonce_authority_account = AccountSharedData::new(3, 0, &Pubkey::default());
let recent_blockhashes_sysvar_account = AccountSharedData::new(4, 0, &Pubkey::default());
let transaction_accounts = vec![
from_account_post,
nonce_authority_account,
nonce_account_post,
to_account,
recent_blockhashes_sysvar_account,
];
let transaction_loaders = vec![]; let transaction_loaders = vec![];
let transaction_rent = 0; let transaction_rent = 0;
let loaded = ( let loaded = (
Ok(LoadedTransaction { Ok(LoadedTransaction {
accounts: transaction_accounts, accounts: transaction_accounts,
account_deps: vec![],
loaders: transaction_loaders, loaders: transaction_loaders,
rent: transaction_rent, rent: transaction_rent,
rent_debits: RentDebits::default(), rent_debits: RentDebits::default(),
@ -2426,6 +2426,7 @@ mod tests {
false, false,
AccountShrinkThreshold::default(), AccountShrinkThreshold::default(),
); );
let txs = &[tx];
let collected_accounts = accounts.collect_accounts_to_store( let collected_accounts = accounts.collect_accounts_to_store(
txs.iter(), txs.iter(),
&loaders, &loaders,
@ -2470,16 +2471,34 @@ mod tests {
let from = keypair_from_seed(&[1; 32]).unwrap(); let from = keypair_from_seed(&[1; 32]).unwrap();
let from_address = from.pubkey(); let from_address = from.pubkey();
let to_address = Pubkey::new_unique(); let to_address = Pubkey::new_unique();
let nonce_state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: nonce_authority.pubkey(),
blockhash: Hash::new_unique(),
fee_calculator: FeeCalculator::default(),
}));
let nonce_account_post =
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
let from_account_post = AccountSharedData::new(4200, 0, &Pubkey::default());
let to_account = AccountSharedData::new(2, 0, &Pubkey::default());
let nonce_authority_account = AccountSharedData::new(3, 0, &Pubkey::default());
let recent_blockhashes_sysvar_account = AccountSharedData::new(4, 0, &Pubkey::default());
let instructions = vec![ let instructions = vec![
system_instruction::advance_nonce_account(&nonce_address, &nonce_authority.pubkey()), system_instruction::advance_nonce_account(&nonce_address, &nonce_authority.pubkey()),
system_instruction::transfer(&from_address, &to_address, 42), system_instruction::transfer(&from_address, &to_address, 42),
]; ];
let message = Message::new(&instructions, Some(&nonce_address)); let message = Message::new(&instructions, Some(&nonce_address));
let blockhash = Hash::new_unique(); let blockhash = Hash::new_unique();
let transaction_accounts = vec![
(message.account_keys[0], from_account_post),
(message.account_keys[1], nonce_authority_account),
(message.account_keys[2], nonce_account_post),
(message.account_keys[3], to_account),
(message.account_keys[4], recent_blockhashes_sysvar_account),
];
let tx = Transaction::new(&[&nonce_authority, &from], message, blockhash); let tx = Transaction::new(&[&nonce_authority, &from], message, blockhash);
let txs = vec![tx];
let nonce_state = let nonce_state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data { nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: nonce_authority.pubkey(), authority: nonce_authority.pubkey(),
@ -2502,33 +2521,11 @@ mod tests {
nonce_rollback.clone(), nonce_rollback.clone(),
)]; )];
let nonce_state =
nonce::state::Versions::new_current(nonce::State::Initialized(nonce::state::Data {
authority: nonce_authority.pubkey(),
blockhash: Hash::new_unique(),
fee_calculator: FeeCalculator::default(),
}));
let nonce_account_post =
AccountSharedData::new_data(43, &nonce_state, &system_program::id()).unwrap();
let from_account_post = AccountSharedData::new(4200, 0, &Pubkey::default());
let to_account = AccountSharedData::new(2, 0, &Pubkey::default());
let nonce_authority_account = AccountSharedData::new(3, 0, &Pubkey::default());
let recent_blockhashes_sysvar_account = AccountSharedData::new(4, 0, &Pubkey::default());
let transaction_accounts = vec![
from_account_post,
nonce_authority_account,
nonce_account_post,
to_account,
recent_blockhashes_sysvar_account,
];
let transaction_loaders = vec![]; let transaction_loaders = vec![];
let transaction_rent = 0; let transaction_rent = 0;
let loaded = ( let loaded = (
Ok(LoadedTransaction { Ok(LoadedTransaction {
accounts: transaction_accounts, accounts: transaction_accounts,
account_deps: vec![],
loaders: transaction_loaders, loaders: transaction_loaders,
rent: transaction_rent, rent: transaction_rent,
rent_debits: RentDebits::default(), rent_debits: RentDebits::default(),
@ -2546,6 +2543,7 @@ mod tests {
false, false,
AccountShrinkThreshold::default(), AccountShrinkThreshold::default(),
); );
let txs = &[tx];
let collected_accounts = accounts.collect_accounts_to_store( let collected_accounts = accounts.collect_accounts_to_store(
txs.iter(), txs.iter(),
&loaders, &loaders,

View File

@ -35,8 +35,8 @@
//! already been signed and verified. //! already been signed and verified.
use crate::{ use crate::{
accounts::{ accounts::{
AccountAddressFilter, Accounts, TransactionAccountDeps, TransactionAccounts, AccountAddressFilter, Accounts, TransactionAccounts, TransactionLoadResult,
TransactionLoadResult, TransactionLoaders, TransactionLoaders,
}, },
accounts_db::{AccountShrinkThreshold, ErrorCounters, SnapshotStorages}, accounts_db::{AccountShrinkThreshold, ErrorCounters, SnapshotStorages},
accounts_index::{AccountSecondaryIndexes, IndexKey, ScanResult}, accounts_index::{AccountSecondaryIndexes, IndexKey, ScanResult},
@ -177,8 +177,7 @@ impl ExecuteTimings {
type BankStatusCache = StatusCache<Result<()>>; type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "HhY4tMP5KZU9fw9VLpMMUikfvNVCLksocZBUKjt8ZjYH")] #[frozen_abi(digest = "HhY4tMP5KZU9fw9VLpMMUikfvNVCLksocZBUKjt8ZjYH")]
pub type BankSlotDelta = SlotDelta<Result<()>>; pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<Rc<RefCell<AccountSharedData>>>; type TransactionAccountRefCells = Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>;
type TransactionAccountDepRefCells = Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>;
type TransactionLoaderRefCells = Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>>; type TransactionLoaderRefCells = Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>>;
// Eager rent collection repeats in cyclic manner. // Eager rent collection repeats in cyclic manner.
@ -625,30 +624,32 @@ impl NonceRollbackFull {
pub fn from_partial( pub fn from_partial(
partial: NonceRollbackPartial, partial: NonceRollbackPartial,
message: &Message, message: &Message,
accounts: &[AccountSharedData], accounts: &[(Pubkey, AccountSharedData)],
) -> Result<Self> { ) -> Result<Self> {
let NonceRollbackPartial { let NonceRollbackPartial {
nonce_address, nonce_address,
nonce_account, nonce_account,
} = partial; } = partial;
let fee_payer = message let fee_payer = (0..message.account_keys.len()).find_map(|i| {
.account_keys if let Some((k, a)) = &accounts.get(i) {
.iter() if message.is_non_loader_key(k, i) {
.enumerate() return Some((k, a));
.find(|(i, k)| message.is_non_loader_key(k, *i)) }
.and_then(|(i, k)| accounts.get(i).cloned().map(|a| (*k, a))); }
None
});
if let Some((fee_pubkey, fee_account)) = fee_payer { if let Some((fee_pubkey, fee_account)) = fee_payer {
if fee_pubkey == nonce_address { if *fee_pubkey == nonce_address {
Ok(Self { Ok(Self {
nonce_address, nonce_address,
nonce_account: fee_account, nonce_account: fee_account.clone(),
fee_account: None, fee_account: None,
}) })
} else { } else {
Ok(Self { Ok(Self {
nonce_address, nonce_address,
nonce_account, nonce_account,
fee_account: Some(fee_account), fee_account: Some(fee_account.clone()),
}) })
} }
} else { } else {
@ -2643,7 +2644,11 @@ impl Bank {
pub fn simulate_transaction( pub fn simulate_transaction(
&self, &self,
transaction: &Transaction, transaction: &Transaction,
) -> (Result<()>, TransactionLogMessages, Vec<AccountSharedData>) { ) -> (
Result<()>,
TransactionLogMessages,
Vec<(Pubkey, AccountSharedData)>,
) {
assert!(self.is_frozen(), "simulation bank must be frozen"); assert!(self.is_frozen(), "simulation bank must be frozen");
let batch = self.prepare_simulation_batch(transaction); let batch = self.prepare_simulation_batch(transaction);
@ -2651,7 +2656,7 @@ impl Bank {
let mut timings = ExecuteTimings::default(); let mut timings = ExecuteTimings::default();
let ( let (
loaded_accounts, loaded_txs,
executed, executed,
_inner_instructions, _inner_instructions,
log_messages, log_messages,
@ -2673,7 +2678,7 @@ impl Bank {
let log_messages = log_messages let log_messages = log_messages
.get(0) .get(0)
.map_or(vec![], |messages| messages.to_vec()); .map_or(vec![], |messages| messages.to_vec());
let post_transaction_accounts = loaded_accounts let post_transaction_accounts = loaded_txs
.into_iter() .into_iter()
.next() .next()
.unwrap() .unwrap()
@ -2940,20 +2945,11 @@ impl Bank {
/// ownership by draining the source /// ownership by draining the source
fn accounts_to_refcells( fn accounts_to_refcells(
accounts: &mut TransactionAccounts, accounts: &mut TransactionAccounts,
account_deps: &mut TransactionAccountDeps,
loaders: &mut TransactionLoaders, loaders: &mut TransactionLoaders,
) -> ( ) -> (TransactionAccountRefCells, TransactionLoaderRefCells) {
TransactionAccountRefCells,
TransactionAccountDepRefCells,
TransactionLoaderRefCells,
) {
let account_refcells: Vec<_> = accounts let account_refcells: Vec<_> = accounts
.drain(..) .drain(..)
.map(|account| Rc::new(RefCell::new(account))) .map(|(pubkey, account)| (pubkey, Rc::new(RefCell::new(account))))
.collect();
let account_dep_refcells: Vec<_> = account_deps
.drain(..)
.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()
@ -2963,7 +2959,7 @@ impl Bank {
.collect() .collect()
}) })
.collect(); .collect();
(account_refcells, account_dep_refcells, loader_refcells) (account_refcells, loader_refcells)
} }
/// Converts back from RefCell<AccountSharedData> to AccountSharedData, this involves moving /// Converts back from RefCell<AccountSharedData> to AccountSharedData, this involves moving
@ -2974,12 +2970,13 @@ impl Bank {
mut account_refcells: TransactionAccountRefCells, mut account_refcells: TransactionAccountRefCells,
loader_refcells: TransactionLoaderRefCells, loader_refcells: TransactionLoaderRefCells,
) -> std::result::Result<(), TransactionError> { ) -> std::result::Result<(), TransactionError> {
for account_refcell in account_refcells.drain(..) { for (pubkey, account_refcell) in account_refcells.drain(..) {
accounts.push( accounts.push((
pubkey,
Rc::try_unwrap(account_refcell) Rc::try_unwrap(account_refcell)
.map_err(|_| TransactionError::AccountBorrowOutstanding)? .map_err(|_| TransactionError::AccountBorrowOutstanding)?
.into_inner(), .into_inner(),
) ))
} }
for (ls, mut lrcs) in loaders.iter_mut().zip(loader_refcells) { for (ls, mut lrcs) in loaders.iter_mut().zip(loader_refcells) {
for (pubkey, lrc) in lrcs.drain(..) { for (pubkey, lrc) in lrcs.drain(..) {
@ -3106,7 +3103,7 @@ impl Bank {
check_time.stop(); check_time.stop();
let mut load_time = Measure::start("accounts_load"); let mut load_time = Measure::start("accounts_load");
let mut loaded_accounts = self.rc.accounts.load_accounts( let mut loaded_txs = self.rc.accounts.load_accounts(
&self.ancestors, &self.ancestors,
hashed_txs.as_transactions_iter(), hashed_txs.as_transactions_iter(),
check_results, check_results,
@ -3126,7 +3123,7 @@ impl Bank {
.bpf_compute_budget .bpf_compute_budget
.unwrap_or_else(BpfComputeBudget::new); .unwrap_or_else(BpfComputeBudget::new);
let executed: Vec<TransactionExecutionResult> = loaded_accounts let executed: Vec<TransactionExecutionResult> = loaded_txs
.iter_mut() .iter_mut()
.zip(hashed_txs.as_transactions_iter()) .zip(hashed_txs.as_transactions_iter())
.map(|(accs, tx)| match accs { .map(|(accs, tx)| match accs {
@ -3135,10 +3132,8 @@ impl Bank {
signature_count += u64::from(tx.message().header.num_required_signatures); signature_count += u64::from(tx.message().header.num_required_signatures);
let executors = self.get_executors(&tx.message, &loaded_transaction.loaders); let executors = self.get_executors(&tx.message, &loaded_transaction.loaders);
let (account_refcells, account_dep_refcells, loader_refcells) = let (account_refcells, loader_refcells) = Self::accounts_to_refcells(
Self::accounts_to_refcells(
&mut loaded_transaction.accounts, &mut loaded_transaction.accounts,
&mut loaded_transaction.account_deps,
&mut loaded_transaction.loaders, &mut loaded_transaction.loaders,
); );
@ -3161,7 +3156,6 @@ impl Bank {
tx.message(), tx.message(),
&loader_refcells, &loader_refcells,
&account_refcells, &account_refcells,
&account_dep_refcells,
&self.rent_collector, &self.rent_collector,
log_collector.clone(), log_collector.clone(),
executors.clone(), executors.clone(),
@ -3308,7 +3302,7 @@ impl Bank {
} }
Self::update_error_counters(&error_counters); Self::update_error_counters(&error_counters);
( (
loaded_accounts, loaded_txs,
executed, executed,
inner_instructions, inner_instructions,
transaction_log_messages, transaction_log_messages,
@ -3380,7 +3374,7 @@ impl Bank {
pub fn commit_transactions( pub fn commit_transactions(
&self, &self,
hashed_txs: &[HashedTransaction], hashed_txs: &[HashedTransaction],
loaded_accounts: &mut [TransactionLoadResult], loaded_txs: &mut [TransactionLoadResult],
executed: &[TransactionExecutionResult], executed: &[TransactionExecutionResult],
tx_count: u64, tx_count: u64,
signature_count: u64, signature_count: u64,
@ -3419,19 +3413,16 @@ impl Bank {
self.slot(), self.slot(),
hashed_txs.as_transactions_iter(), hashed_txs.as_transactions_iter(),
executed, executed,
loaded_accounts, loaded_txs,
&self.rent_collector, &self.rent_collector,
&self.last_blockhash_with_fee_calculator(), &self.last_blockhash_with_fee_calculator(),
self.fix_recent_blockhashes_sysvar_delay(), self.fix_recent_blockhashes_sysvar_delay(),
self.demote_sysvar_write_locks(), self.demote_sysvar_write_locks(),
); );
let rent_debits = self.collect_rent(executed, loaded_accounts); let rent_debits = self.collect_rent(executed, loaded_txs);
let overwritten_vote_accounts = self.update_cached_accounts( let overwritten_vote_accounts =
hashed_txs.as_transactions_iter(), self.update_cached_accounts(hashed_txs.as_transactions_iter(), executed, loaded_txs);
executed,
loaded_accounts,
);
// once committed there is no way to unroll // once committed there is no way to unroll
write_time.stop(); write_time.stop();
@ -3611,11 +3602,11 @@ impl Bank {
fn collect_rent( fn collect_rent(
&self, &self,
res: &[TransactionExecutionResult], res: &[TransactionExecutionResult],
loaded_accounts: &mut [TransactionLoadResult], loaded_txs: &mut [TransactionLoadResult],
) -> Vec<RentDebits> { ) -> Vec<RentDebits> {
let mut collected_rent: u64 = 0; let mut collected_rent: u64 = 0;
let mut rent_debits: Vec<RentDebits> = Vec::with_capacity(loaded_accounts.len()); let mut rent_debits: Vec<RentDebits> = Vec::with_capacity(loaded_txs.len());
for (i, (raccs, _nonce_rollback)) in loaded_accounts.iter_mut().enumerate() { for (i, (raccs, _nonce_rollback)) in loaded_txs.iter_mut().enumerate() {
let (res, _nonce_rollback) = &res[i]; let (res, _nonce_rollback) = &res[i];
if res.is_err() || raccs.is_err() { if res.is_err() || raccs.is_err() {
rent_debits.push(RentDebits::default()); rent_debits.push(RentDebits::default());
@ -4054,7 +4045,7 @@ impl Bank {
}; };
let ( let (
mut loaded_accounts, mut loaded_txs,
executed, executed,
inner_instructions, inner_instructions,
transaction_logs, transaction_logs,
@ -4071,7 +4062,7 @@ impl Bank {
let results = self.commit_transactions( let results = self.commit_transactions(
batch.hashed_transactions(), batch.hashed_transactions(),
&mut loaded_accounts, &mut loaded_txs,
&executed, &executed,
tx_count, tx_count,
signature_count, signature_count,
@ -4793,10 +4784,10 @@ impl Bank {
&self, &self,
txs: impl Iterator<Item = &'a Transaction>, txs: impl Iterator<Item = &'a Transaction>,
res: &[TransactionExecutionResult], res: &[TransactionExecutionResult],
loaded: &[TransactionLoadResult], loaded_txs: &[TransactionLoadResult],
) -> Vec<OverwrittenVoteAccount> { ) -> Vec<OverwrittenVoteAccount> {
let mut overwritten_vote_accounts = vec![]; let mut overwritten_vote_accounts = vec![];
for (i, ((raccs, _load_nonce_rollback), tx)) in loaded.iter().zip(txs).enumerate() { for (i, ((raccs, _load_nonce_rollback), tx)) in loaded_txs.iter().zip(txs).enumerate() {
let (res, _res_nonce_rollback) = &res[i]; let (res, _res_nonce_rollback) = &res[i];
if res.is_err() || raccs.is_err() { if res.is_err() || raccs.is_err() {
continue; continue;
@ -4805,11 +4796,9 @@ impl Bank {
let message = &tx.message(); let message = &tx.message();
let loaded_transaction = raccs.as_ref().unwrap(); let loaded_transaction = raccs.as_ref().unwrap();
for (pubkey, account) in message for (_i, (pubkey, account)) in (0..message.account_keys.len())
.account_keys
.iter()
.zip(loaded_transaction.accounts.iter()) .zip(loaded_transaction.accounts.iter())
.filter(|(_key, account)| (Stakes::is_stake(account))) .filter(|(_i, (_pubkey, account))| (Stakes::is_stake(account)))
{ {
if Stakes::is_stake(account) { if Stakes::is_stake(account) {
if let Some(old_vote_account) = self.stakes.write().unwrap().store( if let Some(old_vote_account) = self.stakes.write().unwrap().store(
@ -5433,10 +5422,13 @@ pub(crate) mod tests {
let to_account = AccountSharedData::new(45, 0, &Pubkey::default()); let to_account = AccountSharedData::new(45, 0, &Pubkey::default());
let recent_blockhashes_sysvar_account = AccountSharedData::new(4, 0, &Pubkey::default()); let recent_blockhashes_sysvar_account = AccountSharedData::new(4, 0, &Pubkey::default());
let accounts = [ let accounts = [
from_account.clone(), (message.account_keys[0], from_account.clone()),
nonce_account.clone(), (message.account_keys[1], nonce_account.clone()),
to_account.clone(), (message.account_keys[2], to_account.clone()),
(
message.account_keys[3],
recent_blockhashes_sysvar_account.clone(), recent_blockhashes_sysvar_account.clone(),
),
]; ];
// NonceRollbackFull create + NonceRollbackInfo impl // NonceRollbackFull create + NonceRollbackInfo impl
@ -5448,10 +5440,10 @@ pub(crate) mod tests {
let message = Message::new(&instructions, Some(&nonce_address)); let message = Message::new(&instructions, Some(&nonce_address));
let accounts = [ let accounts = [
nonce_account, (message.account_keys[0], nonce_account),
from_account, (message.account_keys[1], from_account),
to_account, (message.account_keys[2], to_account),
recent_blockhashes_sysvar_account, (message.account_keys[3], recent_blockhashes_sysvar_account),
]; ];
// Nonce account is fee-payer // Nonce account is fee-payer

View File

@ -260,9 +260,8 @@ impl ComputeMeter for ThisComputeMeter {
pub struct ThisInvokeContext<'a> { pub struct ThisInvokeContext<'a> {
invoke_stack: Vec<InvokeContextStackFrame<'a>>, invoke_stack: Vec<InvokeContextStackFrame<'a>>,
rent: Rent, rent: Rent,
message: &'a Message,
pre_accounts: Vec<PreAccount>, pre_accounts: Vec<PreAccount>,
account_deps: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)], accounts: &'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,
@ -284,8 +283,7 @@ impl<'a> ThisInvokeContext<'a> {
message: &'a Message, message: &'a Message,
instruction: &'a CompiledInstruction, instruction: &'a CompiledInstruction,
executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)], executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &'a [Rc<RefCell<AccountSharedData>>], accounts: &'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,
@ -306,9 +304,8 @@ impl<'a> ThisInvokeContext<'a> {
let mut invoke_context = Self { let mut invoke_context = Self {
invoke_stack: Vec::with_capacity(bpf_compute_budget.max_invoke_depth), invoke_stack: Vec::with_capacity(bpf_compute_budget.max_invoke_depth),
rent, rent,
message,
pre_accounts, pre_accounts,
account_deps, accounts,
programs, programs,
logger: Rc::new(RefCell::new(ThisLogger { log_collector })), logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
bpf_compute_budget, bpf_compute_budget,
@ -361,25 +358,21 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
let keyed_accounts = keyed_accounts let keyed_accounts = keyed_accounts
.iter() .iter()
.map(|(is_signer, is_writable, search_key, account)| { .map(|(is_signer, is_writable, search_key, account)| {
self.account_deps self.accounts
.iter() .iter()
.map(|(key, _account)| key) .position(|(key, _account)| key == *search_key)
.chain(self.message.account_keys.iter()) .map(|index| {
.position(|key| key == *search_key)
.map(|mut index| {
// TODO // TODO
// Currently we are constructing new accounts on the stack // Currently we are constructing new accounts on the stack
// before calling MessageProcessor::process_cross_program_instruction // before calling MessageProcessor::process_cross_program_instruction
// Ideally we would recycle the existing accounts here. // Ideally we would recycle the existing accounts here.
let key = if index < self.account_deps.len() { (
&self.account_deps[index].0 *is_signer,
// &self.account_deps[index].1 as &RefCell<AccountSharedData>, *is_writable,
} else { &self.accounts[index].0,
index = index.saturating_sub(self.account_deps.len()); // &self.accounts[index] as &RefCell<AccountSharedData>
&self.message.account_keys[index] transmute_lifetime(*account),
// &self.accounts[index] as &RefCell<AccountSharedData>, )
};
(*is_signer, *is_writable, key, transmute_lifetime(*account))
}) })
}) })
.collect::<Option<Vec<_>>>() .collect::<Option<Vec<_>>>()
@ -400,7 +393,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
&mut self, &mut self,
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_write_privileges: Option<&[bool]>, caller_write_privileges: Option<&[bool]>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
let stack_frame = self let stack_frame = self
@ -469,16 +462,7 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
self.feature_set.is_active(feature_id) self.feature_set.is_active(feature_id)
} }
fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> { fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>> {
if let Some(account) = self.pre_accounts.iter().find_map(|pre| { self.accounts.iter().find_map(|(key, account)| {
if pre.key == *pubkey {
Some(pre.account.clone())
} else {
None
}
}) {
return Some(account);
}
self.account_deps.iter().find_map(|(key, account)| {
if key == pubkey { if key == pubkey {
Some(account.clone()) Some(account.clone())
} else { } else {
@ -628,7 +612,7 @@ impl MessageProcessor {
message: &'a Message, message: &'a Message,
instruction: &'a CompiledInstruction, instruction: &'a CompiledInstruction,
executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)], executable_accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &'a [Rc<RefCell<AccountSharedData>>], accounts: &'a [(Pubkey, Rc<RefCell<AccountSharedData>>)],
demote_sysvar_write_locks: bool, demote_sysvar_write_locks: bool,
) -> Vec<(bool, bool, &'a Pubkey, &'a RefCell<AccountSharedData>)> { ) -> Vec<(bool, bool, &'a Pubkey, &'a RefCell<AccountSharedData>)> {
executable_accounts executable_accounts
@ -639,8 +623,8 @@ impl MessageProcessor {
( (
message.is_signer(index), message.is_signer(index),
message.is_writable(index, demote_sysvar_write_locks), message.is_writable(index, demote_sysvar_write_locks),
&message.account_keys[index], &accounts[index].0,
&accounts[index] as &RefCell<AccountSharedData>, &accounts[index].1 as &RefCell<AccountSharedData>,
) )
})) }))
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -800,7 +784,7 @@ impl MessageProcessor {
for keyed_account_index in keyed_account_indices { for keyed_account_index in keyed_account_indices {
let keyed_account = &keyed_accounts[*keyed_account_index]; let keyed_account = &keyed_accounts[*keyed_account_index];
if account_key == keyed_account.unsigned_key() { if account_key == keyed_account.unsigned_key() {
accounts.push(Rc::new(keyed_account.account.clone())); accounts.push((*account_key, Rc::new(keyed_account.account.clone())));
keyed_account_indices_reordered.push(*keyed_account_index); keyed_account_indices_reordered.push(*keyed_account_index);
continue 'root; continue 'root;
} }
@ -886,7 +870,7 @@ impl MessageProcessor {
{ {
let invoke_context = invoke_context.borrow(); let invoke_context = invoke_context.borrow();
let keyed_accounts = invoke_context.get_keyed_accounts()?; let keyed_accounts = invoke_context.get_keyed_accounts()?;
for (src_keyed_account_index, (account, dst_keyed_account_index)) in accounts for (src_keyed_account_index, ((_key, account), dst_keyed_account_index)) in accounts
.iter() .iter()
.zip(keyed_account_indices_reordered) .zip(keyed_account_indices_reordered)
.enumerate() .enumerate()
@ -928,7 +912,7 @@ impl MessageProcessor {
pub fn process_cross_program_instruction( pub fn process_cross_program_instruction(
message: &Message, message: &Message,
executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_write_privileges: &[bool], caller_write_privileges: &[bool],
invoke_context: &mut dyn InvokeContext, invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
@ -984,15 +968,17 @@ impl MessageProcessor {
pub fn create_pre_accounts( pub fn create_pre_accounts(
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
) -> Vec<PreAccount> { ) -> Vec<PreAccount> {
let mut pre_accounts = Vec::with_capacity(instruction.accounts.len()); let mut pre_accounts = Vec::with_capacity(instruction.accounts.len());
{ {
let mut work = |_unique_index: usize, account_index: usize| { let mut work = |_unique_index: usize, account_index: usize| {
let key = &message.account_keys[account_index]; if account_index < message.account_keys.len() && account_index < accounts.len() {
let account = accounts[account_index].borrow(); let account = accounts[account_index].1.borrow();
pre_accounts.push(PreAccount::new(key, &account)); pre_accounts.push(PreAccount::new(&accounts[account_index].0, &account));
Ok(()) return Ok(());
}
Err(InstructionError::MissingAccount)
}; };
let _ = instruction.visit_each_account(&mut work); let _ = instruction.visit_each_account(&mut work);
} }
@ -1017,7 +1003,7 @@ impl MessageProcessor {
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
pre_accounts: &[PreAccount], pre_accounts: &[PreAccount],
executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
rent: &Rent, rent: &Rent,
timings: &mut ExecuteDetailsTimings, timings: &mut ExecuteDetailsTimings,
demote_sysvar_write_locks: bool, demote_sysvar_write_locks: bool,
@ -1034,10 +1020,11 @@ impl MessageProcessor {
{ {
// Verify account has no outstanding references // Verify account has no outstanding references
let _ = accounts[account_index] let _ = accounts[account_index]
.1
.try_borrow_mut() .try_borrow_mut()
.map_err(|_| InstructionError::AccountBorrowOutstanding)?; .map_err(|_| InstructionError::AccountBorrowOutstanding)?;
} }
let account = accounts[account_index].borrow(); let account = accounts[account_index].1.borrow();
pre_accounts[unique_index] pre_accounts[unique_index]
.verify( .verify(
program_id, program_id,
@ -1076,7 +1063,7 @@ impl MessageProcessor {
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
pre_accounts: &mut [PreAccount], pre_accounts: &mut [PreAccount],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
program_id: &Pubkey, program_id: &Pubkey,
rent: &Rent, rent: &Rent,
caller_write_privileges: Option<&[bool]>, caller_write_privileges: Option<&[bool]>,
@ -1088,8 +1075,7 @@ impl MessageProcessor {
let (mut pre_sum, mut post_sum) = (0_u128, 0_u128); let (mut pre_sum, mut post_sum) = (0_u128, 0_u128);
let mut work = |_unique_index: usize, account_index: usize| { let mut work = |_unique_index: usize, account_index: usize| {
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, account) = &accounts[account_index];
let account = &accounts[account_index];
let is_writable = if let Some(caller_write_privileges) = caller_write_privileges { let is_writable = if let Some(caller_write_privileges) = caller_write_privileges {
caller_write_privileges[account_index] caller_write_privileges[account_index]
} else { } else {
@ -1142,8 +1128,7 @@ impl MessageProcessor {
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)], executable_accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<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>>,
@ -1159,9 +1144,9 @@ impl MessageProcessor {
// Fixup the special instructions key if present // Fixup the special instructions key if present
// before the account pre-values are taken care of // before the account pre-values are taken care of
if feature_set.is_active(&instructions_sysvar_enabled::id()) { if feature_set.is_active(&instructions_sysvar_enabled::id()) {
for (i, key) in message.account_keys.iter().enumerate() { for (pubkey, accont) in accounts.iter().take(message.account_keys.len()) {
if instructions::check_id(key) { if instructions::check_id(pubkey) {
let mut mut_account_ref = accounts[i].borrow_mut(); let mut mut_account_ref = accont.borrow_mut();
instructions::store_current_index( instructions::store_current_index(
mut_account_ref.data_as_mut_slice(), mut_account_ref.data_as_mut_slice(),
instruction_index as u16, instruction_index as u16,
@ -1179,7 +1164,6 @@ impl MessageProcessor {
instruction, instruction,
executable_accounts, executable_accounts,
accounts, accounts,
account_deps,
&self.programs, &self.programs,
log_collector, log_collector,
bpf_compute_budget, bpf_compute_budget,
@ -1216,8 +1200,7 @@ impl MessageProcessor {
&self, &self,
message: &Message, message: &Message,
loaders: &[Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>], loaders: &[Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>],
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<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>>,
@ -1240,7 +1223,6 @@ impl MessageProcessor {
instruction, instruction,
&loaders[instruction_index], &loaders[instruction_index],
accounts, accounts,
account_deps,
rent_collector, rent_collector,
log_collector.clone(), log_collector.clone(),
executors.clone(), executors.clone(),
@ -1281,25 +1263,29 @@ mod tests {
fn test_invoke_context() { fn test_invoke_context() {
const MAX_DEPTH: usize = 10; const MAX_DEPTH: usize = 10;
let mut invoke_stack = vec![]; let mut invoke_stack = vec![];
let mut keys = vec![];
let mut accounts = vec![]; let mut accounts = vec![];
let mut metas = vec![]; let mut metas = vec![];
for i in 0..MAX_DEPTH { for i in 0..MAX_DEPTH {
invoke_stack.push(solana_sdk::pubkey::new_rand()); invoke_stack.push(solana_sdk::pubkey::new_rand());
keys.push(solana_sdk::pubkey::new_rand()); accounts.push((
accounts.push(Rc::new(RefCell::new(AccountSharedData::new( solana_sdk::pubkey::new_rand(),
Rc::new(RefCell::new(AccountSharedData::new(
i as u64, i as u64,
1, 1,
&invoke_stack[i], &invoke_stack[i],
)))); ))),
metas.push(AccountMeta::new(keys[i], false)); ));
metas.push(AccountMeta::new(accounts[i].0, false));
} }
for program_id in invoke_stack.iter() { for program_id in invoke_stack.iter() {
accounts.push(Rc::new(RefCell::new(AccountSharedData::new( accounts.push((
*program_id,
Rc::new(RefCell::new(AccountSharedData::new(
1, 1,
1, 1,
&solana_sdk::pubkey::Pubkey::default(), &solana_sdk::pubkey::Pubkey::default(),
)))); ))),
));
metas.push(AccountMeta::new(*program_id, false)); metas.push(AccountMeta::new(*program_id, false));
} }
@ -1316,7 +1302,6 @@ mod tests {
&[], &[],
&accounts, &accounts,
&[], &[],
&[],
None, None,
BpfComputeBudget::default(), BpfComputeBudget::default(),
Rc::new(RefCell::new(Executors::default())), Rc::new(RefCell::new(Executors::default())),
@ -1341,8 +1326,8 @@ mod tests {
for owned_index in (1..depth_reached).rev() { for owned_index in (1..depth_reached).rev() {
let not_owned_index = owned_index - 1; let not_owned_index = owned_index - 1;
let metas = vec![ let metas = vec![
AccountMeta::new(keys[not_owned_index], false), AccountMeta::new(accounts[not_owned_index].0, false),
AccountMeta::new(keys[owned_index], false), AccountMeta::new(accounts[owned_index].0, false),
]; ];
let message = Message::new( let message = Message::new(
&[Instruction::new_with_bytes( &[Instruction::new_with_bytes(
@ -1354,14 +1339,17 @@ mod tests {
); );
// modify account owned by the program // modify account owned by the program
accounts[owned_index].borrow_mut().data_as_mut_slice()[0] = accounts[owned_index].1.borrow_mut().data_as_mut_slice()[0] =
(MAX_DEPTH + owned_index) as u8; (MAX_DEPTH + owned_index) as u8;
let mut these_accounts = accounts[not_owned_index..owned_index + 1].to_vec(); let mut these_accounts = accounts[not_owned_index..owned_index + 1].to_vec();
these_accounts.push(Rc::new(RefCell::new(AccountSharedData::new( these_accounts.push((
message.account_keys[2],
Rc::new(RefCell::new(AccountSharedData::new(
1, 1,
1, 1,
&solana_sdk::pubkey::Pubkey::default(), &solana_sdk::pubkey::Pubkey::default(),
)))); ))),
));
invoke_context invoke_context
.verify_and_update(&message, &message.instructions[0], &these_accounts, None) .verify_and_update(&message, &message.instructions[0], &these_accounts, None)
.unwrap(); .unwrap();
@ -1374,8 +1362,8 @@ mod tests {
); );
// modify account not owned by the program // modify account not owned by the program
let data = accounts[not_owned_index].borrow_mut().data()[0]; let data = accounts[not_owned_index].1.borrow_mut().data()[0];
accounts[not_owned_index].borrow_mut().data_as_mut_slice()[0] = accounts[not_owned_index].1.borrow_mut().data_as_mut_slice()[0] =
(MAX_DEPTH + not_owned_index) as u8; (MAX_DEPTH + not_owned_index) as u8;
assert_eq!( assert_eq!(
invoke_context.verify_and_update( invoke_context.verify_and_update(
@ -1393,7 +1381,7 @@ mod tests {
.data()[0], .data()[0],
data data
); );
accounts[not_owned_index].borrow_mut().data_as_mut_slice()[0] = data; accounts[not_owned_index].1.borrow_mut().data_as_mut_slice()[0] = data;
invoke_context.pop(); invoke_context.pop();
} }
@ -1869,26 +1857,28 @@ mod tests {
let mut message_processor = MessageProcessor::default(); let mut message_processor = MessageProcessor::default();
message_processor.add_program(mock_system_program_id, mock_system_process_instruction); message_processor.add_program(mock_system_program_id, mock_system_process_instruction);
let mut accounts: Vec<Rc<RefCell<AccountSharedData>>> = Vec::new(); let accounts = vec![
let account = AccountSharedData::new_ref(100, 1, &mock_system_program_id); (
accounts.push(account); solana_sdk::pubkey::new_rand(),
let account = AccountSharedData::new_ref(0, 1, &mock_system_program_id); AccountSharedData::new_ref(100, 1, &mock_system_program_id),
accounts.push(account); ),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::new_ref(0, 1, &mock_system_program_id),
),
];
let mut loaders: Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>> = Vec::new();
let account = Rc::new(RefCell::new(create_loadable_account_for_test( let account = Rc::new(RefCell::new(create_loadable_account_for_test(
"mock_system_program", "mock_system_program",
))); )));
loaders.push(vec![(mock_system_program_id, account)]); let loaders = vec![vec![(mock_system_program_id, account)]];
let executors = Rc::new(RefCell::new(Executors::default())); let executors = Rc::new(RefCell::new(Executors::default()));
let ancestors = Ancestors::default(); let ancestors = Ancestors::default();
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
let account_metas = vec![ let account_metas = vec![
AccountMeta::new(from_pubkey, true), AccountMeta::new(accounts[0].0, true),
AccountMeta::new_readonly(to_pubkey, false), AccountMeta::new_readonly(accounts[1].0, false),
]; ];
let message = Message::new( let message = Message::new(
&[Instruction::new_with_bincode( &[Instruction::new_with_bincode(
@ -1896,14 +1886,13 @@ mod tests {
&MockSystemInstruction::Correct, &MockSystemInstruction::Correct,
account_metas.clone(), account_metas.clone(),
)], )],
Some(&from_pubkey), Some(&accounts[0].0),
); );
let result = message_processor.process_message( let result = message_processor.process_message(
&message, &message,
&loaders, &loaders,
&accounts, &accounts,
&[],
&rent_collector, &rent_collector,
None, None,
executors.clone(), executors.clone(),
@ -1915,8 +1904,8 @@ mod tests {
&ancestors, &ancestors,
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports(), 100); assert_eq!(accounts[0].1.borrow().lamports(), 100);
assert_eq!(accounts[1].borrow().lamports(), 0); assert_eq!(accounts[1].1.borrow().lamports(), 0);
let message = Message::new( let message = Message::new(
&[Instruction::new_with_bincode( &[Instruction::new_with_bincode(
@ -1924,14 +1913,13 @@ mod tests {
&MockSystemInstruction::AttemptCredit { lamports: 50 }, &MockSystemInstruction::AttemptCredit { lamports: 50 },
account_metas.clone(), account_metas.clone(),
)], )],
Some(&from_pubkey), Some(&accounts[0].0),
); );
let result = message_processor.process_message( let result = message_processor.process_message(
&message, &message,
&loaders, &loaders,
&accounts, &accounts,
&[],
&rent_collector, &rent_collector,
None, None,
executors.clone(), executors.clone(),
@ -1956,14 +1944,13 @@ mod tests {
&MockSystemInstruction::AttemptDataChange { data: 50 }, &MockSystemInstruction::AttemptDataChange { data: 50 },
account_metas, account_metas,
)], )],
Some(&from_pubkey), Some(&accounts[0].0),
); );
let result = message_processor.process_message( let result = message_processor.process_message(
&message, &message,
&loaders, &loaders,
&accounts, &accounts,
&[],
&rent_collector, &rent_collector,
None, None,
executors, executors,
@ -2049,28 +2036,29 @@ mod tests {
let mut message_processor = MessageProcessor::default(); let mut message_processor = MessageProcessor::default();
message_processor.add_program(mock_program_id, mock_system_process_instruction); message_processor.add_program(mock_program_id, mock_system_process_instruction);
let mut accounts: Vec<Rc<RefCell<AccountSharedData>>> = Vec::new(); let accounts = vec![
let account = AccountSharedData::new_ref(100, 1, &mock_program_id); (
accounts.push(account); solana_sdk::pubkey::new_rand(),
let account = AccountSharedData::new_ref(0, 1, &mock_program_id); AccountSharedData::new_ref(100, 1, &mock_program_id),
accounts.push(account); ),
(
solana_sdk::pubkey::new_rand(),
AccountSharedData::new_ref(0, 1, &mock_program_id),
),
];
let mut loaders: Vec<Vec<(Pubkey, Rc<RefCell<AccountSharedData>>)>> = Vec::new();
let account = Rc::new(RefCell::new(create_loadable_account_for_test( let account = Rc::new(RefCell::new(create_loadable_account_for_test(
"mock_system_program", "mock_system_program",
))); )));
loaders.push(vec![(mock_program_id, account)]); let loaders = vec![vec![(mock_program_id, account)]];
let executors = Rc::new(RefCell::new(Executors::default())); let executors = Rc::new(RefCell::new(Executors::default()));
let ancestors = Ancestors::default(); let ancestors = Ancestors::default();
let from_pubkey = solana_sdk::pubkey::new_rand();
let to_pubkey = solana_sdk::pubkey::new_rand();
let dup_pubkey = from_pubkey;
let account_metas = vec![ let account_metas = vec![
AccountMeta::new(from_pubkey, true), AccountMeta::new(accounts[0].0, true),
AccountMeta::new(to_pubkey, false), AccountMeta::new(accounts[1].0, false),
AccountMeta::new(dup_pubkey, false), AccountMeta::new(accounts[0].0, false),
]; ];
// Try to borrow mut the same account // Try to borrow mut the same account
@ -2080,13 +2068,12 @@ mod tests {
&MockSystemInstruction::BorrowFail, &MockSystemInstruction::BorrowFail,
account_metas.clone(), account_metas.clone(),
)], )],
Some(&from_pubkey), Some(&accounts[0].0),
); );
let result = message_processor.process_message( let result = message_processor.process_message(
&message, &message,
&loaders, &loaders,
&accounts, &accounts,
&[],
&rent_collector, &rent_collector,
None, None,
executors.clone(), executors.clone(),
@ -2112,13 +2099,12 @@ mod tests {
&MockSystemInstruction::MultiBorrowMut, &MockSystemInstruction::MultiBorrowMut,
account_metas.clone(), account_metas.clone(),
)], )],
Some(&from_pubkey), Some(&accounts[0].0),
); );
let result = message_processor.process_message( let result = message_processor.process_message(
&message, &message,
&loaders, &loaders,
&accounts, &accounts,
&[],
&rent_collector, &rent_collector,
None, None,
executors.clone(), executors.clone(),
@ -2141,14 +2127,13 @@ mod tests {
}, },
account_metas, account_metas,
)], )],
Some(&from_pubkey), Some(&accounts[0].0),
); );
let ancestors = Ancestors::default(); let ancestors = Ancestors::default();
let result = message_processor.process_message( let result = message_processor.process_message(
&message, &message,
&loaders, &loaders,
&accounts, &accounts,
&[],
&rent_collector, &rent_collector,
None, None,
executors, executors,
@ -2160,9 +2145,9 @@ mod tests {
&ancestors, &ancestors,
); );
assert_eq!(result, Ok(())); assert_eq!(result, Ok(()));
assert_eq!(accounts[0].borrow().lamports(), 80); assert_eq!(accounts[0].1.borrow().lamports(), 80);
assert_eq!(accounts[1].borrow().lamports(), 20); assert_eq!(accounts[1].1.borrow().lamports(), 20);
assert_eq!(accounts[0].borrow().data(), &vec![42]); assert_eq!(accounts[0].1.borrow().data(), &vec![42]);
} }
#[test] #[test]
@ -2214,25 +2199,28 @@ mod tests {
Rc::new(RefCell::new(program_account.clone())), 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); let owned_account = AccountSharedData::new(42, 1, &callee_program_id);
let not_owned_key = solana_sdk::pubkey::new_rand();
let not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand()); let not_owned_account = AccountSharedData::new(84, 1, &solana_sdk::pubkey::new_rand());
#[allow(unused_mut)] #[allow(unused_mut)]
let mut accounts = vec![ let accounts = vec![
(
solana_sdk::pubkey::new_rand(),
Rc::new(RefCell::new(owned_account)), Rc::new(RefCell::new(owned_account)),
),
(
solana_sdk::pubkey::new_rand(),
Rc::new(RefCell::new(not_owned_account)), Rc::new(RefCell::new(not_owned_account)),
Rc::new(RefCell::new(program_account)), ),
(callee_program_id, Rc::new(RefCell::new(program_account))),
]; ];
let compiled_instruction = CompiledInstruction::new(2, &(), vec![0, 1, 2]); let compiled_instruction = CompiledInstruction::new(2, &(), vec![0, 1, 2]);
let programs: Vec<(_, ProcessInstructionWithContext)> = let programs: Vec<(_, ProcessInstructionWithContext)> =
vec![(callee_program_id, mock_process_instruction)]; vec![(callee_program_id, mock_process_instruction)];
let metas = vec![ let metas = vec![
AccountMeta::new(owned_key, false), AccountMeta::new(accounts[0].0, false),
AccountMeta::new(not_owned_key, false), AccountMeta::new(accounts[1].0, false),
]; ];
let instruction = Instruction::new_with_bincode( let instruction = Instruction::new_with_bincode(
@ -2250,7 +2238,6 @@ mod tests {
&compiled_instruction, &compiled_instruction,
&executable_accounts, &executable_accounts,
&accounts, &accounts,
&[],
programs.as_slice(), programs.as_slice(),
None, None,
BpfComputeBudget::default(), BpfComputeBudget::default(),
@ -2270,7 +2257,7 @@ mod tests {
.enumerate() .enumerate()
.map(|(i, _)| message.is_writable(i, demote_sysvar_write_locks)) .map(|(i, _)| message.is_writable(i, demote_sysvar_write_locks))
.collect::<Vec<bool>>(); .collect::<Vec<bool>>();
accounts[0].borrow_mut().data_as_mut_slice()[0] = 1; accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 1;
assert_eq!( assert_eq!(
MessageProcessor::process_cross_program_instruction( MessageProcessor::process_cross_program_instruction(
&message, &message,
@ -2281,7 +2268,7 @@ mod tests {
), ),
Err(InstructionError::ExternalAccountDataModified) Err(InstructionError::ExternalAccountDataModified)
); );
accounts[0].borrow_mut().data_as_mut_slice()[0] = 0; accounts[0].1.borrow_mut().data_as_mut_slice()[0] = 0;
let cases = vec![ let cases = vec![
(MockInstruction::NoopSuccess, Ok(())), (MockInstruction::NoopSuccess, Ok(())),
@ -2309,7 +2296,6 @@ mod tests {
&compiled_instruction, &compiled_instruction,
&executable_accounts, &executable_accounts,
&accounts, &accounts,
&[],
programs.as_slice(), programs.as_slice(),
None, None,
BpfComputeBudget::default(), BpfComputeBudget::default(),

View File

@ -64,7 +64,7 @@ pub trait InvokeContext {
&mut self, &mut self,
message: &Message, message: &Message,
instruction: &CompiledInstruction, instruction: &CompiledInstruction,
accounts: &[Rc<RefCell<AccountSharedData>>], accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
caller_pivileges: Option<&[bool]>, caller_pivileges: Option<&[bool]>,
) -> Result<(), InstructionError>; ) -> Result<(), InstructionError>;
/// Get the program ID of the currently executing program /// Get the program ID of the currently executing program
@ -90,7 +90,7 @@ pub trait InvokeContext {
fn record_instruction(&self, instruction: &Instruction); fn record_instruction(&self, instruction: &Instruction);
/// 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 by its key
fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>>; fn get_account(&self, pubkey: &Pubkey) -> Option<Rc<RefCell<AccountSharedData>>>;
/// Update timing /// Update timing
fn update_timing( fn update_timing(
@ -395,7 +395,7 @@ impl<'a> InvokeContext for MockInvokeContext<'a> {
&mut self, &mut self,
_message: &Message, _message: &Message,
_instruction: &CompiledInstruction, _instruction: &CompiledInstruction,
_accounts: &[Rc<RefCell<AccountSharedData>>], _accounts: &[(Pubkey, Rc<RefCell<AccountSharedData>>)],
_caller_pivileges: Option<&[bool]>, _caller_pivileges: Option<&[bool]>,
) -> Result<(), InstructionError> { ) -> Result<(), InstructionError> {
Ok(()) Ok(())