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