Add way to look at tx instructions (#11943)

This commit is contained in:
sakridge
2020-09-19 12:17:46 -07:00
committed by GitHub
parent cd852a5c22
commit f561eb917f
16 changed files with 545 additions and 15 deletions

View File

@@ -115,6 +115,15 @@ impl Accounts {
false
}
fn construct_instructions_account(message: &Message) -> Account {
let mut account = Account::default();
account.data = message.serialize_instructions();
// add room for current instruction index.
account.data.resize(account.data.len() + 2, 0);
account
}
fn load_tx_accounts(
&self,
storage: &AccountStorage,
@@ -134,15 +143,23 @@ impl Accounts {
// If a fee can pay for execution then the program will be scheduled
let mut payer_index = None;
let mut tx_rent: TransactionRent = 0;
let mut accounts: Vec<_> = message
.account_keys
.iter()
.enumerate()
.map(|(i, key)| {
if Self::is_non_loader_key(message, key, i) {
if payer_index.is_none() {
payer_index = Some(i);
let mut accounts = Vec::with_capacity(message.account_keys.len());
for (i, key) in message.account_keys.iter().enumerate() {
let account = if Self::is_non_loader_key(message, key, i) {
if payer_index.is_none() {
payer_index = Some(i);
}
if solana_sdk::sysvar::instructions::is_enabled(
self.epoch,
self.accounts_db.cluster_type.unwrap(),
) && solana_sdk::sysvar::instructions::check_id(key)
{
if message.is_writable(i) {
return Err(TransactionError::InvalidAccountIndex);
}
Self::construct_instructions_account(message)
} else {
let (account, rent) =
AccountsDB::load(storage, ancestors, accounts_index, key)
.map(|(mut account, _)| {
@@ -158,12 +175,14 @@ impl Accounts {
tx_rent += rent;
account
} else {
// Fill in an empty account for the program slots.
Account::default()
}
})
.collect();
} else {
// Fill in an empty account for the program slots.
Account::default()
};
accounts.push(account);
}
debug_assert_eq!(accounts.len(), message.account_keys.len());
if let Some(payer_index) = payer_index {
if payer_index != 0 {
@@ -1793,4 +1812,47 @@ mod tests {
info!("done..cleaning..");
accounts.accounts_db.clean_accounts();
}
fn load_accounts_no_store(
accounts: &Accounts,
tx: Transaction,
) -> Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)> {
let rent_collector = RentCollector::default();
let fee_calculator = FeeCalculator::new(10);
let mut hash_queue = BlockhashQueue::new(100);
hash_queue.register_hash(&tx.message().recent_blockhash, &fee_calculator);
let ancestors = vec![(0, 0)].into_iter().collect();
let mut error_counters = ErrorCounters::default();
accounts.load_accounts(
&ancestors,
&[tx],
None,
vec![(Ok(()), Some(HashAgeKind::Extant))],
&hash_queue,
&mut error_counters,
&rent_collector,
)
}
#[test]
fn test_instructions() {
solana_logger::setup();
let accounts = Accounts::new(Vec::new(), &ClusterType::Development);
let instructions_key = solana_sdk::sysvar::instructions::id();
let keypair = Keypair::new();
let instructions = vec![CompiledInstruction::new(1, &(), vec![0, 1])];
let tx = Transaction::new_with_compiled_instructions(
&[&keypair],
&[Pubkey::new_rand(), instructions_key],
Hash::default(),
vec![native_loader::id()],
instructions,
);
let loaded_accounts = load_accounts_no_store(&accounts, tx);
assert_eq!(loaded_accounts.len(), 1);
assert!(loaded_accounts[0].0.is_err());
}
}

View File

@@ -665,7 +665,21 @@ impl MessageProcessor {
rent_collector: &RentCollector,
log_collector: Option<Rc<LogCollector>>,
executors: Rc<RefCell<Executors>>,
instruction_index: usize,
) -> Result<(), InstructionError> {
// Fixup the special instructions key if present
// before the account pre-values are taken care of
for (i, key) in message.account_keys.iter().enumerate() {
if solana_sdk::sysvar::instructions::check_id(key) {
let mut mut_account_ref = accounts[i].borrow_mut();
solana_sdk::sysvar::instructions::store_current_instruction(
&mut mut_account_ref.data,
instruction_index as u16,
);
break;
}
}
let pre_accounts = Self::create_pre_accounts(message, instruction, accounts);
let mut invoke_context = ThisInvokeContext::new(
instruction.program_id(&message.account_keys),
@@ -712,6 +726,7 @@ impl MessageProcessor {
rent_collector,
log_collector.clone(),
executors.clone(),
instruction_index,
)
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
}