This commit is contained in:
@ -6,6 +6,7 @@ use {
|
||||
instruction::InstructionError,
|
||||
pubkey::Pubkey,
|
||||
slot_hashes::{SlotHashes, MAX_ENTRIES},
|
||||
transaction::AddressLookupError,
|
||||
},
|
||||
std::borrow::Cow,
|
||||
};
|
||||
@ -133,6 +134,49 @@ impl<'a> AddressLookupTable<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the length of addresses that are active for lookups
|
||||
pub fn get_active_addresses_len(
|
||||
&self,
|
||||
current_slot: Slot,
|
||||
slot_hashes: &SlotHashes,
|
||||
) -> Result<usize, AddressLookupError> {
|
||||
if !self.meta.is_active(current_slot, slot_hashes) {
|
||||
// Once a lookup table is no longer active, it can be closed
|
||||
// at any point, so returning a specific error for deactivated
|
||||
// lookup tables could result in a race condition.
|
||||
return Err(AddressLookupError::LookupTableAccountNotFound);
|
||||
}
|
||||
|
||||
// If the address table was extended in the same slot in which it is used
|
||||
// to lookup addresses for another transaction, the recently extended
|
||||
// addresses are not considered active and won't be accessible.
|
||||
let active_addresses_len = if current_slot > self.meta.last_extended_slot {
|
||||
self.addresses.len()
|
||||
} else {
|
||||
self.meta.last_extended_slot_start_index as usize
|
||||
};
|
||||
|
||||
Ok(active_addresses_len)
|
||||
}
|
||||
|
||||
/// Lookup addresses for provided table indexes. Since lookups are performed on
|
||||
/// tables which are not read-locked, this implementation needs to be careful
|
||||
/// about resolving addresses consistently.
|
||||
pub fn lookup(
|
||||
&self,
|
||||
current_slot: Slot,
|
||||
indexes: &[u8],
|
||||
slot_hashes: &SlotHashes,
|
||||
) -> Result<Vec<Pubkey>, AddressLookupError> {
|
||||
let active_addresses_len = self.get_active_addresses_len(current_slot, slot_hashes)?;
|
||||
let active_addresses = &self.addresses[0..active_addresses_len];
|
||||
indexes
|
||||
.iter()
|
||||
.map(|idx| active_addresses.get(*idx as usize).cloned())
|
||||
.collect::<Option<_>>()
|
||||
.ok_or(AddressLookupError::InvalidLookupIndex)
|
||||
}
|
||||
|
||||
/// Serialize an address table including its addresses
|
||||
pub fn serialize_for_tests(self, data: &mut Vec<u8>) -> Result<(), InstructionError> {
|
||||
data.resize(LOOKUP_TABLE_META_SIZE, 0);
|
||||
@ -322,4 +366,117 @@ mod tests {
|
||||
test_case(case);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookup_from_empty_table() {
|
||||
let lookup_table = AddressLookupTable {
|
||||
meta: LookupTableMeta::default(),
|
||||
addresses: Cow::Owned(vec![]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
lookup_table.lookup(0, &[], &SlotHashes::default()),
|
||||
Ok(vec![])
|
||||
);
|
||||
assert_eq!(
|
||||
lookup_table.lookup(0, &[0], &SlotHashes::default()),
|
||||
Err(AddressLookupError::InvalidLookupIndex)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookup_from_deactivating_table() {
|
||||
let current_slot = 1;
|
||||
let slot_hashes = SlotHashes::default();
|
||||
let addresses = vec![Pubkey::new_unique()];
|
||||
let lookup_table = AddressLookupTable {
|
||||
meta: LookupTableMeta {
|
||||
deactivation_slot: current_slot,
|
||||
last_extended_slot: current_slot - 1,
|
||||
..LookupTableMeta::default()
|
||||
},
|
||||
addresses: Cow::Owned(addresses.clone()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
lookup_table.meta.status(current_slot, &slot_hashes),
|
||||
LookupTableStatus::Deactivating {
|
||||
remaining_blocks: MAX_ENTRIES + 1
|
||||
}
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
lookup_table.lookup(current_slot, &[0], &slot_hashes),
|
||||
Ok(vec![addresses[0]]),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookup_from_deactivated_table() {
|
||||
let current_slot = 1;
|
||||
let slot_hashes = SlotHashes::default();
|
||||
let lookup_table = AddressLookupTable {
|
||||
meta: LookupTableMeta {
|
||||
deactivation_slot: current_slot - 1,
|
||||
last_extended_slot: current_slot - 1,
|
||||
..LookupTableMeta::default()
|
||||
},
|
||||
addresses: Cow::Owned(vec![]),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
lookup_table.meta.status(current_slot, &slot_hashes),
|
||||
LookupTableStatus::Deactivated
|
||||
);
|
||||
assert_eq!(
|
||||
lookup_table.lookup(current_slot, &[0], &slot_hashes),
|
||||
Err(AddressLookupError::LookupTableAccountNotFound)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookup_from_table_extended_in_current_slot() {
|
||||
let current_slot = 0;
|
||||
let addresses: Vec<_> = (0..2).map(|_| Pubkey::new_unique()).collect();
|
||||
let lookup_table = AddressLookupTable {
|
||||
meta: LookupTableMeta {
|
||||
last_extended_slot: current_slot,
|
||||
last_extended_slot_start_index: 1,
|
||||
..LookupTableMeta::default()
|
||||
},
|
||||
addresses: Cow::Owned(addresses.clone()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
lookup_table.lookup(current_slot, &[0], &SlotHashes::default()),
|
||||
Ok(vec![addresses[0]])
|
||||
);
|
||||
assert_eq!(
|
||||
lookup_table.lookup(current_slot, &[1], &SlotHashes::default()),
|
||||
Err(AddressLookupError::InvalidLookupIndex),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lookup_from_table_extended_in_previous_slot() {
|
||||
let current_slot = 1;
|
||||
let addresses: Vec<_> = (0..10).map(|_| Pubkey::new_unique()).collect();
|
||||
let lookup_table = AddressLookupTable {
|
||||
meta: LookupTableMeta {
|
||||
last_extended_slot: current_slot - 1,
|
||||
last_extended_slot_start_index: 1,
|
||||
..LookupTableMeta::default()
|
||||
},
|
||||
addresses: Cow::Owned(addresses.clone()),
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
lookup_table.lookup(current_slot, &[0, 3, 1, 5], &SlotHashes::default()),
|
||||
Ok(vec![addresses[0], addresses[3], addresses[1], addresses[5]])
|
||||
);
|
||||
assert_eq!(
|
||||
lookup_table.lookup(current_slot, &[10], &SlotHashes::default()),
|
||||
Err(AddressLookupError::InvalidLookupIndex),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ mod tests {
|
||||
invoke_context
|
||||
.push(
|
||||
&preparation.message,
|
||||
&preparation.message.instructions[0],
|
||||
&preparation.message.instructions()[0],
|
||||
&program_indices,
|
||||
&preparation.account_indices,
|
||||
)
|
||||
|
@ -33,7 +33,7 @@ use {
|
||||
hash::{Hasher, HASH_BYTES},
|
||||
instruction::{AccountMeta, Instruction, InstructionError},
|
||||
keccak,
|
||||
message::Message,
|
||||
message::{Message, SanitizedMessage},
|
||||
native_loader,
|
||||
precompiles::is_precompile,
|
||||
program::MAX_RETURN_DATA,
|
||||
@ -2365,10 +2365,11 @@ fn call<'a, 'b: 'a>(
|
||||
}
|
||||
|
||||
// Process instruction
|
||||
let message = SanitizedMessage::Legacy(message);
|
||||
invoke_context
|
||||
.process_instruction(
|
||||
&message,
|
||||
&message.instructions[0],
|
||||
&message.instructions()[0],
|
||||
&program_indices,
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
@ -2962,13 +2963,13 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall_panic = SyscallPanic {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3039,13 +3040,13 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall_sol_log = SyscallLog {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3143,13 +3144,13 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let cost = invoke_context.get_compute_budget().log_64_units;
|
||||
let mut syscall_sol_log_u64 = SyscallLogU64 {
|
||||
@ -3185,13 +3186,13 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let cost = invoke_context.get_compute_budget().log_pubkey_units;
|
||||
let mut syscall_sol_pubkey = SyscallLogPubkey {
|
||||
@ -3397,10 +3398,10 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader_deprecated::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
|
||||
let bytes1 = "Gaggablaghblagh!";
|
||||
let bytes2 = "flurbos";
|
||||
@ -3465,7 +3466,7 @@ mod tests {
|
||||
* 4,
|
||||
);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall = SyscallSha256 {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3526,10 +3527,10 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
|
||||
// Test clock sysvar
|
||||
{
|
||||
@ -3564,7 +3565,7 @@ mod tests {
|
||||
let sysvars = [(sysvar::clock::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall = SyscallGetClockSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3609,7 +3610,7 @@ mod tests {
|
||||
let sysvars = [(sysvar::epoch_schedule::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall = SyscallGetEpochScheduleSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3661,7 +3662,7 @@ mod tests {
|
||||
let sysvars = [(sysvar::fees::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall = SyscallGetFeesSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3704,7 +3705,7 @@ mod tests {
|
||||
let sysvars = [(sysvar::rent::id(), data)];
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let mut syscall = SyscallGetRentSysvar {
|
||||
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
|
||||
@ -3836,13 +3837,13 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let address = bpf_loader_upgradeable::id();
|
||||
|
||||
@ -3952,13 +3953,13 @@ mod tests {
|
||||
let program_id = Pubkey::new_unique();
|
||||
let program_account = AccountSharedData::new_ref(0, 0, &bpf_loader::id());
|
||||
let accounts = [(program_id, program_account)];
|
||||
let message = Message::new(
|
||||
let message = SanitizedMessage::Legacy(Message::new(
|
||||
&[Instruction::new_with_bytes(program_id, &[], vec![])],
|
||||
None,
|
||||
);
|
||||
));
|
||||
let mut invoke_context = InvokeContext::new_mock(&accounts, &[]);
|
||||
invoke_context
|
||||
.push(&message, &message.instructions[0], &[0], &[])
|
||||
.push(&message, &message.instructions()[0], &[0], &[])
|
||||
.unwrap();
|
||||
let cost = invoke_context
|
||||
.get_compute_budget()
|
||||
|
@ -435,7 +435,7 @@ mod tests {
|
||||
invoke_context.sysvars = &sysvars;
|
||||
invoke_context.push(
|
||||
&preparation.message,
|
||||
&preparation.message.instructions[0],
|
||||
&preparation.message.instructions()[0],
|
||||
&program_indices,
|
||||
&preparation.account_indices,
|
||||
)?;
|
||||
@ -1082,7 +1082,7 @@ mod tests {
|
||||
invoke_context
|
||||
.push(
|
||||
&preparation.message,
|
||||
&preparation.message.instructions[0],
|
||||
&preparation.message.instructions()[0],
|
||||
&program_indices,
|
||||
&preparation.account_indices,
|
||||
)
|
||||
|
Reference in New Issue
Block a user