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