/// --- programs/address-lookup-table/src/processor.rs ---
fn create_lookup_table(
invoke_context: &mut InvokeContext,
untrusted_recent_slot: Slot,
bump_seed: u8,
) -> Result<(), InstructionError> {
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let lookup_table_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
let lookup_table_lamports = lookup_table_account.get_lamports();
let table_key = *lookup_table_account.get_key();
let lookup_table_owner = *lookup_table_account.get_owner();
if !invoke_context
.feature_set
.is_active(&feature_set::relax_authority_signer_check_for_lookup_table_creation::id())
&& !lookup_table_account.get_data().is_empty()
{
ic_msg!(invoke_context, "Table account must not be allocated");
return Err(InstructionError::AccountAlreadyInitialized);
}
drop(lookup_table_account);
let authority_account =
instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
let authority_key = *authority_account.get_key();
if !invoke_context
.feature_set
.is_active(&feature_set::relax_authority_signer_check_for_lookup_table_creation::id())
&& !authority_account.is_signer()
{
ic_msg!(invoke_context, "Authority account must be a signer");
return Err(InstructionError::MissingRequiredSignature);
}
drop(authority_account);
let payer_account =
instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
let payer_key = *payer_account.get_key();
if !payer_account.is_signer() {
ic_msg!(invoke_context, "Payer account must be a signer");
return Err(InstructionError::MissingRequiredSignature);
}
drop(payer_account);
let derivation_slot = {
let slot_hashes = invoke_context.get_sysvar_cache().get_slot_hashes()?;
if slot_hashes.get(&untrusted_recent_slot).is_some() {
Ok(untrusted_recent_slot)
} else {
ic_msg!(
invoke_context,
"{} is not a recent slot",
untrusted_recent_slot
);
Err(InstructionError::InvalidInstructionData)
}
}?;
// Use a derived address to ensure that an address table can never be
// initialized more than once at the same address.
let derived_table_key = Pubkey::create_program_address(
&[
authority_key.as_ref(),
&derivation_slot.to_le_bytes(),
&[bump_seed],
],
&id(),
)?;
if table_key != derived_table_key {
ic_msg!(
invoke_context,
"Table address must match derived address: {}",
derived_table_key
);
return Err(InstructionError::InvalidArgument);
}
if invoke_context
.feature_set
.is_active(&feature_set::relax_authority_signer_check_for_lookup_table_creation::id())
&& check_id(&lookup_table_owner)
{
return Ok(());
}
let table_account_data_len = LOOKUP_TABLE_META_SIZE;
let rent = invoke_context.get_sysvar_cache().get_rent()?;
let required_lamports = rent
.minimum_balance(table_account_data_len)
.max(1)
.saturating_sub(lookup_table_lamports);
if required_lamports > 0 {
invoke_context.native_invoke(
system_instruction::transfer(&payer_key, &table_key, required_lamports).into(),
&[payer_key],
)?;
}
invoke_context.native_invoke(
system_instruction::allocate(&table_key, table_account_data_len as u64).into(),
&[table_key],
)?;
invoke_context.native_invoke(
system_instruction::assign(&table_key, &id()).into(),
&[table_key],
)?;
let transaction_context = &invoke_context.transaction_context;
let instruction_context = transaction_context.get_current_instruction_context()?;
let mut lookup_table_account =
instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
lookup_table_account.set_state(&ProgramState::LookupTable(LookupTableMeta::new(
authority_key,
)))?;
Ok(())
}