use {
ephemeral_rollups_sdk::consts::{MAGIC_CONTEXT_ID, MAGIC_PROGRAM_ID},
solana_transaction::InstructionError,
solana_transaction_context::{instruction::InstructionContext, IndexOfAccount},
};
const MAGIC_PAYER_IDX: IndexOfAccount = 0;
const MAGIC_CONTEXT_IDX: IndexOfAccount = 1;
const MAGIC_COMMITTEES_START_IDX: IndexOfAccount = 2;
pub(super) fn process_schedule_commit(
instruction_context: &InstructionContext<'_, '_>,
request_undelegation: bool,
) -> Result<(), InstructionError> {
validate_magic_schedule_header(instruction_context)?;
let account_count = instruction_context.get_number_of_instruction_accounts();
if account_count <= MAGIC_COMMITTEES_START_IDX {
return Err(InstructionError::MissingAccount);
}
let account_indices: Vec<_> = (MAGIC_COMMITTEES_START_IDX..account_count).collect();
validate_commit_accounts(instruction_context, &account_indices, request_undelegation)
}
pub(super) fn process_schedule_commit_intent(
instruction_context: &InstructionContext<'_, '_>,
committed_accounts: &[u8],
undelegated_accounts: &[u8],
) -> Result<(), InstructionError> {
validate_magic_schedule_header(instruction_context)?;
let committed_accounts: Vec<_> = committed_accounts
.iter()
.map(|index| u16::from(*index))
.collect();
let undelegated_accounts: Vec<_> = undelegated_accounts
.iter()
.map(|index| u16::from(*index))
.collect();
validate_commit_accounts(instruction_context, &committed_accounts, false)?;
validate_commit_accounts(instruction_context, &undelegated_accounts, true)
}
fn validate_magic_schedule_header(
instruction_context: &InstructionContext<'_, '_>,
) -> Result<(), InstructionError> {
if instruction_context.get_program_key()? != &MAGIC_PROGRAM_ID {
return Err(InstructionError::UnsupportedProgramId);
}
instruction_context.check_number_of_instruction_accounts(MAGIC_CONTEXT_IDX + 1)?;
if instruction_context.get_key_of_instruction_account(MAGIC_CONTEXT_IDX)? != &MAGIC_CONTEXT_ID {
return Err(InstructionError::MissingAccount);
}
if !instruction_context.is_instruction_account_signer(MAGIC_PAYER_IDX)? {
return Err(InstructionError::MissingRequiredSignature);
}
if !instruction_context.is_instruction_account_writable(MAGIC_CONTEXT_IDX)? {
return Err(InstructionError::ReadonlyDataModified);
}
Ok(())
}
fn validate_commit_accounts(
instruction_context: &InstructionContext<'_, '_>,
account_indices: &[IndexOfAccount],
request_undelegation: bool,
) -> Result<(), InstructionError> {
if account_indices.is_empty() {
return Ok(());
}
for account_index in account_indices {
let account = instruction_context.try_borrow_instruction_account(*account_index)?;
if account.get_key() == &MAGIC_CONTEXT_ID || account.get_key() == &MAGIC_PROGRAM_ID {
return Err(InstructionError::MissingAccount);
}
if request_undelegation
&& !instruction_context.is_instruction_account_writable(*account_index)?
{
return Err(InstructionError::ReadonlyDataModified);
}
}
Ok(())
}