|
2 | 2 | //! privilege handling, and program account stubbing. |
3 | 3 |
|
4 | 4 | use { |
5 | | - mollusk_svm_keys::{ |
6 | | - accounts::{ |
7 | | - compile_instruction_accounts, compile_instruction_without_data, |
8 | | - compile_transaction_accounts, |
9 | | - }, |
10 | | - keys::KeyMap, |
11 | | - }, |
12 | | - solana_account::{Account, AccountSharedData}, |
| 5 | + mollusk_svm_error::error::{MolluskError, MolluskPanic}, |
| 6 | + solana_account::{Account, AccountSharedData, WritableAccount}, |
13 | 7 | solana_instruction::Instruction, |
| 8 | + solana_message::{LegacyMessage, Message, SanitizedMessage}, |
14 | 9 | solana_pubkey::Pubkey, |
15 | | - solana_transaction_context::InstructionAccount, |
16 | | - std::collections::HashMap, |
| 10 | + std::collections::{HashMap, HashSet}, |
17 | 11 | }; |
18 | 12 |
|
19 | | -pub struct CompiledAccounts { |
20 | | - pub program_id_index: u16, |
21 | | - pub instruction_accounts: Vec<InstructionAccount>, |
22 | | - pub transaction_accounts: Vec<(Pubkey, AccountSharedData)>, |
23 | | -} |
24 | | - |
25 | 13 | pub fn compile_accounts<'a>( |
26 | 14 | instruction: &Instruction, |
27 | 15 | accounts: impl Iterator<Item = &'a (Pubkey, Account)>, |
28 | 16 | fallback_accounts: &HashMap<Pubkey, Account>, |
29 | | -) -> CompiledAccounts { |
30 | | - let key_map = KeyMap::compile_from_instruction(instruction); |
31 | | - let compiled_instruction = compile_instruction_without_data(&key_map, instruction); |
32 | | - let instruction_accounts = compile_instruction_accounts(&key_map, &compiled_instruction); |
33 | | - let transaction_accounts = compile_transaction_accounts(&key_map, accounts, fallback_accounts); |
34 | | - |
35 | | - CompiledAccounts { |
36 | | - program_id_index: compiled_instruction.program_id_index as u16, |
37 | | - instruction_accounts, |
38 | | - transaction_accounts, |
39 | | - } |
| 17 | +) -> (SanitizedMessage, Vec<(Pubkey, AccountSharedData)>) { |
| 18 | + let message = Message::new(std::slice::from_ref(instruction), None); |
| 19 | + let sanitized_message = SanitizedMessage::Legacy(LegacyMessage::new(message, &HashSet::new())); |
| 20 | + |
| 21 | + let accounts: Vec<_> = accounts.collect(); |
| 22 | + let transaction_accounts = build_transaction_accounts( |
| 23 | + &sanitized_message, |
| 24 | + instruction.program_id, |
| 25 | + &accounts, |
| 26 | + std::slice::from_ref(instruction), |
| 27 | + fallback_accounts, |
| 28 | + ); |
| 29 | + |
| 30 | + (sanitized_message, transaction_accounts) |
| 31 | +} |
| 32 | + |
| 33 | +fn build_transaction_accounts( |
| 34 | + message: &SanitizedMessage, |
| 35 | + program_id: Pubkey, |
| 36 | + accounts: &[&(Pubkey, Account)], |
| 37 | + all_instructions: &[Instruction], |
| 38 | + fallback_accounts: &HashMap<Pubkey, Account>, |
| 39 | +) -> Vec<(Pubkey, AccountSharedData)> { |
| 40 | + message |
| 41 | + .account_keys() |
| 42 | + .iter() |
| 43 | + .map(|key| { |
| 44 | + if *key == program_id { |
| 45 | + if let Some(provided_account) = accounts.iter().find(|(k, _)| k == key) { |
| 46 | + return (*key, AccountSharedData::from(provided_account.1.clone())); |
| 47 | + } |
| 48 | + if let Some(fallback) = fallback_accounts.get(key) { |
| 49 | + return (*key, AccountSharedData::from(fallback.clone())); |
| 50 | + } |
| 51 | + // This shouldn't happen if fallbacks are set up correctly. |
| 52 | + let mut program_account = Account::default(); |
| 53 | + program_account.set_executable(true); |
| 54 | + return (*key, program_account.into()); |
| 55 | + } |
| 56 | + |
| 57 | + if *key == solana_instructions_sysvar::ID { |
| 58 | + if let Some((_, provided_account)) = accounts.iter().find(|(k, _)| k == key) { |
| 59 | + return (*key, AccountSharedData::from(provided_account.clone())); |
| 60 | + } |
| 61 | + if let Some(fallback) = fallback_accounts.get(key) { |
| 62 | + return (*key, AccountSharedData::from(fallback.clone())); |
| 63 | + } |
| 64 | + let (_, account) = |
| 65 | + crate::instructions_sysvar::keyed_account(all_instructions.iter()); |
| 66 | + return (*key, account.into()); |
| 67 | + } |
| 68 | + |
| 69 | + let account = accounts |
| 70 | + .iter() |
| 71 | + .find(|(k, _)| k == key) |
| 72 | + .map(|(_, a)| AccountSharedData::from(a.clone())) |
| 73 | + .or_else(|| { |
| 74 | + fallback_accounts |
| 75 | + .get(key) |
| 76 | + .map(|a| AccountSharedData::from(a.clone())) |
| 77 | + }) |
| 78 | + .or_panic_with(MolluskError::AccountMissing(key)); |
| 79 | + |
| 80 | + (*key, account) |
| 81 | + }) |
| 82 | + .collect() |
40 | 83 | } |
0 commit comments