1use {
4 crate::{account::ExtraAccountMeta, error::AccountResolutionError},
5 solana_account_info::AccountInfo,
6 solana_instruction::{AccountMeta, Instruction},
7 solana_program_error::ProgramError,
8 solana_pubkey::Pubkey,
9 spl_discriminator::SplDiscriminate,
10 spl_pod::{
11 list::{self, ListView},
12 primitives::PodU32,
13 },
14 spl_type_length_value::state::{TlvState, TlvStateBorrowed, TlvStateMut},
15 std::future::Future,
16};
17
18pub type AccountDataResult = Result<Option<Vec<u8>>, AccountFetchError>;
21pub type AccountFetchError = Box<dyn std::error::Error + Send + Sync>;
24
25fn account_info_to_meta(account_info: &AccountInfo) -> AccountMeta {
27 AccountMeta {
28 pubkey: *account_info.key,
29 is_signer: account_info.is_signer,
30 is_writable: account_info.is_writable,
31 }
32}
33
34fn de_escalate_account_meta(account_meta: &mut AccountMeta, account_metas: &[AccountMeta]) {
36 let maybe_highest_privileges = account_metas
40 .iter()
41 .filter(|&x| x.pubkey == account_meta.pubkey)
42 .map(|x| x.is_writable)
43 .reduce(|acc, x| acc || x);
44 if let Some(is_writable) = maybe_highest_privileges {
46 if !is_writable && is_writable != account_meta.is_writable {
47 account_meta.is_writable = false;
50 }
51 }
52
53 account_meta.is_signer = false;
55}
56
57pub struct ExtraAccountMetaList;
154impl ExtraAccountMetaList {
155 pub fn init<T: SplDiscriminate>(
158 data: &mut [u8],
159 extra_account_metas: &[ExtraAccountMeta],
160 ) -> Result<(), ProgramError> {
161 let mut state = TlvStateMut::unpack(data).unwrap();
162 let tlv_size = ListView::<ExtraAccountMeta>::size_of(extra_account_metas.len())?;
163 let (bytes, _) = state.alloc::<T>(tlv_size, false)?;
164 let mut validation_data = ListView::<ExtraAccountMeta>::init(bytes)?;
165 for meta in extra_account_metas {
166 validation_data.push(*meta)?;
167 }
168 Ok(())
169 }
170
171 pub fn update<T: SplDiscriminate>(
174 data: &mut [u8],
175 extra_account_metas: &[ExtraAccountMeta],
176 ) -> Result<(), ProgramError> {
177 let mut state = TlvStateMut::unpack(data).unwrap();
178 let tlv_size = ListView::<ExtraAccountMeta>::size_of(extra_account_metas.len())?;
179 let bytes = state.realloc_first::<T>(tlv_size)?;
180 let mut validation_data = ListView::<ExtraAccountMeta>::init(bytes)?;
181 for meta in extra_account_metas {
182 validation_data.push(*meta)?;
183 }
184 Ok(())
185 }
186
187 pub fn unpack_with_tlv_state<'a, T: SplDiscriminate>(
193 tlv_state: &'a TlvStateBorrowed,
194 ) -> Result<list::ListViewReadOnly<'a, ExtraAccountMeta, PodU32>, ProgramError> {
195 let bytes = tlv_state.get_first_bytes::<T>()?;
196 ListView::<ExtraAccountMeta>::unpack(bytes)
197 }
198
199 pub fn size_of(num_items: usize) -> Result<usize, ProgramError> {
201 Ok(TlvStateBorrowed::get_base_len()
202 .saturating_add(ListView::<ExtraAccountMeta>::size_of(num_items)?))
203 }
204
205 pub fn check_account_infos<T: SplDiscriminate>(
212 account_infos: &[AccountInfo],
213 instruction_data: &[u8],
214 program_id: &Pubkey,
215 data: &[u8],
216 ) -> Result<(), ProgramError> {
217 let state = TlvStateBorrowed::unpack(data).unwrap();
218 let extra_meta_list = ExtraAccountMetaList::unpack_with_tlv_state::<T>(&state)?;
219
220 let initial_accounts_len = account_infos.len() - extra_meta_list.len();
221
222 let provided_metas = account_infos
224 .iter()
225 .map(account_info_to_meta)
226 .collect::<Vec<_>>();
227
228 for (i, config) in extra_meta_list.iter().enumerate() {
229 let meta = {
230 let account_key_data_refs = account_infos
233 .iter()
234 .map(|info| {
235 let key = *info.key;
236 let data = info.try_borrow_data()?;
237 Ok((key, data))
238 })
239 .collect::<Result<Vec<_>, ProgramError>>()?;
240
241 config.resolve(instruction_data, program_id, |usize| {
242 account_key_data_refs
243 .get(usize)
244 .map(|(pubkey, opt_data)| (pubkey, Some(opt_data.as_ref())))
245 })?
246 };
247
248 let expected_index = i
250 .checked_add(initial_accounts_len)
251 .ok_or::<ProgramError>(AccountResolutionError::CalculationFailure.into())?;
252 if provided_metas.get(expected_index) != Some(&meta) {
253 return Err(AccountResolutionError::IncorrectAccount.into());
254 }
255 }
256
257 Ok(())
258 }
259
260 pub async fn add_to_instruction<T: SplDiscriminate, F, Fut>(
262 instruction: &mut Instruction,
263 fetch_account_data_fn: F,
264 data: &[u8],
265 ) -> Result<(), ProgramError>
266 where
267 F: Fn(Pubkey) -> Fut,
268 Fut: Future<Output = AccountDataResult>,
269 {
270 let state = TlvStateBorrowed::unpack(data)?;
271 let bytes = state.get_first_bytes::<T>()?;
272 let extra_account_metas = ListView::<ExtraAccountMeta>::unpack(bytes)?;
273
274 let mut account_key_datas = vec![];
276 for meta in instruction.accounts.iter() {
277 let account_data = fetch_account_data_fn(meta.pubkey)
278 .await
279 .map_err::<ProgramError, _>(|_| {
280 AccountResolutionError::AccountFetchFailed.into()
281 })?;
282 account_key_datas.push((meta.pubkey, account_data));
283 }
284
285 for extra_meta in extra_account_metas.iter() {
286 let mut meta =
287 extra_meta.resolve(&instruction.data, &instruction.program_id, |usize| {
288 account_key_datas
289 .get(usize)
290 .map(|(pubkey, opt_data)| (pubkey, opt_data.as_ref().map(|x| x.as_slice())))
291 })?;
292 de_escalate_account_meta(&mut meta, &instruction.accounts);
293
294 account_key_datas.push((
296 meta.pubkey,
297 fetch_account_data_fn(meta.pubkey)
298 .await
299 .map_err::<ProgramError, _>(|_| {
300 AccountResolutionError::AccountFetchFailed.into()
301 })?,
302 ));
303 instruction.accounts.push(meta);
304 }
305 Ok(())
306 }
307
308 pub fn add_to_cpi_instruction<'a, T: SplDiscriminate>(
310 cpi_instruction: &mut Instruction,
311 cpi_account_infos: &mut Vec<AccountInfo<'a>>,
312 data: &[u8],
313 account_infos: &[AccountInfo<'a>],
314 ) -> Result<(), ProgramError> {
315 let state = TlvStateBorrowed::unpack(data)?;
316 let bytes = state.get_first_bytes::<T>()?;
317 let extra_account_metas = ListView::<ExtraAccountMeta>::unpack(bytes)?;
318
319 for extra_meta in extra_account_metas.iter() {
320 let mut meta = {
321 let account_key_data_refs = cpi_account_infos
324 .iter()
325 .map(|info| {
326 let key = *info.key;
327 let data = info.try_borrow_data()?;
328 Ok((key, data))
329 })
330 .collect::<Result<Vec<_>, ProgramError>>()?;
331
332 extra_meta.resolve(
333 &cpi_instruction.data,
334 &cpi_instruction.program_id,
335 |usize| {
336 account_key_data_refs
337 .get(usize)
338 .map(|(pubkey, opt_data)| (pubkey, Some(opt_data.as_ref())))
339 },
340 )?
341 };
342 de_escalate_account_meta(&mut meta, &cpi_instruction.accounts);
343
344 let account_info = account_infos
345 .iter()
346 .find(|&x| *x.key == meta.pubkey)
347 .ok_or(AccountResolutionError::IncorrectAccount)?
348 .clone();
349
350 cpi_instruction.accounts.push(meta);
351 cpi_account_infos.push(account_info);
352 }
353 Ok(())
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use {
360 super::*,
361 crate::{pubkey_data::PubkeyData, seeds::Seed},
362 solana_instruction::AccountMeta,
363 solana_pubkey::Pubkey,
364 spl_discriminator::{ArrayDiscriminator, SplDiscriminate},
365 std::collections::HashMap,
366 };
367
368 pub struct TestInstruction;
369 impl SplDiscriminate for TestInstruction {
370 const SPL_DISCRIMINATOR: ArrayDiscriminator =
371 ArrayDiscriminator::new([1; ArrayDiscriminator::LENGTH]);
372 }
373
374 pub struct TestOtherInstruction;
375 impl SplDiscriminate for TestOtherInstruction {
376 const SPL_DISCRIMINATOR: ArrayDiscriminator =
377 ArrayDiscriminator::new([2; ArrayDiscriminator::LENGTH]);
378 }
379
380 pub struct MockRpc<'a> {
381 cache: HashMap<Pubkey, &'a AccountInfo<'a>>,
382 }
383 impl<'a> MockRpc<'a> {
384 pub fn setup(account_infos: &'a [AccountInfo<'a>]) -> Self {
385 let mut cache = HashMap::new();
386 for info in account_infos {
387 cache.insert(*info.key, info);
388 }
389 Self { cache }
390 }
391
392 pub async fn get_account_data(&self, pubkey: Pubkey) -> AccountDataResult {
393 Ok(self
394 .cache
395 .get(&pubkey)
396 .map(|account| account.try_borrow_data().unwrap().to_vec()))
397 }
398 }
399
400 fn account_info_to_meta_non_signer(account_info: &AccountInfo) -> AccountMeta {
402 AccountMeta {
403 pubkey: *account_info.key,
404 is_signer: false,
405 is_writable: account_info.is_writable,
406 }
407 }
408
409 fn de_escalate_signer(mut account_meta: AccountMeta) -> AccountMeta {
410 account_meta.is_signer = false;
411 account_meta
412 }
413
414 #[tokio::test]
415 async fn init_with_metas() {
416 let metas = [
417 AccountMeta::new(Pubkey::new_unique(), false).into(),
418 AccountMeta::new(Pubkey::new_unique(), true).into(),
419 AccountMeta::new_readonly(Pubkey::new_unique(), true).into(),
420 AccountMeta::new_readonly(Pubkey::new_unique(), false).into(),
421 ];
422 let account_size = ExtraAccountMetaList::size_of(metas.len()).unwrap();
423 let mut buffer = vec![0; account_size];
424
425 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &metas).unwrap();
426
427 let mock_rpc = MockRpc::setup(&[]);
428
429 let mut instruction = Instruction::new_with_bytes(Pubkey::new_unique(), &[], vec![]);
430 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
431 &mut instruction,
432 |pubkey| mock_rpc.get_account_data(pubkey),
433 &buffer,
434 )
435 .await
436 .unwrap();
437
438 let check_metas = metas
439 .iter()
440 .map(|e| de_escalate_signer(AccountMeta::try_from(e).unwrap()))
441 .collect::<Vec<_>>();
442
443 assert_eq!(instruction.accounts, check_metas,);
444 }
445
446 #[tokio::test]
447 async fn init_with_infos() {
448 let program_id = Pubkey::new_unique();
449
450 let pubkey1 = Pubkey::new_unique();
451 let mut lamports1 = 0;
452 let mut data1 = [];
453 let pubkey2 = Pubkey::new_unique();
454 let mut lamports2 = 0;
455 let mut data2 = [4, 4, 4, 6, 6, 6, 8, 8];
456 let pubkey3 = Pubkey::new_unique();
457 let mut lamports3 = 0;
458 let mut data3 = [];
459 let owner = Pubkey::new_unique();
460 let account_infos = [
461 AccountInfo::new(
462 &pubkey1,
463 false,
464 true,
465 &mut lamports1,
466 &mut data1,
467 &owner,
468 false,
469 ),
470 AccountInfo::new(
471 &pubkey2,
472 true,
473 false,
474 &mut lamports2,
475 &mut data2,
476 &owner,
477 false,
478 ),
479 AccountInfo::new(
480 &pubkey3,
481 false,
482 false,
483 &mut lamports3,
484 &mut data3,
485 &owner,
486 false,
487 ),
488 ];
489
490 let required_pda = ExtraAccountMeta::new_with_seeds(
491 &[
492 Seed::AccountKey { index: 0 },
493 Seed::AccountData {
494 account_index: 1,
495 data_index: 2,
496 length: 4,
497 },
498 ],
499 false,
500 true,
501 )
502 .unwrap();
503
504 let required_extra_accounts = [
506 ExtraAccountMeta::from(&account_infos[0]),
507 ExtraAccountMeta::from(&account_infos[1]),
508 ExtraAccountMeta::from(&account_infos[2]),
509 required_pda,
510 ];
511
512 let account_size = ExtraAccountMetaList::size_of(required_extra_accounts.len()).unwrap();
513 let mut buffer = vec![0; account_size];
514
515 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &required_extra_accounts)
516 .unwrap();
517
518 let mock_rpc = MockRpc::setup(&account_infos);
519
520 let mut instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
521 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
522 &mut instruction,
523 |pubkey| mock_rpc.get_account_data(pubkey),
524 &buffer,
525 )
526 .await
527 .unwrap();
528
529 let (check_required_pda, _) = Pubkey::find_program_address(
530 &[
531 account_infos[0].key.as_ref(), &account_infos[1].try_borrow_data().unwrap()[2..6], ],
534 &program_id,
535 );
536
537 let check_metas = [
539 account_info_to_meta_non_signer(&account_infos[0]),
540 account_info_to_meta_non_signer(&account_infos[1]),
541 account_info_to_meta_non_signer(&account_infos[2]),
542 AccountMeta::new(check_required_pda, false),
543 ];
544
545 assert_eq!(instruction.accounts, check_metas,);
546
547 assert_eq!(
548 instruction.accounts.get(3).unwrap().pubkey,
549 check_required_pda
550 );
551 }
552
553 #[tokio::test]
554 async fn init_with_extra_account_metas() {
555 let program_id = Pubkey::new_unique();
556
557 let extra_meta3_literal_str = "seed_prefix";
558
559 let ix_account1 = AccountMeta::new(Pubkey::new_unique(), false);
560 let ix_account2 = AccountMeta::new(Pubkey::new_unique(), true);
561
562 let extra_meta1 = AccountMeta::new(Pubkey::new_unique(), false);
563 let extra_meta2 = AccountMeta::new(Pubkey::new_unique(), true);
564 let extra_meta3 = ExtraAccountMeta::new_with_seeds(
565 &[
566 Seed::Literal {
567 bytes: extra_meta3_literal_str.as_bytes().to_vec(),
568 },
569 Seed::InstructionData {
570 index: 1,
571 length: 1, },
573 Seed::AccountKey { index: 0 },
574 Seed::AccountKey { index: 2 },
575 ],
576 false,
577 true,
578 )
579 .unwrap();
580 let extra_meta4 = ExtraAccountMeta::new_with_pubkey_data(
581 &PubkeyData::InstructionData { index: 4 },
582 false,
583 true,
584 )
585 .unwrap();
586
587 let metas = [
588 ExtraAccountMeta::from(&extra_meta1),
589 ExtraAccountMeta::from(&extra_meta2),
590 extra_meta3,
591 extra_meta4,
592 ];
593
594 let mut ix_data = vec![1, 2, 3, 4];
595 let check_extra_meta4_pubkey = Pubkey::new_unique();
596 ix_data.extend_from_slice(check_extra_meta4_pubkey.as_ref());
597
598 let ix_accounts = vec![ix_account1.clone(), ix_account2.clone()];
599 let mut instruction = Instruction::new_with_bytes(program_id, &ix_data, ix_accounts);
600
601 let account_size = ExtraAccountMetaList::size_of(metas.len()).unwrap();
602 let mut buffer = vec![0; account_size];
603
604 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &metas).unwrap();
605
606 let mock_rpc = MockRpc::setup(&[]);
607
608 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
609 &mut instruction,
610 |pubkey| mock_rpc.get_account_data(pubkey),
611 &buffer,
612 )
613 .await
614 .unwrap();
615
616 let check_extra_meta3_u8_arg = ix_data[1];
617 let check_extra_meta3_pubkey = Pubkey::find_program_address(
618 &[
619 extra_meta3_literal_str.as_bytes(),
620 &[check_extra_meta3_u8_arg],
621 ix_account1.pubkey.as_ref(),
622 extra_meta1.pubkey.as_ref(),
623 ],
624 &program_id,
625 )
626 .0;
627 let check_metas = [
628 ix_account1, ix_account2, de_escalate_signer(extra_meta1),
631 de_escalate_signer(extra_meta2),
632 AccountMeta::new(check_extra_meta3_pubkey, false),
633 AccountMeta::new(check_extra_meta4_pubkey, false),
634 ];
635
636 assert_eq!(
637 instruction.accounts.get(4).unwrap().pubkey,
638 check_extra_meta3_pubkey,
639 );
640 assert_eq!(
641 instruction.accounts.get(5).unwrap().pubkey,
642 check_extra_meta4_pubkey,
643 );
644 assert_eq!(instruction.accounts, check_metas,);
645 }
646
647 #[tokio::test]
648 async fn init_multiple() {
649 let extra_meta5_literal_str = "seed_prefix";
650 let extra_meta5_literal_u32 = 4u32;
651 let other_meta2_literal_str = "other_seed_prefix";
652
653 let extra_meta1 = AccountMeta::new(Pubkey::new_unique(), false);
654 let extra_meta2 = AccountMeta::new(Pubkey::new_unique(), true);
655 let extra_meta3 = AccountMeta::new_readonly(Pubkey::new_unique(), true);
656 let extra_meta4 = AccountMeta::new_readonly(Pubkey::new_unique(), false);
657 let extra_meta5 = ExtraAccountMeta::new_with_seeds(
658 &[
659 Seed::Literal {
660 bytes: extra_meta5_literal_str.as_bytes().to_vec(),
661 },
662 Seed::Literal {
663 bytes: extra_meta5_literal_u32.to_le_bytes().to_vec(),
664 },
665 Seed::InstructionData {
666 index: 5,
667 length: 1, },
669 Seed::AccountKey { index: 2 },
670 ],
671 false,
672 true,
673 )
674 .unwrap();
675 let extra_meta6 = ExtraAccountMeta::new_with_pubkey_data(
676 &PubkeyData::InstructionData { index: 8 },
677 false,
678 true,
679 )
680 .unwrap();
681
682 let other_meta1 = AccountMeta::new(Pubkey::new_unique(), false);
683 let other_meta2 = ExtraAccountMeta::new_with_seeds(
684 &[
685 Seed::Literal {
686 bytes: other_meta2_literal_str.as_bytes().to_vec(),
687 },
688 Seed::InstructionData {
689 index: 1,
690 length: 4, },
692 Seed::AccountKey { index: 0 },
693 ],
694 false,
695 true,
696 )
697 .unwrap();
698 let other_meta3 = ExtraAccountMeta::new_with_pubkey_data(
699 &PubkeyData::InstructionData { index: 7 },
700 false,
701 true,
702 )
703 .unwrap();
704
705 let metas = [
706 ExtraAccountMeta::from(&extra_meta1),
707 ExtraAccountMeta::from(&extra_meta2),
708 ExtraAccountMeta::from(&extra_meta3),
709 ExtraAccountMeta::from(&extra_meta4),
710 extra_meta5,
711 extra_meta6,
712 ];
713 let other_metas = [
714 ExtraAccountMeta::from(&other_meta1),
715 other_meta2,
716 other_meta3,
717 ];
718
719 let account_size = ExtraAccountMetaList::size_of(metas.len()).unwrap()
720 + ExtraAccountMetaList::size_of(other_metas.len()).unwrap();
721 let mut buffer = vec![0; account_size];
722
723 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &metas).unwrap();
724 ExtraAccountMetaList::init::<TestOtherInstruction>(&mut buffer, &other_metas).unwrap();
725
726 let mock_rpc = MockRpc::setup(&[]);
727
728 let program_id = Pubkey::new_unique();
729
730 let mut ix_data = vec![0, 0, 0, 0, 0, 7, 0, 0];
731 let check_extra_meta6_pubkey = Pubkey::new_unique();
732 ix_data.extend_from_slice(check_extra_meta6_pubkey.as_ref());
733
734 let ix_accounts = vec![];
735
736 let mut instruction = Instruction::new_with_bytes(program_id, &ix_data, ix_accounts);
737 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
738 &mut instruction,
739 |pubkey| mock_rpc.get_account_data(pubkey),
740 &buffer,
741 )
742 .await
743 .unwrap();
744
745 let check_extra_meta5_u8_arg = ix_data[5];
746 let check_extra_meta5_pubkey = Pubkey::find_program_address(
747 &[
748 extra_meta5_literal_str.as_bytes(),
749 extra_meta5_literal_u32.to_le_bytes().as_ref(),
750 &[check_extra_meta5_u8_arg],
751 extra_meta3.pubkey.as_ref(),
752 ],
753 &program_id,
754 )
755 .0;
756 let check_metas = [
757 de_escalate_signer(extra_meta1),
758 de_escalate_signer(extra_meta2),
759 de_escalate_signer(extra_meta3),
760 de_escalate_signer(extra_meta4),
761 AccountMeta::new(check_extra_meta5_pubkey, false),
762 AccountMeta::new(check_extra_meta6_pubkey, false),
763 ];
764
765 assert_eq!(
766 instruction.accounts.get(4).unwrap().pubkey,
767 check_extra_meta5_pubkey,
768 );
769 assert_eq!(
770 instruction.accounts.get(5).unwrap().pubkey,
771 check_extra_meta6_pubkey,
772 );
773 assert_eq!(instruction.accounts, check_metas,);
774
775 let program_id = Pubkey::new_unique();
776
777 let ix_account1 = AccountMeta::new(Pubkey::new_unique(), false);
778 let ix_account2 = AccountMeta::new(Pubkey::new_unique(), true);
779 let ix_accounts = vec![ix_account1.clone(), ix_account2.clone()];
780
781 let mut ix_data = vec![0, 26, 0, 0, 0, 0, 0];
782 let check_other_meta3_pubkey = Pubkey::new_unique();
783 ix_data.extend_from_slice(check_other_meta3_pubkey.as_ref());
784
785 let mut instruction = Instruction::new_with_bytes(program_id, &ix_data, ix_accounts);
786 ExtraAccountMetaList::add_to_instruction::<TestOtherInstruction, _, _>(
787 &mut instruction,
788 |pubkey| mock_rpc.get_account_data(pubkey),
789 &buffer,
790 )
791 .await
792 .unwrap();
793
794 let check_other_meta2_u32_arg = u32::from_le_bytes(ix_data[1..5].try_into().unwrap());
795 let check_other_meta2_pubkey = Pubkey::find_program_address(
796 &[
797 other_meta2_literal_str.as_bytes(),
798 check_other_meta2_u32_arg.to_le_bytes().as_ref(),
799 ix_account1.pubkey.as_ref(),
800 ],
801 &program_id,
802 )
803 .0;
804 let check_other_metas = [
805 ix_account1,
806 ix_account2,
807 other_meta1,
808 AccountMeta::new(check_other_meta2_pubkey, false),
809 AccountMeta::new(check_other_meta3_pubkey, false),
810 ];
811
812 assert_eq!(
813 instruction.accounts.get(3).unwrap().pubkey,
814 check_other_meta2_pubkey,
815 );
816 assert_eq!(
817 instruction.accounts.get(4).unwrap().pubkey,
818 check_other_meta3_pubkey,
819 );
820 assert_eq!(instruction.accounts, check_other_metas,);
821 }
822
823 #[tokio::test]
824 async fn init_mixed() {
825 let extra_meta5_literal_str = "seed_prefix";
826 let extra_meta6_literal_u64 = 28u64;
827
828 let pubkey1 = Pubkey::new_unique();
829 let mut lamports1 = 0;
830 let mut data1 = [];
831 let pubkey2 = Pubkey::new_unique();
832 let mut lamports2 = 0;
833 let mut data2 = [];
834 let pubkey3 = Pubkey::new_unique();
835 let mut lamports3 = 0;
836 let mut data3 = [];
837 let owner = Pubkey::new_unique();
838 let account_infos = [
839 AccountInfo::new(
840 &pubkey1,
841 false,
842 true,
843 &mut lamports1,
844 &mut data1,
845 &owner,
846 false,
847 ),
848 AccountInfo::new(
849 &pubkey2,
850 true,
851 false,
852 &mut lamports2,
853 &mut data2,
854 &owner,
855 false,
856 ),
857 AccountInfo::new(
858 &pubkey3,
859 false,
860 false,
861 &mut lamports3,
862 &mut data3,
863 &owner,
864 false,
865 ),
866 ];
867
868 let extra_meta1 = AccountMeta::new(Pubkey::new_unique(), false);
869 let extra_meta2 = AccountMeta::new(Pubkey::new_unique(), true);
870 let extra_meta3 = AccountMeta::new_readonly(Pubkey::new_unique(), true);
871 let extra_meta4 = AccountMeta::new_readonly(Pubkey::new_unique(), false);
872 let extra_meta5 = ExtraAccountMeta::new_with_seeds(
873 &[
874 Seed::Literal {
875 bytes: extra_meta5_literal_str.as_bytes().to_vec(),
876 },
877 Seed::InstructionData {
878 index: 1,
879 length: 8, },
881 Seed::InstructionData {
882 index: 9,
883 length: 32, },
885 Seed::AccountKey { index: 2 },
886 ],
887 false,
888 true,
889 )
890 .unwrap();
891 let extra_meta6 = ExtraAccountMeta::new_with_seeds(
892 &[
893 Seed::Literal {
894 bytes: extra_meta6_literal_u64.to_le_bytes().to_vec(),
895 },
896 Seed::AccountKey { index: 1 },
897 Seed::AccountKey { index: 4 },
898 ],
899 false,
900 true,
901 )
902 .unwrap();
903 let extra_meta7 = ExtraAccountMeta::new_with_pubkey_data(
904 &PubkeyData::InstructionData { index: 41 }, false,
906 true,
907 )
908 .unwrap();
909
910 let test_ix_required_extra_accounts = account_infos
911 .iter()
912 .map(ExtraAccountMeta::from)
913 .collect::<Vec<_>>();
914 let test_other_ix_required_extra_accounts = [
915 ExtraAccountMeta::from(&extra_meta1),
916 ExtraAccountMeta::from(&extra_meta2),
917 ExtraAccountMeta::from(&extra_meta3),
918 ExtraAccountMeta::from(&extra_meta4),
919 extra_meta5,
920 extra_meta6,
921 extra_meta7,
922 ];
923
924 let account_size = ExtraAccountMetaList::size_of(test_ix_required_extra_accounts.len())
925 .unwrap()
926 + ExtraAccountMetaList::size_of(test_other_ix_required_extra_accounts.len()).unwrap();
927 let mut buffer = vec![0; account_size];
928
929 ExtraAccountMetaList::init::<TestInstruction>(
930 &mut buffer,
931 &test_ix_required_extra_accounts,
932 )
933 .unwrap();
934 ExtraAccountMetaList::init::<TestOtherInstruction>(
935 &mut buffer,
936 &test_other_ix_required_extra_accounts,
937 )
938 .unwrap();
939
940 let mock_rpc = MockRpc::setup(&account_infos);
941
942 let program_id = Pubkey::new_unique();
943 let mut instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
944 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
945 &mut instruction,
946 |pubkey| mock_rpc.get_account_data(pubkey),
947 &buffer,
948 )
949 .await
950 .unwrap();
951
952 let test_ix_check_metas = account_infos
953 .iter()
954 .map(account_info_to_meta_non_signer)
955 .collect::<Vec<_>>();
956 assert_eq!(instruction.accounts, test_ix_check_metas,);
957
958 let program_id = Pubkey::new_unique();
959
960 let instruction_u8array_arg = [1, 2, 3, 4, 5, 6, 7, 8];
961 let instruction_pubkey_arg = Pubkey::new_unique();
962 let instruction_key_data_pubkey_arg = Pubkey::new_unique();
963
964 let mut instruction_data = vec![0];
965 instruction_data.extend_from_slice(&instruction_u8array_arg);
966 instruction_data.extend_from_slice(instruction_pubkey_arg.as_ref());
967 instruction_data.extend_from_slice(instruction_key_data_pubkey_arg.as_ref());
968
969 let mut instruction = Instruction::new_with_bytes(program_id, &instruction_data, vec![]);
970 ExtraAccountMetaList::add_to_instruction::<TestOtherInstruction, _, _>(
971 &mut instruction,
972 |pubkey| mock_rpc.get_account_data(pubkey),
973 &buffer,
974 )
975 .await
976 .unwrap();
977
978 let check_extra_meta5_pubkey = Pubkey::find_program_address(
979 &[
980 extra_meta5_literal_str.as_bytes(),
981 &instruction_u8array_arg,
982 instruction_pubkey_arg.as_ref(),
983 extra_meta3.pubkey.as_ref(),
984 ],
985 &program_id,
986 )
987 .0;
988
989 let check_extra_meta6_pubkey = Pubkey::find_program_address(
990 &[
991 extra_meta6_literal_u64.to_le_bytes().as_ref(),
992 extra_meta2.pubkey.as_ref(),
993 check_extra_meta5_pubkey.as_ref(), ],
995 &program_id,
996 )
997 .0;
998
999 let test_other_ix_check_metas = vec![
1000 de_escalate_signer(extra_meta1),
1001 de_escalate_signer(extra_meta2),
1002 de_escalate_signer(extra_meta3),
1003 de_escalate_signer(extra_meta4),
1004 AccountMeta::new(check_extra_meta5_pubkey, false),
1005 AccountMeta::new(check_extra_meta6_pubkey, false),
1006 AccountMeta::new(instruction_key_data_pubkey_arg, false),
1007 ];
1008
1009 assert_eq!(
1010 instruction.accounts.get(4).unwrap().pubkey,
1011 check_extra_meta5_pubkey,
1012 );
1013 assert_eq!(
1014 instruction.accounts.get(5).unwrap().pubkey,
1015 check_extra_meta6_pubkey,
1016 );
1017 assert_eq!(
1018 instruction.accounts.get(6).unwrap().pubkey,
1019 instruction_key_data_pubkey_arg,
1020 );
1021 assert_eq!(instruction.accounts, test_other_ix_check_metas,);
1022 }
1023
1024 #[tokio::test]
1025 async fn cpi_instruction() {
1026 let program_id = Pubkey::new_unique();
1032 let owner = Pubkey::new_unique();
1033
1034 let required_pda1_literal_string = "required_pda1";
1036 let required_pda2_literal_u32 = 4u32;
1037 let required_key_data_instruction_data = Pubkey::new_unique();
1038
1039 let instruction_u8array_arg = [1, 2, 3, 4, 5, 6, 7, 8];
1044 let instruction_u64_arg = 208u64;
1045 let mut instruction_data = vec![0];
1046 instruction_data.extend_from_slice(&instruction_u8array_arg);
1047 instruction_data.extend_from_slice(instruction_u64_arg.to_le_bytes().as_ref());
1048 instruction_data.extend_from_slice(required_key_data_instruction_data.as_ref());
1049
1050 let ix_accounts = vec![
1052 AccountMeta::new(Pubkey::new_unique(), false),
1053 AccountMeta::new(Pubkey::new_unique(), false),
1054 ];
1055
1056 let extra_meta1 = AccountMeta::new(Pubkey::new_unique(), false);
1058 let extra_meta2 = AccountMeta::new(Pubkey::new_unique(), true);
1059 let extra_meta3 = AccountMeta::new_readonly(Pubkey::new_unique(), false);
1060 let required_accounts = [
1061 ExtraAccountMeta::from(&extra_meta1),
1062 ExtraAccountMeta::from(&extra_meta2),
1063 ExtraAccountMeta::from(&extra_meta3),
1064 ExtraAccountMeta::new_with_seeds(
1065 &[
1066 Seed::Literal {
1067 bytes: required_pda1_literal_string.as_bytes().to_vec(),
1068 },
1069 Seed::InstructionData {
1070 index: 1,
1071 length: 8, },
1073 Seed::AccountKey { index: 1 },
1074 ],
1075 false,
1076 true,
1077 )
1078 .unwrap(),
1079 ExtraAccountMeta::new_with_seeds(
1080 &[
1081 Seed::Literal {
1082 bytes: required_pda2_literal_u32.to_le_bytes().to_vec(),
1083 },
1084 Seed::InstructionData {
1085 index: 9,
1086 length: 8, },
1088 Seed::AccountKey { index: 5 },
1089 ],
1090 false,
1091 true,
1092 )
1093 .unwrap(),
1094 ExtraAccountMeta::new_with_seeds(
1095 &[
1096 Seed::InstructionData {
1097 index: 0,
1098 length: 1, },
1100 Seed::AccountData {
1101 account_index: 2,
1102 data_index: 0,
1103 length: 8,
1104 },
1105 ],
1106 false,
1107 true,
1108 )
1109 .unwrap(),
1110 ExtraAccountMeta::new_with_seeds(
1111 &[
1112 Seed::AccountData {
1113 account_index: 5,
1114 data_index: 4,
1115 length: 4,
1116 }, ],
1118 false,
1119 true,
1120 )
1121 .unwrap(),
1122 ExtraAccountMeta::new_with_pubkey_data(
1123 &PubkeyData::InstructionData { index: 17 },
1124 false,
1125 true,
1126 )
1127 .unwrap(),
1128 ExtraAccountMeta::new_with_pubkey_data(
1129 &PubkeyData::AccountData {
1130 account_index: 6,
1131 data_index: 0,
1132 },
1133 false,
1134 true,
1135 )
1136 .unwrap(),
1137 ExtraAccountMeta::new_with_pubkey_data(
1138 &PubkeyData::AccountData {
1139 account_index: 7,
1140 data_index: 8,
1141 },
1142 false,
1143 true,
1144 )
1145 .unwrap(),
1146 ];
1147
1148 let check_required_pda1_pubkey = Pubkey::find_program_address(
1156 &[
1157 required_pda1_literal_string.as_bytes(),
1158 &instruction_u8array_arg,
1159 ix_accounts.get(1).unwrap().pubkey.as_ref(), ],
1161 &program_id,
1162 )
1163 .0;
1164 let check_required_pda2_pubkey = Pubkey::find_program_address(
1165 &[
1166 required_pda2_literal_u32.to_le_bytes().as_ref(),
1167 instruction_u64_arg.to_le_bytes().as_ref(),
1168 check_required_pda1_pubkey.as_ref(), ],
1170 &program_id,
1171 )
1172 .0;
1173 let check_required_pda3_pubkey = Pubkey::find_program_address(
1174 &[
1175 &[0], &[8; 8], ],
1178 &program_id,
1179 )
1180 .0;
1181 let check_required_pda4_pubkey = Pubkey::find_program_address(
1182 &[
1183 &[7; 4], ],
1186 &program_id,
1187 )
1188 .0;
1189 let check_key_data1_pubkey = required_key_data_instruction_data;
1190 let check_key_data2_pubkey = Pubkey::new_from_array([8; 32]);
1191 let check_key_data3_pubkey = Pubkey::new_from_array([9; 32]);
1192
1193 let pubkey_ix_1 = ix_accounts.first().unwrap().pubkey;
1195 let mut lamports_ix_1 = 0;
1196 let mut data_ix_1 = [];
1197 let pubkey_ix_2 = ix_accounts.get(1).unwrap().pubkey;
1198 let mut lamports_ix_2 = 0;
1199 let mut data_ix_2 = [];
1200
1201 let mut lamports1 = 0;
1203 let mut data1 = [8; 12];
1204 let mut lamports2 = 0;
1205 let mut data2 = [];
1206 let mut lamports3 = 0;
1207 let mut data3 = [];
1208 let mut lamports_pda1 = 0;
1209 let mut data_pda1 = [7; 12];
1210 let mut lamports_pda2 = 0;
1211 let mut data_pda2 = [8; 32];
1212 let mut lamports_pda3 = 0;
1213 let mut data_pda3 = [0; 40];
1214 data_pda3[8..].copy_from_slice(&[9; 32]); let mut lamports_pda4 = 0;
1216 let mut data_pda4 = [];
1217 let mut data_key_data1 = [];
1218 let mut lamports_key_data1 = 0;
1219 let mut data_key_data2 = [];
1220 let mut lamports_key_data2 = 0;
1221 let mut data_key_data3 = [];
1222 let mut lamports_key_data3 = 0;
1223
1224 let pubkey_arb_1 = Pubkey::new_unique();
1226 let mut lamports_arb_1 = 0;
1227 let mut data_arb_1 = [];
1228 let pubkey_arb_2 = Pubkey::new_unique();
1229 let mut lamports_arb_2 = 0;
1230 let mut data_arb_2 = [];
1231
1232 let all_account_infos = [
1233 AccountInfo::new(
1234 &pubkey_ix_1,
1235 ix_accounts.first().unwrap().is_signer,
1236 ix_accounts.first().unwrap().is_writable,
1237 &mut lamports_ix_1,
1238 &mut data_ix_1,
1239 &owner,
1240 false,
1241 ),
1242 AccountInfo::new(
1243 &pubkey_ix_2,
1244 ix_accounts.get(1).unwrap().is_signer,
1245 ix_accounts.get(1).unwrap().is_writable,
1246 &mut lamports_ix_2,
1247 &mut data_ix_2,
1248 &owner,
1249 false,
1250 ),
1251 AccountInfo::new(
1252 &extra_meta1.pubkey,
1253 required_accounts.first().unwrap().is_signer.into(),
1254 required_accounts.first().unwrap().is_writable.into(),
1255 &mut lamports1,
1256 &mut data1,
1257 &owner,
1258 false,
1259 ),
1260 AccountInfo::new(
1261 &extra_meta2.pubkey,
1262 required_accounts.get(1).unwrap().is_signer.into(),
1263 required_accounts.get(1).unwrap().is_writable.into(),
1264 &mut lamports2,
1265 &mut data2,
1266 &owner,
1267 false,
1268 ),
1269 AccountInfo::new(
1270 &extra_meta3.pubkey,
1271 required_accounts.get(2).unwrap().is_signer.into(),
1272 required_accounts.get(2).unwrap().is_writable.into(),
1273 &mut lamports3,
1274 &mut data3,
1275 &owner,
1276 false,
1277 ),
1278 AccountInfo::new(
1279 &check_required_pda1_pubkey,
1280 required_accounts.get(3).unwrap().is_signer.into(),
1281 required_accounts.get(3).unwrap().is_writable.into(),
1282 &mut lamports_pda1,
1283 &mut data_pda1,
1284 &owner,
1285 false,
1286 ),
1287 AccountInfo::new(
1288 &check_required_pda2_pubkey,
1289 required_accounts.get(4).unwrap().is_signer.into(),
1290 required_accounts.get(4).unwrap().is_writable.into(),
1291 &mut lamports_pda2,
1292 &mut data_pda2,
1293 &owner,
1294 false,
1295 ),
1296 AccountInfo::new(
1297 &check_required_pda3_pubkey,
1298 required_accounts.get(5).unwrap().is_signer.into(),
1299 required_accounts.get(5).unwrap().is_writable.into(),
1300 &mut lamports_pda3,
1301 &mut data_pda3,
1302 &owner,
1303 false,
1304 ),
1305 AccountInfo::new(
1306 &check_required_pda4_pubkey,
1307 required_accounts.get(6).unwrap().is_signer.into(),
1308 required_accounts.get(6).unwrap().is_writable.into(),
1309 &mut lamports_pda4,
1310 &mut data_pda4,
1311 &owner,
1312 false,
1313 ),
1314 AccountInfo::new(
1315 &check_key_data1_pubkey,
1316 required_accounts.get(7).unwrap().is_signer.into(),
1317 required_accounts.get(7).unwrap().is_writable.into(),
1318 &mut lamports_key_data1,
1319 &mut data_key_data1,
1320 &owner,
1321 false,
1322 ),
1323 AccountInfo::new(
1324 &check_key_data2_pubkey,
1325 required_accounts.get(8).unwrap().is_signer.into(),
1326 required_accounts.get(8).unwrap().is_writable.into(),
1327 &mut lamports_key_data2,
1328 &mut data_key_data2,
1329 &owner,
1330 false,
1331 ),
1332 AccountInfo::new(
1333 &check_key_data3_pubkey,
1334 required_accounts.get(9).unwrap().is_signer.into(),
1335 required_accounts.get(9).unwrap().is_writable.into(),
1336 &mut lamports_key_data3,
1337 &mut data_key_data3,
1338 &owner,
1339 false,
1340 ),
1341 AccountInfo::new(
1342 &pubkey_arb_1,
1343 false,
1344 true,
1345 &mut lamports_arb_1,
1346 &mut data_arb_1,
1347 &owner,
1348 false,
1349 ),
1350 AccountInfo::new(
1351 &pubkey_arb_2,
1352 false,
1353 true,
1354 &mut lamports_arb_2,
1355 &mut data_arb_2,
1356 &owner,
1357 false,
1358 ),
1359 ];
1360
1361 let rpc_account_infos = all_account_infos.clone();
1364 let mock_rpc = MockRpc::setup(&rpc_account_infos);
1365
1366 let account_size = ExtraAccountMetaList::size_of(required_accounts.len()).unwrap();
1367 let mut buffer = vec![0; account_size];
1368 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &required_accounts).unwrap();
1369
1370 let mut instruction =
1371 Instruction::new_with_bytes(program_id, &instruction_data, ix_accounts.clone());
1372 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
1373 &mut instruction,
1374 |pubkey| mock_rpc.get_account_data(pubkey),
1375 &buffer,
1376 )
1377 .await
1378 .unwrap();
1379
1380 let mut cpi_instruction =
1384 Instruction::new_with_bytes(program_id, &instruction_data, ix_accounts);
1385
1386 let mut cpi_account_infos =
1388 vec![all_account_infos[0].clone(), all_account_infos[1].clone()];
1389
1390 let mut messed_account_infos = all_account_infos.clone();
1392 messed_account_infos.swap(0, 4);
1393 messed_account_infos.swap(1, 2);
1394 messed_account_infos.swap(3, 4);
1395 messed_account_infos.swap(5, 6);
1396 messed_account_infos.swap(8, 7);
1397
1398 ExtraAccountMetaList::add_to_cpi_instruction::<TestInstruction>(
1400 &mut cpi_instruction,
1401 &mut cpi_account_infos,
1402 &buffer,
1403 &messed_account_infos,
1404 )
1405 .unwrap();
1406
1407 assert_eq!(cpi_instruction, instruction);
1409
1410 let check_account_infos = &all_account_infos[..12];
1417 assert_eq!(cpi_account_infos.len(), check_account_infos.len());
1418 for (a, b) in std::iter::zip(cpi_account_infos, check_account_infos) {
1419 assert_eq!(a.key, b.key);
1420 assert_eq!(a.is_signer, b.is_signer);
1421 assert_eq!(a.is_writable, b.is_writable);
1422 }
1423 }
1424
1425 async fn update_and_assert_metas(
1426 program_id: Pubkey,
1427 buffer: &mut Vec<u8>,
1428 updated_metas: &[ExtraAccountMeta],
1429 check_metas: &[AccountMeta],
1430 ) {
1431 let account_size = ExtraAccountMetaList::size_of(updated_metas.len()).unwrap();
1433 if account_size > buffer.len() {
1434 buffer.resize(account_size, 0);
1435 }
1436
1437 ExtraAccountMetaList::update::<TestInstruction>(buffer, updated_metas).unwrap();
1439
1440 let state = TlvStateBorrowed::unpack(buffer).unwrap();
1442 let unpacked_metas_pod =
1443 ExtraAccountMetaList::unpack_with_tlv_state::<TestInstruction>(&state).unwrap();
1444 assert_eq!(
1445 &*unpacked_metas_pod, updated_metas,
1446 "The ExtraAccountMetas in the buffer should match the expected ones."
1447 );
1448
1449 let mock_rpc = MockRpc::setup(&[]);
1450
1451 let mut instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
1452 ExtraAccountMetaList::add_to_instruction::<TestInstruction, _, _>(
1453 &mut instruction,
1454 |pubkey| mock_rpc.get_account_data(pubkey),
1455 buffer,
1456 )
1457 .await
1458 .unwrap();
1459
1460 assert_eq!(instruction.accounts, check_metas,);
1461 }
1462
1463 #[tokio::test]
1464 async fn update_extra_account_meta_list() {
1465 let program_id = Pubkey::new_unique();
1466
1467 let initial_metas = [
1469 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), false, true).unwrap(),
1470 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), true, false).unwrap(),
1471 ];
1472
1473 let initial_account_size = ExtraAccountMetaList::size_of(initial_metas.len()).unwrap();
1475 let mut buffer = vec![0; initial_account_size];
1476 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &initial_metas).unwrap();
1477
1478 let updated_metas_1 = [
1480 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), true, true).unwrap(),
1481 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), false, false).unwrap(),
1482 ];
1483 let check_metas_1 = updated_metas_1
1484 .iter()
1485 .map(|e| de_escalate_signer(AccountMeta::try_from(e).unwrap()))
1486 .collect::<Vec<_>>();
1487 update_and_assert_metas(program_id, &mut buffer, &updated_metas_1, &check_metas_1).await;
1488
1489 let updated_metas_2 = [
1491 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), true, true).unwrap(),
1492 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), false, false).unwrap(),
1493 ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), false, true).unwrap(),
1494 ];
1495 let check_metas_2 = updated_metas_2
1496 .iter()
1497 .map(|e| de_escalate_signer(AccountMeta::try_from(e).unwrap()))
1498 .collect::<Vec<_>>();
1499 update_and_assert_metas(program_id, &mut buffer, &updated_metas_2, &check_metas_2).await;
1500
1501 let updated_metas_3 =
1503 [ExtraAccountMeta::new_with_pubkey(&Pubkey::new_unique(), true, true).unwrap()];
1504 let check_metas_3 = updated_metas_3
1505 .iter()
1506 .map(|e| de_escalate_signer(AccountMeta::try_from(e).unwrap()))
1507 .collect::<Vec<_>>();
1508 update_and_assert_metas(program_id, &mut buffer, &updated_metas_3, &check_metas_3).await;
1509
1510 let seed_pubkey = Pubkey::new_unique();
1512 let updated_metas_4 = [
1513 ExtraAccountMeta::new_with_pubkey(&seed_pubkey, true, true).unwrap(),
1514 ExtraAccountMeta::new_with_seeds(
1515 &[
1516 Seed::Literal {
1517 bytes: b"seed-prefix".to_vec(),
1518 },
1519 Seed::AccountKey { index: 0 },
1520 ],
1521 false,
1522 true,
1523 )
1524 .unwrap(),
1525 ];
1526 let simple_pda = Pubkey::find_program_address(
1527 &[
1528 b"seed-prefix", seed_pubkey.as_ref(), ],
1531 &program_id,
1532 )
1533 .0;
1534 let check_metas_4 = [
1535 AccountMeta::new(seed_pubkey, false),
1536 AccountMeta::new(simple_pda, false),
1537 ];
1538
1539 update_and_assert_metas(program_id, &mut buffer, &updated_metas_4, &check_metas_4).await;
1540 }
1541
1542 #[test]
1543 fn check_account_infos_test() {
1544 let program_id = Pubkey::new_unique();
1545 let owner = Pubkey::new_unique();
1546
1547 let pubkey1 = Pubkey::new_unique();
1549 let pubkey2 = Pubkey::new_unique();
1550 let required_accounts = [
1551 ExtraAccountMeta::new_with_pubkey(&pubkey1, false, true).unwrap(),
1552 ExtraAccountMeta::new_with_pubkey(&pubkey2, false, false).unwrap(),
1553 ExtraAccountMeta::new_with_seeds(
1554 &[
1555 Seed::Literal {
1556 bytes: b"lit_seed".to_vec(),
1557 },
1558 Seed::InstructionData {
1559 index: 0,
1560 length: 4,
1561 },
1562 Seed::AccountKey { index: 0 },
1563 ],
1564 false,
1565 true,
1566 )
1567 .unwrap(),
1568 ExtraAccountMeta::new_with_pubkey_data(
1569 &PubkeyData::InstructionData { index: 8 },
1570 false,
1571 true,
1572 )
1573 .unwrap(),
1574 ];
1575
1576 let account_size = ExtraAccountMetaList::size_of(required_accounts.len()).unwrap();
1578 let mut buffer = vec![0; account_size];
1579 ExtraAccountMetaList::init::<TestInstruction>(&mut buffer, &required_accounts).unwrap();
1580
1581 let mut instruction_data = vec![0, 1, 2, 3, 4, 5, 6, 7];
1583 let key_data_pubkey = Pubkey::new_unique();
1584 instruction_data.extend_from_slice(key_data_pubkey.as_ref());
1585
1586 let pubkey_ix_1 = Pubkey::new_unique();
1589 let mut lamports_ix_1 = 0;
1590 let mut data_ix_1 = [];
1591 let pubkey_ix_2 = Pubkey::new_unique();
1592 let mut lamports_ix_2 = 0;
1593 let mut data_ix_2 = [];
1594 let mut lamports1 = 0;
1595 let mut data1 = [];
1596 let mut lamports2 = 0;
1597 let mut data2 = [];
1598 let mut lamports3 = 0;
1599 let mut data3 = [];
1600 let mut lamports4 = 0;
1601 let mut data4 = [];
1602 let pda = Pubkey::find_program_address(
1603 &[b"lit_seed", &instruction_data[..4], pubkey_ix_1.as_ref()],
1604 &program_id,
1605 )
1606 .0;
1607 let account_infos = [
1608 AccountInfo::new(
1610 &pubkey_ix_1,
1611 false,
1612 true,
1613 &mut lamports_ix_1,
1614 &mut data_ix_1,
1615 &owner,
1616 false,
1617 ),
1618 AccountInfo::new(
1620 &pubkey_ix_2,
1621 false,
1622 true,
1623 &mut lamports_ix_2,
1624 &mut data_ix_2,
1625 &owner,
1626 false,
1627 ),
1628 AccountInfo::new(
1630 &pubkey1,
1631 false,
1632 true,
1633 &mut lamports1,
1634 &mut data1,
1635 &owner,
1636 false,
1637 ),
1638 AccountInfo::new(
1640 &pubkey2,
1641 false,
1642 false,
1643 &mut lamports2,
1644 &mut data2,
1645 &owner,
1646 false,
1647 ),
1648 AccountInfo::new(&pda, false, true, &mut lamports3, &mut data3, &owner, false),
1650 AccountInfo::new(
1652 &key_data_pubkey,
1653 false,
1654 true,
1655 &mut lamports4,
1656 &mut data4,
1657 &owner,
1658 false,
1659 ),
1660 ];
1661
1662 let mut messed_account_infos = account_infos.clone().to_vec();
1664 messed_account_infos.swap(0, 2);
1665 messed_account_infos.swap(1, 4);
1666 messed_account_infos.swap(3, 2);
1667 messed_account_infos.swap(5, 4);
1668
1669 assert_eq!(
1671 ExtraAccountMetaList::check_account_infos::<TestInstruction>(
1672 &messed_account_infos,
1673 &instruction_data,
1674 &program_id,
1675 &buffer,
1676 )
1677 .unwrap_err(),
1678 AccountResolutionError::IncorrectAccount.into(),
1679 );
1680
1681 assert_eq!(
1683 ExtraAccountMetaList::check_account_infos::<TestInstruction>(
1684 &account_infos,
1685 &instruction_data,
1686 &program_id,
1687 &buffer,
1688 ),
1689 Ok(()),
1690 );
1691 }
1692}