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