Fixes the empty transaction bug in ThisInvokeContext::push() and adds a test for it to the bank.
This commit is contained in:
parent
0bda0c3e0c
commit
8a50b6302f
@ -377,7 +377,8 @@ impl InstructionProcessor {
|
|||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||||
let root_account = keyed_account_at_index(keyed_accounts, 0)?;
|
let root_account = keyed_account_at_index(keyed_accounts, 0)
|
||||||
|
.map_err(|_| InstructionError::UnsupportedProgramId)?;
|
||||||
let root_id = root_account.unsigned_key();
|
let root_id = root_account.unsigned_key();
|
||||||
let owner_id = &root_account.owner()?;
|
let owner_id = &root_account.owner()?;
|
||||||
if solana_sdk::native_loader::check_id(owner_id) {
|
if solana_sdk::native_loader::check_id(owner_id) {
|
||||||
|
@ -327,38 +327,21 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
|||||||
return Err(InstructionError::CallDepth);
|
return Err(InstructionError::CallDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
let program_id = if let Some(index_of_program_id) = program_indices.last() {
|
let program_id = program_indices
|
||||||
let program_id = &self.accounts[*index_of_program_id].0;
|
.last()
|
||||||
let contains = self
|
.map(|index_of_program_id| &self.accounts[*index_of_program_id].0);
|
||||||
.invoke_stack
|
|
||||||
.iter()
|
|
||||||
.any(|frame| frame.program_id() == Some(program_id));
|
|
||||||
let is_last = if let Some(last_frame) = self.invoke_stack.last() {
|
|
||||||
last_frame.program_id() == Some(program_id)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
if contains && !is_last {
|
|
||||||
// Reentrancy not allowed unless caller is calling itself
|
|
||||||
return Err(InstructionError::ReentrancyNotAllowed);
|
|
||||||
}
|
|
||||||
*program_id
|
|
||||||
} else {
|
|
||||||
return Err(InstructionError::UnsupportedProgramId);
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.invoke_stack.is_empty() {
|
if self.invoke_stack.is_empty() {
|
||||||
let mut compute_budget = self.compute_budget;
|
let mut compute_budget = self.compute_budget;
|
||||||
if !self.is_feature_active(&tx_wide_compute_cap::id())
|
if !self.is_feature_active(&tx_wide_compute_cap::id())
|
||||||
&& self.is_feature_active(&neon_evm_compute_budget::id())
|
&& self.is_feature_active(&neon_evm_compute_budget::id())
|
||||||
&& program_id == crate::neon_evm_program::id()
|
&& program_id == Some(&crate::neon_evm_program::id())
|
||||||
{
|
{
|
||||||
// Bump the compute budget for neon_evm
|
// Bump the compute budget for neon_evm
|
||||||
compute_budget.max_units = compute_budget.max_units.max(500_000);
|
compute_budget.max_units = compute_budget.max_units.max(500_000);
|
||||||
}
|
}
|
||||||
if !self.is_feature_active(&requestable_heap_size::id())
|
if !self.is_feature_active(&requestable_heap_size::id())
|
||||||
&& self.is_feature_active(&neon_evm_compute_budget::id())
|
&& self.is_feature_active(&neon_evm_compute_budget::id())
|
||||||
&& program_id == crate::neon_evm_program::id()
|
&& program_id == Some(&crate::neon_evm_program::id())
|
||||||
{
|
{
|
||||||
// Bump the compute budget for neon_evm
|
// Bump the compute budget for neon_evm
|
||||||
compute_budget.heap_size = Some(256_usize.saturating_mul(1024));
|
compute_budget.heap_size = Some(256_usize.saturating_mul(1024));
|
||||||
@ -381,6 +364,20 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
|||||||
Err(InstructionError::MissingAccount)
|
Err(InstructionError::MissingAccount)
|
||||||
};
|
};
|
||||||
instruction.visit_each_account(&mut work)?;
|
instruction.visit_each_account(&mut work)?;
|
||||||
|
} else {
|
||||||
|
let contains = self
|
||||||
|
.invoke_stack
|
||||||
|
.iter()
|
||||||
|
.any(|frame| frame.program_id() == program_id);
|
||||||
|
let is_last = if let Some(last_frame) = self.invoke_stack.last() {
|
||||||
|
last_frame.program_id() == program_id
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if contains && !is_last {
|
||||||
|
// Reentrancy not allowed unless caller is calling itself
|
||||||
|
return Err(InstructionError::ReentrancyNotAllowed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the KeyedAccounts that will be passed to the program
|
// Create the KeyedAccounts that will be passed to the program
|
||||||
|
@ -15391,4 +15391,18 @@ pub(crate) mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(Bank::calculate_fee(&message, 1), 11);
|
assert_eq!(Bank::calculate_fee(&message, 1), 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_an_empty_transaction_without_program() {
|
||||||
|
let (genesis_config, mint_keypair) = create_genesis_config(1);
|
||||||
|
let bank = Bank::new_for_tests(&genesis_config);
|
||||||
|
|
||||||
|
let destination = solana_sdk::pubkey::new_rand();
|
||||||
|
let mut ix = system_instruction::transfer(&mint_keypair.pubkey(), &destination, 0);
|
||||||
|
ix.program_id = native_loader::id(); // Empty executable account chain
|
||||||
|
|
||||||
|
let message = Message::new(&[ix], Some(&mint_keypair.pubkey()));
|
||||||
|
let tx = Transaction::new(&[&mint_keypair], message, genesis_config.hash());
|
||||||
|
bank.process_transaction(&tx).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@ fn process_instruction_with_program_logging(
|
|||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
debug_assert_eq!(first_instruction_account, 1);
|
|
||||||
|
|
||||||
let logger = invoke_context.get_logger();
|
let logger = invoke_context.get_logger();
|
||||||
let program_id = invoke_context.get_caller()?;
|
let program_id = invoke_context.get_caller()?;
|
||||||
stable_log::program_invoke(&logger, program_id, invoke_context.invoke_depth());
|
stable_log::program_invoke(&logger, program_id, invoke_context.invoke_depth());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user