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