2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
serde::{Deserialize, Serialize},
|
|
|
|
solana_measure::measure::Measure,
|
|
|
|
solana_program_runtime::{
|
2023-04-24 10:01:40 -07:00
|
|
|
builtin_program::BuiltinPrograms,
|
2022-01-17 04:48:00 -08:00
|
|
|
compute_budget::ComputeBudget,
|
2022-10-12 09:09:03 -07:00
|
|
|
executor_cache::TransactionExecutorCache,
|
2023-04-24 10:01:40 -07:00
|
|
|
invoke_context::InvokeContext,
|
2021-12-03 09:00:31 -08:00
|
|
|
log_collector::LogCollector,
|
2022-01-11 19:19:11 -08:00
|
|
|
sysvar_cache::SysvarCache,
|
2022-05-27 07:06:29 -07:00
|
|
|
timings::{ExecuteDetailsTimings, ExecuteTimings},
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
solana_sdk::{
|
2021-12-09 22:38:36 -08:00
|
|
|
account::WritableAccount,
|
2022-08-17 22:21:16 -07:00
|
|
|
feature_set::FeatureSet,
|
2021-12-03 09:00:31 -08:00
|
|
|
hash::Hash,
|
2022-01-06 19:59:09 -08:00
|
|
|
message::SanitizedMessage,
|
2021-12-03 09:00:31 -08:00
|
|
|
precompiles::is_precompile,
|
|
|
|
rent::Rent,
|
2022-01-05 16:08:35 -08:00
|
|
|
saturating_add_assign,
|
2021-12-03 09:00:31 -08:00
|
|
|
sysvar::instructions,
|
|
|
|
transaction::TransactionError,
|
2022-09-06 02:31:40 -07:00
|
|
|
transaction_context::{IndexOfAccount, InstructionAccount, TransactionContext},
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
2023-04-03 08:23:24 -07:00
|
|
|
std::{cell::RefCell, rc::Rc, sync::Arc},
|
2020-01-28 17:03:20 -08:00
|
|
|
};
|
2019-02-18 22:26:22 -08:00
|
|
|
|
2021-08-26 17:30:36 -07:00
|
|
|
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
2021-09-29 10:05:25 -07:00
|
|
|
pub struct MessageProcessor {}
|
2020-07-06 04:22:23 -07:00
|
|
|
|
|
|
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
2020-10-19 21:07:46 -07:00
|
|
|
impl ::solana_frozen_abi::abi_example::AbiExample for MessageProcessor {
|
2020-07-06 04:22:23 -07:00
|
|
|
fn example() -> Self {
|
|
|
|
// MessageProcessor's fields are #[serde(skip)]-ed and not Serialize
|
|
|
|
// so, just rely on Default anyway.
|
|
|
|
MessageProcessor::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-15 14:41:38 -08:00
|
|
|
/// Resultant information gathered from calling process_message()
|
|
|
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
|
|
|
pub struct ProcessedMessageInfo {
|
2022-02-08 17:24:47 -08:00
|
|
|
/// The change in accounts data len
|
|
|
|
pub accounts_data_len_delta: i64,
|
2021-12-15 14:41:38 -08:00
|
|
|
}
|
|
|
|
|
2019-04-02 08:35:38 -07:00
|
|
|
impl MessageProcessor {
|
2021-09-29 10:05:25 -07:00
|
|
|
/// Process a message.
|
|
|
|
/// This method calls each instruction in the message over the set of loaded accounts.
|
|
|
|
/// For each instruction it calls the program entrypoint method and verifies that the result of
|
2019-03-15 19:48:11 -07:00
|
|
|
/// the call does not violate the bank's accounting rules.
|
2021-09-29 10:05:25 -07:00
|
|
|
/// The accounts are committed back to the bank only if every instruction succeeds.
|
2020-09-20 10:58:12 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-09-29 10:05:25 -07:00
|
|
|
pub fn process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
builtin_programs: &BuiltinPrograms,
|
2022-01-06 19:59:09 -08:00
|
|
|
message: &SanitizedMessage,
|
2022-09-06 02:31:40 -07:00
|
|
|
program_indices: &[Vec<IndexOfAccount>],
|
2022-01-03 14:30:56 -08:00
|
|
|
transaction_context: &mut TransactionContext,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent: Rent,
|
2021-11-23 04:23:40 -08:00
|
|
|
log_collector: Option<Rc<RefCell<LogCollector>>>,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache: Rc<RefCell<TransactionExecutorCache>>,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set: Arc<FeatureSet>,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget: ComputeBudget,
|
2021-12-20 20:03:20 -08:00
|
|
|
timings: &mut ExecuteTimings,
|
2022-01-11 19:19:11 -08:00
|
|
|
sysvar_cache: &SysvarCache,
|
2021-09-29 10:05:25 -07:00
|
|
|
blockhash: Hash,
|
2021-10-22 14:32:40 -07:00
|
|
|
lamports_per_signature: u64,
|
2021-12-28 03:14:48 -08:00
|
|
|
current_accounts_data_len: u64,
|
2022-04-21 00:38:07 -07:00
|
|
|
accumulated_consumed_units: &mut u64,
|
2021-12-15 14:41:38 -08:00
|
|
|
) -> Result<ProcessedMessageInfo, TransactionError> {
|
2021-12-02 09:47:16 -08:00
|
|
|
let mut invoke_context = InvokeContext::new(
|
2021-12-27 09:49:32 -08:00
|
|
|
transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent,
|
2021-11-30 23:54:42 -08:00
|
|
|
builtin_programs,
|
2023-04-03 08:23:24 -07:00
|
|
|
sysvar_cache,
|
2020-06-06 10:18:28 -07:00
|
|
|
log_collector,
|
2021-07-22 10:18:51 -07:00
|
|
|
compute_budget,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache,
|
2020-09-29 14:36:30 -07:00
|
|
|
feature_set,
|
2021-10-21 11:57:42 -07:00
|
|
|
blockhash,
|
2021-10-22 14:32:40 -07:00
|
|
|
lamports_per_signature,
|
2021-12-28 03:14:48 -08:00
|
|
|
current_accounts_data_len,
|
2021-09-29 10:05:25 -07:00
|
|
|
);
|
2021-10-11 16:47:17 -07:00
|
|
|
|
2022-01-06 19:59:09 -08:00
|
|
|
debug_assert_eq!(program_indices.len(), message.instructions().len());
|
|
|
|
for (instruction_index, ((program_id, instruction), program_indices)) in message
|
|
|
|
.program_instructions_iter()
|
2021-09-29 10:05:25 -07:00
|
|
|
.zip(program_indices.iter())
|
|
|
|
.enumerate()
|
|
|
|
{
|
2022-08-17 22:21:16 -07:00
|
|
|
let is_precompile =
|
|
|
|
is_precompile(program_id, |id| invoke_context.feature_set.is_active(id));
|
2021-09-26 23:28:45 -07:00
|
|
|
|
2021-09-29 10:05:25 -07:00
|
|
|
// Fixup the special instructions key if present
|
|
|
|
// before the account pre-values are taken care of
|
2021-12-27 09:49:32 -08:00
|
|
|
if let Some(account_index) = invoke_context
|
|
|
|
.transaction_context
|
|
|
|
.find_index_of_account(&instructions::id())
|
|
|
|
{
|
|
|
|
let mut mut_account_ref = invoke_context
|
|
|
|
.transaction_context
|
|
|
|
.get_account_at_index(account_index)
|
2022-02-03 02:34:51 -08:00
|
|
|
.map_err(|_| TransactionError::InvalidAccountIndex)?
|
2021-12-27 09:49:32 -08:00
|
|
|
.borrow_mut();
|
|
|
|
instructions::store_current_index(
|
|
|
|
mut_account_ref.data_as_mut_slice(),
|
|
|
|
instruction_index as u16,
|
|
|
|
);
|
2021-09-29 10:05:25 -07:00
|
|
|
}
|
|
|
|
|
2022-05-24 15:04:46 -07:00
|
|
|
let mut instruction_accounts = Vec::with_capacity(instruction.accounts.len());
|
2022-06-16 09:46:17 -07:00
|
|
|
for (instruction_account_index, index_in_transaction) in
|
2022-05-24 15:04:46 -07:00
|
|
|
instruction.accounts.iter().enumerate()
|
|
|
|
{
|
|
|
|
let index_in_callee = instruction
|
|
|
|
.accounts
|
2022-06-16 09:46:17 -07:00
|
|
|
.get(0..instruction_account_index)
|
2022-05-24 15:04:46 -07:00
|
|
|
.ok_or(TransactionError::InvalidAccountIndex)?
|
|
|
|
.iter()
|
|
|
|
.position(|account_index| account_index == index_in_transaction)
|
2022-09-06 02:31:40 -07:00
|
|
|
.unwrap_or(instruction_account_index)
|
|
|
|
as IndexOfAccount;
|
2022-05-24 15:04:46 -07:00
|
|
|
let index_in_transaction = *index_in_transaction as usize;
|
|
|
|
instruction_accounts.push(InstructionAccount {
|
2022-09-06 02:31:40 -07:00
|
|
|
index_in_transaction: index_in_transaction as IndexOfAccount,
|
|
|
|
index_in_caller: index_in_transaction as IndexOfAccount,
|
2022-05-24 15:04:46 -07:00
|
|
|
index_in_callee,
|
|
|
|
is_signer: message.is_signer(index_in_transaction),
|
|
|
|
is_writable: message.is_writable(index_in_transaction),
|
|
|
|
});
|
|
|
|
}
|
2022-05-04 07:32:14 -07:00
|
|
|
|
2022-07-21 03:49:34 -07:00
|
|
|
let result = if is_precompile {
|
2022-05-04 07:32:14 -07:00
|
|
|
invoke_context
|
|
|
|
.transaction_context
|
2022-09-03 01:34:57 -07:00
|
|
|
.get_next_instruction_context()
|
|
|
|
.map(|instruction_context| {
|
|
|
|
instruction_context.configure(
|
|
|
|
program_indices,
|
|
|
|
&instruction_accounts,
|
|
|
|
&instruction.data,
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.and_then(|_| {
|
|
|
|
invoke_context.transaction_context.push()?;
|
|
|
|
invoke_context.transaction_context.pop()
|
|
|
|
})
|
2022-05-04 07:32:14 -07:00
|
|
|
} else {
|
|
|
|
let mut time = Measure::start("execute_instruction");
|
|
|
|
let mut compute_units_consumed = 0;
|
|
|
|
let result = invoke_context.process_instruction(
|
|
|
|
&instruction.data,
|
|
|
|
&instruction_accounts,
|
|
|
|
program_indices,
|
|
|
|
&mut compute_units_consumed,
|
|
|
|
timings,
|
|
|
|
);
|
|
|
|
time.stop();
|
|
|
|
*accumulated_consumed_units =
|
|
|
|
accumulated_consumed_units.saturating_add(compute_units_consumed);
|
|
|
|
timings.details.accumulate_program(
|
|
|
|
program_id,
|
|
|
|
time.as_us(),
|
|
|
|
compute_units_consumed,
|
|
|
|
result.is_err(),
|
|
|
|
);
|
2022-05-27 07:06:29 -07:00
|
|
|
invoke_context.timings = {
|
|
|
|
timings.details.accumulate(&invoke_context.timings);
|
|
|
|
ExecuteDetailsTimings::default()
|
|
|
|
};
|
2022-05-04 07:32:14 -07:00
|
|
|
saturating_add_assign!(
|
|
|
|
timings.execute_accessories.process_instructions.total_us,
|
|
|
|
time.as_us()
|
|
|
|
);
|
|
|
|
result
|
|
|
|
};
|
|
|
|
|
2021-12-30 18:21:42 -08:00
|
|
|
result
|
|
|
|
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
2019-03-11 15:35:25 -07:00
|
|
|
}
|
2021-12-28 03:14:48 -08:00
|
|
|
Ok(ProcessedMessageInfo {
|
2022-02-08 17:24:47 -08:00
|
|
|
accounts_data_len_delta: invoke_context.get_accounts_data_meter().delta(),
|
2021-12-28 03:14:48 -08:00
|
|
|
})
|
2019-03-15 19:48:11 -07:00
|
|
|
}
|
2019-03-11 15:35:25 -07:00
|
|
|
}
|
|
|
|
|
2019-02-18 22:26:22 -08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
crate::rent_collector::RentCollector,
|
2023-04-07 03:53:19 -07:00
|
|
|
solana_program_runtime::declare_process_instruction,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_sdk::{
|
2021-12-09 22:38:36 -08:00
|
|
|
account::{AccountSharedData, ReadableAccount},
|
2021-12-03 09:00:31 -08:00
|
|
|
instruction::{AccountMeta, Instruction, InstructionError},
|
2022-08-25 14:33:41 -07:00
|
|
|
message::{AccountKeys, LegacyMessage, Message},
|
2021-12-03 09:00:31 -08:00
|
|
|
native_loader::{self, create_loadable_account_for_test},
|
2022-01-11 19:19:11 -08:00
|
|
|
pubkey::Pubkey,
|
2021-12-03 09:00:31 -08:00
|
|
|
secp256k1_instruction::new_secp256k1_instruction,
|
|
|
|
secp256k1_program,
|
|
|
|
},
|
2020-01-28 17:03:20 -08:00
|
|
|
};
|
2019-02-18 22:26:22 -08:00
|
|
|
|
2021-09-29 10:05:25 -07:00
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
enum MockInstruction {
|
|
|
|
NoopSuccess,
|
|
|
|
NoopFail,
|
|
|
|
ModifyOwned,
|
|
|
|
ModifyNotOwned,
|
|
|
|
ModifyReadonly,
|
|
|
|
}
|
|
|
|
|
2019-06-10 19:50:02 -07:00
|
|
|
#[test]
|
2019-11-05 08:38:35 -08:00
|
|
|
fn test_process_message_readonly_handling() {
|
2019-06-10 19:50:02 -07:00
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
enum MockSystemInstruction {
|
2019-11-05 08:38:35 -08:00
|
|
|
Correct,
|
2022-01-05 00:39:37 -08:00
|
|
|
TransferLamports { lamports: u64 },
|
|
|
|
ChangeData { data: u8 },
|
2019-06-10 19:50:02 -07:00
|
|
|
}
|
|
|
|
|
2023-04-07 03:53:19 -07:00
|
|
|
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
2022-01-05 00:39:37 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-04-01 06:48:05 -07:00
|
|
|
let instruction_data = instruction_context.get_instruction_data();
|
|
|
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
2019-06-10 19:50:02 -07:00
|
|
|
match instruction {
|
2019-11-05 08:38:35 -08:00
|
|
|
MockSystemInstruction::Correct => Ok(()),
|
2022-01-05 00:39:37 -08:00
|
|
|
MockSystemInstruction::TransferLamports { lamports } => {
|
|
|
|
instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 0)?
|
2021-05-03 08:45:15 -07:00
|
|
|
.checked_sub_lamports(lamports)?;
|
2022-01-05 00:39:37 -08:00
|
|
|
instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 1)?
|
2021-04-27 07:56:18 -07:00
|
|
|
.checked_add_lamports(lamports)?;
|
2019-06-10 19:50:02 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
2022-01-05 00:39:37 -08:00
|
|
|
MockSystemInstruction::ChangeData { data } => {
|
|
|
|
instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 1)?
|
2022-09-23 17:37:02 -07:00
|
|
|
.set_data(vec![data])?;
|
2019-06-10 19:50:02 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-04-07 03:53:19 -07:00
|
|
|
Err(InstructionError::InvalidInstructionData)
|
2019-06-10 19:50:02 -07:00
|
|
|
}
|
2023-04-07 03:53:19 -07:00
|
|
|
});
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2022-03-21 05:53:32 -07:00
|
|
|
let writable_pubkey = Pubkey::new_unique();
|
|
|
|
let readonly_pubkey = Pubkey::new_unique();
|
|
|
|
let mock_system_program_id = Pubkey::new_unique();
|
|
|
|
|
2020-03-31 10:07:38 -07:00
|
|
|
let rent_collector = RentCollector::default();
|
2023-04-24 10:01:40 -07:00
|
|
|
let builtin_programs =
|
|
|
|
BuiltinPrograms::new_mock(mock_system_program_id, process_instruction);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2021-07-05 04:49:37 -07:00
|
|
|
let accounts = vec![
|
|
|
|
(
|
2022-03-21 05:53:32 -07:00
|
|
|
writable_pubkey,
|
2021-12-27 09:49:32 -08:00
|
|
|
AccountSharedData::new(100, 1, &mock_system_program_id),
|
2021-07-05 04:49:37 -07:00
|
|
|
),
|
|
|
|
(
|
2022-03-21 05:53:32 -07:00
|
|
|
readonly_pubkey,
|
2021-12-27 09:49:32 -08:00
|
|
|
AccountSharedData::new(0, 1, &mock_system_program_id),
|
2021-12-17 05:01:12 -08:00
|
|
|
),
|
|
|
|
(
|
|
|
|
mock_system_program_id,
|
2021-12-27 09:49:32 -08:00
|
|
|
create_loadable_account_for_test("mock_system_program"),
|
2021-07-05 04:49:37 -07:00
|
|
|
),
|
|
|
|
];
|
2022-07-15 00:31:34 -07:00
|
|
|
let mut transaction_context =
|
|
|
|
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
|
2021-09-09 23:36:21 -07:00
|
|
|
let program_indices = vec![vec![2]];
|
2022-10-12 09:09:03 -07:00
|
|
|
let tx_executor_cache = Rc::new(RefCell::new(TransactionExecutorCache::default()));
|
2022-08-31 08:47:47 -07:00
|
|
|
let account_keys = (0..transaction_context.get_number_of_accounts())
|
|
|
|
.map(|index| {
|
|
|
|
*transaction_context
|
|
|
|
.get_key_of_account_at_index(index)
|
|
|
|
.unwrap()
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
2019-06-10 19:50:02 -07:00
|
|
|
let account_metas = vec![
|
2022-03-21 05:53:32 -07:00
|
|
|
AccountMeta::new(writable_pubkey, true),
|
|
|
|
AccountMeta::new_readonly(readonly_pubkey, false),
|
2019-06-10 19:50:02 -07:00
|
|
|
];
|
2021-12-27 09:49:32 -08:00
|
|
|
|
2022-08-25 14:33:41 -07:00
|
|
|
let message =
|
|
|
|
SanitizedMessage::Legacy(LegacyMessage::new(Message::new_with_compiled_instructions(
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
2,
|
|
|
|
account_keys.clone(),
|
|
|
|
Hash::default(),
|
|
|
|
AccountKeys::new(&account_keys, None).compile_instructions(&[
|
|
|
|
Instruction::new_with_bincode(
|
|
|
|
mock_system_program_id,
|
|
|
|
&MockSystemInstruction::Correct,
|
|
|
|
account_metas.clone(),
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
)));
|
2022-01-11 19:19:11 -08:00
|
|
|
let sysvar_cache = SysvarCache::default();
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2020-09-14 17:42:37 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent_collector.rent,
|
2020-09-14 17:42:37 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache.clone(),
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2021-12-15 14:41:38 -08:00
|
|
|
assert!(result.is_ok());
|
2021-12-27 09:49:32 -08:00
|
|
|
assert_eq!(
|
|
|
|
transaction_context
|
|
|
|
.get_account_at_index(0)
|
2022-02-03 02:34:51 -08:00
|
|
|
.unwrap()
|
2021-12-27 09:49:32 -08:00
|
|
|
.borrow()
|
|
|
|
.lamports(),
|
|
|
|
100
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
transaction_context
|
|
|
|
.get_account_at_index(1)
|
2022-02-03 02:34:51 -08:00
|
|
|
.unwrap()
|
2021-12-27 09:49:32 -08:00
|
|
|
.borrow()
|
|
|
|
.lamports(),
|
|
|
|
0
|
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
|
2022-08-25 14:33:41 -07:00
|
|
|
let message =
|
|
|
|
SanitizedMessage::Legacy(LegacyMessage::new(Message::new_with_compiled_instructions(
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
2,
|
|
|
|
account_keys.clone(),
|
|
|
|
Hash::default(),
|
|
|
|
AccountKeys::new(&account_keys, None).compile_instructions(&[
|
|
|
|
Instruction::new_with_bincode(
|
|
|
|
mock_system_program_id,
|
|
|
|
&MockSystemInstruction::TransferLamports { lamports: 50 },
|
|
|
|
account_metas.clone(),
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
)));
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2020-09-14 17:42:37 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent_collector.rent,
|
2020-09-14 17:42:37 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache.clone(),
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
2019-11-05 08:38:35 -08:00
|
|
|
InstructionError::ReadonlyLamportChange
|
2019-06-10 19:50:02 -07:00
|
|
|
))
|
|
|
|
);
|
|
|
|
|
2022-08-25 14:33:41 -07:00
|
|
|
let message =
|
|
|
|
SanitizedMessage::Legacy(LegacyMessage::new(Message::new_with_compiled_instructions(
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
2,
|
|
|
|
account_keys.clone(),
|
|
|
|
Hash::default(),
|
|
|
|
AccountKeys::new(&account_keys, None).compile_instructions(&[
|
|
|
|
Instruction::new_with_bincode(
|
|
|
|
mock_system_program_id,
|
|
|
|
&MockSystemInstruction::ChangeData { data: 50 },
|
|
|
|
account_metas,
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
)));
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2020-09-14 17:42:37 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent_collector.rent,
|
2020-09-14 17:42:37 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2019-06-10 19:50:02 -07:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
2019-11-05 08:38:35 -08:00
|
|
|
InstructionError::ReadonlyDataModified
|
2019-06-10 19:50:02 -07:00
|
|
|
))
|
|
|
|
);
|
2019-02-22 12:08:54 -08:00
|
|
|
}
|
2020-01-22 09:11:56 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_process_message_duplicate_accounts() {
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
enum MockSystemInstruction {
|
|
|
|
BorrowFail,
|
|
|
|
MultiBorrowMut,
|
|
|
|
DoWork { lamports: u64, data: u8 },
|
|
|
|
}
|
|
|
|
|
2023-04-07 03:53:19 -07:00
|
|
|
declare_process_instruction!(process_instruction, 1, |invoke_context| {
|
2022-01-05 00:39:37 -08:00
|
|
|
let transaction_context = &invoke_context.transaction_context;
|
|
|
|
let instruction_context = transaction_context.get_current_instruction_context()?;
|
2022-04-01 06:48:05 -07:00
|
|
|
let instruction_data = instruction_context.get_instruction_data();
|
2022-01-05 00:39:37 -08:00
|
|
|
let mut to_account =
|
|
|
|
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
|
2022-04-01 06:48:05 -07:00
|
|
|
if let Ok(instruction) = bincode::deserialize(instruction_data) {
|
2020-01-22 09:11:56 -08:00
|
|
|
match instruction {
|
|
|
|
MockSystemInstruction::BorrowFail => {
|
2022-01-05 00:39:37 -08:00
|
|
|
let from_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
let dup_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
if from_account.get_lamports() != dup_account.get_lamports() {
|
2023-04-07 03:53:19 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
2020-01-22 09:11:56 -08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
MockSystemInstruction::MultiBorrowMut => {
|
2022-01-05 00:39:37 -08:00
|
|
|
let lamports_a = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 0)?
|
|
|
|
.get_lamports();
|
|
|
|
let lamports_b = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 2)?
|
|
|
|
.get_lamports();
|
|
|
|
if lamports_a != lamports_b {
|
2023-04-07 03:53:19 -07:00
|
|
|
return Err(InstructionError::InvalidArgument);
|
2020-01-22 09:11:56 -08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
MockSystemInstruction::DoWork { lamports, data } => {
|
2022-01-05 00:39:37 -08:00
|
|
|
let mut dup_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 2)?;
|
|
|
|
dup_account.checked_sub_lamports(lamports)?;
|
|
|
|
to_account.checked_add_lamports(lamports)?;
|
2022-09-23 17:37:02 -07:00
|
|
|
dup_account.set_data(vec![data])?;
|
2022-01-05 00:39:37 -08:00
|
|
|
drop(dup_account);
|
|
|
|
let mut from_account = instruction_context
|
|
|
|
.try_borrow_instruction_account(transaction_context, 0)?;
|
|
|
|
from_account.checked_sub_lamports(lamports)?;
|
|
|
|
to_account.checked_add_lamports(lamports)?;
|
2020-01-22 09:11:56 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2023-04-07 03:53:19 -07:00
|
|
|
Err(InstructionError::InvalidInstructionData)
|
2020-01-22 09:11:56 -08:00
|
|
|
}
|
2023-04-07 03:53:19 -07:00
|
|
|
});
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2023-01-21 10:06:27 -08:00
|
|
|
let mock_program_id = Pubkey::from([2u8; 32]);
|
2020-03-31 10:07:38 -07:00
|
|
|
let rent_collector = RentCollector::default();
|
2023-04-24 10:01:40 -07:00
|
|
|
let builtin_programs = BuiltinPrograms::new_mock(mock_program_id, process_instruction);
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2021-07-05 04:49:37 -07:00
|
|
|
let accounts = vec![
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
2021-12-27 09:49:32 -08:00
|
|
|
AccountSharedData::new(100, 1, &mock_program_id),
|
2021-07-05 04:49:37 -07:00
|
|
|
),
|
|
|
|
(
|
|
|
|
solana_sdk::pubkey::new_rand(),
|
2021-12-27 09:49:32 -08:00
|
|
|
AccountSharedData::new(0, 1, &mock_program_id),
|
2021-12-17 05:01:12 -08:00
|
|
|
),
|
|
|
|
(
|
|
|
|
mock_program_id,
|
2021-12-27 09:49:32 -08:00
|
|
|
create_loadable_account_for_test("mock_system_program"),
|
2021-07-05 04:49:37 -07:00
|
|
|
),
|
|
|
|
];
|
2022-07-15 00:31:34 -07:00
|
|
|
let mut transaction_context =
|
|
|
|
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
|
2021-09-09 23:36:21 -07:00
|
|
|
let program_indices = vec![vec![2]];
|
2022-10-12 09:09:03 -07:00
|
|
|
let tx_executor_cache = Rc::new(RefCell::new(TransactionExecutorCache::default()));
|
2020-01-22 09:11:56 -08:00
|
|
|
let account_metas = vec![
|
2022-02-03 02:34:51 -08:00
|
|
|
AccountMeta::new(
|
|
|
|
*transaction_context.get_key_of_account_at_index(0).unwrap(),
|
|
|
|
true,
|
|
|
|
),
|
|
|
|
AccountMeta::new(
|
|
|
|
*transaction_context.get_key_of_account_at_index(1).unwrap(),
|
|
|
|
false,
|
|
|
|
),
|
|
|
|
AccountMeta::new(
|
|
|
|
*transaction_context.get_key_of_account_at_index(0).unwrap(),
|
|
|
|
false,
|
|
|
|
),
|
2020-01-22 09:11:56 -08:00
|
|
|
];
|
|
|
|
|
|
|
|
// Try to borrow mut the same account
|
2022-08-25 14:33:41 -07:00
|
|
|
let message = SanitizedMessage::Legacy(LegacyMessage::new(Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_program_id,
|
|
|
|
&MockSystemInstruction::BorrowFail,
|
|
|
|
account_metas.clone(),
|
|
|
|
)],
|
2022-02-03 02:34:51 -08:00
|
|
|
Some(transaction_context.get_key_of_account_at_index(0).unwrap()),
|
2022-08-25 14:33:41 -07:00
|
|
|
)));
|
2022-01-11 19:19:11 -08:00
|
|
|
let sysvar_cache = SysvarCache::default();
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2020-09-14 17:42:37 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent_collector.rent,
|
2020-09-14 17:42:37 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache.clone(),
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2020-01-22 09:11:56 -08:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
0,
|
|
|
|
InstructionError::AccountBorrowFailed
|
|
|
|
))
|
|
|
|
);
|
|
|
|
|
|
|
|
// Try to borrow mut the same account in a safe way
|
2022-08-25 14:33:41 -07:00
|
|
|
let message = SanitizedMessage::Legacy(LegacyMessage::new(Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_program_id,
|
|
|
|
&MockSystemInstruction::MultiBorrowMut,
|
|
|
|
account_metas.clone(),
|
|
|
|
)],
|
2022-02-03 02:34:51 -08:00
|
|
|
Some(transaction_context.get_key_of_account_at_index(0).unwrap()),
|
2022-08-25 14:33:41 -07:00
|
|
|
)));
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2020-09-14 17:42:37 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent_collector.rent,
|
2020-09-14 17:42:37 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache.clone(),
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2021-12-15 14:41:38 -08:00
|
|
|
assert!(result.is_ok());
|
2020-01-22 09:11:56 -08:00
|
|
|
|
2022-01-05 00:39:37 -08:00
|
|
|
// Do work on the same transaction account but at different instruction accounts
|
2022-08-25 14:33:41 -07:00
|
|
|
let message = SanitizedMessage::Legacy(LegacyMessage::new(Message::new(
|
2021-03-03 21:46:48 -08:00
|
|
|
&[Instruction::new_with_bincode(
|
2020-06-24 13:52:38 -07:00
|
|
|
mock_program_id,
|
|
|
|
&MockSystemInstruction::DoWork {
|
|
|
|
lamports: 10,
|
|
|
|
data: 42,
|
|
|
|
},
|
|
|
|
account_metas,
|
|
|
|
)],
|
2022-02-03 02:34:51 -08:00
|
|
|
Some(transaction_context.get_key_of_account_at_index(0).unwrap()),
|
2022-08-25 14:33:41 -07:00
|
|
|
)));
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2020-09-14 17:42:37 -07:00
|
|
|
&message,
|
2021-09-09 23:36:21 -07:00
|
|
|
&program_indices,
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
rent_collector.rent,
|
2020-09-14 17:42:37 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
tx_executor_cache,
|
2020-09-29 20:18:28 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-07-29 01:50:20 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2020-09-14 17:42:37 -07:00
|
|
|
);
|
2021-12-15 14:41:38 -08:00
|
|
|
assert!(result.is_ok());
|
2021-12-27 09:49:32 -08:00
|
|
|
assert_eq!(
|
|
|
|
transaction_context
|
|
|
|
.get_account_at_index(0)
|
2022-02-03 02:34:51 -08:00
|
|
|
.unwrap()
|
2021-12-27 09:49:32 -08:00
|
|
|
.borrow()
|
|
|
|
.lamports(),
|
|
|
|
80
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
transaction_context
|
|
|
|
.get_account_at_index(1)
|
2022-02-03 02:34:51 -08:00
|
|
|
.unwrap()
|
2021-12-27 09:49:32 -08:00
|
|
|
.borrow()
|
|
|
|
.lamports(),
|
|
|
|
20
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-02-03 02:34:51 -08:00
|
|
|
transaction_context
|
|
|
|
.get_account_at_index(0)
|
|
|
|
.unwrap()
|
|
|
|
.borrow()
|
|
|
|
.data(),
|
2021-12-27 09:49:32 -08:00
|
|
|
&vec![42]
|
|
|
|
);
|
2020-01-22 09:11:56 -08:00
|
|
|
}
|
2020-04-28 14:33:56 -07:00
|
|
|
|
2021-09-28 23:25:08 -07:00
|
|
|
#[test]
|
|
|
|
fn test_precompile() {
|
|
|
|
let mock_program_id = Pubkey::new_unique();
|
2023-04-07 03:53:19 -07:00
|
|
|
declare_process_instruction!(process_instruction, 1, |_invoke_context| {
|
|
|
|
Err(InstructionError::Custom(0xbabb1e))
|
|
|
|
});
|
2023-04-24 10:01:40 -07:00
|
|
|
let builtin_programs = BuiltinPrograms::new_mock(mock_program_id, process_instruction);
|
2021-09-28 23:25:08 -07:00
|
|
|
|
2021-12-17 05:01:12 -08:00
|
|
|
let mut secp256k1_account = AccountSharedData::new(1, 0, &native_loader::id());
|
|
|
|
secp256k1_account.set_executable(true);
|
|
|
|
let mut mock_program_account = AccountSharedData::new(1, 0, &native_loader::id());
|
|
|
|
mock_program_account.set_executable(true);
|
2021-09-28 23:25:08 -07:00
|
|
|
let accounts = vec![
|
2021-12-27 09:49:32 -08:00
|
|
|
(secp256k1_program::id(), secp256k1_account),
|
|
|
|
(mock_program_id, mock_program_account),
|
2021-09-28 23:25:08 -07:00
|
|
|
];
|
2022-07-15 00:31:34 -07:00
|
|
|
let mut transaction_context =
|
|
|
|
TransactionContext::new(accounts, Some(Rent::default()), 1, 2);
|
2021-09-28 23:25:08 -07:00
|
|
|
|
2022-08-25 14:33:41 -07:00
|
|
|
let message = SanitizedMessage::Legacy(LegacyMessage::new(Message::new(
|
2021-09-28 23:25:08 -07:00
|
|
|
&[
|
|
|
|
new_secp256k1_instruction(
|
|
|
|
&libsecp256k1::SecretKey::random(&mut rand::thread_rng()),
|
|
|
|
b"hello",
|
|
|
|
),
|
|
|
|
Instruction::new_with_bytes(mock_program_id, &[], vec![]),
|
|
|
|
],
|
|
|
|
None,
|
2022-08-25 14:33:41 -07:00
|
|
|
)));
|
2022-01-11 19:19:11 -08:00
|
|
|
let sysvar_cache = SysvarCache::default();
|
2021-09-29 10:05:25 -07:00
|
|
|
let result = MessageProcessor::process_message(
|
2023-04-24 10:01:40 -07:00
|
|
|
&builtin_programs,
|
2021-09-28 23:25:08 -07:00
|
|
|
&message,
|
|
|
|
&[vec![0], vec![1]],
|
2022-01-03 14:30:56 -08:00
|
|
|
&mut transaction_context,
|
2021-11-04 13:47:32 -07:00
|
|
|
RentCollector::default().rent,
|
2021-09-28 23:25:08 -07:00
|
|
|
None,
|
2022-10-12 09:09:03 -07:00
|
|
|
Rc::new(RefCell::new(TransactionExecutorCache::default())),
|
2021-09-28 23:25:08 -07:00
|
|
|
Arc::new(FeatureSet::all_enabled()),
|
2022-02-11 16:23:16 -08:00
|
|
|
ComputeBudget::default(),
|
2021-12-20 20:03:20 -08:00
|
|
|
&mut ExecuteTimings::default(),
|
2022-01-11 19:19:11 -08:00
|
|
|
&sysvar_cache,
|
2021-09-28 23:25:08 -07:00
|
|
|
Hash::default(),
|
2021-10-22 14:32:40 -07:00
|
|
|
0,
|
2021-12-28 03:14:48 -08:00
|
|
|
0,
|
2022-04-21 00:38:07 -07:00
|
|
|
&mut 0,
|
2021-09-28 23:25:08 -07:00
|
|
|
);
|
2022-04-21 00:38:07 -07:00
|
|
|
|
2021-09-28 23:25:08 -07:00
|
|
|
assert_eq!(
|
|
|
|
result,
|
|
|
|
Err(TransactionError::InstructionError(
|
|
|
|
1,
|
|
|
|
InstructionError::Custom(0xbabb1e)
|
|
|
|
))
|
|
|
|
);
|
2022-08-20 02:20:47 -07:00
|
|
|
assert_eq!(transaction_context.get_instruction_trace_length(), 2);
|
2021-09-28 23:25:08 -07:00
|
|
|
}
|
2019-02-18 22:26:22 -08:00
|
|
|
}
|