1use std::collections::HashSet;
6
7use log::*;
8use rialo_s_bincode::limited_deserialize;
9use rialo_s_instruction::error::InstructionError;
10use rialo_s_log_collector::ic_msg;
11use rialo_s_nonce as nonce;
12use rialo_s_program_runtime::{
13 declare_process_instruction, invoke_context::InvokeContext,
14 sysvar_cache::get_sysvar_with_account_check,
15};
16use rialo_s_pubkey::Pubkey;
17use rialo_s_sdk_ids::system_program;
18use rialo_s_system_interface::{
19 error::SystemError, instruction::SystemInstruction, MAX_PERMITTED_DATA_LENGTH,
20};
21use rialo_s_transaction_context::{
22 BorrowedAccount, IndexOfAccount, InstructionContext, TransactionContext,
23};
24
25use crate::system_instruction::{
26 advance_nonce_account, authorize_nonce_account, initialize_nonce_account,
27 withdraw_nonce_account,
28};
29
30#[derive(PartialEq, Eq, Default, Debug)]
33struct Address {
34 address: Pubkey,
35 base: Option<Pubkey>,
36}
37
38impl Address {
39 fn is_signer(&self, signers: &HashSet<Pubkey>) -> bool {
40 if let Some(base) = self.base {
41 signers.contains(&base)
42 } else {
43 signers.contains(&self.address)
44 }
45 }
46 fn create(
47 address: &Pubkey,
48 with_seed: Option<(&Pubkey, &str, &Pubkey)>,
49 invoke_context: &InvokeContext<'_>,
50 ) -> Result<Self, InstructionError> {
51 let base = if let Some((base, seed, owner)) = with_seed {
52 let address_with_seed = Pubkey::create_with_seed(base, seed, owner)?;
53 if *address != address_with_seed {
55 ic_msg!(
56 invoke_context,
57 "Create: address {} does not match derived address {}",
58 address,
59 address_with_seed
60 );
61 return Err(SystemError::AddressWithSeedMismatch.into());
62 }
63 Some(*base)
64 } else {
65 None
66 };
67
68 Ok(Self {
69 address: *address,
70 base,
71 })
72 }
73}
74
75fn allocate(
76 account: &mut BorrowedAccount<'_>,
77 address: &Address,
78 space: u64,
79 signers: &HashSet<Pubkey>,
80 invoke_context: &InvokeContext<'_>,
81) -> Result<(), InstructionError> {
82 if !address.is_signer(signers) {
83 ic_msg!(
84 invoke_context,
85 "Allocate: 'to' account {:?} must sign",
86 address
87 );
88 return Err(InstructionError::MissingRequiredSignature);
89 }
90
91 if !account.get_data().is_empty() || !system_program::check_id(account.get_owner()) {
94 ic_msg!(
95 invoke_context,
96 "Allocate: account {:?} already in use",
97 address
98 );
99 return Err(SystemError::AccountAlreadyInUse.into());
100 }
101
102 if space > MAX_PERMITTED_DATA_LENGTH {
103 ic_msg!(
104 invoke_context,
105 "Allocate: requested {}, max allowed {}",
106 space,
107 MAX_PERMITTED_DATA_LENGTH
108 );
109 return Err(SystemError::InvalidAccountDataLength.into());
110 }
111
112 account.set_data_length(space as usize)?;
113
114 Ok(())
115}
116
117fn assign(
118 account: &mut BorrowedAccount<'_>,
119 address: &Address,
120 owner: &Pubkey,
121 signers: &HashSet<Pubkey>,
122 invoke_context: &InvokeContext<'_>,
123) -> Result<(), InstructionError> {
124 if account.get_owner() == owner {
126 return Ok(());
127 }
128
129 if !address.is_signer(signers) {
130 ic_msg!(invoke_context, "Assign: account {:?} must sign", address);
131 return Err(InstructionError::MissingRequiredSignature);
132 }
133
134 account.set_owner(&owner.to_bytes())
135}
136
137fn allocate_and_assign(
138 to: &mut BorrowedAccount<'_>,
139 to_address: &Address,
140 space: u64,
141 owner: &Pubkey,
142 signers: &HashSet<Pubkey>,
143 invoke_context: &InvokeContext<'_>,
144) -> Result<(), InstructionError> {
145 allocate(to, to_address, space, signers, invoke_context)?;
146 assign(to, to_address, owner, signers, invoke_context)
147}
148
149#[allow(clippy::too_many_arguments)]
150fn create_account(
151 from_account_index: IndexOfAccount,
152 to_account_index: IndexOfAccount,
153 to_address: &Address,
154 kelvins: u64,
155 space: u64,
156 owner: &Pubkey,
157 signers: &HashSet<Pubkey>,
158 invoke_context: &InvokeContext<'_>,
159 transaction_context: &TransactionContext,
160 instruction_context: &InstructionContext,
161) -> Result<(), InstructionError> {
162 {
164 let mut to = instruction_context
165 .try_borrow_instruction_account(transaction_context, to_account_index)?;
166 if to.get_kelvins() > 0 {
167 ic_msg!(
168 invoke_context,
169 "Create Account: account {:?} already in use",
170 to_address
171 );
172 return Err(SystemError::AccountAlreadyInUse.into());
173 }
174
175 allocate_and_assign(&mut to, to_address, space, owner, signers, invoke_context)?;
176 }
177 transfer(
178 from_account_index,
179 to_account_index,
180 kelvins,
181 invoke_context,
182 transaction_context,
183 instruction_context,
184 )
185}
186
187fn transfer_verified(
188 from_account_index: IndexOfAccount,
189 to_account_index: IndexOfAccount,
190 kelvins: u64,
191 invoke_context: &InvokeContext<'_>,
192 transaction_context: &TransactionContext,
193 instruction_context: &InstructionContext,
194) -> Result<(), InstructionError> {
195 let mut from = instruction_context
196 .try_borrow_instruction_account(transaction_context, from_account_index)?;
197 if !from.get_data().is_empty() {
198 ic_msg!(invoke_context, "Transfer: `from` must not carry data");
199 return Err(InstructionError::InvalidArgument);
200 }
201 if kelvins > from.get_kelvins() {
202 ic_msg!(
203 invoke_context,
204 "Transfer: insufficient kelvins {}, need {}",
205 from.get_kelvins(),
206 kelvins
207 );
208 return Err(SystemError::ResultWithNegativeKelvins.into());
209 }
210
211 from.checked_sub_kelvins(kelvins)?;
212 drop(from);
213 let mut to = instruction_context
214 .try_borrow_instruction_account(transaction_context, to_account_index)?;
215 to.checked_add_kelvins(kelvins)?;
216 Ok(())
217}
218
219fn transfer(
220 from_account_index: IndexOfAccount,
221 to_account_index: IndexOfAccount,
222 kelvins: u64,
223 invoke_context: &InvokeContext<'_>,
224 transaction_context: &TransactionContext,
225 instruction_context: &InstructionContext,
226) -> Result<(), InstructionError> {
227 if !instruction_context.is_instruction_account_signer(from_account_index)? {
228 ic_msg!(
229 invoke_context,
230 "Transfer: `from` account {} must sign",
231 transaction_context.get_key_of_account_at_index(
232 instruction_context
233 .get_index_of_instruction_account_in_transaction(from_account_index)?,
234 )?,
235 );
236 return Err(InstructionError::MissingRequiredSignature);
237 }
238
239 transfer_verified(
240 from_account_index,
241 to_account_index,
242 kelvins,
243 invoke_context,
244 transaction_context,
245 instruction_context,
246 )
247}
248
249fn transfer_with_seed(
250 from_account_index: IndexOfAccount,
251 from_base_account_index: IndexOfAccount,
252 from_seed: &str,
253 from_owner: &Pubkey,
254 to_account_index: IndexOfAccount,
255 kelvins: u64,
256 invoke_context: &InvokeContext<'_>,
257 transaction_context: &TransactionContext,
258 instruction_context: &InstructionContext,
259) -> Result<(), InstructionError> {
260 if !instruction_context.is_instruction_account_signer(from_base_account_index)? {
261 ic_msg!(
262 invoke_context,
263 "Transfer: 'from' account {:?} must sign",
264 transaction_context.get_key_of_account_at_index(
265 instruction_context
266 .get_index_of_instruction_account_in_transaction(from_base_account_index)?,
267 )?,
268 );
269 return Err(InstructionError::MissingRequiredSignature);
270 }
271 let address_from_seed = Pubkey::create_with_seed(
272 transaction_context.get_key_of_account_at_index(
273 instruction_context
274 .get_index_of_instruction_account_in_transaction(from_base_account_index)?,
275 )?,
276 from_seed,
277 from_owner,
278 )?;
279
280 let from_key = transaction_context.get_key_of_account_at_index(
281 instruction_context.get_index_of_instruction_account_in_transaction(from_account_index)?,
282 )?;
283 if *from_key != address_from_seed {
284 ic_msg!(
285 invoke_context,
286 "Transfer: 'from' address {} does not match derived address {}",
287 from_key,
288 address_from_seed
289 );
290 return Err(SystemError::AddressWithSeedMismatch.into());
291 }
292
293 transfer_verified(
294 from_account_index,
295 to_account_index,
296 kelvins,
297 invoke_context,
298 transaction_context,
299 instruction_context,
300 )
301}
302
303pub const DEFAULT_COMPUTE_UNITS: u64 = 150;
304
305declare_process_instruction!(Entrypoint, DEFAULT_COMPUTE_UNITS, |invoke_context| {
306 let transaction_context = &invoke_context.transaction_context;
307 let instruction_context = transaction_context.get_current_instruction_context()?;
308 let instruction_data = instruction_context.get_instruction_data();
309 let instruction =
310 limited_deserialize(instruction_data, rialo_s_packet::PACKET_DATA_SIZE as u64)?;
311
312 trace!("process_instruction: {:?}", instruction);
313
314 let signers = instruction_context.get_signers(transaction_context)?;
315 match instruction {
316 SystemInstruction::CreateAccount {
317 kelvins,
318 space,
319 owner,
320 } => {
321 instruction_context.check_number_of_instruction_accounts(2)?;
322 let to_address = Address::create(
323 transaction_context.get_key_of_account_at_index(
324 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
325 )?,
326 None,
327 invoke_context,
328 )?;
329 create_account(
330 0,
331 1,
332 &to_address,
333 kelvins,
334 space,
335 &owner,
336 &signers,
337 invoke_context,
338 transaction_context,
339 instruction_context,
340 )
341 }
342 SystemInstruction::CreateAccountWithSeed {
343 base,
344 seed,
345 kelvins,
346 space,
347 owner,
348 } => {
349 instruction_context.check_number_of_instruction_accounts(2)?;
350 let to_address = Address::create(
351 transaction_context.get_key_of_account_at_index(
352 instruction_context.get_index_of_instruction_account_in_transaction(1)?,
353 )?,
354 Some((&base, &seed, &owner)),
355 invoke_context,
356 )?;
357 create_account(
358 0,
359 1,
360 &to_address,
361 kelvins,
362 space,
363 &owner,
364 &signers,
365 invoke_context,
366 transaction_context,
367 instruction_context,
368 )
369 }
370 SystemInstruction::Assign { owner } => {
371 instruction_context.check_number_of_instruction_accounts(1)?;
372 let mut account =
373 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
374 let address = Address::create(
375 transaction_context.get_key_of_account_at_index(
376 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
377 )?,
378 None,
379 invoke_context,
380 )?;
381 assign(&mut account, &address, &owner, &signers, invoke_context)
382 }
383 SystemInstruction::Transfer { kelvins } => {
384 instruction_context.check_number_of_instruction_accounts(2)?;
385 transfer(
386 0,
387 1,
388 kelvins,
389 invoke_context,
390 transaction_context,
391 instruction_context,
392 )
393 }
394 SystemInstruction::TransferWithSeed {
395 kelvins,
396 from_seed,
397 from_owner,
398 } => {
399 instruction_context.check_number_of_instruction_accounts(3)?;
400 transfer_with_seed(
401 0,
402 1,
403 &from_seed,
404 &from_owner,
405 2,
406 kelvins,
407 invoke_context,
408 transaction_context,
409 instruction_context,
410 )
411 }
412 SystemInstruction::AdvanceNonceAccount => {
413 instruction_context.check_number_of_instruction_accounts(1)?;
414 let mut me =
415 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
416 #[allow(deprecated)]
417 let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
418 invoke_context,
419 instruction_context,
420 1,
421 )?;
422 if recent_blockhashes.is_empty() {
423 ic_msg!(
424 invoke_context,
425 "Advance nonce account: recent blockhash list is empty",
426 );
427 return Err(SystemError::NonceNoRecentBlockhashes.into());
428 }
429 advance_nonce_account(&mut me, &signers, invoke_context)
430 }
431 SystemInstruction::WithdrawNonceAccount(kelvins) => {
432 instruction_context.check_number_of_instruction_accounts(2)?;
433 #[allow(deprecated)]
434 let _recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
435 invoke_context,
436 instruction_context,
437 2,
438 )?;
439 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 3)?;
440 withdraw_nonce_account(
441 0,
442 kelvins,
443 1,
444 &rent,
445 &signers,
446 invoke_context,
447 transaction_context,
448 instruction_context,
449 )
450 }
451 SystemInstruction::InitializeNonceAccount(authorized) => {
452 instruction_context.check_number_of_instruction_accounts(1)?;
453 let mut me =
454 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
455 #[allow(deprecated)]
456 let recent_blockhashes = get_sysvar_with_account_check::recent_blockhashes(
457 invoke_context,
458 instruction_context,
459 1,
460 )?;
461 if recent_blockhashes.is_empty() {
462 ic_msg!(
463 invoke_context,
464 "Initialize nonce account: recent blockhash list is empty",
465 );
466 return Err(SystemError::NonceNoRecentBlockhashes.into());
467 }
468 let rent = get_sysvar_with_account_check::rent(invoke_context, instruction_context, 2)?;
469 initialize_nonce_account(&mut me, &authorized, &rent, invoke_context)
470 }
471 SystemInstruction::AuthorizeNonceAccount(nonce_authority) => {
472 instruction_context.check_number_of_instruction_accounts(1)?;
473 let mut me =
474 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
475 authorize_nonce_account(&mut me, &nonce_authority, &signers, invoke_context)
476 }
477 SystemInstruction::UpgradeNonceAccount => {
478 instruction_context.check_number_of_instruction_accounts(1)?;
479 let mut nonce_account =
480 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
481 if !system_program::check_id(nonce_account.get_owner()) {
482 return Err(InstructionError::InvalidAccountOwner);
483 }
484 if !nonce_account.is_writable() {
485 return Err(InstructionError::InvalidArgument);
486 }
487 let nonce_versions: nonce::versions::Versions = nonce_account.get_state()?;
488 match nonce_versions.upgrade() {
489 None => Err(InstructionError::InvalidArgument),
490 Some(nonce_versions) => nonce_account.set_state(&nonce_versions),
491 }
492 }
493 SystemInstruction::Allocate { space } => {
494 instruction_context.check_number_of_instruction_accounts(1)?;
495 let mut account =
496 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
497 let address = Address::create(
498 transaction_context.get_key_of_account_at_index(
499 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
500 )?,
501 None,
502 invoke_context,
503 )?;
504 allocate(&mut account, &address, space, &signers, invoke_context)
505 }
506 SystemInstruction::AllocateWithSeed {
507 base,
508 seed,
509 space,
510 owner,
511 } => {
512 instruction_context.check_number_of_instruction_accounts(1)?;
513 let mut account =
514 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
515 let address = Address::create(
516 transaction_context.get_key_of_account_at_index(
517 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
518 )?,
519 Some((&base, &seed, &owner)),
520 invoke_context,
521 )?;
522 allocate_and_assign(
523 &mut account,
524 &address,
525 space,
526 &owner,
527 &signers,
528 invoke_context,
529 )
530 }
531 SystemInstruction::AssignWithSeed { base, seed, owner } => {
532 instruction_context.check_number_of_instruction_accounts(1)?;
533 let mut account =
534 instruction_context.try_borrow_instruction_account(transaction_context, 0)?;
535 let address = Address::create(
536 transaction_context.get_key_of_account_at_index(
537 instruction_context.get_index_of_instruction_account_in_transaction(0)?,
538 )?,
539 Some((&base, &seed, &owner)),
540 invoke_context,
541 )?;
542 assign(&mut account, &address, &owner, &signers, invoke_context)
543 }
544 }
545});
546
547#[cfg(test)]
548mod tests {
549 use std::collections::BinaryHeap;
550
551 use bincode::serialize;
552 use rialo_s_account::StoredAccount;
553 use rialo_s_nonce_account::{get_system_account_kind, SystemAccountKind};
554 use rialo_s_program_runtime::{
555 invoke_context::mock_process_instruction, with_mock_invoke_context,
556 };
557 #[allow(deprecated)]
558 use rialo_s_sdk::{
559 account::{
560 self, create_account_shared_data_with_fields, to_account, Account, AccountSharedData,
561 ReadableAccount, DUMMY_INHERITABLE_ACCOUNT_FIELDS,
562 },
563 fee_calculator::FeeCalculator,
564 hash::{hash, Hash},
565 instruction::{AccountMeta, Instruction, InstructionError},
566 nonce::{
567 self,
568 state::{
569 Data as NonceData, DurableNonce, State as NonceState, Versions as NonceVersions,
570 },
571 },
572 nonce_account, system_instruction, system_program,
573 sysvar::{
574 self,
575 recent_blockhashes::{IntoIterSorted, IterItem, RecentBlockhashes, MAX_ENTRIES},
576 rent::Rent,
577 },
578 };
579
580 use super::*;
581
582 impl From<Pubkey> for Address {
583 fn from(address: Pubkey) -> Self {
584 Self {
585 address,
586 base: None,
587 }
588 }
589 }
590
591 fn process_instruction(
592 instruction_data: &[u8],
593 transaction_accounts: Vec<(Pubkey, AccountSharedData)>,
594 instruction_accounts: Vec<AccountMeta>,
595 expected_result: Result<(), InstructionError>,
596 ) -> Vec<AccountSharedData> {
597 let transaction_accounts: Vec<(Pubkey, StoredAccount)> = transaction_accounts
598 .into_iter()
599 .map(|(k, v)| (k, StoredAccount::from(v)))
600 .collect();
601 mock_process_instruction(
602 &system_program::id(),
603 Vec::new(),
604 instruction_data,
605 transaction_accounts,
606 instruction_accounts,
607 expected_result,
608 Entrypoint::vm,
609 |_invoke_context| {},
610 |_invoke_context| {},
611 )
612 .into_iter()
613 .map(AccountSharedData::from)
614 .collect()
615 }
616
617 fn create_default_account() -> AccountSharedData {
618 AccountSharedData::new(0, 0, &Pubkey::new_unique())
619 }
620 #[allow(deprecated)]
621 fn create_recent_blockhashes_account_for_test<'a, I>(
622 recent_blockhash_iter: I,
623 ) -> AccountSharedData
624 where
625 I: IntoIterator<Item = IterItem<'a>>,
626 {
627 let mut account: AccountSharedData =
628 AccountSharedData::from(create_account_shared_data_with_fields::<RecentBlockhashes>(
629 &RecentBlockhashes::default(),
630 DUMMY_INHERITABLE_ACCOUNT_FIELDS,
631 ));
632 let sorted = BinaryHeap::from_iter(recent_blockhash_iter);
633 let sorted_iter = IntoIterSorted::new(sorted);
634 let recent_blockhash_iter = sorted_iter.take(MAX_ENTRIES);
635 let recent_blockhashes: RecentBlockhashes = recent_blockhash_iter.collect();
636 to_account(&recent_blockhashes, &mut account);
637 account
638 }
639 fn create_default_recent_blockhashes_account() -> AccountSharedData {
640 #[allow(deprecated)]
641 create_recent_blockhashes_account_for_test(vec![
642 IterItem(0u64, &Hash::default(), 0);
643 sysvar::recent_blockhashes::MAX_ENTRIES
644 ])
645 }
646 fn create_default_rent_account() -> AccountSharedData {
647 account::create_account_shared_data_for_test(&Rent::free()).into()
648 }
649
650 #[test]
651 fn test_create_account() {
652 let new_owner = Pubkey::from([9; 32]);
653 let from = Pubkey::new_unique();
654 let to = Pubkey::new_unique();
655 let from_account = AccountSharedData::new(100, 0, &system_program::id());
656 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
657
658 let accounts = process_instruction(
659 &bincode::serialize(&SystemInstruction::CreateAccount {
660 kelvins: 50,
661 space: 2,
662 owner: new_owner,
663 })
664 .unwrap(),
665 vec![(from, from_account), (to, to_account)],
666 vec![
667 AccountMeta {
668 pubkey: from,
669 is_signer: true,
670 is_writable: true,
671 },
672 AccountMeta {
673 pubkey: to,
674 is_signer: true,
675 is_writable: true,
676 },
677 ],
678 Ok(()),
679 );
680 assert_eq!(accounts[0].kelvins(), 50);
681 assert_eq!(accounts[1].kelvins(), 50);
682 assert_eq!(accounts[1].owner(), &new_owner);
683 assert_eq!(accounts[1].data(), &[0, 0]);
684 }
685
686 #[test]
687 fn test_create_account_with_seed() {
688 let new_owner = Pubkey::from([9; 32]);
689 let from = Pubkey::new_unique();
690 let seed = "shiny pepper";
691 let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
692 let from_account = AccountSharedData::new(100, 0, &system_program::id());
693 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
694
695 let accounts = process_instruction(
696 &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
697 base: from,
698 seed: seed.to_string(),
699 kelvins: 50,
700 space: 2,
701 owner: new_owner,
702 })
703 .unwrap(),
704 vec![(from, from_account), (to, to_account)],
705 vec![
706 AccountMeta {
707 pubkey: from,
708 is_signer: true,
709 is_writable: true,
710 },
711 AccountMeta {
712 pubkey: to,
713 is_signer: true,
714 is_writable: true,
715 },
716 ],
717 Ok(()),
718 );
719 assert_eq!(accounts[0].kelvins(), 50);
720 assert_eq!(accounts[1].kelvins(), 50);
721 assert_eq!(accounts[1].owner(), &new_owner);
722 assert_eq!(accounts[1].data(), &[0, 0]);
723 }
724
725 #[test]
726 fn test_create_account_with_seed_separate_base_account() {
727 let new_owner = Pubkey::from([9; 32]);
728 let from = Pubkey::new_unique();
729 let base = Pubkey::new_unique();
730 let seed = "shiny pepper";
731 let to = Pubkey::create_with_seed(&base, seed, &new_owner).unwrap();
732 let from_account = AccountSharedData::new(100, 0, &system_program::id());
733 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
734 let base_account = AccountSharedData::new(0, 0, &Pubkey::default());
735
736 let accounts = process_instruction(
737 &bincode::serialize(&SystemInstruction::CreateAccountWithSeed {
738 base,
739 seed: seed.to_string(),
740 kelvins: 50,
741 space: 2,
742 owner: new_owner,
743 })
744 .unwrap(),
745 vec![(from, from_account), (to, to_account), (base, base_account)],
746 vec![
747 AccountMeta {
748 pubkey: from,
749 is_signer: true,
750 is_writable: true,
751 },
752 AccountMeta {
753 pubkey: to,
754 is_signer: false,
755 is_writable: true,
756 },
757 AccountMeta {
758 pubkey: base,
759 is_signer: true,
760 is_writable: false,
761 },
762 ],
763 Ok(()),
764 );
765 assert_eq!(accounts[0].kelvins(), 50);
766 assert_eq!(accounts[1].kelvins(), 50);
767 assert_eq!(accounts[1].owner(), &new_owner);
768 assert_eq!(accounts[1].data(), &[0, 0]);
769 }
770
771 #[test]
772 fn test_address_create_with_seed_mismatch() {
773 with_mock_invoke_context!(
774 invoke_context,
775 transaction_context,
776 Vec::<(Pubkey, StoredAccount)>::new()
777 );
778 let from = Pubkey::new_unique();
779 let seed = "dull boy";
780 let to = Pubkey::new_unique();
781 let owner = Pubkey::new_unique();
782
783 assert_eq!(
784 Address::create(&to, Some((&from, seed, &owner)), &invoke_context),
785 Err(SystemError::AddressWithSeedMismatch.into())
786 );
787 }
788
789 #[test]
790 fn test_create_account_with_seed_missing_sig() {
791 let new_owner = Pubkey::from([9; 32]);
792 let from = Pubkey::new_unique();
793 let seed = "dull boy";
794 let to = Pubkey::create_with_seed(&from, seed, &new_owner).unwrap();
795 let from_account = AccountSharedData::new(100, 0, &system_program::id());
796 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
797
798 let accounts = process_instruction(
799 &bincode::serialize(&SystemInstruction::CreateAccount {
800 kelvins: 50,
801 space: 2,
802 owner: new_owner,
803 })
804 .unwrap(),
805 vec![(from, from_account), (to, to_account)],
806 vec![
807 AccountMeta {
808 pubkey: from,
809 is_signer: true,
810 is_writable: false,
811 },
812 AccountMeta {
813 pubkey: to,
814 is_signer: false,
815 is_writable: false,
816 },
817 ],
818 Err(InstructionError::MissingRequiredSignature),
819 );
820 assert_eq!(accounts[0].kelvins(), 100);
821 assert_eq!(accounts[1], AccountSharedData::default());
822 }
823
824 #[test]
825 fn test_create_with_zero_kelvins() {
826 let new_owner = Pubkey::from([9; 32]);
828 let from = Pubkey::new_unique();
829 let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique()); let to = Pubkey::new_unique();
831 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
832
833 let accounts = process_instruction(
834 &bincode::serialize(&SystemInstruction::CreateAccount {
835 kelvins: 0,
836 space: 2,
837 owner: new_owner,
838 })
839 .unwrap(),
840 vec![(from, from_account), (to, to_account)],
841 vec![
842 AccountMeta {
843 pubkey: from,
844 is_signer: true,
845 is_writable: true,
846 },
847 AccountMeta {
848 pubkey: to,
849 is_signer: true,
850 is_writable: true,
851 },
852 ],
853 Ok(()),
854 );
855 assert_eq!(accounts[0].kelvins(), 100);
856 assert_eq!(accounts[1].kelvins(), 0);
857 assert_eq!(*accounts[1].owner(), new_owner);
858 assert_eq!(accounts[1].data(), &[0, 0]);
859 }
860
861 #[test]
862 fn test_create_negative_kelvins() {
863 let new_owner = Pubkey::from([9; 32]);
865 let from = Pubkey::new_unique();
866 let from_account = AccountSharedData::new(100, 0, &Pubkey::new_unique());
867 let to = Pubkey::new_unique();
868 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
869
870 process_instruction(
871 &bincode::serialize(&SystemInstruction::CreateAccount {
872 kelvins: 150,
873 space: 2,
874 owner: new_owner,
875 })
876 .unwrap(),
877 vec![(from, from_account), (to, to_account)],
878 vec![
879 AccountMeta {
880 pubkey: from,
881 is_signer: true,
882 is_writable: true,
883 },
884 AccountMeta {
885 pubkey: to,
886 is_signer: true,
887 is_writable: true,
888 },
889 ],
890 Err(SystemError::ResultWithNegativeKelvins.into()),
891 );
892 }
893
894 #[test]
895 fn test_request_more_than_allowed_data_length() {
896 let from = Pubkey::new_unique();
897 let from_account = AccountSharedData::new(100, 0, &system_program::id());
898 let to = Pubkey::new_unique();
899 let to_account = AccountSharedData::new(0, 0, &Pubkey::default());
900 let instruction_accounts = vec![
901 AccountMeta {
902 pubkey: from,
903 is_signer: true,
904 is_writable: true,
905 },
906 AccountMeta {
907 pubkey: to,
908 is_signer: true,
909 is_writable: true,
910 },
911 ];
912
913 process_instruction(
915 &bincode::serialize(&SystemInstruction::CreateAccount {
916 kelvins: 50,
917 space: MAX_PERMITTED_DATA_LENGTH + 1,
918 owner: system_program::id(),
919 })
920 .unwrap(),
921 vec![(from, from_account.clone()), (to, to_account.clone())],
922 instruction_accounts.clone(),
923 Err(SystemError::InvalidAccountDataLength.into()),
924 );
925
926 let accounts = process_instruction(
928 &bincode::serialize(&SystemInstruction::CreateAccount {
929 kelvins: 50,
930 space: MAX_PERMITTED_DATA_LENGTH,
931 owner: system_program::id(),
932 })
933 .unwrap(),
934 vec![(from, from_account), (to, to_account)],
935 instruction_accounts,
936 Ok(()),
937 );
938 assert_eq!(accounts[1].kelvins(), 50);
939 assert_eq!(accounts[1].data().len() as u64, MAX_PERMITTED_DATA_LENGTH);
940 }
941
942 #[test]
943 fn test_create_already_in_use() {
944 let new_owner = Pubkey::from([9; 32]);
945 let from = Pubkey::new_unique();
946 let from_account = AccountSharedData::new(100, 0, &system_program::id());
947 let owned_key = Pubkey::new_unique();
948
949 let original_program_owner = Pubkey::from([5; 32]);
951 let owned_account = AccountSharedData::new(0, 0, &original_program_owner);
952 let unchanged_account = owned_account.clone();
953 let accounts = process_instruction(
954 &bincode::serialize(&SystemInstruction::CreateAccount {
955 kelvins: 50,
956 space: 2,
957 owner: new_owner,
958 })
959 .unwrap(),
960 vec![(from, from_account.clone()), (owned_key, owned_account)],
961 vec![
962 AccountMeta {
963 pubkey: from,
964 is_signer: true,
965 is_writable: false,
966 },
967 AccountMeta {
968 pubkey: owned_key,
969 is_signer: true,
970 is_writable: false,
971 },
972 ],
973 Err(SystemError::AccountAlreadyInUse.into()),
974 );
975 assert_eq!(accounts[0].kelvins(), 100);
976 assert_eq!(accounts[1], unchanged_account);
977
978 let owned_account = AccountSharedData::new(0, 1, &Pubkey::default());
980 let unchanged_account = owned_account.clone();
981 let accounts = process_instruction(
982 &bincode::serialize(&SystemInstruction::CreateAccount {
983 kelvins: 50,
984 space: 2,
985 owner: new_owner,
986 })
987 .unwrap(),
988 vec![(from, from_account.clone()), (owned_key, owned_account)],
989 vec![
990 AccountMeta {
991 pubkey: from,
992 is_signer: true,
993 is_writable: false,
994 },
995 AccountMeta {
996 pubkey: owned_key,
997 is_signer: true,
998 is_writable: false,
999 },
1000 ],
1001 Err(SystemError::AccountAlreadyInUse.into()),
1002 );
1003 assert_eq!(accounts[0].kelvins(), 100);
1004 assert_eq!(accounts[1], unchanged_account);
1005
1006 let owned_account = AccountSharedData::new(1, 0, &Pubkey::default());
1008 let unchanged_account = owned_account.clone();
1009 let accounts = process_instruction(
1010 &bincode::serialize(&SystemInstruction::CreateAccount {
1011 kelvins: 50,
1012 space: 2,
1013 owner: new_owner,
1014 })
1015 .unwrap(),
1016 vec![(from, from_account), (owned_key, owned_account)],
1017 vec![
1018 AccountMeta {
1019 pubkey: from,
1020 is_signer: true,
1021 is_writable: false,
1022 },
1023 AccountMeta {
1024 pubkey: owned_key,
1025 is_signer: true,
1026 is_writable: false,
1027 },
1028 ],
1029 Err(SystemError::AccountAlreadyInUse.into()),
1030 );
1031 assert_eq!(accounts[0].kelvins(), 100);
1032 assert_eq!(accounts[1], unchanged_account);
1033 }
1034
1035 #[test]
1036 fn test_create_unsigned() {
1037 let new_owner = Pubkey::from([9; 32]);
1039 let from = Pubkey::new_unique();
1040 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1041 let owned_key = Pubkey::new_unique();
1042 let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1043
1044 process_instruction(
1046 &bincode::serialize(&SystemInstruction::CreateAccount {
1047 kelvins: 50,
1048 space: 2,
1049 owner: new_owner,
1050 })
1051 .unwrap(),
1052 vec![
1053 (from, from_account.clone()),
1054 (owned_key, owned_account.clone()),
1055 ],
1056 vec![
1057 AccountMeta {
1058 pubkey: from,
1059 is_signer: false,
1060 is_writable: false,
1061 },
1062 AccountMeta {
1063 pubkey: owned_key,
1064 is_signer: false,
1065 is_writable: false,
1066 },
1067 ],
1068 Err(InstructionError::MissingRequiredSignature),
1069 );
1070
1071 process_instruction(
1073 &bincode::serialize(&SystemInstruction::CreateAccount {
1074 kelvins: 50,
1075 space: 2,
1076 owner: new_owner,
1077 })
1078 .unwrap(),
1079 vec![(from, from_account.clone()), (owned_key, owned_account)],
1080 vec![
1081 AccountMeta {
1082 pubkey: from,
1083 is_signer: true,
1084 is_writable: false,
1085 },
1086 AccountMeta {
1087 pubkey: owned_key,
1088 is_signer: false,
1089 is_writable: false,
1090 },
1091 ],
1092 Err(InstructionError::MissingRequiredSignature),
1093 );
1094
1095 let owned_account = AccountSharedData::new(0, 0, &Pubkey::default());
1097 process_instruction(
1098 &bincode::serialize(&SystemInstruction::CreateAccount {
1099 kelvins: 50,
1100 space: 2,
1101 owner: new_owner,
1102 })
1103 .unwrap(),
1104 vec![(from, from_account), (owned_key, owned_account)],
1105 vec![
1106 AccountMeta {
1107 pubkey: from,
1108 is_signer: false,
1109 is_writable: false,
1110 },
1111 AccountMeta {
1112 pubkey: owned_key,
1113 is_signer: false,
1114 is_writable: false,
1115 },
1116 ],
1117 Err(InstructionError::MissingRequiredSignature),
1118 );
1119 }
1120
1121 #[test]
1122 fn test_create_sysvar_invalid_id_with_feature() {
1123 let from = Pubkey::new_unique();
1125 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1126 let to = Pubkey::new_unique();
1127 let to_account = AccountSharedData::new(0, 0, &system_program::id());
1128
1129 process_instruction(
1131 &bincode::serialize(&SystemInstruction::CreateAccount {
1132 kelvins: 50,
1133 space: 2,
1134 owner: sysvar::id(),
1135 })
1136 .unwrap(),
1137 vec![(from, from_account), (to, to_account)],
1138 vec![
1139 AccountMeta {
1140 pubkey: from,
1141 is_signer: true,
1142 is_writable: true,
1143 },
1144 AccountMeta {
1145 pubkey: to,
1146 is_signer: true,
1147 is_writable: true,
1148 },
1149 ],
1150 Ok(()),
1151 );
1152 }
1153
1154 #[test]
1155 fn test_create_data_populated() {
1156 let new_owner = Pubkey::from([9; 32]);
1158 let from = Pubkey::new_unique();
1159 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1160 let populated_key = Pubkey::new_unique();
1161 let populated_account = AccountSharedData::from(Account {
1162 data: vec![0, 1, 2, 3],
1163 ..Account::default()
1164 });
1165
1166 process_instruction(
1167 &bincode::serialize(&SystemInstruction::CreateAccount {
1168 kelvins: 50,
1169 space: 2,
1170 owner: new_owner,
1171 })
1172 .unwrap(),
1173 vec![(from, from_account), (populated_key, populated_account)],
1174 vec![
1175 AccountMeta {
1176 pubkey: from,
1177 is_signer: true,
1178 is_writable: false,
1179 },
1180 AccountMeta {
1181 pubkey: populated_key,
1182 is_signer: true,
1183 is_writable: false,
1184 },
1185 ],
1186 Err(SystemError::AccountAlreadyInUse.into()),
1187 );
1188 }
1189
1190 #[test]
1191 fn test_create_from_account_is_nonce_fail() {
1192 let nonce = Pubkey::new_unique();
1193 let nonce_account = AccountSharedData::new_data(
1194 42,
1195 &nonce::state::Versions::new(nonce::State::Initialized(nonce::state::Data::default())),
1196 &system_program::id(),
1197 )
1198 .unwrap();
1199 let new = Pubkey::new_unique();
1200 let new_account = AccountSharedData::new(0, 0, &system_program::id());
1201
1202 process_instruction(
1203 &bincode::serialize(&SystemInstruction::CreateAccount {
1204 kelvins: 42,
1205 space: 0,
1206 owner: Pubkey::new_unique(),
1207 })
1208 .unwrap(),
1209 vec![(nonce, nonce_account), (new, new_account)],
1210 vec![
1211 AccountMeta {
1212 pubkey: nonce,
1213 is_signer: true,
1214 is_writable: false,
1215 },
1216 AccountMeta {
1217 pubkey: new,
1218 is_signer: true,
1219 is_writable: true,
1220 },
1221 ],
1222 Err(InstructionError::InvalidArgument),
1223 );
1224 }
1225
1226 #[test]
1227 fn test_assign() {
1228 let new_owner = Pubkey::from([9; 32]);
1229 let pubkey = Pubkey::new_unique();
1230 let account = AccountSharedData::new(100, 0, &system_program::id());
1231
1232 process_instruction(
1234 &bincode::serialize(&SystemInstruction::Assign {
1235 owner: system_program::id(),
1236 })
1237 .unwrap(),
1238 vec![(pubkey, account.clone())],
1239 vec![AccountMeta {
1240 pubkey,
1241 is_signer: false,
1242 is_writable: true,
1243 }],
1244 Ok(()),
1245 );
1246
1247 process_instruction(
1249 &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1250 vec![(pubkey, account.clone())],
1251 vec![AccountMeta {
1252 pubkey,
1253 is_signer: false,
1254 is_writable: true,
1255 }],
1256 Err(InstructionError::MissingRequiredSignature),
1257 );
1258
1259 process_instruction(
1260 &bincode::serialize(&SystemInstruction::Assign { owner: new_owner }).unwrap(),
1261 vec![(pubkey, account.clone())],
1262 vec![AccountMeta {
1263 pubkey,
1264 is_signer: true,
1265 is_writable: true,
1266 }],
1267 Ok(()),
1268 );
1269
1270 process_instruction(
1272 &bincode::serialize(&SystemInstruction::Assign {
1273 owner: sysvar::id(),
1274 })
1275 .unwrap(),
1276 vec![(pubkey, account)],
1277 vec![AccountMeta {
1278 pubkey,
1279 is_signer: true,
1280 is_writable: true,
1281 }],
1282 Ok(()),
1283 );
1284 }
1285
1286 #[test]
1287 fn test_process_bogus_instruction() {
1288 let instruction = SystemInstruction::Assign {
1290 owner: Pubkey::new_unique(),
1291 };
1292 let data = serialize(&instruction).unwrap();
1293 process_instruction(
1294 &data,
1295 Vec::new(),
1296 Vec::new(),
1297 Err(InstructionError::NotEnoughAccountKeys),
1298 );
1299
1300 let from = Pubkey::new_unique();
1302 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1303 let instruction = SystemInstruction::Transfer { kelvins: 0 };
1304 let data = serialize(&instruction).unwrap();
1305 process_instruction(
1306 &data,
1307 vec![(from, from_account)],
1308 vec![AccountMeta {
1309 pubkey: from,
1310 is_signer: true,
1311 is_writable: false,
1312 }],
1313 Err(InstructionError::NotEnoughAccountKeys),
1314 );
1315 }
1316
1317 #[test]
1318 fn test_transfer_kelvins() {
1319 let from = Pubkey::new_unique();
1320 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1321 let to = Pubkey::from([3; 32]);
1322 let to_account = AccountSharedData::new(1, 0, &to); let transaction_accounts = vec![(from, from_account), (to, to_account)];
1324 let instruction_accounts = vec![
1325 AccountMeta {
1326 pubkey: from,
1327 is_signer: true,
1328 is_writable: true,
1329 },
1330 AccountMeta {
1331 pubkey: to,
1332 is_signer: false,
1333 is_writable: true,
1334 },
1335 ];
1336
1337 let accounts = process_instruction(
1339 &bincode::serialize(&SystemInstruction::Transfer { kelvins: 50 }).unwrap(),
1340 transaction_accounts.clone(),
1341 instruction_accounts.clone(),
1342 Ok(()),
1343 );
1344 assert_eq!(accounts[0].kelvins(), 50);
1345 assert_eq!(accounts[1].kelvins(), 51);
1346
1347 let accounts = process_instruction(
1349 &bincode::serialize(&SystemInstruction::Transfer { kelvins: 101 }).unwrap(),
1350 transaction_accounts.clone(),
1351 instruction_accounts.clone(),
1352 Err(SystemError::ResultWithNegativeKelvins.into()),
1353 );
1354 assert_eq!(accounts[0].kelvins(), 100);
1355 assert_eq!(accounts[1].kelvins(), 1);
1356
1357 let accounts = process_instruction(
1359 &bincode::serialize(&SystemInstruction::Transfer { kelvins: 0 }).unwrap(),
1360 transaction_accounts.clone(),
1361 instruction_accounts,
1362 Ok(()),
1363 );
1364 assert_eq!(accounts[0].kelvins(), 100);
1365 assert_eq!(accounts[1].kelvins(), 1);
1366
1367 let accounts = process_instruction(
1369 &bincode::serialize(&SystemInstruction::Transfer { kelvins: 0 }).unwrap(),
1370 transaction_accounts,
1371 vec![
1372 AccountMeta {
1373 pubkey: from,
1374 is_signer: false,
1375 is_writable: true,
1376 },
1377 AccountMeta {
1378 pubkey: to,
1379 is_signer: false,
1380 is_writable: true,
1381 },
1382 ],
1383 Err(InstructionError::MissingRequiredSignature),
1384 );
1385 assert_eq!(accounts[0].kelvins(), 100);
1386 assert_eq!(accounts[1].kelvins(), 1);
1387 }
1388
1389 #[test]
1390 fn test_transfer_with_seed() {
1391 let base = Pubkey::new_unique();
1392 let base_account = AccountSharedData::new(100, 0, &Pubkey::from([2; 32])); let from_seed = "42".to_string();
1394 let from_owner = system_program::id();
1395 let from = Pubkey::create_with_seed(&base, from_seed.as_str(), &from_owner).unwrap();
1396 let from_account = AccountSharedData::new(100, 0, &system_program::id());
1397 let to = Pubkey::from([3; 32]);
1398 let to_account = AccountSharedData::new(1, 0, &to); let transaction_accounts =
1400 vec![(from, from_account), (base, base_account), (to, to_account)];
1401 let instruction_accounts = vec![
1402 AccountMeta {
1403 pubkey: from,
1404 is_signer: true,
1405 is_writable: true,
1406 },
1407 AccountMeta {
1408 pubkey: base,
1409 is_signer: true,
1410 is_writable: false,
1411 },
1412 AccountMeta {
1413 pubkey: to,
1414 is_signer: false,
1415 is_writable: true,
1416 },
1417 ];
1418
1419 let accounts = process_instruction(
1421 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1422 kelvins: 50,
1423 from_seed: from_seed.clone(),
1424 from_owner,
1425 })
1426 .unwrap(),
1427 transaction_accounts.clone(),
1428 instruction_accounts.clone(),
1429 Ok(()),
1430 );
1431 assert_eq!(accounts[0].kelvins(), 50);
1432 assert_eq!(accounts[2].kelvins(), 51);
1433
1434 let accounts = process_instruction(
1436 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1437 kelvins: 101,
1438 from_seed: from_seed.clone(),
1439 from_owner,
1440 })
1441 .unwrap(),
1442 transaction_accounts.clone(),
1443 instruction_accounts.clone(),
1444 Err(SystemError::ResultWithNegativeKelvins.into()),
1445 );
1446 assert_eq!(accounts[0].kelvins(), 100);
1447 assert_eq!(accounts[2].kelvins(), 1);
1448
1449 let accounts = process_instruction(
1451 &bincode::serialize(&SystemInstruction::TransferWithSeed {
1452 kelvins: 0,
1453 from_seed,
1454 from_owner,
1455 })
1456 .unwrap(),
1457 transaction_accounts,
1458 instruction_accounts,
1459 Ok(()),
1460 );
1461 assert_eq!(accounts[0].kelvins(), 100);
1462 assert_eq!(accounts[2].kelvins(), 1);
1463 }
1464
1465 #[test]
1466 fn test_transfer_kelvins_from_nonce_account_fail() {
1467 let from = Pubkey::new_unique();
1468 let from_account = AccountSharedData::new_data(
1469 100,
1470 &nonce::state::Versions::new(nonce::State::Initialized(nonce::state::Data {
1471 authority: from,
1472 ..nonce::state::Data::default()
1473 })),
1474 &system_program::id(),
1475 )
1476 .unwrap();
1477 assert_eq!(
1478 get_system_account_kind(&from_account),
1479 Some(SystemAccountKind::Nonce)
1480 );
1481 let to = Pubkey::from([3; 32]);
1482 let to_account = AccountSharedData::new(1, 0, &to); process_instruction(
1485 &bincode::serialize(&SystemInstruction::Transfer { kelvins: 50 }).unwrap(),
1486 vec![(from, from_account), (to, to_account)],
1487 vec![
1488 AccountMeta {
1489 pubkey: from,
1490 is_signer: true,
1491 is_writable: false,
1492 },
1493 AccountMeta {
1494 pubkey: to,
1495 is_signer: false,
1496 is_writable: false,
1497 },
1498 ],
1499 Err(InstructionError::InvalidArgument),
1500 );
1501 }
1502
1503 fn process_nonce_instruction(
1504 instruction: Instruction,
1505 expected_result: Result<(), InstructionError>,
1506 ) -> Vec<AccountSharedData> {
1507 let transaction_accounts: Vec<(Pubkey, AccountSharedData)> = instruction
1508 .accounts
1509 .iter()
1510 .map(|meta| {
1511 #[allow(deprecated)]
1512 (
1513 meta.pubkey,
1514 if sysvar::recent_blockhashes::check_id(&meta.pubkey) {
1515 create_default_recent_blockhashes_account()
1516 } else if sysvar::rent::check_id(&meta.pubkey) {
1517 account::create_account_shared_data_for_test(&Rent::free()).into()
1518 } else {
1519 AccountSharedData::new(0, 0, &Pubkey::new_unique())
1520 },
1521 )
1522 })
1523 .collect();
1524 process_instruction(
1525 &instruction.data,
1526 transaction_accounts,
1527 instruction.accounts,
1528 expected_result,
1529 )
1530 }
1531
1532 #[test]
1533 fn test_process_nonce_ix_no_acc_data_fail() {
1534 let none_address = Pubkey::new_unique();
1535 process_nonce_instruction(
1536 system_instruction::advance_nonce_account(&none_address, &none_address),
1537 Err(InstructionError::InvalidAccountData),
1538 );
1539 }
1540
1541 #[test]
1542 fn test_process_nonce_ix_no_keyed_accs_fail() {
1543 process_instruction(
1544 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1545 Vec::new(),
1546 Vec::new(),
1547 Err(InstructionError::NotEnoughAccountKeys),
1548 );
1549 }
1550
1551 #[test]
1552 fn test_process_nonce_ix_only_nonce_acc_fail() {
1553 let pubkey = Pubkey::new_unique();
1554 process_instruction(
1555 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1556 vec![(pubkey, create_default_account())],
1557 vec![AccountMeta {
1558 pubkey,
1559 is_signer: true,
1560 is_writable: true,
1561 }],
1562 Err(InstructionError::NotEnoughAccountKeys),
1563 );
1564 }
1565
1566 #[test]
1567 fn test_process_nonce_ix_ok() {
1568 let nonce_address = Pubkey::new_unique();
1569 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1570 #[allow(deprecated)]
1571 let blockhash_id = sysvar::recent_blockhashes::id();
1572 let accounts = process_instruction(
1573 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1574 vec![
1575 (nonce_address, nonce_account),
1576 (blockhash_id, create_default_recent_blockhashes_account()),
1577 (sysvar::rent::id(), create_default_rent_account()),
1578 ],
1579 vec![
1580 AccountMeta {
1581 pubkey: nonce_address,
1582 is_signer: true,
1583 is_writable: true,
1584 },
1585 AccountMeta {
1586 pubkey: blockhash_id,
1587 is_signer: false,
1588 is_writable: false,
1589 },
1590 AccountMeta {
1591 pubkey: sysvar::rent::id(),
1592 is_signer: false,
1593 is_writable: false,
1594 },
1595 ],
1596 Ok(()),
1597 );
1598 let blockhash = hash(&serialize(&0).unwrap());
1599 #[allow(deprecated)]
1600 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![
1601 IterItem(0u64, &blockhash, 0);
1602 sysvar::recent_blockhashes::MAX_ENTRIES
1603 ]);
1604 mock_process_instruction(
1605 &system_program::id(),
1606 Vec::new(),
1607 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1608 vec![
1609 (nonce_address, StoredAccount::from(accounts[0].clone())),
1610 (
1611 blockhash_id,
1612 StoredAccount::from(new_recent_blockhashes_account),
1613 ),
1614 ],
1615 vec![
1616 AccountMeta {
1617 pubkey: nonce_address,
1618 is_signer: true,
1619 is_writable: true,
1620 },
1621 AccountMeta {
1622 pubkey: blockhash_id,
1623 is_signer: false,
1624 is_writable: false,
1625 },
1626 ],
1627 Ok(()),
1628 Entrypoint::vm,
1629 |invoke_context: &mut InvokeContext<'_>| {
1630 invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1631 },
1632 |_invoke_context| {},
1633 );
1634 }
1635
1636 #[test]
1637 fn test_process_withdraw_ix_no_acc_data_fail() {
1638 let nonce_address = Pubkey::new_unique();
1639 process_nonce_instruction(
1640 system_instruction::withdraw_nonce_account(
1641 &nonce_address,
1642 &Pubkey::new_unique(),
1643 &nonce_address,
1644 1,
1645 ),
1646 Err(InstructionError::InvalidAccountData),
1647 );
1648 }
1649
1650 #[test]
1651 fn test_process_withdraw_ix_no_keyed_accs_fail() {
1652 process_instruction(
1653 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1654 Vec::new(),
1655 Vec::new(),
1656 Err(InstructionError::NotEnoughAccountKeys),
1657 );
1658 }
1659
1660 #[test]
1661 fn test_process_withdraw_ix_only_nonce_acc_fail() {
1662 let nonce_address = Pubkey::new_unique();
1663 process_instruction(
1664 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1665 vec![(nonce_address, create_default_account())],
1666 vec![AccountMeta {
1667 pubkey: nonce_address,
1668 is_signer: true,
1669 is_writable: true,
1670 }],
1671 Err(InstructionError::NotEnoughAccountKeys),
1672 );
1673 }
1674
1675 #[test]
1676 fn test_process_withdraw_ix_ok() {
1677 let nonce_address = Pubkey::new_unique();
1678 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1679 let pubkey = Pubkey::new_unique();
1680 #[allow(deprecated)]
1681 let blockhash_id = sysvar::recent_blockhashes::id();
1682 process_instruction(
1683 &serialize(&SystemInstruction::WithdrawNonceAccount(42)).unwrap(),
1684 vec![
1685 (nonce_address, nonce_account),
1686 (pubkey, create_default_account()),
1687 (blockhash_id, create_default_recent_blockhashes_account()),
1688 (sysvar::rent::id(), create_default_rent_account()),
1689 ],
1690 vec![
1691 AccountMeta {
1692 pubkey: nonce_address,
1693 is_signer: true,
1694 is_writable: true,
1695 },
1696 AccountMeta {
1697 pubkey,
1698 is_signer: true,
1699 is_writable: true,
1700 },
1701 AccountMeta {
1702 pubkey: blockhash_id,
1703 is_signer: false,
1704 is_writable: false,
1705 },
1706 AccountMeta {
1707 pubkey: sysvar::rent::id(),
1708 is_signer: false,
1709 is_writable: false,
1710 },
1711 ],
1712 Ok(()),
1713 );
1714 }
1715
1716 #[test]
1717 fn test_process_initialize_ix_no_keyed_accs_fail() {
1718 process_instruction(
1719 &serialize(&SystemInstruction::InitializeNonceAccount(Pubkey::default())).unwrap(),
1720 Vec::new(),
1721 Vec::new(),
1722 Err(InstructionError::NotEnoughAccountKeys),
1723 );
1724 }
1725
1726 #[test]
1727 fn test_process_initialize_ix_only_nonce_acc_fail() {
1728 let nonce_address = Pubkey::new_unique();
1729 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1730 process_instruction(
1731 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1732 vec![(nonce_address, nonce_account)],
1733 vec![AccountMeta {
1734 pubkey: nonce_address,
1735 is_signer: true,
1736 is_writable: true,
1737 }],
1738 Err(InstructionError::NotEnoughAccountKeys),
1739 );
1740 }
1741
1742 #[test]
1743 fn test_process_initialize_ix_ok() {
1744 let nonce_address = Pubkey::new_unique();
1745 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1746 #[allow(deprecated)]
1747 let blockhash_id = sysvar::recent_blockhashes::id();
1748 process_instruction(
1749 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1750 vec![
1751 (nonce_address, nonce_account),
1752 (blockhash_id, create_default_recent_blockhashes_account()),
1753 (sysvar::rent::id(), create_default_rent_account()),
1754 ],
1755 vec![
1756 AccountMeta {
1757 pubkey: nonce_address,
1758 is_signer: true,
1759 is_writable: true,
1760 },
1761 AccountMeta {
1762 pubkey: blockhash_id,
1763 is_signer: false,
1764 is_writable: false,
1765 },
1766 AccountMeta {
1767 pubkey: sysvar::rent::id(),
1768 is_signer: false,
1769 is_writable: false,
1770 },
1771 ],
1772 Ok(()),
1773 );
1774 }
1775
1776 #[test]
1777 fn test_process_authorize_ix_ok() {
1778 let nonce_address = Pubkey::new_unique();
1779 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1780 #[allow(deprecated)]
1781 let blockhash_id = sysvar::recent_blockhashes::id();
1782 let accounts = process_instruction(
1783 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1784 vec![
1785 (nonce_address, nonce_account),
1786 (blockhash_id, create_default_recent_blockhashes_account()),
1787 (sysvar::rent::id(), create_default_rent_account()),
1788 ],
1789 vec![
1790 AccountMeta {
1791 pubkey: nonce_address,
1792 is_signer: true,
1793 is_writable: true,
1794 },
1795 AccountMeta {
1796 pubkey: blockhash_id,
1797 is_signer: false,
1798 is_writable: false,
1799 },
1800 AccountMeta {
1801 pubkey: sysvar::rent::id(),
1802 is_signer: false,
1803 is_writable: false,
1804 },
1805 ],
1806 Ok(()),
1807 );
1808 process_instruction(
1809 &serialize(&SystemInstruction::AuthorizeNonceAccount(nonce_address)).unwrap(),
1810 vec![(nonce_address, accounts[0].clone())],
1811 vec![AccountMeta {
1812 pubkey: nonce_address,
1813 is_signer: true,
1814 is_writable: true,
1815 }],
1816 Ok(()),
1817 );
1818 }
1819
1820 #[test]
1821 fn test_process_authorize_bad_account_data_fail() {
1822 let nonce_address = Pubkey::new_unique();
1823 process_nonce_instruction(
1824 system_instruction::authorize_nonce_account(
1825 &nonce_address,
1826 &Pubkey::new_unique(),
1827 &nonce_address,
1828 ),
1829 Err(InstructionError::InvalidAccountData),
1830 );
1831 }
1832
1833 #[test]
1834 fn test_nonce_initialize_with_empty_recent_blockhashes_fail() {
1835 let nonce_address = Pubkey::new_unique();
1836 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1837 #[allow(deprecated)]
1838 let blockhash_id = sysvar::recent_blockhashes::id();
1839 #[allow(deprecated)]
1840 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1841 process_instruction(
1842 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1843 vec![
1844 (nonce_address, nonce_account),
1845 (blockhash_id, new_recent_blockhashes_account),
1846 (sysvar::rent::id(), create_default_rent_account()),
1847 ],
1848 vec![
1849 AccountMeta {
1850 pubkey: nonce_address,
1851 is_signer: true,
1852 is_writable: true,
1853 },
1854 AccountMeta {
1855 pubkey: blockhash_id,
1856 is_signer: false,
1857 is_writable: false,
1858 },
1859 AccountMeta {
1860 pubkey: sysvar::rent::id(),
1861 is_signer: false,
1862 is_writable: false,
1863 },
1864 ],
1865 Err(SystemError::NonceNoRecentBlockhashes.into()),
1866 );
1867 }
1868
1869 #[test]
1870 fn test_nonce_advance_with_empty_recent_blockhashes_fail() {
1871 let nonce_address = Pubkey::new_unique();
1872 let nonce_account = nonce_account::create_account(1_000_000).into_inner();
1873 #[allow(deprecated)]
1874 let blockhash_id = sysvar::recent_blockhashes::id();
1875 let accounts = process_instruction(
1876 &serialize(&SystemInstruction::InitializeNonceAccount(nonce_address)).unwrap(),
1877 vec![
1878 (nonce_address, nonce_account),
1879 (blockhash_id, create_default_recent_blockhashes_account()),
1880 (sysvar::rent::id(), create_default_rent_account()),
1881 ],
1882 vec![
1883 AccountMeta {
1884 pubkey: nonce_address,
1885 is_signer: true,
1886 is_writable: true,
1887 },
1888 AccountMeta {
1889 pubkey: blockhash_id,
1890 is_signer: false,
1891 is_writable: false,
1892 },
1893 AccountMeta {
1894 pubkey: sysvar::rent::id(),
1895 is_signer: false,
1896 is_writable: false,
1897 },
1898 ],
1899 Ok(()),
1900 );
1901 #[allow(deprecated)]
1902 let new_recent_blockhashes_account = create_recent_blockhashes_account_for_test(vec![]);
1903 mock_process_instruction(
1904 &system_program::id(),
1905 Vec::new(),
1906 &serialize(&SystemInstruction::AdvanceNonceAccount).unwrap(),
1907 vec![
1908 (nonce_address, StoredAccount::from(accounts[0].clone())),
1909 (
1910 blockhash_id,
1911 StoredAccount::from(new_recent_blockhashes_account),
1912 ),
1913 ],
1914 vec![
1915 AccountMeta {
1916 pubkey: nonce_address,
1917 is_signer: true,
1918 is_writable: true,
1919 },
1920 AccountMeta {
1921 pubkey: blockhash_id,
1922 is_signer: false,
1923 is_writable: false,
1924 },
1925 ],
1926 Err(SystemError::NonceNoRecentBlockhashes.into()),
1927 Entrypoint::vm,
1928 |invoke_context: &mut InvokeContext<'_>| {
1929 invoke_context.environment_config.blockhash = hash(&serialize(&0).unwrap());
1930 },
1931 |_invoke_context| {},
1932 );
1933 }
1934
1935 #[test]
1936 fn test_nonce_account_upgrade_check_owner() {
1937 let nonce_address = Pubkey::new_unique();
1938 let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1939 let nonce_account = AccountSharedData::new_data(
1940 1_000_000, &versions, &Pubkey::new_unique(), )
1944 .unwrap();
1945 let accounts = process_instruction(
1946 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1947 vec![(nonce_address, nonce_account.clone())],
1948 vec![AccountMeta {
1949 pubkey: nonce_address,
1950 is_signer: false,
1951 is_writable: true,
1952 }],
1953 Err(InstructionError::InvalidAccountOwner),
1954 );
1955 assert_eq!(accounts.len(), 1);
1956 assert_eq!(accounts[0], nonce_account);
1957 }
1958
1959 fn new_nonce_account(versions: NonceVersions) -> AccountSharedData {
1960 let nonce_account = AccountSharedData::new_data(
1961 1_000_000, &versions, &system_program::id(), )
1965 .unwrap();
1966 assert_eq!(
1967 nonce_account.deserialize_data::<NonceVersions>().unwrap(),
1968 versions
1969 );
1970 nonce_account
1971 }
1972
1973 #[test]
1974 fn test_nonce_account_upgrade() {
1975 let nonce_address = Pubkey::new_unique();
1976 let versions = NonceVersions::Legacy(Box::new(NonceState::Uninitialized));
1977 let nonce_account = new_nonce_account(versions);
1978 let accounts = process_instruction(
1979 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1980 vec![(nonce_address, nonce_account.clone())],
1981 vec![AccountMeta {
1982 pubkey: nonce_address,
1983 is_signer: false,
1984 is_writable: true,
1985 }],
1986 Err(InstructionError::InvalidArgument),
1987 );
1988 assert_eq!(accounts.len(), 1);
1989 assert_eq!(accounts[0], nonce_account);
1990 let versions = NonceVersions::Current(Box::new(NonceState::Uninitialized));
1991 let nonce_account = new_nonce_account(versions);
1992 let accounts = process_instruction(
1993 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
1994 vec![(nonce_address, nonce_account.clone())],
1995 vec![AccountMeta {
1996 pubkey: nonce_address,
1997 is_signer: false,
1998 is_writable: true,
1999 }],
2000 Err(InstructionError::InvalidArgument),
2001 );
2002 assert_eq!(accounts.len(), 1);
2003 assert_eq!(accounts[0], nonce_account);
2004 let blockhash = Hash::from([171; 32]);
2005 let durable_nonce = DurableNonce::from_blockhash(&blockhash);
2006 let data = NonceData {
2007 authority: Pubkey::new_unique(),
2008 durable_nonce,
2009 fee_calculator: FeeCalculator {
2010 kelvins_per_signature: 2718,
2011 },
2012 };
2013 let versions = NonceVersions::Legacy(Box::new(NonceState::Initialized(data.clone())));
2014 let nonce_account = new_nonce_account(versions);
2015 let accounts = process_instruction(
2016 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2017 vec![(nonce_address, nonce_account.clone())],
2018 vec![AccountMeta {
2019 pubkey: nonce_address,
2020 is_signer: false,
2021 is_writable: false, }],
2023 Err(InstructionError::InvalidArgument),
2024 );
2025 assert_eq!(accounts.len(), 1);
2026 assert_eq!(accounts[0], nonce_account);
2027 let mut accounts = process_instruction(
2028 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2029 vec![(nonce_address, nonce_account)],
2030 vec![AccountMeta {
2031 pubkey: nonce_address,
2032 is_signer: false,
2033 is_writable: true,
2034 }],
2035 Ok(()),
2036 );
2037 assert_eq!(accounts.len(), 1);
2038 let nonce_account = accounts.remove(0);
2039 let durable_nonce = DurableNonce::from_blockhash(durable_nonce.as_hash());
2040 assert_ne!(data.durable_nonce, durable_nonce);
2041 let data = NonceData {
2042 durable_nonce,
2043 ..data
2044 };
2045 let upgraded_nonce_account =
2046 NonceVersions::Current(Box::new(NonceState::Initialized(data)));
2047 assert_eq!(
2048 nonce_account.deserialize_data::<NonceVersions>().unwrap(),
2049 upgraded_nonce_account
2050 );
2051 let accounts = process_instruction(
2052 &serialize(&SystemInstruction::UpgradeNonceAccount).unwrap(),
2053 vec![(nonce_address, nonce_account)],
2054 vec![AccountMeta {
2055 pubkey: nonce_address,
2056 is_signer: false,
2057 is_writable: true,
2058 }],
2059 Err(InstructionError::InvalidArgument),
2060 );
2061 assert_eq!(accounts.len(), 1);
2062 assert_eq!(
2063 accounts[0].deserialize_data::<NonceVersions>().unwrap(),
2064 upgraded_nonce_account
2065 );
2066 }
2067
2068 #[test]
2069 fn test_assign_native_loader_and_transfer() {
2070 for size in [0, 10] {
2071 let pubkey = Pubkey::new_unique();
2072 let account = AccountSharedData::new(100, size, &system_program::id());
2073 let accounts = process_instruction(
2074 &bincode::serialize(&SystemInstruction::Assign {
2075 owner: rialo_s_sdk::native_loader::id(),
2076 })
2077 .unwrap(),
2078 vec![(pubkey, account.clone())],
2079 vec![AccountMeta {
2080 pubkey,
2081 is_signer: true,
2082 is_writable: true,
2083 }],
2084 Ok(()),
2085 );
2086 assert_eq!(accounts[0].owner(), &rialo_s_sdk::native_loader::id());
2087 assert_eq!(accounts[0].kelvins(), 100);
2088
2089 let pubkey2 = Pubkey::new_unique();
2090 let accounts = process_instruction(
2091 &bincode::serialize(&SystemInstruction::Transfer { kelvins: 50 }).unwrap(),
2092 vec![
2093 (
2094 pubkey2,
2095 AccountSharedData::new(100, 0, &system_program::id()),
2096 ),
2097 (pubkey, accounts[0].clone()),
2098 ],
2099 vec![
2100 AccountMeta {
2101 pubkey: pubkey2,
2102 is_signer: true,
2103 is_writable: true,
2104 },
2105 AccountMeta {
2106 pubkey,
2107 is_signer: false,
2108 is_writable: true,
2109 },
2110 ],
2111 Ok(()),
2112 );
2113 assert_eq!(accounts[1].owner(), &rialo_s_sdk::native_loader::id());
2114 assert_eq!(accounts[1].kelvins(), 150);
2115 }
2116 }
2117}