Refactor: Remove KeyedAccount from program runtime (#22226)

* Makes error handling in BorrowedAccount optional.
Adds BorrowedAccount ::get_rent_epoch().
Exposes InstructionContext::get_index_in_transaction().
Turns accounts and account_keys into pinned boxed slices.

* Introduces "unsafe" to InvokeContext::push().

* Turns &TransactionContext into &mut TransactionContext in InvokeContext.

* Push and pop InstructionContext in InvokeContext.
Makes test_process_cross_program and test_native_invoke symmetric.
Removes the borrow check from test_invoke_context_verify.

* Removes keyed_accounts from prepare_instruction()

* Removes usage of invoke_stack.

* Removes keyed_accounts from program-test.

* Removes caller_write_privileges.

* Removes keyed_accounts from BPF parameter (de-)serialization.
This commit is contained in:
Alexander Meißner
2022-01-03 23:30:56 +01:00
committed by GitHub
parent 672fed04cb
commit 73e6038986
18 changed files with 847 additions and 805 deletions

View File

@@ -246,7 +246,8 @@ pub fn bind_syscall_context_objects<'a, 'b>(
.is_active(&sol_log_data_syscall_enabled::id());
let loader_id = invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError)?;
let invoke_context = Rc::new(RefCell::new(invoke_context));
@@ -581,7 +582,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallPanic<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -620,7 +622,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLog<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -734,7 +737,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLogPubkey<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -850,7 +854,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallCreateProgramAddress<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -909,7 +914,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallTryFindProgramAddress<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -983,7 +989,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSha256<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1064,7 +1071,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetClockSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1100,7 +1108,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetEpochScheduleSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1137,7 +1146,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetFeesSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1173,7 +1183,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetRentSysvar<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1216,7 +1227,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallKeccak256<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1316,7 +1328,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcpy<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1360,7 +1373,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemmove<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1404,7 +1418,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemcmp<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1461,7 +1476,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallMemset<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1503,7 +1519,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSecp256k1Recover<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -1608,7 +1625,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallBlake3<'a, 'b> {
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -2202,14 +2220,10 @@ fn get_translated_accounts<'a, T, F>(
where
F: Fn(&T, &InvokeContext) -> Result<CallerAccount<'a>, EbpfError<BpfError>>,
{
let keyed_accounts = invoke_context
.get_keyed_accounts()
let instruction_context = invoke_context
.transaction_context
.get_current_instruction_context()
.map_err(SyscallError::InstructionError)?;
let number_of_program_accounts = keyed_accounts.len()
- invoke_context
.get_instruction_keyed_accounts()
.map_err(SyscallError::InstructionError)?
.len();
let mut accounts = Vec::with_capacity(instruction_accounts.len().saturating_add(1));
let program_account_index = program_indices
@@ -2245,10 +2259,8 @@ where
let caller_account = if instruction_account.is_writable {
let orig_data_len_index = instruction_account
.index_in_caller
.saturating_sub(number_of_program_accounts);
if keyed_accounts[instruction_account.index_in_caller].unsigned_key() == account_key
&& orig_data_len_index < orig_data_lens.len()
{
.saturating_sub(instruction_context.get_number_of_program_accounts());
if orig_data_len_index < orig_data_lens.len() {
caller_account.original_data_len = orig_data_lens[orig_data_len_index];
} else {
ic_msg!(
@@ -2351,7 +2363,8 @@ fn call<'a, 'b: 'a>(
// Translate and verify caller's data
let loader_id = invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError)?;
let instruction = syscall.translate_instruction(
&loader_id,
@@ -2360,7 +2373,8 @@ fn call<'a, 'b: 'a>(
*invoke_context,
)?;
let caller_program_id = invoke_context
.get_caller()
.transaction_context
.get_program_key()
.map_err(SyscallError::InstructionError)?;
let signers = syscall.translate_signers(
&loader_id,
@@ -2369,7 +2383,7 @@ fn call<'a, 'b: 'a>(
signers_seeds_len,
memory_mapping,
)?;
let (instruction_accounts, caller_write_privileges, program_indices) = invoke_context
let (instruction_accounts, program_indices) = invoke_context
.prepare_instruction(&instruction, &signers)
.map_err(SyscallError::InstructionError)?;
check_authorized_program(&instruction.program_id, &instruction.data, *invoke_context)?;
@@ -2389,7 +2403,6 @@ fn call<'a, 'b: 'a>(
.process_instruction(
&instruction.data,
&instruction_accounts,
Some(&caller_write_privileges),
&program_indices,
&mut compute_units_consumed,
)
@@ -2476,7 +2489,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSetReturnData<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -2506,7 +2520,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallSetReturnData<'a, 'b> {
};
let program_id = question_mark!(
invoke_context
.get_caller()
.transaction_context
.get_program_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -2538,7 +2553,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallGetReturnData<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -2605,7 +2621,8 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallLogData<'a, 'b> {
);
let loader_id = question_mark!(
invoke_context
.get_loader()
.transaction_context
.get_loader_key()
.map_err(SyscallError::InstructionError),
result
);
@@ -2984,12 +3001,12 @@ mod tests {
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
fn test_syscall_sol_panic() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let mut syscall_panic = SyscallPanic {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
};
@@ -3057,12 +3074,12 @@ mod tests {
#[test]
fn test_syscall_sol_log() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let mut syscall_sol_log = SyscallLog {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
};
@@ -3157,12 +3174,12 @@ mod tests {
#[test]
fn test_syscall_sol_log_u64() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let cost = invoke_context.get_compute_budget().log_64_units;
let mut syscall_sol_log_u64 = SyscallLogU64 {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@@ -3195,12 +3212,12 @@ mod tests {
#[test]
fn test_syscall_sol_pubkey() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let cost = invoke_context.get_compute_budget().log_pubkey_units;
let mut syscall_sol_pubkey = SyscallLogPubkey {
invoke_context: Rc::new(RefCell::new(&mut invoke_context)),
@@ -3403,15 +3420,15 @@ mod tests {
fn test_syscall_sha256() {
let config = Config::default();
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(
program_id,
AccountSharedData::new(0, 0, &bpf_loader_deprecated::id()),
)],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let bytes1 = "Gaggablaghblagh!";
let bytes2 = "flurbos";
@@ -3570,13 +3587,13 @@ mod tests {
(sysvar::rent::id(), data_rent),
];
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.sysvars = &sysvars;
invoke_context.push(&[], &[0]).unwrap();
invoke_context.push(&[], &[0], &[]).unwrap();
// Test clock sysvar
{
@@ -3820,12 +3837,12 @@ mod tests {
// These tests duplicate the direct tests in solana_program::pubkey
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let address = bpf_loader_upgradeable::id();
let exceeded_seed = &[127; MAX_SEED_LEN + 1];
@@ -3932,12 +3949,12 @@ mod tests {
#[test]
fn test_find_program_address() {
let program_id = Pubkey::new_unique();
let transaction_context = TransactionContext::new(
let mut transaction_context = TransactionContext::new(
vec![(program_id, AccountSharedData::new(0, 0, &bpf_loader::id()))],
1,
);
let mut invoke_context = InvokeContext::new_mock(&transaction_context, &[]);
invoke_context.push(&[], &[0]).unwrap();
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
invoke_context.push(&[], &[0], &[]).unwrap();
let cost = invoke_context
.get_compute_budget()
.create_program_address_units;