1use {
4 crate::ConfigKeys,
5 bincode::deserialize,
6 solana_program_runtime::{ic_msg, invoke_context::InvokeContext},
7 solana_sdk::{
8 feature_set, instruction::InstructionError, program_utils::limited_deserialize,
9 pubkey::Pubkey,
10 },
11 std::collections::BTreeSet,
12};
13
14pub fn process_instruction(
15 _first_instruction_account: usize,
16 invoke_context: &mut InvokeContext,
17) -> Result<(), InstructionError> {
18 let transaction_context = &invoke_context.transaction_context;
19 let instruction_context = transaction_context.get_current_instruction_context()?;
20 let data = instruction_context.get_instruction_data();
21
22 let key_list: ConfigKeys = limited_deserialize(data)?;
23 let config_account_key = transaction_context.get_key_of_account_at_index(
24 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
25 )?;
26 let config_account =
27 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
28 let is_config_account_signer = config_account.is_signer();
29 let current_data: ConfigKeys = {
30 if config_account.get_owner() != &crate::id() {
31 return Err(InstructionError::InvalidAccountOwner);
32 }
33
34 deserialize(config_account.get_data()).map_err(|err| {
35 ic_msg!(
36 invoke_context,
37 "Unable to deserialize config account: {}",
38 err
39 );
40 InstructionError::InvalidAccountData
41 })?
42 };
43 drop(config_account);
44
45 let current_signer_keys: Vec<Pubkey> = current_data
46 .keys
47 .iter()
48 .filter(|(_, is_signer)| *is_signer)
49 .map(|(pubkey, _)| *pubkey)
50 .collect();
51 if current_signer_keys.is_empty() {
52 if !is_config_account_signer {
55 return Err(InstructionError::MissingRequiredSignature);
56 }
57 }
58
59 let mut counter = 0;
60 for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
61 counter += 1;
62 if signer != config_account_key {
63 let signer_account = instruction_context
64 .try_borrow_instruction_account(transaction_context, counter)
65 .map_err(|_| {
66 ic_msg!(
67 invoke_context,
68 "account {:?} is not in account list",
69 signer,
70 );
71 InstructionError::MissingRequiredSignature
72 })?;
73 if !signer_account.is_signer() {
74 ic_msg!(
75 invoke_context,
76 "account {:?} signer_key().is_none()",
77 signer
78 );
79 return Err(InstructionError::MissingRequiredSignature);
80 }
81 if signer_account.get_key() != signer {
82 ic_msg!(
83 invoke_context,
84 "account[{:?}].signer_key() does not match Config data)",
85 counter + 1
86 );
87 return Err(InstructionError::MissingRequiredSignature);
88 }
89 if !current_data.keys.is_empty()
91 && !current_signer_keys.iter().any(|pubkey| pubkey == signer)
92 {
93 ic_msg!(
94 invoke_context,
95 "account {:?} is not in stored signer list",
96 signer
97 );
98 return Err(InstructionError::MissingRequiredSignature);
99 }
100 } else if !is_config_account_signer {
101 ic_msg!(invoke_context, "account[0].signer_key().is_none()");
102 return Err(InstructionError::MissingRequiredSignature);
103 }
104 }
105
106 if invoke_context
107 .feature_set
108 .is_active(&feature_set::dedupe_config_program_signers::id())
109 {
110 let total_new_keys = key_list.keys.len();
111 let unique_new_keys = key_list.keys.into_iter().collect::<BTreeSet<_>>();
112 if unique_new_keys.len() != total_new_keys {
113 ic_msg!(invoke_context, "new config contains duplicate keys");
114 return Err(InstructionError::InvalidArgument);
115 }
116 }
117
118 if current_signer_keys.len() > counter {
120 ic_msg!(
121 invoke_context,
122 "too few signers: {:?}; expected: {:?}",
123 counter,
124 current_signer_keys.len()
125 );
126 return Err(InstructionError::MissingRequiredSignature);
127 }
128
129 let mut config_account =
130 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
131 if config_account.get_data().len() < data.len() {
132 ic_msg!(invoke_context, "instruction data too large");
133 return Err(InstructionError::InvalidInstructionData);
134 }
135 config_account.get_data_mut()?[..data.len()].copy_from_slice(data);
136 Ok(())
137}
138
139#[cfg(test)]
140mod tests {
141 use {
142 super::*,
143 crate::{config_instruction, get_config_data, id, ConfigKeys, ConfigState},
144 bincode::serialized_size,
145 serde_derive::{Deserialize, Serialize},
146 solana_program_runtime::invoke_context::mock_process_instruction,
147 solana_sdk::{
148 account::{AccountSharedData, ReadableAccount},
149 instruction::AccountMeta,
150 pubkey::Pubkey,
151 signature::{Keypair, Signer},
152 system_instruction::SystemInstruction,
153 },
154 };
155
156 fn process_instruction(
157 instruction_data: &[u8],
158 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
159 instruction_accounts: Vec<AccountMeta>,
160 expected_result: Result<(), InstructionError>,
161 ) -> Vec<AccountSharedData> {
162 mock_process_instruction(
163 &id(),
164 Vec::new(),
165 instruction_data,
166 transaction_accounts,
167 instruction_accounts,
168 None,
169 None,
170 expected_result,
171 super::process_instruction,
172 )
173 }
174
175 #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
176 struct MyConfig {
177 pub item: u64,
178 }
179 impl Default for MyConfig {
180 fn default() -> Self {
181 Self { item: 123_456_789 }
182 }
183 }
184 impl MyConfig {
185 pub fn new(item: u64) -> Self {
186 Self { item }
187 }
188 pub fn deserialize(input: &[u8]) -> Option<Self> {
189 deserialize(input).ok()
190 }
191 }
192
193 impl ConfigState for MyConfig {
194 fn max_space() -> u64 {
195 serialized_size(&Self::default()).unwrap()
196 }
197 }
198
199 fn create_config_account(keys: Vec<(Pubkey, bool)>) -> (Keypair, AccountSharedData) {
200 let from_pubkey = Pubkey::new_unique();
201 let config_keypair = Keypair::new();
202 let config_pubkey = config_keypair.pubkey();
203 let instructions =
204 config_instruction::create_account::<MyConfig>(&from_pubkey, &config_pubkey, 1, keys);
205 let system_instruction = limited_deserialize(&instructions[0].data).unwrap();
206 let space = match system_instruction {
207 SystemInstruction::CreateAccount {
208 lamports: _,
209 space,
210 owner: _,
211 } => space,
212 _ => panic!("Not a CreateAccount system instruction"),
213 };
214 let config_account = AccountSharedData::new(0, space as usize, &id());
215 let accounts = process_instruction(
216 &instructions[1].data,
217 vec![(config_pubkey, config_account)],
218 vec![AccountMeta {
219 pubkey: config_pubkey,
220 is_signer: true,
221 is_writable: true,
222 }],
223 Ok(()),
224 );
225 (config_keypair, accounts[0].clone())
226 }
227
228 #[test]
229 fn test_process_create_ok() {
230 solana_logger::setup();
231 let (_, config_account) = create_config_account(vec![]);
232 assert_eq!(
233 Some(MyConfig::default()),
234 deserialize(get_config_data(config_account.data()).unwrap()).ok()
235 );
236 }
237
238 #[test]
239 fn test_process_store_ok() {
240 solana_logger::setup();
241 let keys = vec![];
242 let (config_keypair, config_account) = create_config_account(keys.clone());
243 let config_pubkey = config_keypair.pubkey();
244 let my_config = MyConfig::new(42);
245
246 let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
247 let accounts = process_instruction(
248 &instruction.data,
249 vec![(config_pubkey, config_account)],
250 vec![AccountMeta {
251 pubkey: config_pubkey,
252 is_signer: true,
253 is_writable: true,
254 }],
255 Ok(()),
256 );
257 assert_eq!(
258 Some(my_config),
259 deserialize(get_config_data(accounts[0].data()).unwrap()).ok()
260 );
261 }
262
263 #[test]
264 fn test_process_store_fail_instruction_data_too_large() {
265 solana_logger::setup();
266 let keys = vec![];
267 let (config_keypair, config_account) = create_config_account(keys.clone());
268 let config_pubkey = config_keypair.pubkey();
269 let my_config = MyConfig::new(42);
270
271 let mut instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
272 instruction.data = vec![0; 123]; process_instruction(
274 &instruction.data,
275 vec![(config_pubkey, config_account)],
276 vec![AccountMeta {
277 pubkey: config_pubkey,
278 is_signer: true,
279 is_writable: true,
280 }],
281 Err(InstructionError::InvalidInstructionData),
282 );
283 }
284
285 #[test]
286 fn test_process_store_fail_account0_not_signer() {
287 solana_logger::setup();
288 let keys = vec![];
289 let (config_keypair, config_account) = create_config_account(keys);
290 let config_pubkey = config_keypair.pubkey();
291 let my_config = MyConfig::new(42);
292
293 let mut instruction = config_instruction::store(&config_pubkey, true, vec![], &my_config);
294 instruction.accounts[0].is_signer = false; process_instruction(
296 &instruction.data,
297 vec![(config_pubkey, config_account)],
298 vec![AccountMeta {
299 pubkey: config_pubkey,
300 is_signer: false,
301 is_writable: true,
302 }],
303 Err(InstructionError::MissingRequiredSignature),
304 );
305 }
306
307 #[test]
308 fn test_process_store_with_additional_signers() {
309 solana_logger::setup();
310 let pubkey = Pubkey::new_unique();
311 let signer0_pubkey = Pubkey::new_unique();
312 let signer1_pubkey = Pubkey::new_unique();
313 let keys = vec![
314 (pubkey, false),
315 (signer0_pubkey, true),
316 (signer1_pubkey, true),
317 ];
318 let (config_keypair, config_account) = create_config_account(keys.clone());
319 let config_pubkey = config_keypair.pubkey();
320 let my_config = MyConfig::new(42);
321 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
322 let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
323
324 let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
325 let accounts = process_instruction(
326 &instruction.data,
327 vec![
328 (config_pubkey, config_account),
329 (signer0_pubkey, signer0_account),
330 (signer1_pubkey, signer1_account),
331 ],
332 vec![
333 AccountMeta {
334 pubkey: config_pubkey,
335 is_signer: true,
336 is_writable: true,
337 },
338 AccountMeta {
339 pubkey: signer0_pubkey,
340 is_signer: true,
341 is_writable: false,
342 },
343 AccountMeta {
344 pubkey: signer1_pubkey,
345 is_signer: true,
346 is_writable: false,
347 },
348 ],
349 Ok(()),
350 );
351 let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap();
352 assert_eq!(meta_data.keys, keys);
353 assert_eq!(
354 Some(my_config),
355 deserialize(get_config_data(accounts[0].data()).unwrap()).ok()
356 );
357 }
358
359 #[test]
360 fn test_process_store_without_config_signer() {
361 solana_logger::setup();
362 let pubkey = Pubkey::new_unique();
363 let signer0_pubkey = Pubkey::new_unique();
364 let keys = vec![(pubkey, false), (signer0_pubkey, true)];
365 let (config_keypair, _) = create_config_account(keys.clone());
366 let config_pubkey = config_keypair.pubkey();
367 let my_config = MyConfig::new(42);
368 let signer0_account = AccountSharedData::new(0, 0, &id());
369
370 let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
371 process_instruction(
372 &instruction.data,
373 vec![(signer0_pubkey, signer0_account)],
374 vec![AccountMeta {
375 pubkey: signer0_pubkey,
376 is_signer: true,
377 is_writable: false,
378 }],
379 Err(InstructionError::InvalidAccountData),
380 );
381 }
382
383 #[test]
384 fn test_process_store_with_bad_additional_signer() {
385 solana_logger::setup();
386 let signer0_pubkey = Pubkey::new_unique();
387 let signer1_pubkey = Pubkey::new_unique();
388 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
389 let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
390 let keys = vec![(signer0_pubkey, true)];
391 let (config_keypair, config_account) = create_config_account(keys.clone());
392 let config_pubkey = config_keypair.pubkey();
393 let my_config = MyConfig::new(42);
394
395 let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
397 process_instruction(
398 &instruction.data,
399 vec![
400 (config_pubkey, config_account.clone()),
401 (signer1_pubkey, signer1_account),
402 ],
403 vec![
404 AccountMeta {
405 pubkey: config_pubkey,
406 is_signer: true,
407 is_writable: true,
408 },
409 AccountMeta {
410 pubkey: signer1_pubkey,
411 is_signer: true,
412 is_writable: false,
413 },
414 ],
415 Err(InstructionError::MissingRequiredSignature),
416 );
417
418 process_instruction(
420 &instruction.data,
421 vec![
422 (config_pubkey, config_account),
423 (signer0_pubkey, signer0_account),
424 ],
425 vec![
426 AccountMeta {
427 pubkey: config_pubkey,
428 is_signer: true,
429 is_writable: true,
430 },
431 AccountMeta {
432 pubkey: signer0_pubkey,
433 is_signer: false,
434 is_writable: false,
435 },
436 ],
437 Err(InstructionError::MissingRequiredSignature),
438 );
439 }
440
441 #[test]
442 fn test_config_updates() {
443 solana_logger::setup();
444 let pubkey = Pubkey::new_unique();
445 let signer0_pubkey = Pubkey::new_unique();
446 let signer1_pubkey = Pubkey::new_unique();
447 let signer2_pubkey = Pubkey::new_unique();
448 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
449 let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
450 let signer2_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
451 let keys = vec![
452 (pubkey, false),
453 (signer0_pubkey, true),
454 (signer1_pubkey, true),
455 ];
456 let (config_keypair, config_account) = create_config_account(keys.clone());
457 let config_pubkey = config_keypair.pubkey();
458 let my_config = MyConfig::new(42);
459
460 let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
461 let accounts = process_instruction(
462 &instruction.data,
463 vec![
464 (config_pubkey, config_account),
465 (signer0_pubkey, signer0_account.clone()),
466 (signer1_pubkey, signer1_account.clone()),
467 ],
468 vec![
469 AccountMeta {
470 pubkey: config_pubkey,
471 is_signer: true,
472 is_writable: true,
473 },
474 AccountMeta {
475 pubkey: signer0_pubkey,
476 is_signer: true,
477 is_writable: false,
478 },
479 AccountMeta {
480 pubkey: signer1_pubkey,
481 is_signer: true,
482 is_writable: false,
483 },
484 ],
485 Ok(()),
486 );
487
488 let new_config = MyConfig::new(84);
490 let instruction =
491 config_instruction::store(&config_pubkey, false, keys.clone(), &new_config);
492 let accounts = process_instruction(
493 &instruction.data,
494 vec![
495 (config_pubkey, accounts[0].clone()),
496 (signer0_pubkey, signer0_account.clone()),
497 (signer1_pubkey, signer1_account.clone()),
498 ],
499 vec![
500 AccountMeta {
501 pubkey: config_pubkey,
502 is_signer: false,
503 is_writable: true,
504 },
505 AccountMeta {
506 pubkey: signer0_pubkey,
507 is_signer: true,
508 is_writable: false,
509 },
510 AccountMeta {
511 pubkey: signer1_pubkey,
512 is_signer: true,
513 is_writable: false,
514 },
515 ],
516 Ok(()),
517 );
518 let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap();
519 assert_eq!(meta_data.keys, keys);
520 assert_eq!(
521 new_config,
522 MyConfig::deserialize(get_config_data(accounts[0].data()).unwrap()).unwrap()
523 );
524
525 let keys = vec![(pubkey, false), (signer0_pubkey, true)];
527 let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
528 process_instruction(
529 &instruction.data,
530 vec![
531 (config_pubkey, accounts[0].clone()),
532 (signer0_pubkey, signer0_account.clone()),
533 (signer1_pubkey, signer1_account),
534 ],
535 vec![
536 AccountMeta {
537 pubkey: config_pubkey,
538 is_signer: false,
539 is_writable: true,
540 },
541 AccountMeta {
542 pubkey: signer0_pubkey,
543 is_signer: true,
544 is_writable: false,
545 },
546 AccountMeta {
547 pubkey: signer1_pubkey,
548 is_signer: false,
549 is_writable: false,
550 },
551 ],
552 Err(InstructionError::MissingRequiredSignature),
553 );
554
555 let keys = vec![
557 (pubkey, false),
558 (signer0_pubkey, true),
559 (signer2_pubkey, true),
560 ];
561 let instruction = config_instruction::store(&config_pubkey, false, keys, &my_config);
562 process_instruction(
563 &instruction.data,
564 vec![
565 (config_pubkey, accounts[0].clone()),
566 (signer0_pubkey, signer0_account),
567 (signer2_pubkey, signer2_account),
568 ],
569 vec![
570 AccountMeta {
571 pubkey: config_pubkey,
572 is_signer: false,
573 is_writable: true,
574 },
575 AccountMeta {
576 pubkey: signer0_pubkey,
577 is_signer: true,
578 is_writable: false,
579 },
580 AccountMeta {
581 pubkey: signer2_pubkey,
582 is_signer: true,
583 is_writable: false,
584 },
585 ],
586 Err(InstructionError::MissingRequiredSignature),
587 );
588 }
589
590 #[test]
591 fn test_config_initialize_contains_duplicates_fails() {
592 solana_logger::setup();
593 let config_address = Pubkey::new_unique();
594 let signer0_pubkey = Pubkey::new_unique();
595 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
596 let keys = vec![
597 (config_address, false),
598 (signer0_pubkey, true),
599 (signer0_pubkey, true),
600 ];
601 let (config_keypair, config_account) = create_config_account(keys.clone());
602 let config_pubkey = config_keypair.pubkey();
603 let my_config = MyConfig::new(42);
604
605 let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
607 process_instruction(
608 &instruction.data,
609 vec![
610 (config_pubkey, config_account),
611 (signer0_pubkey, signer0_account),
612 ],
613 vec![
614 AccountMeta {
615 pubkey: config_pubkey,
616 is_signer: true,
617 is_writable: true,
618 },
619 AccountMeta {
620 pubkey: signer0_pubkey,
621 is_signer: true,
622 is_writable: false,
623 },
624 AccountMeta {
625 pubkey: signer0_pubkey,
626 is_signer: true,
627 is_writable: false,
628 },
629 ],
630 Err(InstructionError::InvalidArgument),
631 );
632 }
633
634 #[test]
635 fn test_config_update_contains_duplicates_fails() {
636 solana_logger::setup();
637 let config_address = Pubkey::new_unique();
638 let signer0_pubkey = Pubkey::new_unique();
639 let signer1_pubkey = Pubkey::new_unique();
640 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
641 let signer1_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
642 let keys = vec![
643 (config_address, false),
644 (signer0_pubkey, true),
645 (signer1_pubkey, true),
646 ];
647 let (config_keypair, config_account) = create_config_account(keys.clone());
648 let config_pubkey = config_keypair.pubkey();
649 let my_config = MyConfig::new(42);
650
651 let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
652 let accounts = process_instruction(
653 &instruction.data,
654 vec![
655 (config_pubkey, config_account),
656 (signer0_pubkey, signer0_account.clone()),
657 (signer1_pubkey, signer1_account),
658 ],
659 vec![
660 AccountMeta {
661 pubkey: config_pubkey,
662 is_signer: true,
663 is_writable: true,
664 },
665 AccountMeta {
666 pubkey: signer0_pubkey,
667 is_signer: true,
668 is_writable: false,
669 },
670 AccountMeta {
671 pubkey: signer1_pubkey,
672 is_signer: true,
673 is_writable: false,
674 },
675 ],
676 Ok(()),
677 );
678
679 let new_config = MyConfig::new(84);
681 let dupe_keys = vec![
682 (config_address, false),
683 (signer0_pubkey, true),
684 (signer0_pubkey, true),
685 ];
686 let instruction = config_instruction::store(&config_pubkey, false, dupe_keys, &new_config);
687 process_instruction(
688 &instruction.data,
689 vec![
690 (config_pubkey, accounts[0].clone()),
691 (signer0_pubkey, signer0_account),
692 ],
693 vec![
694 AccountMeta {
695 pubkey: config_pubkey,
696 is_signer: true,
697 is_writable: true,
698 },
699 AccountMeta {
700 pubkey: signer0_pubkey,
701 is_signer: true,
702 is_writable: false,
703 },
704 AccountMeta {
705 pubkey: signer0_pubkey,
706 is_signer: true,
707 is_writable: false,
708 },
709 ],
710 Err(InstructionError::InvalidArgument),
711 );
712 }
713
714 #[test]
715 fn test_config_updates_requiring_config() {
716 solana_logger::setup();
717 let pubkey = Pubkey::new_unique();
718 let signer0_pubkey = Pubkey::new_unique();
719 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
720 let keys = vec![
721 (pubkey, false),
722 (signer0_pubkey, true),
723 (signer0_pubkey, true),
724 ]; let (config_keypair, config_account) = create_config_account(keys);
726 let config_pubkey = config_keypair.pubkey();
727 let my_config = MyConfig::new(42);
728 let keys = vec![
729 (pubkey, false),
730 (signer0_pubkey, true),
731 (config_keypair.pubkey(), true),
732 ];
733
734 let instruction = config_instruction::store(&config_pubkey, true, keys.clone(), &my_config);
735 let accounts = process_instruction(
736 &instruction.data,
737 vec![
738 (config_pubkey, config_account),
739 (signer0_pubkey, signer0_account.clone()),
740 ],
741 vec![
742 AccountMeta {
743 pubkey: config_pubkey,
744 is_signer: true,
745 is_writable: true,
746 },
747 AccountMeta {
748 pubkey: signer0_pubkey,
749 is_signer: true,
750 is_writable: false,
751 },
752 ],
753 Ok(()),
754 );
755
756 let new_config = MyConfig::new(84);
758 let instruction =
759 config_instruction::store(&config_pubkey, true, keys.clone(), &new_config);
760 let accounts = process_instruction(
761 &instruction.data,
762 vec![
763 (config_pubkey, accounts[0].clone()),
764 (signer0_pubkey, signer0_account),
765 ],
766 vec![
767 AccountMeta {
768 pubkey: config_pubkey,
769 is_signer: true,
770 is_writable: true,
771 },
772 AccountMeta {
773 pubkey: signer0_pubkey,
774 is_signer: true,
775 is_writable: false,
776 },
777 ],
778 Ok(()),
779 );
780 let meta_data: ConfigKeys = deserialize(accounts[0].data()).unwrap();
781 assert_eq!(meta_data.keys, keys);
782 assert_eq!(
783 new_config,
784 MyConfig::deserialize(get_config_data(accounts[0].data()).unwrap()).unwrap()
785 );
786
787 let keys = vec![(pubkey, false), (config_keypair.pubkey(), true)];
789 let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
790 process_instruction(
791 &instruction.data,
792 vec![(config_pubkey, accounts[0].clone())],
793 vec![AccountMeta {
794 pubkey: config_pubkey,
795 is_signer: true,
796 is_writable: true,
797 }],
798 Err(InstructionError::MissingRequiredSignature),
799 );
800 }
801
802 #[test]
803 fn test_config_initialize_no_panic() {
804 let from_pubkey = Pubkey::new_unique();
805 let config_pubkey = Pubkey::new_unique();
806 let (_, _config_account) = create_config_account(vec![]);
807 let instructions =
808 config_instruction::create_account::<MyConfig>(&from_pubkey, &config_pubkey, 1, vec![]);
809 process_instruction(
810 &instructions[1].data,
811 Vec::new(),
812 Vec::new(),
813 Err(InstructionError::NotEnoughAccountKeys),
814 );
815 }
816
817 #[test]
818 fn test_config_bad_owner() {
819 let from_pubkey = Pubkey::new_unique();
820 let config_pubkey = Pubkey::new_unique();
821 let new_config = MyConfig::new(84);
822 let signer0_pubkey = Pubkey::new_unique();
823 let signer0_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
824 let config_account = AccountSharedData::new(0, 0, &Pubkey::new_unique());
825 let (_, _config_account) = create_config_account(vec![]);
826 let keys = vec![
827 (from_pubkey, false),
828 (signer0_pubkey, true),
829 (config_pubkey, true),
830 ];
831
832 let instruction = config_instruction::store(&config_pubkey, true, keys, &new_config);
833 process_instruction(
834 &instruction.data,
835 vec![
836 (config_pubkey, config_account),
837 (signer0_pubkey, signer0_account),
838 ],
839 vec![
840 AccountMeta {
841 pubkey: config_pubkey,
842 is_signer: true,
843 is_writable: true,
844 },
845 AccountMeta {
846 pubkey: signer0_pubkey,
847 is_signer: true,
848 is_writable: false,
849 },
850 ],
851 Err(InstructionError::InvalidAccountOwner),
852 );
853 }
854}