1#![deny(clippy::arithmetic_side_effects)]
2#![deny(clippy::indexing_slicing)]
3
4pub mod serialization;
5pub mod syscalls;
6
7use {
8 miraland_measure::measure::Measure,
9 miraland_program_runtime::{
10 ic_logger_msg, ic_msg,
11 invoke_context::{BpfAllocator, InvokeContext, SerializedAccountMetadata, SyscallContext},
12 loaded_programs::{
13 LoadProgramMetrics, LoadedProgram, LoadedProgramType, DELAY_VISIBILITY_SLOT_OFFSET,
14 },
15 log_collector::LogCollector,
16 stable_log,
17 sysvar_cache::get_sysvar_with_account_check,
18 },
19 solana_rbpf::{
20 aligned_memory::AlignedMemory,
21 declare_builtin_function,
22 ebpf::{self, HOST_ALIGN, MM_HEAP_START},
23 elf::Executable,
24 error::{EbpfError, ProgramResult},
25 memory_region::{AccessType, MemoryCowCallback, MemoryMapping, MemoryRegion},
26 program::BuiltinProgram,
27 verifier::RequisiteVerifier,
28 vm::{ContextObject, EbpfVm},
29 },
30 miraland_sdk::{
31 account::WritableAccount,
32 bpf_loader, bpf_loader_deprecated,
33 bpf_loader_upgradeable::{self, UpgradeableLoaderState},
34 clock::Slot,
35 entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS},
36 feature_set::{
37 bpf_account_data_direct_mapping, deprecate_executable_meta_update_in_bpf_loader,
38 enable_bpf_loader_set_authority_checked_ix, FeatureSet,
39 },
40 instruction::{AccountMeta, InstructionError},
41 loader_upgradeable_instruction::UpgradeableLoaderInstruction,
42 native_loader,
43 program_utils::limited_deserialize,
44 pubkey::Pubkey,
45 saturating_add_assign,
46 system_instruction::{self, MAX_PERMITTED_DATA_LENGTH},
47 transaction_context::{IndexOfAccount, InstructionContext, TransactionContext},
48 },
49 std::{
50 cell::RefCell,
51 mem,
52 rc::Rc,
53 sync::{atomic::Ordering, Arc},
54 },
55 syscalls::create_program_runtime_environment_v1,
56};
57
58pub const DEFAULT_LOADER_COMPUTE_UNITS: u64 = 570;
59pub const DEPRECATED_LOADER_COMPUTE_UNITS: u64 = 1_140;
60pub const UPGRADEABLE_LOADER_COMPUTE_UNITS: u64 = 2_370;
61
62#[allow(clippy::too_many_arguments)]
63pub fn load_program_from_bytes(
64 log_collector: Option<Rc<RefCell<LogCollector>>>,
65 load_program_metrics: &mut LoadProgramMetrics,
66 programdata: &[u8],
67 loader_key: &Pubkey,
68 account_size: usize,
69 deployment_slot: Slot,
70 program_runtime_environment: Arc<BuiltinProgram<InvokeContext<'static>>>,
71 reloading: bool,
72) -> Result<LoadedProgram, InstructionError> {
73 let effective_slot = deployment_slot.saturating_add(DELAY_VISIBILITY_SLOT_OFFSET);
74 let loaded_program = if reloading {
75 unsafe {
77 LoadedProgram::reload(
78 loader_key,
79 program_runtime_environment,
80 deployment_slot,
81 effective_slot,
82 programdata,
83 account_size,
84 load_program_metrics,
85 )
86 }
87 } else {
88 LoadedProgram::new(
89 loader_key,
90 program_runtime_environment,
91 deployment_slot,
92 effective_slot,
93 programdata,
94 account_size,
95 load_program_metrics,
96 )
97 }
98 .map_err(|err| {
99 ic_logger_msg!(log_collector, "{}", err);
100 InstructionError::InvalidAccountData
101 })?;
102 Ok(loaded_program)
103}
104
105macro_rules! deploy_program {
106 ($invoke_context:expr, $program_id:expr, $loader_key:expr,
107 $account_size:expr, $slot:expr, $drop:expr, $new_programdata:expr $(,)?) => {{
108 let mut load_program_metrics = LoadProgramMetrics::default();
109 let mut register_syscalls_time = Measure::start("register_syscalls_time");
110 let deployment_program_runtime_environment = create_program_runtime_environment_v1(
111 &$invoke_context.feature_set,
112 $invoke_context.get_compute_budget(),
113 true, false, ).map_err(|e| {
116 ic_msg!($invoke_context, "Failed to register syscalls: {}", e);
117 InstructionError::ProgramEnvironmentSetupFailure
118 })?;
119 register_syscalls_time.stop();
120 load_program_metrics.register_syscalls_us = register_syscalls_time.as_us();
121 let mut load_elf_time = Measure::start("load_elf_time");
123 let executable = Executable::<InvokeContext>::load(
124 $new_programdata,
125 Arc::new(deployment_program_runtime_environment),
126 ).map_err(|err| {
127 ic_logger_msg!($invoke_context.get_log_collector(), "{}", err);
128 InstructionError::InvalidAccountData
129 })?;
130 load_elf_time.stop();
131 load_program_metrics.load_elf_us = load_elf_time.as_us();
132 let mut verify_code_time = Measure::start("verify_code_time");
133 executable.verify::<RequisiteVerifier>().map_err(|err| {
134 ic_logger_msg!($invoke_context.get_log_collector(), "{}", err);
135 InstructionError::InvalidAccountData
136 })?;
137 verify_code_time.stop();
138 load_program_metrics.verify_code_us = verify_code_time.as_us();
139 let executor = load_program_from_bytes(
141 $invoke_context.get_log_collector(),
142 &mut load_program_metrics,
143 $new_programdata,
144 $loader_key,
145 $account_size,
146 $slot,
147 $invoke_context.programs_modified_by_tx.environments.program_runtime_v1.clone(),
148 true,
149 )?;
150 if let Some(old_entry) = $invoke_context.find_program_in_cache(&$program_id) {
151 executor.tx_usage_counter.store(
152 old_entry.tx_usage_counter.load(Ordering::Relaxed),
153 Ordering::Relaxed
154 );
155 executor.ix_usage_counter.store(
156 old_entry.ix_usage_counter.load(Ordering::Relaxed),
157 Ordering::Relaxed
158 );
159 }
160 $drop
161 load_program_metrics.program_id = $program_id.to_string();
162 load_program_metrics.submit_datapoint(&mut $invoke_context.timings);
163 $invoke_context.programs_modified_by_tx.replenish($program_id, Arc::new(executor));
164 }};
165}
166
167fn write_program_data(
168 program_data_offset: usize,
169 bytes: &[u8],
170 invoke_context: &mut InvokeContext,
171) -> Result<(), InstructionError> {
172 let transaction_context = &invoke_context.transaction_context;
173 let instruction_context = transaction_context.get_current_instruction_context()?;
174 let mut program = instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
175 let data = program.get_data_mut(&invoke_context.feature_set)?;
176 let write_offset = program_data_offset.saturating_add(bytes.len());
177 if data.len() < write_offset {
178 ic_msg!(
179 invoke_context,
180 "Write overflow: {} < {}",
181 data.len(),
182 write_offset,
183 );
184 return Err(InstructionError::AccountDataTooSmall);
185 }
186 data.get_mut(program_data_offset..write_offset)
187 .ok_or(InstructionError::AccountDataTooSmall)?
188 .copy_from_slice(bytes);
189 Ok(())
190}
191
192pub fn check_loader_id(id: &Pubkey) -> bool {
193 bpf_loader::check_id(id)
194 || bpf_loader_deprecated::check_id(id)
195 || bpf_loader_upgradeable::check_id(id)
196}
197
198pub fn calculate_heap_cost(heap_size: u32, heap_cost: u64) -> u64 {
200 const KIBIBYTE: u64 = 1024;
201 const PAGE_SIZE_KB: u64 = 32;
202 let mut rounded_heap_size = u64::from(heap_size);
203 rounded_heap_size =
204 rounded_heap_size.saturating_add(PAGE_SIZE_KB.saturating_mul(KIBIBYTE).saturating_sub(1));
205 rounded_heap_size
206 .checked_div(PAGE_SIZE_KB.saturating_mul(KIBIBYTE))
207 .expect("PAGE_SIZE_KB * KIBIBYTE > 0")
208 .saturating_sub(1)
209 .saturating_mul(heap_cost)
210}
211
212pub fn create_vm<'a, 'b>(
214 program: &'a Executable<InvokeContext<'b>>,
215 regions: Vec<MemoryRegion>,
216 accounts_metadata: Vec<SerializedAccountMetadata>,
217 invoke_context: &'a mut InvokeContext<'b>,
218 stack: &mut AlignedMemory<HOST_ALIGN>,
219 heap: &mut AlignedMemory<HOST_ALIGN>,
220) -> Result<EbpfVm<'a, InvokeContext<'b>>, Box<dyn std::error::Error>> {
221 let stack_size = stack.len();
222 let heap_size = heap.len();
223 let accounts = Rc::clone(invoke_context.transaction_context.accounts());
224 let memory_mapping = create_memory_mapping(
225 program,
226 stack,
227 heap,
228 regions,
229 Some(Box::new(move |index_in_transaction| {
230 let mut account = accounts
234 .try_borrow_mut(index_in_transaction as IndexOfAccount)
235 .map_err(|_| ())?;
236 accounts
237 .touch(index_in_transaction as IndexOfAccount)
238 .map_err(|_| ())?;
239
240 if account.is_shared() {
241 account.reserve(MAX_PERMITTED_DATA_INCREASE);
244 }
245 Ok(account.data_as_mut_slice().as_mut_ptr() as u64)
246 })),
247 )?;
248 invoke_context.set_syscall_context(SyscallContext {
249 allocator: BpfAllocator::new(heap_size as u64),
250 accounts_metadata,
251 trace_log: Vec::new(),
252 })?;
253 Ok(EbpfVm::new(
254 program.get_loader().clone(),
255 program.get_sbpf_version(),
256 invoke_context,
257 memory_mapping,
258 stack_size,
259 ))
260}
261
262#[macro_export]
264macro_rules! create_vm {
265 ($vm:ident, $program:expr, $regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
266 let invoke_context = &*$invoke_context;
267 let stack_size = $program.get_config().stack_size();
268 let heap_size = invoke_context.get_compute_budget().heap_size;
269 let heap_cost_result = invoke_context.consume_checked($crate::calculate_heap_cost(
270 heap_size,
271 invoke_context.get_compute_budget().heap_cost,
272 ));
273 let mut allocations = None;
274 let $vm = heap_cost_result.and_then(|_| {
275 let mut stack = solana_rbpf::aligned_memory::AlignedMemory::<
276 { solana_rbpf::ebpf::HOST_ALIGN },
277 >::zero_filled(stack_size);
278 let mut heap = solana_rbpf::aligned_memory::AlignedMemory::<
279 { solana_rbpf::ebpf::HOST_ALIGN },
280 >::zero_filled(usize::try_from(heap_size).unwrap());
281 let vm = $crate::create_vm(
282 $program,
283 $regions,
284 $accounts_metadata,
285 $invoke_context,
286 &mut stack,
287 &mut heap,
288 );
289 allocations = Some((stack, heap));
290 vm
291 });
292 };
293}
294
295#[macro_export]
296macro_rules! mock_create_vm {
297 ($vm:ident, $additional_regions:expr, $accounts_metadata:expr, $invoke_context:expr $(,)?) => {
298 let loader = std::sync::Arc::new(BuiltinProgram::new_mock());
299 let function_registry = solana_rbpf::program::FunctionRegistry::default();
300 let executable = solana_rbpf::elf::Executable::<InvokeContext>::from_text_bytes(
301 &[0x95, 0, 0, 0, 0, 0, 0, 0],
302 loader,
303 SBPFVersion::V2,
304 function_registry,
305 )
306 .unwrap();
307 executable
308 .verify::<solana_rbpf::verifier::RequisiteVerifier>()
309 .unwrap();
310 $crate::create_vm!(
311 $vm,
312 &executable,
313 $additional_regions,
314 $accounts_metadata,
315 $invoke_context,
316 );
317 };
318}
319
320fn create_memory_mapping<'a, 'b, C: ContextObject>(
321 executable: &'a Executable<C>,
322 stack: &'b mut AlignedMemory<{ HOST_ALIGN }>,
323 heap: &'b mut AlignedMemory<{ HOST_ALIGN }>,
324 additional_regions: Vec<MemoryRegion>,
325 cow_cb: Option<MemoryCowCallback>,
326) -> Result<MemoryMapping<'a>, Box<dyn std::error::Error>> {
327 let config = executable.get_config();
328 let sbpf_version = executable.get_sbpf_version();
329 let regions: Vec<MemoryRegion> = vec![
330 executable.get_ro_region(),
331 MemoryRegion::new_writable_gapped(
332 stack.as_slice_mut(),
333 ebpf::MM_STACK_START,
334 if !sbpf_version.dynamic_stack_frames() && config.enable_stack_frame_gaps {
335 config.stack_frame_size as u64
336 } else {
337 0
338 },
339 ),
340 MemoryRegion::new_writable(heap.as_slice_mut(), MM_HEAP_START),
341 ]
342 .into_iter()
343 .chain(additional_regions)
344 .collect();
345
346 Ok(if let Some(cow_cb) = cow_cb {
347 MemoryMapping::new_with_cow(regions, cow_cb, config, sbpf_version)?
348 } else {
349 MemoryMapping::new(regions, config, sbpf_version)?
350 })
351}
352
353declare_builtin_function!(
354 Entrypoint,
355 fn rust(
356 invoke_context: &mut InvokeContext,
357 _arg0: u64,
358 _arg1: u64,
359 _arg2: u64,
360 _arg3: u64,
361 _arg4: u64,
362 _memory_mapping: &mut MemoryMapping,
363 ) -> Result<u64, Box<dyn std::error::Error>> {
364 process_instruction_inner(invoke_context)
365 }
366);
367
368pub fn process_instruction_inner(
369 invoke_context: &mut InvokeContext,
370) -> Result<u64, Box<dyn std::error::Error>> {
371 let log_collector = invoke_context.get_log_collector();
372 let transaction_context = &invoke_context.transaction_context;
373 let instruction_context = transaction_context.get_current_instruction_context()?;
374 let program_account =
375 instruction_context.try_borrow_last_program_account(transaction_context)?;
376
377 if native_loader::check_id(program_account.get_owner()) {
379 drop(program_account);
380 let program_id = instruction_context.get_last_program_key(transaction_context)?;
381 return if bpf_loader_upgradeable::check_id(program_id) {
382 invoke_context.consume_checked(UPGRADEABLE_LOADER_COMPUTE_UNITS)?;
383 process_loader_upgradeable_instruction(invoke_context)
384 } else if bpf_loader::check_id(program_id) {
385 invoke_context.consume_checked(DEFAULT_LOADER_COMPUTE_UNITS)?;
386 ic_logger_msg!(
387 log_collector,
388 "BPF loader management instructions are no longer supported",
389 );
390 Err(InstructionError::UnsupportedProgramId)
391 } else if bpf_loader_deprecated::check_id(program_id) {
392 invoke_context.consume_checked(DEPRECATED_LOADER_COMPUTE_UNITS)?;
393 ic_logger_msg!(log_collector, "Deprecated loader is no longer supported");
394 Err(InstructionError::UnsupportedProgramId)
395 } else {
396 ic_logger_msg!(log_collector, "Invalid BPF loader id");
397 Err(InstructionError::IncorrectProgramId)
398 }
399 .map(|_| 0)
400 .map_err(|error| Box::new(error) as Box<dyn std::error::Error>);
401 }
402
403 if !program_account.is_executable(&invoke_context.feature_set) {
405 ic_logger_msg!(log_collector, "Program is not executable");
406 return Err(Box::new(InstructionError::IncorrectProgramId));
407 }
408
409 let mut get_or_create_executor_time = Measure::start("get_or_create_executor_time");
410 let executor = invoke_context
411 .find_program_in_cache(program_account.get_key())
412 .ok_or_else(|| {
413 ic_logger_msg!(log_collector, "Program is not cached");
414 InstructionError::InvalidAccountData
415 })?;
416 drop(program_account);
417 get_or_create_executor_time.stop();
418 saturating_add_assign!(
419 invoke_context.timings.get_or_create_executor_us,
420 get_or_create_executor_time.as_us()
421 );
422
423 executor.ix_usage_counter.fetch_add(1, Ordering::Relaxed);
424 match &executor.program {
425 LoadedProgramType::FailedVerification(_)
426 | LoadedProgramType::Closed
427 | LoadedProgramType::DelayVisibility => {
428 ic_logger_msg!(log_collector, "Program is not deployed");
429 Err(Box::new(InstructionError::InvalidAccountData) as Box<dyn std::error::Error>)
430 }
431 LoadedProgramType::LegacyV0(executable) => execute(executable, invoke_context),
432 LoadedProgramType::LegacyV1(executable) => execute(executable, invoke_context),
433 _ => Err(Box::new(InstructionError::IncorrectProgramId) as Box<dyn std::error::Error>),
434 }
435 .map(|_| 0)
436}
437
438fn process_loader_upgradeable_instruction(
439 invoke_context: &mut InvokeContext,
440) -> Result<(), InstructionError> {
441 let log_collector = invoke_context.get_log_collector();
442 let transaction_context = &invoke_context.transaction_context;
443 let instruction_context = transaction_context.get_current_instruction_context()?;
444 let instruction_data = instruction_context.get_instruction_data();
445 let program_id = instruction_context.get_last_program_key(transaction_context)?;
446
447 match limited_deserialize(instruction_data)? {
448 UpgradeableLoaderInstruction::InitializeBuffer => {
449 instruction_context.check_number_of_instruction_accounts(2)?;
450 let mut buffer =
451 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
452
453 if UpgradeableLoaderState::Uninitialized != buffer.get_state()? {
454 ic_logger_msg!(log_collector, "Buffer account already initialized");
455 return Err(InstructionError::AccountAlreadyInitialized);
456 }
457
458 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
459 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
460 )?);
461
462 buffer.set_state(
463 &UpgradeableLoaderState::Buffer {
464 authority_address: authority_key,
465 },
466 &invoke_context.feature_set,
467 )?;
468 }
469 UpgradeableLoaderInstruction::Write { offset, bytes } => {
470 instruction_context.check_number_of_instruction_accounts(2)?;
471 let buffer =
472 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
473
474 if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
475 if authority_address.is_none() {
476 ic_logger_msg!(log_collector, "Buffer is immutable");
477 return Err(InstructionError::Immutable); }
479 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
480 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
481 )?);
482 if authority_address != authority_key {
483 ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
484 return Err(InstructionError::IncorrectAuthority);
485 }
486 if !instruction_context.is_instruction_account_signer(1)? {
487 ic_logger_msg!(log_collector, "Buffer authority did not sign");
488 return Err(InstructionError::MissingRequiredSignature);
489 }
490 } else {
491 ic_logger_msg!(log_collector, "Invalid Buffer account");
492 return Err(InstructionError::InvalidAccountData);
493 }
494 drop(buffer);
495 write_program_data(
496 UpgradeableLoaderState::size_of_buffer_metadata().saturating_add(offset as usize),
497 &bytes,
498 invoke_context,
499 )?;
500 }
501 UpgradeableLoaderInstruction::DeployWithMaxDataLen { max_data_len } => {
502 instruction_context.check_number_of_instruction_accounts(4)?;
503 let payer_key = *transaction_context.get_key_of_account_at_index(
504 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
505 )?;
506 let programdata_key = *transaction_context.get_key_of_account_at_index(
507 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
508 )?;
509 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
510 let clock =
511 get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
512 instruction_context.check_number_of_instruction_accounts(8)?;
513 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
514 instruction_context.get_index_of_instruction_account_in_transaction(7)?,
515 )?);
516
517 let program =
520 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
521 if UpgradeableLoaderState::Uninitialized != program.get_state()? {
522 ic_logger_msg!(log_collector, "Program account already initialized");
523 return Err(InstructionError::AccountAlreadyInitialized);
524 }
525 if program.get_data().len() < UpgradeableLoaderState::size_of_program() {
526 ic_logger_msg!(log_collector, "Program account too small");
527 return Err(InstructionError::AccountDataTooSmall);
528 }
529 if program.get_lamports() < rent.minimum_balance(program.get_data().len()) {
530 ic_logger_msg!(log_collector, "Program account not rent-exempt");
531 return Err(InstructionError::ExecutableAccountNotRentExempt);
532 }
533 let new_program_id = *program.get_key();
534 drop(program);
535
536 let buffer =
539 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
540 if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
541 if authority_address != authority_key {
542 ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
543 return Err(InstructionError::IncorrectAuthority);
544 }
545 if !instruction_context.is_instruction_account_signer(7)? {
546 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
547 return Err(InstructionError::MissingRequiredSignature);
548 }
549 } else {
550 ic_logger_msg!(log_collector, "Invalid Buffer account");
551 return Err(InstructionError::InvalidArgument);
552 }
553 let buffer_key = *buffer.get_key();
554 let buffer_data_offset = UpgradeableLoaderState::size_of_buffer_metadata();
555 let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset);
556 let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
557 let programdata_len = UpgradeableLoaderState::size_of_programdata(max_data_len);
558 if buffer.get_data().len() < UpgradeableLoaderState::size_of_buffer_metadata()
559 || buffer_data_len == 0
560 {
561 ic_logger_msg!(log_collector, "Buffer account too small");
562 return Err(InstructionError::InvalidAccountData);
563 }
564 drop(buffer);
565 if max_data_len < buffer_data_len {
566 ic_logger_msg!(
567 log_collector,
568 "Max data length is too small to hold Buffer data"
569 );
570 return Err(InstructionError::AccountDataTooSmall);
571 }
572 if programdata_len > MAX_PERMITTED_DATA_LENGTH as usize {
573 ic_logger_msg!(log_collector, "Max data length is too large");
574 return Err(InstructionError::InvalidArgument);
575 }
576
577 let (derived_address, bump_seed) =
579 Pubkey::find_program_address(&[new_program_id.as_ref()], program_id);
580 if derived_address != programdata_key {
581 ic_logger_msg!(log_collector, "ProgramData address is not derived");
582 return Err(InstructionError::InvalidArgument);
583 }
584
585 {
587 let mut buffer =
588 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
589 let mut payer =
590 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
591 payer.checked_add_lamports(buffer.get_lamports(), &invoke_context.feature_set)?;
592 buffer.set_lamports(0, &invoke_context.feature_set)?;
593 }
594
595 let owner_id = *program_id;
596 let mut instruction = system_instruction::create_account(
597 &payer_key,
598 &programdata_key,
599 1.max(rent.minimum_balance(programdata_len)),
600 programdata_len as u64,
601 program_id,
602 );
603
604 instruction
606 .accounts
607 .push(AccountMeta::new(buffer_key, false));
608
609 let transaction_context = &invoke_context.transaction_context;
610 let instruction_context = transaction_context.get_current_instruction_context()?;
611 let caller_program_id =
612 instruction_context.get_last_program_key(transaction_context)?;
613 let signers = [[new_program_id.as_ref(), &[bump_seed]]]
614 .iter()
615 .map(|seeds| Pubkey::create_program_address(seeds, caller_program_id))
616 .collect::<Result<Vec<Pubkey>, miraland_sdk::pubkey::PubkeyError>>()?;
617 invoke_context.native_invoke(instruction.into(), signers.as_slice())?;
618
619 let transaction_context = &invoke_context.transaction_context;
621 let instruction_context = transaction_context.get_current_instruction_context()?;
622 let buffer =
623 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
624 deploy_program!(
625 invoke_context,
626 new_program_id,
627 &owner_id,
628 UpgradeableLoaderState::size_of_program().saturating_add(programdata_len),
629 clock.slot,
630 {
631 drop(buffer);
632 },
633 buffer
634 .get_data()
635 .get(buffer_data_offset..)
636 .ok_or(InstructionError::AccountDataTooSmall)?,
637 );
638
639 let transaction_context = &invoke_context.transaction_context;
640 let instruction_context = transaction_context.get_current_instruction_context()?;
641
642 {
644 let mut programdata =
645 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
646 programdata.set_state(
647 &UpgradeableLoaderState::ProgramData {
648 slot: clock.slot,
649 upgrade_authority_address: authority_key,
650 },
651 &invoke_context.feature_set,
652 )?;
653 let dst_slice = programdata
654 .get_data_mut(&invoke_context.feature_set)?
655 .get_mut(
656 programdata_data_offset
657 ..programdata_data_offset.saturating_add(buffer_data_len),
658 )
659 .ok_or(InstructionError::AccountDataTooSmall)?;
660 let mut buffer =
661 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
662 let src_slice = buffer
663 .get_data()
664 .get(buffer_data_offset..)
665 .ok_or(InstructionError::AccountDataTooSmall)?;
666 dst_slice.copy_from_slice(src_slice);
667 buffer.set_data_length(
668 UpgradeableLoaderState::size_of_buffer(0),
669 &invoke_context.feature_set,
670 )?;
671 }
672
673 let mut program =
675 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
676 program.set_state(
677 &UpgradeableLoaderState::Program {
678 programdata_address: programdata_key,
679 },
680 &invoke_context.feature_set,
681 )?;
682
683 if !invoke_context
686 .feature_set
687 .is_active(&deprecate_executable_meta_update_in_bpf_loader::id())
688 {
689 program.set_executable(true)?;
690 }
691 drop(program);
692
693 ic_logger_msg!(log_collector, "Deployed program {:?}", new_program_id);
694 }
695 UpgradeableLoaderInstruction::Upgrade => {
696 instruction_context.check_number_of_instruction_accounts(3)?;
697 let programdata_key = *transaction_context.get_key_of_account_at_index(
698 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
699 )?;
700 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 4)?;
701 let clock =
702 get_sysvar_with_account_check::clock(invoke_context, instruction_context, 5)?;
703 instruction_context.check_number_of_instruction_accounts(7)?;
704 let authority_key = Some(*transaction_context.get_key_of_account_at_index(
705 instruction_context.get_index_of_instruction_account_in_transaction(6)?,
706 )?);
707
708 let program =
711 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
712 if !program.is_executable(&invoke_context.feature_set) {
713 ic_logger_msg!(log_collector, "Program account not executable");
714 return Err(InstructionError::AccountNotExecutable);
715 }
716 if !program.is_writable() {
717 ic_logger_msg!(log_collector, "Program account not writeable");
718 return Err(InstructionError::InvalidArgument);
719 }
720 if program.get_owner() != program_id {
721 ic_logger_msg!(log_collector, "Program account not owned by loader");
722 return Err(InstructionError::IncorrectProgramId);
723 }
724 if let UpgradeableLoaderState::Program {
725 programdata_address,
726 } = program.get_state()?
727 {
728 if programdata_address != programdata_key {
729 ic_logger_msg!(log_collector, "Program and ProgramData account mismatch");
730 return Err(InstructionError::InvalidArgument);
731 }
732 } else {
733 ic_logger_msg!(log_collector, "Invalid Program account");
734 return Err(InstructionError::InvalidAccountData);
735 }
736 let new_program_id = *program.get_key();
737 drop(program);
738
739 let buffer =
742 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
743 if let UpgradeableLoaderState::Buffer { authority_address } = buffer.get_state()? {
744 if authority_address != authority_key {
745 ic_logger_msg!(log_collector, "Buffer and upgrade authority don't match");
746 return Err(InstructionError::IncorrectAuthority);
747 }
748 if !instruction_context.is_instruction_account_signer(6)? {
749 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
750 return Err(InstructionError::MissingRequiredSignature);
751 }
752 } else {
753 ic_logger_msg!(log_collector, "Invalid Buffer account");
754 return Err(InstructionError::InvalidArgument);
755 }
756 let buffer_lamports = buffer.get_lamports();
757 let buffer_data_offset = UpgradeableLoaderState::size_of_buffer_metadata();
758 let buffer_data_len = buffer.get_data().len().saturating_sub(buffer_data_offset);
759 if buffer.get_data().len() < UpgradeableLoaderState::size_of_buffer_metadata()
760 || buffer_data_len == 0
761 {
762 ic_logger_msg!(log_collector, "Buffer account too small");
763 return Err(InstructionError::InvalidAccountData);
764 }
765 drop(buffer);
766
767 let programdata =
770 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
771 let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
772 let programdata_balance_required =
773 1.max(rent.minimum_balance(programdata.get_data().len()));
774 if programdata.get_data().len()
775 < UpgradeableLoaderState::size_of_programdata(buffer_data_len)
776 {
777 ic_logger_msg!(log_collector, "ProgramData account not large enough");
778 return Err(InstructionError::AccountDataTooSmall);
779 }
780 if programdata.get_lamports().saturating_add(buffer_lamports)
781 < programdata_balance_required
782 {
783 ic_logger_msg!(
784 log_collector,
785 "Buffer account balance too low to fund upgrade"
786 );
787 return Err(InstructionError::InsufficientFunds);
788 }
789 if let UpgradeableLoaderState::ProgramData {
790 slot,
791 upgrade_authority_address,
792 } = programdata.get_state()?
793 {
794 if clock.slot == slot {
795 ic_logger_msg!(log_collector, "Program was deployed in this block already");
796 return Err(InstructionError::InvalidArgument);
797 }
798 if upgrade_authority_address.is_none() {
799 ic_logger_msg!(log_collector, "Program not upgradeable");
800 return Err(InstructionError::Immutable);
801 }
802 if upgrade_authority_address != authority_key {
803 ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
804 return Err(InstructionError::IncorrectAuthority);
805 }
806 if !instruction_context.is_instruction_account_signer(6)? {
807 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
808 return Err(InstructionError::MissingRequiredSignature);
809 }
810 } else {
811 ic_logger_msg!(log_collector, "Invalid ProgramData account");
812 return Err(InstructionError::InvalidAccountData);
813 };
814 let programdata_len = programdata.get_data().len();
815 drop(programdata);
816
817 let buffer =
819 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
820 deploy_program!(
821 invoke_context,
822 new_program_id,
823 program_id,
824 UpgradeableLoaderState::size_of_program().saturating_add(programdata_len),
825 clock.slot,
826 {
827 drop(buffer);
828 },
829 buffer
830 .get_data()
831 .get(buffer_data_offset..)
832 .ok_or(InstructionError::AccountDataTooSmall)?,
833 );
834
835 let transaction_context = &invoke_context.transaction_context;
836 let instruction_context = transaction_context.get_current_instruction_context()?;
837
838 let mut programdata =
841 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
842 {
843 programdata.set_state(
844 &UpgradeableLoaderState::ProgramData {
845 slot: clock.slot,
846 upgrade_authority_address: authority_key,
847 },
848 &invoke_context.feature_set,
849 )?;
850 let dst_slice = programdata
851 .get_data_mut(&invoke_context.feature_set)?
852 .get_mut(
853 programdata_data_offset
854 ..programdata_data_offset.saturating_add(buffer_data_len),
855 )
856 .ok_or(InstructionError::AccountDataTooSmall)?;
857 let buffer =
858 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
859 let src_slice = buffer
860 .get_data()
861 .get(buffer_data_offset..)
862 .ok_or(InstructionError::AccountDataTooSmall)?;
863 dst_slice.copy_from_slice(src_slice);
864 }
865 programdata
866 .get_data_mut(&invoke_context.feature_set)?
867 .get_mut(programdata_data_offset.saturating_add(buffer_data_len)..)
868 .ok_or(InstructionError::AccountDataTooSmall)?
869 .fill(0);
870
871 let mut buffer =
873 instruction_context.try_borrow_instruction_account(transaction_context, 2)?;
874 let mut spill =
875 instruction_context.try_borrow_instruction_account(transaction_context, 3)?;
876 spill.checked_add_lamports(
877 programdata
878 .get_lamports()
879 .saturating_add(buffer_lamports)
880 .saturating_sub(programdata_balance_required),
881 &invoke_context.feature_set,
882 )?;
883 buffer.set_lamports(0, &invoke_context.feature_set)?;
884 programdata.set_lamports(programdata_balance_required, &invoke_context.feature_set)?;
885 buffer.set_data_length(
886 UpgradeableLoaderState::size_of_buffer(0),
887 &invoke_context.feature_set,
888 )?;
889
890 ic_logger_msg!(log_collector, "Upgraded program {:?}", new_program_id);
891 }
892 UpgradeableLoaderInstruction::SetAuthority => {
893 instruction_context.check_number_of_instruction_accounts(2)?;
894 let mut account =
895 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
896 let present_authority_key = transaction_context.get_key_of_account_at_index(
897 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
898 )?;
899 let new_authority = instruction_context
900 .get_index_of_instruction_account_in_transaction(2)
901 .and_then(|index_in_transaction| {
902 transaction_context.get_key_of_account_at_index(index_in_transaction)
903 })
904 .ok();
905
906 match account.get_state()? {
907 UpgradeableLoaderState::Buffer { authority_address } => {
908 if new_authority.is_none() {
909 ic_logger_msg!(log_collector, "Buffer authority is not optional");
910 return Err(InstructionError::IncorrectAuthority);
911 }
912 if authority_address.is_none() {
913 ic_logger_msg!(log_collector, "Buffer is immutable");
914 return Err(InstructionError::Immutable);
915 }
916 if authority_address != Some(*present_authority_key) {
917 ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
918 return Err(InstructionError::IncorrectAuthority);
919 }
920 if !instruction_context.is_instruction_account_signer(1)? {
921 ic_logger_msg!(log_collector, "Buffer authority did not sign");
922 return Err(InstructionError::MissingRequiredSignature);
923 }
924 account.set_state(
925 &UpgradeableLoaderState::Buffer {
926 authority_address: new_authority.cloned(),
927 },
928 &invoke_context.feature_set,
929 )?;
930 }
931 UpgradeableLoaderState::ProgramData {
932 slot,
933 upgrade_authority_address,
934 } => {
935 if upgrade_authority_address.is_none() {
936 ic_logger_msg!(log_collector, "Program not upgradeable");
937 return Err(InstructionError::Immutable);
938 }
939 if upgrade_authority_address != Some(*present_authority_key) {
940 ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
941 return Err(InstructionError::IncorrectAuthority);
942 }
943 if !instruction_context.is_instruction_account_signer(1)? {
944 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
945 return Err(InstructionError::MissingRequiredSignature);
946 }
947 account.set_state(
948 &UpgradeableLoaderState::ProgramData {
949 slot,
950 upgrade_authority_address: new_authority.cloned(),
951 },
952 &invoke_context.feature_set,
953 )?;
954 }
955 _ => {
956 ic_logger_msg!(log_collector, "Account does not support authorities");
957 return Err(InstructionError::InvalidArgument);
958 }
959 }
960
961 ic_logger_msg!(log_collector, "New authority {:?}", new_authority);
962 }
963 UpgradeableLoaderInstruction::SetAuthorityChecked => {
964 if !invoke_context
965 .feature_set
966 .is_active(&enable_bpf_loader_set_authority_checked_ix::id())
967 {
968 return Err(InstructionError::InvalidInstructionData);
969 }
970
971 instruction_context.check_number_of_instruction_accounts(3)?;
972 let mut account =
973 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
974 let present_authority_key = transaction_context.get_key_of_account_at_index(
975 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
976 )?;
977 let new_authority_key = transaction_context.get_key_of_account_at_index(
978 instruction_context.get_index_of_instruction_account_in_transaction(2)?,
979 )?;
980
981 match account.get_state()? {
982 UpgradeableLoaderState::Buffer { authority_address } => {
983 if authority_address.is_none() {
984 ic_logger_msg!(log_collector, "Buffer is immutable");
985 return Err(InstructionError::Immutable);
986 }
987 if authority_address != Some(*present_authority_key) {
988 ic_logger_msg!(log_collector, "Incorrect buffer authority provided");
989 return Err(InstructionError::IncorrectAuthority);
990 }
991 if !instruction_context.is_instruction_account_signer(1)? {
992 ic_logger_msg!(log_collector, "Buffer authority did not sign");
993 return Err(InstructionError::MissingRequiredSignature);
994 }
995 if !instruction_context.is_instruction_account_signer(2)? {
996 ic_logger_msg!(log_collector, "New authority did not sign");
997 return Err(InstructionError::MissingRequiredSignature);
998 }
999 account.set_state(
1000 &UpgradeableLoaderState::Buffer {
1001 authority_address: Some(*new_authority_key),
1002 },
1003 &invoke_context.feature_set,
1004 )?;
1005 }
1006 UpgradeableLoaderState::ProgramData {
1007 slot,
1008 upgrade_authority_address,
1009 } => {
1010 if upgrade_authority_address.is_none() {
1011 ic_logger_msg!(log_collector, "Program not upgradeable");
1012 return Err(InstructionError::Immutable);
1013 }
1014 if upgrade_authority_address != Some(*present_authority_key) {
1015 ic_logger_msg!(log_collector, "Incorrect upgrade authority provided");
1016 return Err(InstructionError::IncorrectAuthority);
1017 }
1018 if !instruction_context.is_instruction_account_signer(1)? {
1019 ic_logger_msg!(log_collector, "Upgrade authority did not sign");
1020 return Err(InstructionError::MissingRequiredSignature);
1021 }
1022 if !instruction_context.is_instruction_account_signer(2)? {
1023 ic_logger_msg!(log_collector, "New authority did not sign");
1024 return Err(InstructionError::MissingRequiredSignature);
1025 }
1026 account.set_state(
1027 &UpgradeableLoaderState::ProgramData {
1028 slot,
1029 upgrade_authority_address: Some(*new_authority_key),
1030 },
1031 &invoke_context.feature_set,
1032 )?;
1033 }
1034 _ => {
1035 ic_logger_msg!(log_collector, "Account does not support authorities");
1036 return Err(InstructionError::InvalidArgument);
1037 }
1038 }
1039
1040 ic_logger_msg!(log_collector, "New authority {:?}", new_authority_key);
1041 }
1042 UpgradeableLoaderInstruction::Close => {
1043 instruction_context.check_number_of_instruction_accounts(2)?;
1044 if instruction_context.get_index_of_instruction_account_in_transaction(0)?
1045 == instruction_context.get_index_of_instruction_account_in_transaction(1)?
1046 {
1047 ic_logger_msg!(
1048 log_collector,
1049 "Recipient is the same as the account being closed"
1050 );
1051 return Err(InstructionError::InvalidArgument);
1052 }
1053 let mut close_account =
1054 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1055 let close_key = *close_account.get_key();
1056 let close_account_state = close_account.get_state()?;
1057 close_account.set_data_length(
1058 UpgradeableLoaderState::size_of_uninitialized(),
1059 &invoke_context.feature_set,
1060 )?;
1061 match close_account_state {
1062 UpgradeableLoaderState::Uninitialized => {
1063 let mut recipient_account = instruction_context
1064 .try_borrow_instruction_account(transaction_context, 1)?;
1065 recipient_account.checked_add_lamports(
1066 close_account.get_lamports(),
1067 &invoke_context.feature_set,
1068 )?;
1069 close_account.set_lamports(0, &invoke_context.feature_set)?;
1070
1071 ic_logger_msg!(log_collector, "Closed Uninitialized {}", close_key);
1072 }
1073 UpgradeableLoaderState::Buffer { authority_address } => {
1074 instruction_context.check_number_of_instruction_accounts(3)?;
1075 drop(close_account);
1076 common_close_account(
1077 &authority_address,
1078 transaction_context,
1079 instruction_context,
1080 &log_collector,
1081 &invoke_context.feature_set,
1082 )?;
1083
1084 ic_logger_msg!(log_collector, "Closed Buffer {}", close_key);
1085 }
1086 UpgradeableLoaderState::ProgramData {
1087 slot,
1088 upgrade_authority_address: authority_address,
1089 } => {
1090 instruction_context.check_number_of_instruction_accounts(4)?;
1091 drop(close_account);
1092 let program_account = instruction_context
1093 .try_borrow_instruction_account(transaction_context, 3)?;
1094 let program_key = *program_account.get_key();
1095
1096 if !program_account.is_writable() {
1097 ic_logger_msg!(log_collector, "Program account is not writable");
1098 return Err(InstructionError::InvalidArgument);
1099 }
1100 if program_account.get_owner() != program_id {
1101 ic_logger_msg!(log_collector, "Program account not owned by loader");
1102 return Err(InstructionError::IncorrectProgramId);
1103 }
1104 let clock = invoke_context.get_sysvar_cache().get_clock()?;
1105 if clock.slot == slot {
1106 ic_logger_msg!(log_collector, "Program was deployed in this block already");
1107 return Err(InstructionError::InvalidArgument);
1108 }
1109
1110 match program_account.get_state()? {
1111 UpgradeableLoaderState::Program {
1112 programdata_address,
1113 } => {
1114 if programdata_address != close_key {
1115 ic_logger_msg!(
1116 log_collector,
1117 "ProgramData account does not match ProgramData account"
1118 );
1119 return Err(InstructionError::InvalidArgument);
1120 }
1121
1122 drop(program_account);
1123 common_close_account(
1124 &authority_address,
1125 transaction_context,
1126 instruction_context,
1127 &log_collector,
1128 &invoke_context.feature_set,
1129 )?;
1130 let clock = invoke_context.get_sysvar_cache().get_clock()?;
1131 invoke_context.programs_modified_by_tx.replenish(
1132 program_key,
1133 Arc::new(LoadedProgram::new_tombstone(
1134 clock.slot,
1135 LoadedProgramType::Closed,
1136 )),
1137 );
1138 }
1139 _ => {
1140 ic_logger_msg!(log_collector, "Invalid Program account");
1141 return Err(InstructionError::InvalidArgument);
1142 }
1143 }
1144
1145 ic_logger_msg!(log_collector, "Closed Program {}", program_key);
1146 }
1147 _ => {
1148 ic_logger_msg!(log_collector, "Account does not support closing");
1149 return Err(InstructionError::InvalidArgument);
1150 }
1151 }
1152 }
1153 UpgradeableLoaderInstruction::ExtendProgram { additional_bytes } => {
1154 if additional_bytes == 0 {
1155 ic_logger_msg!(log_collector, "Additional bytes must be greater than 0");
1156 return Err(InstructionError::InvalidInstructionData);
1157 }
1158
1159 const PROGRAM_DATA_ACCOUNT_INDEX: IndexOfAccount = 0;
1160 const PROGRAM_ACCOUNT_INDEX: IndexOfAccount = 1;
1161 #[allow(dead_code)]
1162 const OPTIONAL_SYSTEM_PROGRAM_ACCOUNT_INDEX: IndexOfAccount = 2;
1164 const OPTIONAL_PAYER_ACCOUNT_INDEX: IndexOfAccount = 3;
1165
1166 let programdata_account = instruction_context
1167 .try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
1168 let programdata_key = *programdata_account.get_key();
1169
1170 if program_id != programdata_account.get_owner() {
1171 ic_logger_msg!(log_collector, "ProgramData owner is invalid");
1172 return Err(InstructionError::InvalidAccountOwner);
1173 }
1174 if !programdata_account.is_writable() {
1175 ic_logger_msg!(log_collector, "ProgramData is not writable");
1176 return Err(InstructionError::InvalidArgument);
1177 }
1178
1179 let program_account = instruction_context
1180 .try_borrow_instruction_account(transaction_context, PROGRAM_ACCOUNT_INDEX)?;
1181 if !program_account.is_writable() {
1182 ic_logger_msg!(log_collector, "Program account is not writable");
1183 return Err(InstructionError::InvalidArgument);
1184 }
1185 if program_account.get_owner() != program_id {
1186 ic_logger_msg!(log_collector, "Program account not owned by loader");
1187 return Err(InstructionError::InvalidAccountOwner);
1188 }
1189 let program_key = *program_account.get_key();
1190 match program_account.get_state()? {
1191 UpgradeableLoaderState::Program {
1192 programdata_address,
1193 } => {
1194 if programdata_address != programdata_key {
1195 ic_logger_msg!(
1196 log_collector,
1197 "Program account does not match ProgramData account"
1198 );
1199 return Err(InstructionError::InvalidArgument);
1200 }
1201 }
1202 _ => {
1203 ic_logger_msg!(log_collector, "Invalid Program account");
1204 return Err(InstructionError::InvalidAccountData);
1205 }
1206 }
1207 drop(program_account);
1208
1209 let old_len = programdata_account.get_data().len();
1210 let new_len = old_len.saturating_add(additional_bytes as usize);
1211 if new_len > MAX_PERMITTED_DATA_LENGTH as usize {
1212 ic_logger_msg!(
1213 log_collector,
1214 "Extended ProgramData length of {} bytes exceeds max account data length of {} bytes",
1215 new_len,
1216 MAX_PERMITTED_DATA_LENGTH
1217 );
1218 return Err(InstructionError::InvalidRealloc);
1219 }
1220
1221 let clock_slot = invoke_context
1222 .get_sysvar_cache()
1223 .get_clock()
1224 .map(|clock| clock.slot)?;
1225
1226 let upgrade_authority_address = if let UpgradeableLoaderState::ProgramData {
1227 slot,
1228 upgrade_authority_address,
1229 } = programdata_account.get_state()?
1230 {
1231 if clock_slot == slot {
1232 ic_logger_msg!(log_collector, "Program was extended in this block already");
1233 return Err(InstructionError::InvalidArgument);
1234 }
1235
1236 if upgrade_authority_address.is_none() {
1237 ic_logger_msg!(
1238 log_collector,
1239 "Cannot extend ProgramData accounts that are not upgradeable"
1240 );
1241 return Err(InstructionError::Immutable);
1242 }
1243 upgrade_authority_address
1244 } else {
1245 ic_logger_msg!(log_collector, "ProgramData state is invalid");
1246 return Err(InstructionError::InvalidAccountData);
1247 };
1248
1249 let required_payment = {
1250 let balance = programdata_account.get_lamports();
1251 let rent = invoke_context.get_sysvar_cache().get_rent()?;
1252 let min_balance = rent.minimum_balance(new_len).max(1);
1253 min_balance.saturating_sub(balance)
1254 };
1255
1256 drop(programdata_account);
1258
1259 let program_id = *program_id;
1261 if required_payment > 0 {
1262 let payer_key = *transaction_context.get_key_of_account_at_index(
1263 instruction_context.get_index_of_instruction_account_in_transaction(
1264 OPTIONAL_PAYER_ACCOUNT_INDEX,
1265 )?,
1266 )?;
1267
1268 invoke_context.native_invoke(
1269 system_instruction::transfer(&payer_key, &programdata_key, required_payment)
1270 .into(),
1271 &[],
1272 )?;
1273 }
1274
1275 let transaction_context = &invoke_context.transaction_context;
1276 let instruction_context = transaction_context.get_current_instruction_context()?;
1277 let mut programdata_account = instruction_context
1278 .try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
1279 programdata_account.set_data_length(new_len, &invoke_context.feature_set)?;
1280
1281 let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
1282
1283 deploy_program!(
1284 invoke_context,
1285 program_key,
1286 &program_id,
1287 UpgradeableLoaderState::size_of_program().saturating_add(new_len),
1288 clock_slot,
1289 {
1290 drop(programdata_account);
1291 },
1292 programdata_account
1293 .get_data()
1294 .get(programdata_data_offset..)
1295 .ok_or(InstructionError::AccountDataTooSmall)?,
1296 );
1297
1298 let mut programdata_account = instruction_context
1299 .try_borrow_instruction_account(transaction_context, PROGRAM_DATA_ACCOUNT_INDEX)?;
1300 programdata_account.set_state(
1301 &UpgradeableLoaderState::ProgramData {
1302 slot: clock_slot,
1303 upgrade_authority_address,
1304 },
1305 &invoke_context.feature_set,
1306 )?;
1307
1308 ic_logger_msg!(
1309 log_collector,
1310 "Extended ProgramData account by {} bytes",
1311 additional_bytes
1312 );
1313 }
1314 }
1315
1316 Ok(())
1317}
1318
1319fn common_close_account(
1320 authority_address: &Option<Pubkey>,
1321 transaction_context: &TransactionContext,
1322 instruction_context: &InstructionContext,
1323 log_collector: &Option<Rc<RefCell<LogCollector>>>,
1324 feature_set: &FeatureSet,
1325) -> Result<(), InstructionError> {
1326 if authority_address.is_none() {
1327 ic_logger_msg!(log_collector, "Account is immutable");
1328 return Err(InstructionError::Immutable);
1329 }
1330 if *authority_address
1331 != Some(*transaction_context.get_key_of_account_at_index(
1332 instruction_context.get_index_of_instruction_account_in_transaction(2)?,
1333 )?)
1334 {
1335 ic_logger_msg!(log_collector, "Incorrect authority provided");
1336 return Err(InstructionError::IncorrectAuthority);
1337 }
1338 if !instruction_context.is_instruction_account_signer(2)? {
1339 ic_logger_msg!(log_collector, "Authority did not sign");
1340 return Err(InstructionError::MissingRequiredSignature);
1341 }
1342
1343 let mut close_account =
1344 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
1345 let mut recipient_account =
1346 instruction_context.try_borrow_instruction_account(transaction_context, 1)?;
1347
1348 recipient_account.checked_add_lamports(close_account.get_lamports(), feature_set)?;
1349 close_account.set_lamports(0, feature_set)?;
1350 close_account.set_state(&UpgradeableLoaderState::Uninitialized, feature_set)?;
1351 Ok(())
1352}
1353
1354fn execute<'a, 'b: 'a>(
1355 executable: &'a Executable<InvokeContext<'static>>,
1356 invoke_context: &'a mut InvokeContext<'b>,
1357) -> Result<(), Box<dyn std::error::Error>> {
1358 let executable = unsafe { mem::transmute::<_, &'a Executable<InvokeContext<'b>>>(executable) };
1361 let log_collector = invoke_context.get_log_collector();
1362 let transaction_context = &invoke_context.transaction_context;
1363 let instruction_context = transaction_context.get_current_instruction_context()?;
1364 let (program_id, is_loader_deprecated) = {
1365 let program_account =
1366 instruction_context.try_borrow_last_program_account(transaction_context)?;
1367 (
1368 *program_account.get_key(),
1369 *program_account.get_owner() == bpf_loader_deprecated::id(),
1370 )
1371 };
1372 #[cfg(any(target_os = "windows", not(target_arch = "x86_64")))]
1373 let use_jit = false;
1374 #[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))]
1375 let use_jit = executable.get_compiled_program().is_some();
1376 let direct_mapping = invoke_context
1377 .feature_set
1378 .is_active(&bpf_account_data_direct_mapping::id());
1379
1380 let mut serialize_time = Measure::start("serialize");
1381 let (parameter_bytes, regions, accounts_metadata) = serialization::serialize_parameters(
1382 invoke_context.transaction_context,
1383 instruction_context,
1384 !direct_mapping,
1385 &invoke_context.feature_set,
1386 )?;
1387 serialize_time.stop();
1388
1389 let account_region_addrs = accounts_metadata
1392 .iter()
1393 .map(|m| {
1394 let vm_end = m
1395 .vm_data_addr
1396 .saturating_add(m.original_data_len as u64)
1397 .saturating_add(if !is_loader_deprecated {
1398 MAX_PERMITTED_DATA_INCREASE as u64
1399 } else {
1400 0
1401 });
1402 m.vm_data_addr..vm_end
1403 })
1404 .collect::<Vec<_>>();
1405
1406 let mut create_vm_time = Measure::start("create_vm");
1407 let mut execute_time;
1408 let execution_result = {
1409 let compute_meter_prev = invoke_context.get_remaining();
1410 create_vm!(vm, executable, regions, accounts_metadata, invoke_context,);
1411 let mut vm = match vm {
1412 Ok(info) => info,
1413 Err(e) => {
1414 ic_logger_msg!(log_collector, "Failed to create SBF VM: {}", e);
1415 return Err(Box::new(InstructionError::ProgramEnvironmentSetupFailure));
1416 }
1417 };
1418 create_vm_time.stop();
1419
1420 execute_time = Measure::start("execute");
1421 let (compute_units_consumed, result) = vm.execute_program(executable, !use_jit);
1422 drop(vm);
1423 ic_logger_msg!(
1424 log_collector,
1425 "Program {} consumed {} of {} compute units",
1426 &program_id,
1427 compute_units_consumed,
1428 compute_meter_prev
1429 );
1430 let (_returned_from_program_id, return_data) =
1431 invoke_context.transaction_context.get_return_data();
1432 if !return_data.is_empty() {
1433 stable_log::program_return(&log_collector, &program_id, return_data);
1434 }
1435 match result {
1436 ProgramResult::Ok(status) if status != SUCCESS => {
1437 let error: InstructionError = status.into();
1438 Err(Box::new(error) as Box<dyn std::error::Error>)
1439 }
1440 ProgramResult::Err(mut error) => {
1441 if direct_mapping {
1442 if let EbpfError::AccessViolation(
1443 AccessType::Store,
1444 address,
1445 _size,
1446 _section_name,
1447 ) = error
1448 {
1449 if let Some((instruction_account_index, _)) = account_region_addrs
1453 .iter()
1454 .enumerate()
1455 .find(|(_, vm_region)| vm_region.contains(&address))
1456 {
1457 let transaction_context = &invoke_context.transaction_context;
1458 let instruction_context =
1459 transaction_context.get_current_instruction_context()?;
1460
1461 let account = instruction_context.try_borrow_instruction_account(
1462 transaction_context,
1463 instruction_account_index as IndexOfAccount,
1464 )?;
1465
1466 error = EbpfError::SyscallError(Box::new(
1467 if account.is_executable(&invoke_context.feature_set) {
1468 InstructionError::ExecutableDataModified
1469 } else if account.is_writable() {
1470 InstructionError::ExternalAccountDataModified
1471 } else {
1472 InstructionError::ReadonlyDataModified
1473 },
1474 ));
1475 }
1476 }
1477 }
1478 Err(if let EbpfError::SyscallError(err) = error {
1479 err
1480 } else {
1481 error.into()
1482 })
1483 }
1484 _ => Ok(()),
1485 }
1486 };
1487 execute_time.stop();
1488
1489 fn deserialize_parameters(
1490 invoke_context: &mut InvokeContext,
1491 parameter_bytes: &[u8],
1492 copy_account_data: bool,
1493 ) -> Result<(), InstructionError> {
1494 serialization::deserialize_parameters(
1495 invoke_context.transaction_context,
1496 invoke_context
1497 .transaction_context
1498 .get_current_instruction_context()?,
1499 copy_account_data,
1500 parameter_bytes,
1501 &invoke_context.get_syscall_context()?.accounts_metadata,
1502 &invoke_context.feature_set,
1503 )
1504 }
1505
1506 let mut deserialize_time = Measure::start("deserialize");
1507 let execute_or_deserialize_result = execution_result.and_then(|_| {
1508 deserialize_parameters(invoke_context, parameter_bytes.as_slice(), !direct_mapping)
1509 .map_err(|error| Box::new(error) as Box<dyn std::error::Error>)
1510 });
1511 deserialize_time.stop();
1512
1513 let timings = &mut invoke_context.timings;
1515 timings.serialize_us = timings.serialize_us.saturating_add(serialize_time.as_us());
1516 timings.create_vm_us = timings.create_vm_us.saturating_add(create_vm_time.as_us());
1517 timings.execute_us = timings.execute_us.saturating_add(execute_time.as_us());
1518 timings.deserialize_us = timings
1519 .deserialize_us
1520 .saturating_add(deserialize_time.as_us());
1521
1522 execute_or_deserialize_result
1523}
1524
1525pub mod test_utils {
1526 use {
1527 super::*, miraland_program_runtime::loaded_programs::DELAY_VISIBILITY_SLOT_OFFSET,
1528 miraland_sdk::account::ReadableAccount,
1529 };
1530
1531 pub fn load_all_invoked_programs(invoke_context: &mut InvokeContext) {
1532 let mut load_program_metrics = LoadProgramMetrics::default();
1533 let program_runtime_environment = create_program_runtime_environment_v1(
1534 &invoke_context.feature_set,
1535 invoke_context.get_compute_budget(),
1536 false, false, );
1539 let program_runtime_environment = Arc::new(program_runtime_environment.unwrap());
1540 let num_accounts = invoke_context.transaction_context.get_number_of_accounts();
1541 for index in 0..num_accounts {
1542 let account = invoke_context
1543 .transaction_context
1544 .get_account_at_index(index)
1545 .expect("Failed to get the account")
1546 .borrow();
1547
1548 let owner = account.owner();
1549 if check_loader_id(owner) {
1550 let pubkey = invoke_context
1551 .transaction_context
1552 .get_key_of_account_at_index(index)
1553 .expect("Failed to get account key");
1554
1555 if let Ok(loaded_program) = load_program_from_bytes(
1556 None,
1557 &mut load_program_metrics,
1558 account.data(),
1559 owner,
1560 account.data().len(),
1561 0,
1562 program_runtime_environment.clone(),
1563 false,
1564 ) {
1565 invoke_context
1566 .programs_modified_by_tx
1567 .set_slot_for_tests(DELAY_VISIBILITY_SLOT_OFFSET);
1568 invoke_context
1569 .programs_modified_by_tx
1570 .replenish(*pubkey, Arc::new(loaded_program));
1571 }
1572 }
1573 }
1574 }
1575}
1576
1577#[cfg(test)]
1578mod tests {
1579 use {
1580 super::*,
1581 assert_matches::assert_matches,
1582 rand::Rng,
1583 miraland_program_runtime::{
1584 invoke_context::mock_process_instruction, with_mock_invoke_context,
1585 },
1586 solana_rbpf::vm::ContextObject,
1587 miraland_sdk::{
1588 account::{
1589 create_account_shared_data_for_test as create_account_for_test, AccountSharedData,
1590 ReadableAccount, WritableAccount,
1591 },
1592 account_utils::StateMut,
1593 clock::Clock,
1594 instruction::{AccountMeta, InstructionError},
1595 pubkey::Pubkey,
1596 rent::Rent,
1597 system_program, sysvar,
1598 },
1599 std::{fs::File, io::Read, ops::Range, sync::atomic::AtomicU64},
1600 };
1601
1602 struct TestContextObject {
1603 remaining: u64,
1604 }
1605 impl ContextObject for TestContextObject {
1606 fn trace(&mut self, _state: [u64; 12]) {}
1607 fn consume(&mut self, amount: u64) {
1608 self.remaining = self.remaining.saturating_sub(amount);
1609 }
1610 fn get_remaining(&self) -> u64 {
1611 self.remaining
1612 }
1613 }
1614
1615 fn process_instruction(
1616 loader_id: &Pubkey,
1617 program_indices: &[IndexOfAccount],
1618 instruction_data: &[u8],
1619 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
1620 instruction_accounts: Vec<AccountMeta>,
1621 expected_result: Result<(), InstructionError>,
1622 ) -> Vec<AccountSharedData> {
1623 mock_process_instruction(
1624 loader_id,
1625 program_indices.to_vec(),
1626 instruction_data,
1627 transaction_accounts,
1628 instruction_accounts,
1629 expected_result,
1630 Entrypoint::vm,
1631 |invoke_context| {
1632 let mut features = FeatureSet::all_enabled();
1633 features.deactivate(&deprecate_executable_meta_update_in_bpf_loader::id());
1634 invoke_context.feature_set = Arc::new(features);
1635 test_utils::load_all_invoked_programs(invoke_context);
1636 },
1637 |_invoke_context| {},
1638 )
1639 }
1640
1641 fn load_program_account_from_elf(loader_id: &Pubkey, path: &str) -> AccountSharedData {
1642 let mut file = File::open(path).expect("file open failed");
1643 let mut elf = Vec::new();
1644 file.read_to_end(&mut elf).unwrap();
1645 let rent = Rent::default();
1646 let mut program_account =
1647 AccountSharedData::new(rent.minimum_balance(elf.len()), 0, loader_id);
1648 program_account.set_data(elf);
1649 program_account.set_executable(true);
1650 program_account
1651 }
1652
1653 #[test]
1654 fn test_bpf_loader_invoke_main() {
1655 let loader_id = bpf_loader::id();
1656 let program_id = Pubkey::new_unique();
1657 let mut program_account =
1658 load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
1659 let parameter_id = Pubkey::new_unique();
1660 let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1661 let parameter_meta = AccountMeta {
1662 pubkey: parameter_id,
1663 is_signer: false,
1664 is_writable: false,
1665 };
1666
1667 process_instruction(
1669 &loader_id,
1670 &[],
1671 &[],
1672 Vec::new(),
1673 Vec::new(),
1674 Err(InstructionError::UnsupportedProgramId),
1675 );
1676
1677 process_instruction(
1679 &loader_id,
1680 &[0],
1681 &[],
1682 vec![(program_id, program_account.clone())],
1683 Vec::new(),
1684 Ok(()),
1685 );
1686
1687 process_instruction(
1689 &loader_id,
1690 &[0],
1691 &[],
1692 vec![
1693 (program_id, program_account.clone()),
1694 (parameter_id, parameter_account.clone()),
1695 ],
1696 vec![parameter_meta.clone()],
1697 Ok(()),
1698 );
1699
1700 process_instruction(
1702 &loader_id,
1703 &[0],
1704 &[],
1705 vec![
1706 (program_id, program_account.clone()),
1707 (parameter_id, parameter_account),
1708 ],
1709 vec![parameter_meta.clone(), parameter_meta],
1710 Ok(()),
1711 );
1712
1713 mock_process_instruction(
1715 &loader_id,
1716 vec![0],
1717 &[],
1718 vec![(program_id, program_account.clone())],
1719 Vec::new(),
1720 Err(InstructionError::ProgramFailedToComplete),
1721 Entrypoint::vm,
1722 |invoke_context| {
1723 let mut features = FeatureSet::all_enabled();
1724 features.deactivate(&deprecate_executable_meta_update_in_bpf_loader::id());
1725 invoke_context.feature_set = Arc::new(features);
1726 invoke_context.mock_set_remaining(0);
1727 test_utils::load_all_invoked_programs(invoke_context);
1728 },
1729 |_invoke_context| {},
1730 );
1731
1732 program_account.set_executable(false);
1734 process_instruction(
1735 &loader_id,
1736 &[0],
1737 &[],
1738 vec![(program_id, program_account)],
1739 Vec::new(),
1740 Err(InstructionError::IncorrectProgramId),
1741 );
1742 }
1743
1744 #[test]
1745 fn test_bpf_loader_serialize_unaligned() {
1746 let loader_id = bpf_loader_deprecated::id();
1747 let program_id = Pubkey::new_unique();
1748 let program_account =
1749 load_program_account_from_elf(&loader_id, "test_elfs/out/noop_unaligned.so");
1750 let parameter_id = Pubkey::new_unique();
1751 let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1752 let parameter_meta = AccountMeta {
1753 pubkey: parameter_id,
1754 is_signer: false,
1755 is_writable: false,
1756 };
1757
1758 process_instruction(
1760 &loader_id,
1761 &[0],
1762 &[],
1763 vec![
1764 (program_id, program_account.clone()),
1765 (parameter_id, parameter_account.clone()),
1766 ],
1767 vec![parameter_meta.clone()],
1768 Ok(()),
1769 );
1770
1771 process_instruction(
1773 &loader_id,
1774 &[0],
1775 &[],
1776 vec![
1777 (program_id, program_account),
1778 (parameter_id, parameter_account),
1779 ],
1780 vec![parameter_meta.clone(), parameter_meta],
1781 Ok(()),
1782 );
1783 }
1784
1785 #[test]
1786 fn test_bpf_loader_serialize_aligned() {
1787 let loader_id = bpf_loader::id();
1788 let program_id = Pubkey::new_unique();
1789 let program_account =
1790 load_program_account_from_elf(&loader_id, "test_elfs/out/noop_aligned.so");
1791 let parameter_id = Pubkey::new_unique();
1792 let parameter_account = AccountSharedData::new(1, 0, &loader_id);
1793 let parameter_meta = AccountMeta {
1794 pubkey: parameter_id,
1795 is_signer: false,
1796 is_writable: false,
1797 };
1798
1799 process_instruction(
1801 &loader_id,
1802 &[0],
1803 &[],
1804 vec![
1805 (program_id, program_account.clone()),
1806 (parameter_id, parameter_account.clone()),
1807 ],
1808 vec![parameter_meta.clone()],
1809 Ok(()),
1810 );
1811
1812 process_instruction(
1814 &loader_id,
1815 &[0],
1816 &[],
1817 vec![
1818 (program_id, program_account),
1819 (parameter_id, parameter_account),
1820 ],
1821 vec![parameter_meta.clone(), parameter_meta],
1822 Ok(()),
1823 );
1824 }
1825
1826 #[test]
1827 fn test_bpf_loader_upgradeable_initialize_buffer() {
1828 let loader_id = bpf_loader_upgradeable::id();
1829 let buffer_address = Pubkey::new_unique();
1830 let buffer_account =
1831 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1832 let authority_address = Pubkey::new_unique();
1833 let authority_account =
1834 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1835 let instruction_data =
1836 bincode::serialize(&UpgradeableLoaderInstruction::InitializeBuffer).unwrap();
1837 let instruction_accounts = vec![
1838 AccountMeta {
1839 pubkey: buffer_address,
1840 is_signer: false,
1841 is_writable: true,
1842 },
1843 AccountMeta {
1844 pubkey: authority_address,
1845 is_signer: false,
1846 is_writable: false,
1847 },
1848 ];
1849
1850 let accounts = process_instruction(
1852 &loader_id,
1853 &[],
1854 &instruction_data,
1855 vec![
1856 (buffer_address, buffer_account),
1857 (authority_address, authority_account),
1858 ],
1859 instruction_accounts.clone(),
1860 Ok(()),
1861 );
1862 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1863 assert_eq!(
1864 state,
1865 UpgradeableLoaderState::Buffer {
1866 authority_address: Some(authority_address)
1867 }
1868 );
1869
1870 let accounts = process_instruction(
1872 &loader_id,
1873 &[],
1874 &instruction_data,
1875 vec![
1876 (buffer_address, accounts.first().unwrap().clone()),
1877 (authority_address, accounts.get(1).unwrap().clone()),
1878 ],
1879 instruction_accounts,
1880 Err(InstructionError::AccountAlreadyInitialized),
1881 );
1882 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1883 assert_eq!(
1884 state,
1885 UpgradeableLoaderState::Buffer {
1886 authority_address: Some(authority_address)
1887 }
1888 );
1889 }
1890
1891 #[test]
1892 fn test_bpf_loader_upgradeable_write() {
1893 let loader_id = bpf_loader_upgradeable::id();
1894 let buffer_address = Pubkey::new_unique();
1895 let mut buffer_account =
1896 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1897 let instruction_accounts = vec![
1898 AccountMeta {
1899 pubkey: buffer_address,
1900 is_signer: false,
1901 is_writable: true,
1902 },
1903 AccountMeta {
1904 pubkey: buffer_address,
1905 is_signer: true,
1906 is_writable: false,
1907 },
1908 ];
1909
1910 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1912 offset: 0,
1913 bytes: vec![42; 9],
1914 })
1915 .unwrap();
1916 process_instruction(
1917 &loader_id,
1918 &[],
1919 &instruction,
1920 vec![(buffer_address, buffer_account.clone())],
1921 instruction_accounts.clone(),
1922 Err(InstructionError::InvalidAccountData),
1923 );
1924
1925 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1927 offset: 0,
1928 bytes: vec![42; 9],
1929 })
1930 .unwrap();
1931 buffer_account
1932 .set_state(&UpgradeableLoaderState::Buffer {
1933 authority_address: Some(buffer_address),
1934 })
1935 .unwrap();
1936 let accounts = process_instruction(
1937 &loader_id,
1938 &[],
1939 &instruction,
1940 vec![(buffer_address, buffer_account.clone())],
1941 instruction_accounts.clone(),
1942 Ok(()),
1943 );
1944 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1945 assert_eq!(
1946 state,
1947 UpgradeableLoaderState::Buffer {
1948 authority_address: Some(buffer_address)
1949 }
1950 );
1951 assert_eq!(
1952 &accounts
1953 .first()
1954 .unwrap()
1955 .data()
1956 .get(UpgradeableLoaderState::size_of_buffer_metadata()..)
1957 .unwrap(),
1958 &[42; 9]
1959 );
1960
1961 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
1963 offset: 3,
1964 bytes: vec![42; 6],
1965 })
1966 .unwrap();
1967 let mut buffer_account =
1968 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(9), &loader_id);
1969 buffer_account
1970 .set_state(&UpgradeableLoaderState::Buffer {
1971 authority_address: Some(buffer_address),
1972 })
1973 .unwrap();
1974 let accounts = process_instruction(
1975 &loader_id,
1976 &[],
1977 &instruction,
1978 vec![(buffer_address, buffer_account.clone())],
1979 instruction_accounts.clone(),
1980 Ok(()),
1981 );
1982 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
1983 assert_eq!(
1984 state,
1985 UpgradeableLoaderState::Buffer {
1986 authority_address: Some(buffer_address)
1987 }
1988 );
1989 assert_eq!(
1990 &accounts
1991 .first()
1992 .unwrap()
1993 .data()
1994 .get(UpgradeableLoaderState::size_of_buffer_metadata()..)
1995 .unwrap(),
1996 &[0, 0, 0, 42, 42, 42, 42, 42, 42]
1997 );
1998
1999 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2001 offset: 0,
2002 bytes: vec![42; 10],
2003 })
2004 .unwrap();
2005 buffer_account
2006 .set_state(&UpgradeableLoaderState::Buffer {
2007 authority_address: Some(buffer_address),
2008 })
2009 .unwrap();
2010 process_instruction(
2011 &loader_id,
2012 &[],
2013 &instruction,
2014 vec![(buffer_address, buffer_account.clone())],
2015 instruction_accounts.clone(),
2016 Err(InstructionError::AccountDataTooSmall),
2017 );
2018
2019 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2021 offset: 1,
2022 bytes: vec![42; 9],
2023 })
2024 .unwrap();
2025 buffer_account
2026 .set_state(&UpgradeableLoaderState::Buffer {
2027 authority_address: Some(buffer_address),
2028 })
2029 .unwrap();
2030 process_instruction(
2031 &loader_id,
2032 &[],
2033 &instruction,
2034 vec![(buffer_address, buffer_account.clone())],
2035 instruction_accounts.clone(),
2036 Err(InstructionError::AccountDataTooSmall),
2037 );
2038
2039 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2041 offset: 0,
2042 bytes: vec![42; 9],
2043 })
2044 .unwrap();
2045 buffer_account
2046 .set_state(&UpgradeableLoaderState::Buffer {
2047 authority_address: Some(buffer_address),
2048 })
2049 .unwrap();
2050 process_instruction(
2051 &loader_id,
2052 &[],
2053 &instruction,
2054 vec![(buffer_address, buffer_account.clone())],
2055 vec![
2056 AccountMeta {
2057 pubkey: buffer_address,
2058 is_signer: false,
2059 is_writable: false,
2060 },
2061 AccountMeta {
2062 pubkey: buffer_address,
2063 is_signer: false,
2064 is_writable: false,
2065 },
2066 ],
2067 Err(InstructionError::MissingRequiredSignature),
2068 );
2069
2070 let authority_address = Pubkey::new_unique();
2072 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2073 offset: 1,
2074 bytes: vec![42; 9],
2075 })
2076 .unwrap();
2077 buffer_account
2078 .set_state(&UpgradeableLoaderState::Buffer {
2079 authority_address: Some(buffer_address),
2080 })
2081 .unwrap();
2082 process_instruction(
2083 &loader_id,
2084 &[],
2085 &instruction,
2086 vec![
2087 (buffer_address, buffer_account.clone()),
2088 (authority_address, buffer_account.clone()),
2089 ],
2090 vec![
2091 AccountMeta {
2092 pubkey: buffer_address,
2093 is_signer: false,
2094 is_writable: false,
2095 },
2096 AccountMeta {
2097 pubkey: authority_address,
2098 is_signer: false,
2099 is_writable: false,
2100 },
2101 ],
2102 Err(InstructionError::IncorrectAuthority),
2103 );
2104
2105 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Write {
2107 offset: 1,
2108 bytes: vec![42; 9],
2109 })
2110 .unwrap();
2111 buffer_account
2112 .set_state(&UpgradeableLoaderState::Buffer {
2113 authority_address: None,
2114 })
2115 .unwrap();
2116 process_instruction(
2117 &loader_id,
2118 &[],
2119 &instruction,
2120 vec![(buffer_address, buffer_account.clone())],
2121 instruction_accounts,
2122 Err(InstructionError::Immutable),
2123 );
2124 }
2125
2126 fn truncate_data(account: &mut AccountSharedData, len: usize) {
2127 let mut data = account.data().to_vec();
2128 data.truncate(len);
2129 account.set_data(data);
2130 }
2131
2132 #[test]
2133 fn test_bpf_loader_upgradeable_upgrade() {
2134 let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed");
2135 let mut elf_orig = Vec::new();
2136 file.read_to_end(&mut elf_orig).unwrap();
2137 let mut file = File::open("test_elfs/out/noop_unaligned.so").expect("file open failed");
2138 let mut elf_new = Vec::new();
2139 file.read_to_end(&mut elf_new).unwrap();
2140 assert_ne!(elf_orig.len(), elf_new.len());
2141 const SLOT: u64 = 42;
2142 let buffer_address = Pubkey::new_unique();
2143 let upgrade_authority_address = Pubkey::new_unique();
2144
2145 fn get_accounts(
2146 buffer_address: &Pubkey,
2147 buffer_authority: &Pubkey,
2148 upgrade_authority_address: &Pubkey,
2149 elf_orig: &[u8],
2150 elf_new: &[u8],
2151 ) -> (Vec<(Pubkey, AccountSharedData)>, Vec<AccountMeta>) {
2152 let loader_id = bpf_loader_upgradeable::id();
2153 let program_address = Pubkey::new_unique();
2154 let spill_address = Pubkey::new_unique();
2155 let rent = Rent::default();
2156 let min_program_balance =
2157 1.max(rent.minimum_balance(UpgradeableLoaderState::size_of_program()));
2158 let min_programdata_balance = 1.max(rent.minimum_balance(
2159 UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
2160 ));
2161 let (programdata_address, _) =
2162 Pubkey::find_program_address(&[program_address.as_ref()], &loader_id);
2163 let mut buffer_account = AccountSharedData::new(
2164 1,
2165 UpgradeableLoaderState::size_of_buffer(elf_new.len()),
2166 &bpf_loader_upgradeable::id(),
2167 );
2168 buffer_account
2169 .set_state(&UpgradeableLoaderState::Buffer {
2170 authority_address: Some(*buffer_authority),
2171 })
2172 .unwrap();
2173 buffer_account
2174 .data_as_mut_slice()
2175 .get_mut(UpgradeableLoaderState::size_of_buffer_metadata()..)
2176 .unwrap()
2177 .copy_from_slice(elf_new);
2178 let mut programdata_account = AccountSharedData::new(
2179 min_programdata_balance,
2180 UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
2181 &bpf_loader_upgradeable::id(),
2182 );
2183 programdata_account
2184 .set_state(&UpgradeableLoaderState::ProgramData {
2185 slot: SLOT,
2186 upgrade_authority_address: Some(*upgrade_authority_address),
2187 })
2188 .unwrap();
2189 let mut program_account = AccountSharedData::new(
2190 min_program_balance,
2191 UpgradeableLoaderState::size_of_program(),
2192 &bpf_loader_upgradeable::id(),
2193 );
2194 program_account.set_executable(true);
2195 program_account
2196 .set_state(&UpgradeableLoaderState::Program {
2197 programdata_address,
2198 })
2199 .unwrap();
2200 let spill_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
2201 let rent_account = create_account_for_test(&rent);
2202 let clock_account = create_account_for_test(&Clock {
2203 slot: SLOT.saturating_add(1),
2204 ..Clock::default()
2205 });
2206 let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2207 let transaction_accounts = vec![
2208 (programdata_address, programdata_account),
2209 (program_address, program_account),
2210 (*buffer_address, buffer_account),
2211 (spill_address, spill_account),
2212 (sysvar::rent::id(), rent_account),
2213 (sysvar::clock::id(), clock_account),
2214 (*upgrade_authority_address, upgrade_authority_account),
2215 ];
2216 let instruction_accounts = vec![
2217 AccountMeta {
2218 pubkey: programdata_address,
2219 is_signer: false,
2220 is_writable: true,
2221 },
2222 AccountMeta {
2223 pubkey: program_address,
2224 is_signer: false,
2225 is_writable: true,
2226 },
2227 AccountMeta {
2228 pubkey: *buffer_address,
2229 is_signer: false,
2230 is_writable: true,
2231 },
2232 AccountMeta {
2233 pubkey: spill_address,
2234 is_signer: false,
2235 is_writable: true,
2236 },
2237 AccountMeta {
2238 pubkey: sysvar::rent::id(),
2239 is_signer: false,
2240 is_writable: false,
2241 },
2242 AccountMeta {
2243 pubkey: sysvar::clock::id(),
2244 is_signer: false,
2245 is_writable: false,
2246 },
2247 AccountMeta {
2248 pubkey: *upgrade_authority_address,
2249 is_signer: true,
2250 is_writable: false,
2251 },
2252 ];
2253 (transaction_accounts, instruction_accounts)
2254 }
2255
2256 fn process_instruction(
2257 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
2258 instruction_accounts: Vec<AccountMeta>,
2259 expected_result: Result<(), InstructionError>,
2260 ) -> Vec<AccountSharedData> {
2261 let instruction_data =
2262 bincode::serialize(&UpgradeableLoaderInstruction::Upgrade).unwrap();
2263 mock_process_instruction(
2264 &bpf_loader_upgradeable::id(),
2265 Vec::new(),
2266 &instruction_data,
2267 transaction_accounts,
2268 instruction_accounts,
2269 expected_result,
2270 Entrypoint::vm,
2271 |invoke_context| {
2272 let mut features = FeatureSet::all_enabled();
2273 features.deactivate(&deprecate_executable_meta_update_in_bpf_loader::id());
2274 invoke_context.feature_set = Arc::new(features);
2275 },
2276 |_invoke_context| {},
2277 )
2278 }
2279
2280 let (transaction_accounts, instruction_accounts) = get_accounts(
2282 &buffer_address,
2283 &upgrade_authority_address,
2284 &upgrade_authority_address,
2285 &elf_orig,
2286 &elf_new,
2287 );
2288 let accounts = process_instruction(transaction_accounts, instruction_accounts, Ok(()));
2289 let min_programdata_balance = Rent::default().minimum_balance(
2290 UpgradeableLoaderState::size_of_programdata(elf_orig.len().max(elf_new.len())),
2291 );
2292 assert_eq!(
2293 min_programdata_balance,
2294 accounts.first().unwrap().lamports()
2295 );
2296 assert_eq!(0, accounts.get(2).unwrap().lamports());
2297 assert_eq!(1, accounts.get(3).unwrap().lamports());
2298 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2299 assert_eq!(
2300 state,
2301 UpgradeableLoaderState::ProgramData {
2302 slot: SLOT.saturating_add(1),
2303 upgrade_authority_address: Some(upgrade_authority_address)
2304 }
2305 );
2306 for (i, byte) in accounts
2307 .first()
2308 .unwrap()
2309 .data()
2310 .get(
2311 UpgradeableLoaderState::size_of_programdata_metadata()
2312 ..UpgradeableLoaderState::size_of_programdata(elf_new.len()),
2313 )
2314 .unwrap()
2315 .iter()
2316 .enumerate()
2317 {
2318 assert_eq!(*elf_new.get(i).unwrap(), *byte);
2319 }
2320
2321 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2323 &buffer_address,
2324 &upgrade_authority_address,
2325 &upgrade_authority_address,
2326 &elf_orig,
2327 &elf_new,
2328 );
2329 transaction_accounts
2330 .get_mut(0)
2331 .unwrap()
2332 .1
2333 .set_state(&UpgradeableLoaderState::ProgramData {
2334 slot: SLOT,
2335 upgrade_authority_address: None,
2336 })
2337 .unwrap();
2338 process_instruction(
2339 transaction_accounts,
2340 instruction_accounts,
2341 Err(InstructionError::Immutable),
2342 );
2343
2344 let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2346 &buffer_address,
2347 &upgrade_authority_address,
2348 &upgrade_authority_address,
2349 &elf_orig,
2350 &elf_new,
2351 );
2352 let invalid_upgrade_authority_address = Pubkey::new_unique();
2353 transaction_accounts.get_mut(6).unwrap().0 = invalid_upgrade_authority_address;
2354 instruction_accounts.get_mut(6).unwrap().pubkey = invalid_upgrade_authority_address;
2355 process_instruction(
2356 transaction_accounts,
2357 instruction_accounts,
2358 Err(InstructionError::IncorrectAuthority),
2359 );
2360
2361 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2363 &buffer_address,
2364 &upgrade_authority_address,
2365 &upgrade_authority_address,
2366 &elf_orig,
2367 &elf_new,
2368 );
2369 instruction_accounts.get_mut(6).unwrap().is_signer = false;
2370 process_instruction(
2371 transaction_accounts,
2372 instruction_accounts,
2373 Err(InstructionError::MissingRequiredSignature),
2374 );
2375
2376 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2378 &buffer_address,
2379 &upgrade_authority_address,
2380 &upgrade_authority_address,
2381 &elf_orig,
2382 &elf_new,
2383 );
2384 *instruction_accounts.get_mut(3).unwrap() = instruction_accounts.get(2).unwrap().clone();
2385 process_instruction(
2386 transaction_accounts,
2387 instruction_accounts,
2388 Err(InstructionError::AccountBorrowFailed),
2389 );
2390
2391 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2393 &buffer_address,
2394 &upgrade_authority_address,
2395 &upgrade_authority_address,
2396 &elf_orig,
2397 &elf_new,
2398 );
2399 *instruction_accounts.get_mut(3).unwrap() = instruction_accounts.first().unwrap().clone();
2400 process_instruction(
2401 transaction_accounts,
2402 instruction_accounts,
2403 Err(InstructionError::AccountBorrowFailed),
2404 );
2405
2406 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2408 &buffer_address,
2409 &upgrade_authority_address,
2410 &upgrade_authority_address,
2411 &elf_orig,
2412 &elf_new,
2413 );
2414 transaction_accounts
2415 .get_mut(1)
2416 .unwrap()
2417 .1
2418 .set_executable(false);
2419 process_instruction(
2420 transaction_accounts,
2421 instruction_accounts,
2422 Err(InstructionError::AccountNotExecutable),
2423 );
2424
2425 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2427 &buffer_address,
2428 &upgrade_authority_address,
2429 &upgrade_authority_address,
2430 &elf_orig,
2431 &elf_new,
2432 );
2433 transaction_accounts
2434 .get_mut(1)
2435 .unwrap()
2436 .1
2437 .set_owner(Pubkey::new_unique());
2438 process_instruction(
2439 transaction_accounts,
2440 instruction_accounts,
2441 Err(InstructionError::IncorrectProgramId),
2442 );
2443
2444 let (transaction_accounts, mut instruction_accounts) = get_accounts(
2446 &buffer_address,
2447 &upgrade_authority_address,
2448 &upgrade_authority_address,
2449 &elf_orig,
2450 &elf_new,
2451 );
2452 instruction_accounts.get_mut(1).unwrap().is_writable = false;
2453 process_instruction(
2454 transaction_accounts,
2455 instruction_accounts,
2456 Err(InstructionError::InvalidArgument),
2457 );
2458
2459 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2461 &buffer_address,
2462 &upgrade_authority_address,
2463 &upgrade_authority_address,
2464 &elf_orig,
2465 &elf_new,
2466 );
2467 transaction_accounts
2468 .get_mut(1)
2469 .unwrap()
2470 .1
2471 .set_state(&UpgradeableLoaderState::Uninitialized)
2472 .unwrap();
2473 process_instruction(
2474 transaction_accounts,
2475 instruction_accounts,
2476 Err(InstructionError::InvalidAccountData),
2477 );
2478
2479 let (mut transaction_accounts, mut instruction_accounts) = get_accounts(
2481 &buffer_address,
2482 &upgrade_authority_address,
2483 &upgrade_authority_address,
2484 &elf_orig,
2485 &elf_new,
2486 );
2487 let invalid_programdata_address = Pubkey::new_unique();
2488 transaction_accounts.get_mut(0).unwrap().0 = invalid_programdata_address;
2489 instruction_accounts.get_mut(0).unwrap().pubkey = invalid_programdata_address;
2490 process_instruction(
2491 transaction_accounts,
2492 instruction_accounts,
2493 Err(InstructionError::InvalidArgument),
2494 );
2495
2496 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2498 &buffer_address,
2499 &upgrade_authority_address,
2500 &upgrade_authority_address,
2501 &elf_orig,
2502 &elf_new,
2503 );
2504 transaction_accounts
2505 .get_mut(2)
2506 .unwrap()
2507 .1
2508 .set_state(&UpgradeableLoaderState::Uninitialized)
2509 .unwrap();
2510 process_instruction(
2511 transaction_accounts,
2512 instruction_accounts,
2513 Err(InstructionError::InvalidArgument),
2514 );
2515
2516 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2518 &buffer_address,
2519 &upgrade_authority_address,
2520 &upgrade_authority_address,
2521 &elf_orig,
2522 &elf_new,
2523 );
2524 transaction_accounts.get_mut(2).unwrap().1 = AccountSharedData::new(
2525 1,
2526 UpgradeableLoaderState::size_of_buffer(
2527 elf_orig.len().max(elf_new.len()).saturating_add(1),
2528 ),
2529 &bpf_loader_upgradeable::id(),
2530 );
2531 transaction_accounts
2532 .get_mut(2)
2533 .unwrap()
2534 .1
2535 .set_state(&UpgradeableLoaderState::Buffer {
2536 authority_address: Some(upgrade_authority_address),
2537 })
2538 .unwrap();
2539 process_instruction(
2540 transaction_accounts,
2541 instruction_accounts,
2542 Err(InstructionError::AccountDataTooSmall),
2543 );
2544
2545 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2547 &buffer_address,
2548 &upgrade_authority_address,
2549 &upgrade_authority_address,
2550 &elf_orig,
2551 &elf_new,
2552 );
2553 transaction_accounts
2554 .get_mut(2)
2555 .unwrap()
2556 .1
2557 .set_state(&UpgradeableLoaderState::Buffer {
2558 authority_address: Some(upgrade_authority_address),
2559 })
2560 .unwrap();
2561 truncate_data(&mut transaction_accounts.get_mut(2).unwrap().1, 5);
2562 process_instruction(
2563 transaction_accounts,
2564 instruction_accounts,
2565 Err(InstructionError::InvalidAccountData),
2566 );
2567
2568 let (transaction_accounts, instruction_accounts) = get_accounts(
2570 &buffer_address,
2571 &buffer_address,
2572 &upgrade_authority_address,
2573 &elf_orig,
2574 &elf_new,
2575 );
2576 process_instruction(
2577 transaction_accounts,
2578 instruction_accounts,
2579 Err(InstructionError::IncorrectAuthority),
2580 );
2581
2582 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2584 &buffer_address,
2585 &buffer_address,
2586 &upgrade_authority_address,
2587 &elf_orig,
2588 &elf_new,
2589 );
2590 transaction_accounts
2591 .get_mut(2)
2592 .unwrap()
2593 .1
2594 .set_state(&UpgradeableLoaderState::Buffer {
2595 authority_address: None,
2596 })
2597 .unwrap();
2598 process_instruction(
2599 transaction_accounts,
2600 instruction_accounts,
2601 Err(InstructionError::IncorrectAuthority),
2602 );
2603
2604 let (mut transaction_accounts, instruction_accounts) = get_accounts(
2606 &buffer_address,
2607 &buffer_address,
2608 &upgrade_authority_address,
2609 &elf_orig,
2610 &elf_new,
2611 );
2612 transaction_accounts
2613 .get_mut(0)
2614 .unwrap()
2615 .1
2616 .set_state(&UpgradeableLoaderState::ProgramData {
2617 slot: SLOT,
2618 upgrade_authority_address: None,
2619 })
2620 .unwrap();
2621 transaction_accounts
2622 .get_mut(2)
2623 .unwrap()
2624 .1
2625 .set_state(&UpgradeableLoaderState::Buffer {
2626 authority_address: None,
2627 })
2628 .unwrap();
2629 process_instruction(
2630 transaction_accounts,
2631 instruction_accounts,
2632 Err(InstructionError::IncorrectAuthority),
2633 );
2634 }
2635
2636 #[test]
2637 fn test_bpf_loader_upgradeable_set_upgrade_authority() {
2638 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
2639 let loader_id = bpf_loader_upgradeable::id();
2640 let slot = 0;
2641 let upgrade_authority_address = Pubkey::new_unique();
2642 let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2643 let new_upgrade_authority_address = Pubkey::new_unique();
2644 let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2645 let program_address = Pubkey::new_unique();
2646 let (programdata_address, _) = Pubkey::find_program_address(
2647 &[program_address.as_ref()],
2648 &bpf_loader_upgradeable::id(),
2649 );
2650 let mut programdata_account = AccountSharedData::new(
2651 1,
2652 UpgradeableLoaderState::size_of_programdata(0),
2653 &bpf_loader_upgradeable::id(),
2654 );
2655 programdata_account
2656 .set_state(&UpgradeableLoaderState::ProgramData {
2657 slot,
2658 upgrade_authority_address: Some(upgrade_authority_address),
2659 })
2660 .unwrap();
2661 let programdata_meta = AccountMeta {
2662 pubkey: programdata_address,
2663 is_signer: false,
2664 is_writable: true,
2665 };
2666 let upgrade_authority_meta = AccountMeta {
2667 pubkey: upgrade_authority_address,
2668 is_signer: true,
2669 is_writable: false,
2670 };
2671 let new_upgrade_authority_meta = AccountMeta {
2672 pubkey: new_upgrade_authority_address,
2673 is_signer: false,
2674 is_writable: false,
2675 };
2676
2677 let accounts = process_instruction(
2679 &loader_id,
2680 &[],
2681 &instruction,
2682 vec![
2683 (programdata_address, programdata_account.clone()),
2684 (upgrade_authority_address, upgrade_authority_account.clone()),
2685 (
2686 new_upgrade_authority_address,
2687 new_upgrade_authority_account.clone(),
2688 ),
2689 ],
2690 vec![
2691 programdata_meta.clone(),
2692 upgrade_authority_meta.clone(),
2693 new_upgrade_authority_meta.clone(),
2694 ],
2695 Ok(()),
2696 );
2697 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2698 assert_eq!(
2699 state,
2700 UpgradeableLoaderState::ProgramData {
2701 slot,
2702 upgrade_authority_address: Some(new_upgrade_authority_address),
2703 }
2704 );
2705
2706 let accounts = process_instruction(
2708 &loader_id,
2709 &[],
2710 &instruction,
2711 vec![
2712 (programdata_address, programdata_account.clone()),
2713 (upgrade_authority_address, upgrade_authority_account.clone()),
2714 ],
2715 vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
2716 Ok(()),
2717 );
2718 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2719 assert_eq!(
2720 state,
2721 UpgradeableLoaderState::ProgramData {
2722 slot,
2723 upgrade_authority_address: None,
2724 }
2725 );
2726
2727 process_instruction(
2729 &loader_id,
2730 &[],
2731 &instruction,
2732 vec![
2733 (programdata_address, programdata_account.clone()),
2734 (upgrade_authority_address, upgrade_authority_account.clone()),
2735 ],
2736 vec![
2737 programdata_meta.clone(),
2738 AccountMeta {
2739 pubkey: upgrade_authority_address,
2740 is_signer: false,
2741 is_writable: false,
2742 },
2743 ],
2744 Err(InstructionError::MissingRequiredSignature),
2745 );
2746
2747 let invalid_upgrade_authority_address = Pubkey::new_unique();
2749 process_instruction(
2750 &loader_id,
2751 &[],
2752 &instruction,
2753 vec![
2754 (programdata_address, programdata_account.clone()),
2755 (
2756 invalid_upgrade_authority_address,
2757 upgrade_authority_account.clone(),
2758 ),
2759 (new_upgrade_authority_address, new_upgrade_authority_account),
2760 ],
2761 vec![
2762 programdata_meta.clone(),
2763 AccountMeta {
2764 pubkey: invalid_upgrade_authority_address,
2765 is_signer: true,
2766 is_writable: false,
2767 },
2768 new_upgrade_authority_meta,
2769 ],
2770 Err(InstructionError::IncorrectAuthority),
2771 );
2772
2773 programdata_account
2775 .set_state(&UpgradeableLoaderState::ProgramData {
2776 slot,
2777 upgrade_authority_address: None,
2778 })
2779 .unwrap();
2780 process_instruction(
2781 &loader_id,
2782 &[],
2783 &instruction,
2784 vec![
2785 (programdata_address, programdata_account.clone()),
2786 (upgrade_authority_address, upgrade_authority_account.clone()),
2787 ],
2788 vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
2789 Err(InstructionError::Immutable),
2790 );
2791
2792 programdata_account
2794 .set_state(&UpgradeableLoaderState::Program {
2795 programdata_address: Pubkey::new_unique(),
2796 })
2797 .unwrap();
2798 process_instruction(
2799 &loader_id,
2800 &[],
2801 &instruction,
2802 vec![
2803 (programdata_address, programdata_account.clone()),
2804 (upgrade_authority_address, upgrade_authority_account),
2805 ],
2806 vec![programdata_meta, upgrade_authority_meta],
2807 Err(InstructionError::InvalidArgument),
2808 );
2809 }
2810
2811 #[test]
2812 fn test_bpf_loader_upgradeable_set_upgrade_authority_checked() {
2813 let instruction =
2814 bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
2815 let loader_id = bpf_loader_upgradeable::id();
2816 let slot = 0;
2817 let upgrade_authority_address = Pubkey::new_unique();
2818 let upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2819 let new_upgrade_authority_address = Pubkey::new_unique();
2820 let new_upgrade_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
2821 let program_address = Pubkey::new_unique();
2822 let (programdata_address, _) = Pubkey::find_program_address(
2823 &[program_address.as_ref()],
2824 &bpf_loader_upgradeable::id(),
2825 );
2826 let mut programdata_account = AccountSharedData::new(
2827 1,
2828 UpgradeableLoaderState::size_of_programdata(0),
2829 &bpf_loader_upgradeable::id(),
2830 );
2831 programdata_account
2832 .set_state(&UpgradeableLoaderState::ProgramData {
2833 slot,
2834 upgrade_authority_address: Some(upgrade_authority_address),
2835 })
2836 .unwrap();
2837 let programdata_meta = AccountMeta {
2838 pubkey: programdata_address,
2839 is_signer: false,
2840 is_writable: true,
2841 };
2842 let upgrade_authority_meta = AccountMeta {
2843 pubkey: upgrade_authority_address,
2844 is_signer: true,
2845 is_writable: false,
2846 };
2847 let new_upgrade_authority_meta = AccountMeta {
2848 pubkey: new_upgrade_authority_address,
2849 is_signer: true,
2850 is_writable: false,
2851 };
2852
2853 let accounts = process_instruction(
2855 &loader_id,
2856 &[],
2857 &instruction,
2858 vec![
2859 (programdata_address, programdata_account.clone()),
2860 (upgrade_authority_address, upgrade_authority_account.clone()),
2861 (
2862 new_upgrade_authority_address,
2863 new_upgrade_authority_account.clone(),
2864 ),
2865 ],
2866 vec![
2867 programdata_meta.clone(),
2868 upgrade_authority_meta.clone(),
2869 new_upgrade_authority_meta.clone(),
2870 ],
2871 Ok(()),
2872 );
2873
2874 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
2875 assert_eq!(
2876 state,
2877 UpgradeableLoaderState::ProgramData {
2878 slot,
2879 upgrade_authority_address: Some(new_upgrade_authority_address),
2880 }
2881 );
2882
2883 process_instruction(
2885 &loader_id,
2886 &[],
2887 &instruction,
2888 vec![
2889 (programdata_address, programdata_account.clone()),
2890 (upgrade_authority_address, upgrade_authority_account.clone()),
2891 ],
2892 vec![
2893 programdata_meta.clone(),
2894 upgrade_authority_meta.clone(),
2895 upgrade_authority_meta.clone(),
2896 ],
2897 Ok(()),
2898 );
2899
2900 process_instruction(
2902 &loader_id,
2903 &[],
2904 &instruction,
2905 vec![
2906 (programdata_address, programdata_account.clone()),
2907 (upgrade_authority_address, upgrade_authority_account.clone()),
2908 (
2909 new_upgrade_authority_address,
2910 new_upgrade_authority_account.clone(),
2911 ),
2912 ],
2913 vec![programdata_meta.clone(), new_upgrade_authority_meta.clone()],
2914 Err(InstructionError::NotEnoughAccountKeys),
2915 );
2916
2917 process_instruction(
2919 &loader_id,
2920 &[],
2921 &instruction,
2922 vec![
2923 (programdata_address, programdata_account.clone()),
2924 (upgrade_authority_address, upgrade_authority_account.clone()),
2925 (
2926 new_upgrade_authority_address,
2927 new_upgrade_authority_account.clone(),
2928 ),
2929 ],
2930 vec![programdata_meta.clone(), upgrade_authority_meta.clone()],
2931 Err(InstructionError::NotEnoughAccountKeys),
2932 );
2933
2934 process_instruction(
2936 &loader_id,
2937 &[],
2938 &instruction,
2939 vec![
2940 (programdata_address, programdata_account.clone()),
2941 (upgrade_authority_address, upgrade_authority_account.clone()),
2942 (
2943 new_upgrade_authority_address,
2944 new_upgrade_authority_account.clone(),
2945 ),
2946 ],
2947 vec![
2948 programdata_meta.clone(),
2949 AccountMeta {
2950 pubkey: upgrade_authority_address,
2951 is_signer: false,
2952 is_writable: false,
2953 },
2954 new_upgrade_authority_meta.clone(),
2955 ],
2956 Err(InstructionError::MissingRequiredSignature),
2957 );
2958
2959 process_instruction(
2961 &loader_id,
2962 &[],
2963 &instruction,
2964 vec![
2965 (programdata_address, programdata_account.clone()),
2966 (upgrade_authority_address, upgrade_authority_account.clone()),
2967 (
2968 new_upgrade_authority_address,
2969 new_upgrade_authority_account.clone(),
2970 ),
2971 ],
2972 vec![
2973 programdata_meta.clone(),
2974 upgrade_authority_meta.clone(),
2975 AccountMeta {
2976 pubkey: new_upgrade_authority_address,
2977 is_signer: false,
2978 is_writable: false,
2979 },
2980 ],
2981 Err(InstructionError::MissingRequiredSignature),
2982 );
2983
2984 let invalid_upgrade_authority_address = Pubkey::new_unique();
2986 process_instruction(
2987 &loader_id,
2988 &[],
2989 &instruction,
2990 vec![
2991 (programdata_address, programdata_account.clone()),
2992 (
2993 invalid_upgrade_authority_address,
2994 upgrade_authority_account.clone(),
2995 ),
2996 (new_upgrade_authority_address, new_upgrade_authority_account),
2997 ],
2998 vec![
2999 programdata_meta.clone(),
3000 AccountMeta {
3001 pubkey: invalid_upgrade_authority_address,
3002 is_signer: true,
3003 is_writable: false,
3004 },
3005 new_upgrade_authority_meta.clone(),
3006 ],
3007 Err(InstructionError::IncorrectAuthority),
3008 );
3009
3010 programdata_account
3012 .set_state(&UpgradeableLoaderState::ProgramData {
3013 slot,
3014 upgrade_authority_address: None,
3015 })
3016 .unwrap();
3017 process_instruction(
3018 &loader_id,
3019 &[],
3020 &instruction,
3021 vec![
3022 (programdata_address, programdata_account.clone()),
3023 (upgrade_authority_address, upgrade_authority_account.clone()),
3024 ],
3025 vec![
3026 programdata_meta.clone(),
3027 upgrade_authority_meta.clone(),
3028 new_upgrade_authority_meta.clone(),
3029 ],
3030 Err(InstructionError::Immutable),
3031 );
3032
3033 programdata_account
3035 .set_state(&UpgradeableLoaderState::Program {
3036 programdata_address: Pubkey::new_unique(),
3037 })
3038 .unwrap();
3039 process_instruction(
3040 &loader_id,
3041 &[],
3042 &instruction,
3043 vec![
3044 (programdata_address, programdata_account.clone()),
3045 (upgrade_authority_address, upgrade_authority_account),
3046 ],
3047 vec![
3048 programdata_meta,
3049 upgrade_authority_meta,
3050 new_upgrade_authority_meta,
3051 ],
3052 Err(InstructionError::InvalidArgument),
3053 );
3054 }
3055
3056 #[test]
3057 fn test_bpf_loader_upgradeable_set_buffer_authority() {
3058 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::SetAuthority).unwrap();
3059 let loader_id = bpf_loader_upgradeable::id();
3060 let invalid_authority_address = Pubkey::new_unique();
3061 let authority_address = Pubkey::new_unique();
3062 let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3063 let new_authority_address = Pubkey::new_unique();
3064 let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3065 let buffer_address = Pubkey::new_unique();
3066 let mut buffer_account =
3067 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3068 buffer_account
3069 .set_state(&UpgradeableLoaderState::Buffer {
3070 authority_address: Some(authority_address),
3071 })
3072 .unwrap();
3073 let mut transaction_accounts = vec![
3074 (buffer_address, buffer_account.clone()),
3075 (authority_address, authority_account.clone()),
3076 (new_authority_address, new_authority_account.clone()),
3077 ];
3078 let buffer_meta = AccountMeta {
3079 pubkey: buffer_address,
3080 is_signer: false,
3081 is_writable: true,
3082 };
3083 let authority_meta = AccountMeta {
3084 pubkey: authority_address,
3085 is_signer: true,
3086 is_writable: false,
3087 };
3088 let new_authority_meta = AccountMeta {
3089 pubkey: new_authority_address,
3090 is_signer: false,
3091 is_writable: false,
3092 };
3093
3094 let accounts = process_instruction(
3096 &loader_id,
3097 &[],
3098 &instruction,
3099 transaction_accounts.clone(),
3100 vec![buffer_meta.clone(), authority_meta.clone()],
3101 Err(InstructionError::IncorrectAuthority),
3102 );
3103 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3104 assert_eq!(
3105 state,
3106 UpgradeableLoaderState::Buffer {
3107 authority_address: Some(authority_address),
3108 }
3109 );
3110
3111 buffer_account
3113 .set_state(&UpgradeableLoaderState::Buffer {
3114 authority_address: Some(authority_address),
3115 })
3116 .unwrap();
3117 let accounts = process_instruction(
3118 &loader_id,
3119 &[],
3120 &instruction,
3121 transaction_accounts.clone(),
3122 vec![
3123 buffer_meta.clone(),
3124 authority_meta.clone(),
3125 new_authority_meta.clone(),
3126 ],
3127 Ok(()),
3128 );
3129 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3130 assert_eq!(
3131 state,
3132 UpgradeableLoaderState::Buffer {
3133 authority_address: Some(new_authority_address),
3134 }
3135 );
3136
3137 process_instruction(
3139 &loader_id,
3140 &[],
3141 &instruction,
3142 transaction_accounts.clone(),
3143 vec![
3144 buffer_meta.clone(),
3145 AccountMeta {
3146 pubkey: authority_address,
3147 is_signer: false,
3148 is_writable: false,
3149 },
3150 new_authority_meta.clone(),
3151 ],
3152 Err(InstructionError::MissingRequiredSignature),
3153 );
3154
3155 process_instruction(
3157 &loader_id,
3158 &[],
3159 &instruction,
3160 vec![
3161 (buffer_address, buffer_account.clone()),
3162 (invalid_authority_address, authority_account),
3163 (new_authority_address, new_authority_account),
3164 ],
3165 vec![
3166 buffer_meta.clone(),
3167 AccountMeta {
3168 pubkey: invalid_authority_address,
3169 is_signer: true,
3170 is_writable: false,
3171 },
3172 new_authority_meta.clone(),
3173 ],
3174 Err(InstructionError::IncorrectAuthority),
3175 );
3176
3177 process_instruction(
3179 &loader_id,
3180 &[],
3181 &instruction,
3182 transaction_accounts.clone(),
3183 vec![buffer_meta.clone(), authority_meta.clone()],
3184 Err(InstructionError::IncorrectAuthority),
3185 );
3186
3187 transaction_accounts
3189 .get_mut(0)
3190 .unwrap()
3191 .1
3192 .set_state(&UpgradeableLoaderState::Buffer {
3193 authority_address: None,
3194 })
3195 .unwrap();
3196 process_instruction(
3197 &loader_id,
3198 &[],
3199 &instruction,
3200 transaction_accounts.clone(),
3201 vec![
3202 buffer_meta.clone(),
3203 authority_meta.clone(),
3204 new_authority_meta.clone(),
3205 ],
3206 Err(InstructionError::Immutable),
3207 );
3208
3209 transaction_accounts
3211 .get_mut(0)
3212 .unwrap()
3213 .1
3214 .set_state(&UpgradeableLoaderState::Program {
3215 programdata_address: Pubkey::new_unique(),
3216 })
3217 .unwrap();
3218 process_instruction(
3219 &loader_id,
3220 &[],
3221 &instruction,
3222 transaction_accounts.clone(),
3223 vec![buffer_meta, authority_meta, new_authority_meta],
3224 Err(InstructionError::InvalidArgument),
3225 );
3226 }
3227
3228 #[test]
3229 fn test_bpf_loader_upgradeable_set_buffer_authority_checked() {
3230 let instruction =
3231 bincode::serialize(&UpgradeableLoaderInstruction::SetAuthorityChecked).unwrap();
3232 let loader_id = bpf_loader_upgradeable::id();
3233 let invalid_authority_address = Pubkey::new_unique();
3234 let authority_address = Pubkey::new_unique();
3235 let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3236 let new_authority_address = Pubkey::new_unique();
3237 let new_authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3238 let buffer_address = Pubkey::new_unique();
3239 let mut buffer_account =
3240 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(0), &loader_id);
3241 buffer_account
3242 .set_state(&UpgradeableLoaderState::Buffer {
3243 authority_address: Some(authority_address),
3244 })
3245 .unwrap();
3246 let mut transaction_accounts = vec![
3247 (buffer_address, buffer_account.clone()),
3248 (authority_address, authority_account.clone()),
3249 (new_authority_address, new_authority_account.clone()),
3250 ];
3251 let buffer_meta = AccountMeta {
3252 pubkey: buffer_address,
3253 is_signer: false,
3254 is_writable: true,
3255 };
3256 let authority_meta = AccountMeta {
3257 pubkey: authority_address,
3258 is_signer: true,
3259 is_writable: false,
3260 };
3261 let new_authority_meta = AccountMeta {
3262 pubkey: new_authority_address,
3263 is_signer: true,
3264 is_writable: false,
3265 };
3266
3267 buffer_account
3269 .set_state(&UpgradeableLoaderState::Buffer {
3270 authority_address: Some(authority_address),
3271 })
3272 .unwrap();
3273 let accounts = process_instruction(
3274 &loader_id,
3275 &[],
3276 &instruction,
3277 transaction_accounts.clone(),
3278 vec![
3279 buffer_meta.clone(),
3280 authority_meta.clone(),
3281 new_authority_meta.clone(),
3282 ],
3283 Ok(()),
3284 );
3285 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3286 assert_eq!(
3287 state,
3288 UpgradeableLoaderState::Buffer {
3289 authority_address: Some(new_authority_address),
3290 }
3291 );
3292
3293 process_instruction(
3295 &loader_id,
3296 &[],
3297 &instruction,
3298 transaction_accounts.clone(),
3299 vec![
3300 buffer_meta.clone(),
3301 authority_meta.clone(),
3302 authority_meta.clone(),
3303 ],
3304 Ok(()),
3305 );
3306
3307 process_instruction(
3309 &loader_id,
3310 &[],
3311 &instruction,
3312 transaction_accounts.clone(),
3313 vec![buffer_meta.clone(), new_authority_meta.clone()],
3314 Err(InstructionError::NotEnoughAccountKeys),
3315 );
3316
3317 process_instruction(
3319 &loader_id,
3320 &[],
3321 &instruction,
3322 transaction_accounts.clone(),
3323 vec![buffer_meta.clone(), authority_meta.clone()],
3324 Err(InstructionError::NotEnoughAccountKeys),
3325 );
3326
3327 process_instruction(
3329 &loader_id,
3330 &[],
3331 &instruction,
3332 vec![
3333 (buffer_address, buffer_account.clone()),
3334 (invalid_authority_address, authority_account),
3335 (new_authority_address, new_authority_account),
3336 ],
3337 vec![
3338 buffer_meta.clone(),
3339 AccountMeta {
3340 pubkey: invalid_authority_address,
3341 is_signer: true,
3342 is_writable: false,
3343 },
3344 new_authority_meta.clone(),
3345 ],
3346 Err(InstructionError::IncorrectAuthority),
3347 );
3348
3349 process_instruction(
3351 &loader_id,
3352 &[],
3353 &instruction,
3354 transaction_accounts.clone(),
3355 vec![
3356 buffer_meta.clone(),
3357 AccountMeta {
3358 pubkey: authority_address,
3359 is_signer: false,
3360 is_writable: false,
3361 },
3362 new_authority_meta.clone(),
3363 ],
3364 Err(InstructionError::MissingRequiredSignature),
3365 );
3366
3367 process_instruction(
3369 &loader_id,
3370 &[],
3371 &instruction,
3372 transaction_accounts.clone(),
3373 vec![
3374 buffer_meta.clone(),
3375 authority_meta.clone(),
3376 AccountMeta {
3377 pubkey: new_authority_address,
3378 is_signer: false,
3379 is_writable: false,
3380 },
3381 ],
3382 Err(InstructionError::MissingRequiredSignature),
3383 );
3384
3385 transaction_accounts
3387 .get_mut(0)
3388 .unwrap()
3389 .1
3390 .set_state(&UpgradeableLoaderState::Program {
3391 programdata_address: Pubkey::new_unique(),
3392 })
3393 .unwrap();
3394 process_instruction(
3395 &loader_id,
3396 &[],
3397 &instruction,
3398 transaction_accounts.clone(),
3399 vec![
3400 buffer_meta.clone(),
3401 authority_meta.clone(),
3402 new_authority_meta.clone(),
3403 ],
3404 Err(InstructionError::InvalidArgument),
3405 );
3406
3407 transaction_accounts
3409 .get_mut(0)
3410 .unwrap()
3411 .1
3412 .set_state(&UpgradeableLoaderState::Buffer {
3413 authority_address: None,
3414 })
3415 .unwrap();
3416 process_instruction(
3417 &loader_id,
3418 &[],
3419 &instruction,
3420 transaction_accounts.clone(),
3421 vec![buffer_meta, authority_meta, new_authority_meta],
3422 Err(InstructionError::Immutable),
3423 );
3424 }
3425
3426 #[test]
3427 fn test_bpf_loader_upgradeable_close() {
3428 let instruction = bincode::serialize(&UpgradeableLoaderInstruction::Close).unwrap();
3429 let loader_id = bpf_loader_upgradeable::id();
3430 let invalid_authority_address = Pubkey::new_unique();
3431 let authority_address = Pubkey::new_unique();
3432 let authority_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3433 let recipient_address = Pubkey::new_unique();
3434 let recipient_account = AccountSharedData::new(1, 0, &Pubkey::new_unique());
3435 let buffer_address = Pubkey::new_unique();
3436 let mut buffer_account =
3437 AccountSharedData::new(1, UpgradeableLoaderState::size_of_buffer(128), &loader_id);
3438 buffer_account
3439 .set_state(&UpgradeableLoaderState::Buffer {
3440 authority_address: Some(authority_address),
3441 })
3442 .unwrap();
3443 let uninitialized_address = Pubkey::new_unique();
3444 let mut uninitialized_account = AccountSharedData::new(
3445 1,
3446 UpgradeableLoaderState::size_of_programdata(0),
3447 &loader_id,
3448 );
3449 uninitialized_account
3450 .set_state(&UpgradeableLoaderState::Uninitialized)
3451 .unwrap();
3452 let programdata_address = Pubkey::new_unique();
3453 let mut programdata_account = AccountSharedData::new(
3454 1,
3455 UpgradeableLoaderState::size_of_programdata(128),
3456 &loader_id,
3457 );
3458 programdata_account
3459 .set_state(&UpgradeableLoaderState::ProgramData {
3460 slot: 0,
3461 upgrade_authority_address: Some(authority_address),
3462 })
3463 .unwrap();
3464 let program_address = Pubkey::new_unique();
3465 let mut program_account =
3466 AccountSharedData::new(1, UpgradeableLoaderState::size_of_program(), &loader_id);
3467 program_account.set_executable(true);
3468 program_account
3469 .set_state(&UpgradeableLoaderState::Program {
3470 programdata_address,
3471 })
3472 .unwrap();
3473 let clock_account = create_account_for_test(&Clock {
3474 slot: 1,
3475 ..Clock::default()
3476 });
3477 let transaction_accounts = vec![
3478 (buffer_address, buffer_account.clone()),
3479 (recipient_address, recipient_account.clone()),
3480 (authority_address, authority_account.clone()),
3481 ];
3482 let buffer_meta = AccountMeta {
3483 pubkey: buffer_address,
3484 is_signer: false,
3485 is_writable: true,
3486 };
3487 let recipient_meta = AccountMeta {
3488 pubkey: recipient_address,
3489 is_signer: false,
3490 is_writable: true,
3491 };
3492 let authority_meta = AccountMeta {
3493 pubkey: authority_address,
3494 is_signer: true,
3495 is_writable: false,
3496 };
3497
3498 let accounts = process_instruction(
3500 &loader_id,
3501 &[],
3502 &instruction,
3503 transaction_accounts,
3504 vec![
3505 buffer_meta.clone(),
3506 recipient_meta.clone(),
3507 authority_meta.clone(),
3508 ],
3509 Ok(()),
3510 );
3511 assert_eq!(0, accounts.first().unwrap().lamports());
3512 assert_eq!(2, accounts.get(1).unwrap().lamports());
3513 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3514 assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3515 assert_eq!(
3516 UpgradeableLoaderState::size_of_uninitialized(),
3517 accounts.first().unwrap().data().len()
3518 );
3519
3520 process_instruction(
3522 &loader_id,
3523 &[],
3524 &instruction,
3525 vec![
3526 (buffer_address, buffer_account.clone()),
3527 (recipient_address, recipient_account.clone()),
3528 (invalid_authority_address, authority_account.clone()),
3529 ],
3530 vec![
3531 buffer_meta,
3532 recipient_meta.clone(),
3533 AccountMeta {
3534 pubkey: invalid_authority_address,
3535 is_signer: true,
3536 is_writable: false,
3537 },
3538 ],
3539 Err(InstructionError::IncorrectAuthority),
3540 );
3541
3542 let accounts = process_instruction(
3544 &loader_id,
3545 &[],
3546 &instruction,
3547 vec![
3548 (uninitialized_address, uninitialized_account.clone()),
3549 (recipient_address, recipient_account.clone()),
3550 (invalid_authority_address, authority_account.clone()),
3551 ],
3552 vec![
3553 AccountMeta {
3554 pubkey: uninitialized_address,
3555 is_signer: false,
3556 is_writable: true,
3557 },
3558 recipient_meta.clone(),
3559 authority_meta.clone(),
3560 ],
3561 Ok(()),
3562 );
3563 assert_eq!(0, accounts.first().unwrap().lamports());
3564 assert_eq!(2, accounts.get(1).unwrap().lamports());
3565 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3566 assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3567 assert_eq!(
3568 UpgradeableLoaderState::size_of_uninitialized(),
3569 accounts.first().unwrap().data().len()
3570 );
3571
3572 let accounts = process_instruction(
3574 &loader_id,
3575 &[],
3576 &instruction,
3577 vec![
3578 (programdata_address, programdata_account.clone()),
3579 (recipient_address, recipient_account.clone()),
3580 (authority_address, authority_account.clone()),
3581 (program_address, program_account.clone()),
3582 (sysvar::clock::id(), clock_account.clone()),
3583 ],
3584 vec![
3585 AccountMeta {
3586 pubkey: programdata_address,
3587 is_signer: false,
3588 is_writable: true,
3589 },
3590 recipient_meta,
3591 authority_meta,
3592 AccountMeta {
3593 pubkey: program_address,
3594 is_signer: false,
3595 is_writable: true,
3596 },
3597 ],
3598 Ok(()),
3599 );
3600 assert_eq!(0, accounts.first().unwrap().lamports());
3601 assert_eq!(2, accounts.get(1).unwrap().lamports());
3602 let state: UpgradeableLoaderState = accounts.first().unwrap().state().unwrap();
3603 assert_eq!(state, UpgradeableLoaderState::Uninitialized);
3604 assert_eq!(
3605 UpgradeableLoaderState::size_of_uninitialized(),
3606 accounts.first().unwrap().data().len()
3607 );
3608
3609 programdata_account = accounts.first().unwrap().clone();
3611 program_account = accounts.get(3).unwrap().clone();
3612 process_instruction(
3613 &loader_id,
3614 &[0, 1],
3615 &[],
3616 vec![
3617 (programdata_address, programdata_account.clone()),
3618 (program_address, program_account.clone()),
3619 ],
3620 Vec::new(),
3621 Err(InstructionError::InvalidAccountData),
3622 );
3623
3624 process_instruction(
3626 &loader_id,
3627 &[],
3628 &bincode::serialize(&UpgradeableLoaderInstruction::DeployWithMaxDataLen {
3629 max_data_len: 0,
3630 })
3631 .unwrap(),
3632 vec![
3633 (recipient_address, recipient_account),
3634 (programdata_address, programdata_account),
3635 (program_address, program_account),
3636 (buffer_address, buffer_account),
3637 (
3638 sysvar::rent::id(),
3639 create_account_for_test(&Rent::default()),
3640 ),
3641 (sysvar::clock::id(), clock_account),
3642 (
3643 system_program::id(),
3644 AccountSharedData::new(0, 0, &system_program::id()),
3645 ),
3646 (authority_address, authority_account),
3647 ],
3648 vec![
3649 AccountMeta {
3650 pubkey: recipient_address,
3651 is_signer: true,
3652 is_writable: true,
3653 },
3654 AccountMeta {
3655 pubkey: programdata_address,
3656 is_signer: false,
3657 is_writable: true,
3658 },
3659 AccountMeta {
3660 pubkey: program_address,
3661 is_signer: false,
3662 is_writable: true,
3663 },
3664 AccountMeta {
3665 pubkey: buffer_address,
3666 is_signer: false,
3667 is_writable: false,
3668 },
3669 AccountMeta {
3670 pubkey: sysvar::rent::id(),
3671 is_signer: false,
3672 is_writable: false,
3673 },
3674 AccountMeta {
3675 pubkey: sysvar::clock::id(),
3676 is_signer: false,
3677 is_writable: false,
3678 },
3679 AccountMeta {
3680 pubkey: system_program::id(),
3681 is_signer: false,
3682 is_writable: false,
3683 },
3684 AccountMeta {
3685 pubkey: authority_address,
3686 is_signer: false,
3687 is_writable: false,
3688 },
3689 ],
3690 Err(InstructionError::AccountAlreadyInitialized),
3691 );
3692 }
3693
3694 fn fuzz<F>(
3696 bytes: &[u8],
3697 outer_iters: usize,
3698 inner_iters: usize,
3699 offset: Range<usize>,
3700 value: Range<u8>,
3701 work: F,
3702 ) where
3703 F: Fn(&mut [u8]),
3704 {
3705 let mut rng = rand::thread_rng();
3706 for _ in 0..outer_iters {
3707 let mut mangled_bytes = bytes.to_vec();
3708 for _ in 0..inner_iters {
3709 let offset = rng.gen_range(offset.start..offset.end);
3710 let value = rng.gen_range(value.start..value.end);
3711 *mangled_bytes.get_mut(offset).unwrap() = value;
3712 work(&mut mangled_bytes);
3713 }
3714 }
3715 }
3716
3717 #[test]
3718 #[ignore]
3719 fn test_fuzz() {
3720 let loader_id = bpf_loader::id();
3721 let program_id = Pubkey::new_unique();
3722
3723 let mut file = File::open("test_elfs/out/noop_aligned.so").expect("file open failed");
3725 let mut elf = Vec::new();
3726 file.read_to_end(&mut elf).unwrap();
3727
3728 fuzz(
3730 &elf,
3731 1_000_000_000,
3732 100,
3733 0..elf.len(),
3734 0..255,
3735 |bytes: &mut [u8]| {
3736 let mut program_account = AccountSharedData::new(1, 0, &loader_id);
3737 program_account.set_data(bytes.to_vec());
3738 program_account.set_executable(true);
3739 process_instruction(
3740 &loader_id,
3741 &[],
3742 &[],
3743 vec![(program_id, program_account)],
3744 Vec::new(),
3745 Ok(()),
3746 );
3747 },
3748 );
3749 }
3750
3751 #[test]
3752 fn test_calculate_heap_cost() {
3753 let heap_cost = 8_u64;
3754
3755 assert_eq!(0, calculate_heap_cost(31 * 1024, heap_cost));
3759
3760 assert_eq!(0, calculate_heap_cost(32 * 1024, heap_cost));
3762
3763 assert_eq!(heap_cost, calculate_heap_cost(33 * 1024, heap_cost));
3765
3766 assert_eq!(heap_cost, calculate_heap_cost(64 * 1024, heap_cost));
3768 }
3769
3770 fn deploy_test_program(
3771 invoke_context: &mut InvokeContext,
3772 program_id: Pubkey,
3773 ) -> Result<(), InstructionError> {
3774 let mut file = File::open("test_elfs/out/noop_unaligned.so").expect("file open failed");
3775 let mut elf = Vec::new();
3776 file.read_to_end(&mut elf).unwrap();
3777 deploy_program!(
3778 invoke_context,
3779 program_id,
3780 &bpf_loader_upgradeable::id(),
3781 elf.len(),
3782 2,
3783 {},
3784 &elf
3785 );
3786 Ok(())
3787 }
3788
3789 #[test]
3790 fn test_program_usage_count_on_upgrade() {
3791 let transaction_accounts = vec![];
3792 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
3793 let program_id = Pubkey::new_unique();
3794 let env = Arc::new(BuiltinProgram::new_mock());
3795 let program = LoadedProgram {
3796 program: LoadedProgramType::Unloaded(env),
3797 account_size: 0,
3798 deployment_slot: 0,
3799 effective_slot: 0,
3800 tx_usage_counter: AtomicU64::new(100),
3801 ix_usage_counter: AtomicU64::new(100),
3802 latest_access_slot: AtomicU64::new(0),
3803 };
3804 invoke_context
3805 .programs_modified_by_tx
3806 .replenish(program_id, Arc::new(program));
3807
3808 assert_matches!(
3809 deploy_test_program(&mut invoke_context, program_id,),
3810 Ok(())
3811 );
3812
3813 let updated_program = invoke_context
3814 .programs_modified_by_tx
3815 .find(&program_id)
3816 .expect("Didn't find upgraded program in the cache");
3817
3818 assert_eq!(updated_program.deployment_slot, 2);
3819 assert_eq!(
3820 updated_program.tx_usage_counter.load(Ordering::Relaxed),
3821 100
3822 );
3823 assert_eq!(
3824 updated_program.ix_usage_counter.load(Ordering::Relaxed),
3825 100
3826 );
3827 }
3828
3829 #[test]
3830 fn test_program_usage_count_on_non_upgrade() {
3831 let transaction_accounts = vec![];
3832 with_mock_invoke_context!(invoke_context, transaction_context, transaction_accounts);
3833 let program_id = Pubkey::new_unique();
3834 let env = Arc::new(BuiltinProgram::new_mock());
3835 let program = LoadedProgram {
3836 program: LoadedProgramType::Unloaded(env),
3837 account_size: 0,
3838 deployment_slot: 0,
3839 effective_slot: 0,
3840 tx_usage_counter: AtomicU64::new(100),
3841 ix_usage_counter: AtomicU64::new(100),
3842 latest_access_slot: AtomicU64::new(0),
3843 };
3844 invoke_context
3845 .programs_modified_by_tx
3846 .replenish(program_id, Arc::new(program));
3847
3848 let program_id2 = Pubkey::new_unique();
3849 assert_matches!(
3850 deploy_test_program(&mut invoke_context, program_id2),
3851 Ok(())
3852 );
3853
3854 let program2 = invoke_context
3855 .programs_modified_by_tx
3856 .find(&program_id2)
3857 .expect("Didn't find upgraded program in the cache");
3858
3859 assert_eq!(program2.deployment_slot, 2);
3860 assert_eq!(program2.tx_usage_counter.load(Ordering::Relaxed), 0);
3861 assert_eq!(program2.ix_usage_counter.load(Ordering::Relaxed), 0);
3862 }
3863}