Refactor: Make program_id always last in program chain (#20598)
* Replaces program_id field in InvokeContextStackFrame by index. * Swaps order of program account and programdata account. * Removes program_id parameter from InvokeContext::push().
This commit is contained in:
committed by
GitHub
parent
c231cfe235
commit
1d813ea078
@ -199,72 +199,71 @@ fn process_instruction_common(
|
||||
use_jit: bool,
|
||||
) -> Result<(), InstructionError> {
|
||||
let logger = invoke_context.get_logger();
|
||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||
let program_id = invoke_context.get_caller()?;
|
||||
|
||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||
let first_account = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
||||
if first_account.executable()? {
|
||||
let second_account = keyed_account_at_index(keyed_accounts, first_instruction_account + 1);
|
||||
let (program, next_first_instruction_account) = if first_account.unsigned_key() == program_id {
|
||||
(first_account, first_instruction_account)
|
||||
} else if second_account
|
||||
.as_ref()
|
||||
.map(|keyed_account| keyed_account.unsigned_key() == program_id)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
(second_account?, first_instruction_account + 1)
|
||||
} else {
|
||||
if first_account.executable()? {
|
||||
ic_logger_msg!(logger, "BPF loader is executable");
|
||||
return Err(InstructionError::IncorrectProgramId);
|
||||
}
|
||||
(first_account, first_instruction_account)
|
||||
};
|
||||
|
||||
if program.executable()? {
|
||||
debug_assert_eq!(
|
||||
first_instruction_account,
|
||||
1 - (invoke_context.invoke_depth() > 1) as usize,
|
||||
);
|
||||
|
||||
let program_id = invoke_context.get_caller()?;
|
||||
if first_account.unsigned_key() != program_id {
|
||||
ic_logger_msg!(logger, "Program id mismatch");
|
||||
return Err(InstructionError::IncorrectProgramId);
|
||||
}
|
||||
|
||||
let (first_instruction_account, program_data_offset) =
|
||||
if bpf_loader_upgradeable::check_id(&first_account.owner()?) {
|
||||
if let UpgradeableLoaderState::Program {
|
||||
programdata_address,
|
||||
} = first_account.state()?
|
||||
{
|
||||
let programdata =
|
||||
keyed_account_at_index(keyed_accounts, first_instruction_account + 1)?;
|
||||
if programdata_address != *programdata.unsigned_key() {
|
||||
ic_logger_msg!(
|
||||
logger,
|
||||
"Wrong ProgramData account for this Program account"
|
||||
);
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
if !matches!(
|
||||
programdata.state()?,
|
||||
UpgradeableLoaderState::ProgramData {
|
||||
slot: _,
|
||||
upgrade_authority_address: _,
|
||||
}
|
||||
) {
|
||||
ic_logger_msg!(logger, "Program has been closed");
|
||||
return Err(InstructionError::InvalidAccountData);
|
||||
}
|
||||
(
|
||||
first_instruction_account + 1,
|
||||
UpgradeableLoaderState::programdata_data_offset()?,
|
||||
)
|
||||
} else {
|
||||
ic_logger_msg!(logger, "Invalid Program account");
|
||||
return Err(InstructionError::InvalidAccountData);
|
||||
}
|
||||
} else {
|
||||
(first_instruction_account, 0)
|
||||
};
|
||||
|
||||
let keyed_accounts = invoke_context.get_keyed_accounts()?;
|
||||
let program = keyed_account_at_index(keyed_accounts, first_instruction_account)?;
|
||||
let loader_id = &program.owner()?;
|
||||
|
||||
if !check_loader_id(loader_id) {
|
||||
if !check_loader_id(&program.owner()?) {
|
||||
ic_logger_msg!(logger, "Executable account not owned by the BPF loader");
|
||||
return Err(InstructionError::IncorrectProgramId);
|
||||
}
|
||||
|
||||
let program_data_offset = if bpf_loader_upgradeable::check_id(&program.owner()?) {
|
||||
if let UpgradeableLoaderState::Program {
|
||||
programdata_address,
|
||||
} = program.state()?
|
||||
{
|
||||
if programdata_address != *first_account.unsigned_key() {
|
||||
ic_logger_msg!(logger, "Wrong ProgramData account for this Program account");
|
||||
return Err(InstructionError::InvalidArgument);
|
||||
}
|
||||
if !matches!(
|
||||
first_account.state()?,
|
||||
UpgradeableLoaderState::ProgramData {
|
||||
slot: _,
|
||||
upgrade_authority_address: _,
|
||||
}
|
||||
) {
|
||||
ic_logger_msg!(logger, "Program has been closed");
|
||||
return Err(InstructionError::InvalidAccountData);
|
||||
}
|
||||
UpgradeableLoaderState::programdata_data_offset()?
|
||||
} else {
|
||||
ic_logger_msg!(logger, "Invalid Program account");
|
||||
return Err(InstructionError::InvalidAccountData);
|
||||
}
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let executor = match invoke_context.get_executor(program_id) {
|
||||
Some(executor) => executor,
|
||||
None => {
|
||||
let executor = create_executor(
|
||||
first_instruction_account,
|
||||
next_first_instruction_account,
|
||||
program_data_offset,
|
||||
invoke_context,
|
||||
use_jit,
|
||||
@ -275,37 +274,32 @@ fn process_instruction_common(
|
||||
}
|
||||
};
|
||||
executor.execute(
|
||||
first_instruction_account,
|
||||
next_first_instruction_account,
|
||||
instruction_data,
|
||||
invoke_context,
|
||||
use_jit,
|
||||
)?
|
||||
)
|
||||
} else {
|
||||
debug_assert_eq!(first_instruction_account, 1);
|
||||
|
||||
let program_id = invoke_context.get_caller()?;
|
||||
if !check_loader_id(program_id) {
|
||||
ic_logger_msg!(logger, "Invalid BPF loader id");
|
||||
return Err(InstructionError::IncorrectProgramId);
|
||||
}
|
||||
|
||||
if bpf_loader_upgradeable::check_id(program_id) {
|
||||
process_loader_upgradeable_instruction(
|
||||
first_instruction_account,
|
||||
instruction_data,
|
||||
invoke_context,
|
||||
use_jit,
|
||||
)?;
|
||||
} else {
|
||||
)
|
||||
} else if bpf_loader::check_id(program_id) || bpf_loader_deprecated::check_id(program_id) {
|
||||
process_loader_instruction(
|
||||
first_instruction_account,
|
||||
instruction_data,
|
||||
invoke_context,
|
||||
use_jit,
|
||||
)?;
|
||||
)
|
||||
} else {
|
||||
ic_logger_msg!(logger, "Invalid BPF loader id");
|
||||
Err(InstructionError::IncorrectProgramId)
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_loader_upgradeable_instruction(
|
||||
@ -3374,8 +3368,8 @@ mod tests {
|
||||
|
||||
// Try to invoke closed account
|
||||
let keyed_accounts: Vec<KeyedAccountTuple> = vec![
|
||||
(false, false, &program_address, &program_account),
|
||||
(false, false, &programdata_address, &programdata_account),
|
||||
(false, false, &program_address, &program_account),
|
||||
];
|
||||
assert_eq!(
|
||||
Err(InstructionError::InvalidAccountData),
|
||||
|
Reference in New Issue
Block a user