1use {
4 solana_account_info::AccountInfo, solana_msg::msg, solana_program_entrypoint::ProgramResult,
5 solana_program_error::ProgramError, solana_pubkey::Pubkey, std::str::from_utf8,
6};
7
8pub fn process_instruction(
10 _program_id: &Pubkey,
11 accounts: &[AccountInfo],
12 input: &[u8],
13) -> ProgramResult {
14 let account_info_iter = &mut accounts.iter();
15 let mut missing_required_signature = false;
16 for account_info in account_info_iter {
17 if let Some(address) = account_info.signer_key() {
18 msg!("Signed by {:?}", address);
19 } else {
20 missing_required_signature = true;
21 }
22 }
23 if missing_required_signature {
24 return Err(ProgramError::MissingRequiredSignature);
25 }
26
27 let memo = from_utf8(input).map_err(|err| {
28 msg!("Invalid UTF-8, from byte {}", err.valid_up_to());
29 ProgramError::InvalidInstructionData
30 })?;
31 msg!("Memo (len {}): {:?}", memo.len(), memo);
32
33 Ok(())
34}
35
36#[cfg(test)]
37mod tests {
38 use {
39 super::*, solana_account_info::IntoAccountInfo, solana_program_error::ProgramError,
40 solana_pubkey::Pubkey, solana_sdk::account::Account,
41 };
42
43 #[test]
44 fn test_utf8_memo() {
45 let program_id = Pubkey::new_from_array([0; 32]);
46
47 let string = b"letters and such";
48 assert_eq!(Ok(()), process_instruction(&program_id, &[], string));
49
50 let emoji = "🐆".as_bytes();
51 let bytes = [0xF0, 0x9F, 0x90, 0x86];
52 assert_eq!(emoji, bytes);
53 assert_eq!(Ok(()), process_instruction(&program_id, &[], emoji));
54
55 let mut bad_utf8 = bytes;
56 bad_utf8[3] = 0xFF; assert_eq!(
58 Err(ProgramError::InvalidInstructionData),
59 process_instruction(&program_id, &[], &bad_utf8)
60 );
61 }
62
63 #[test]
64 fn test_signers() {
65 let program_id = Pubkey::new_from_array([0; 32]);
66 let memo = "🐆".as_bytes();
67
68 let pubkey0 = Pubkey::new_unique();
69 let pubkey1 = Pubkey::new_unique();
70 let pubkey2 = Pubkey::new_unique();
71 let mut account0 = Account::default();
72 let mut account1 = Account::default();
73 let mut account2 = Account::default();
74
75 let signed_account_infos = vec![
76 (&pubkey0, true, &mut account0).into_account_info(),
77 (&pubkey1, true, &mut account1).into_account_info(),
78 (&pubkey2, true, &mut account2).into_account_info(),
79 ];
80 assert_eq!(
81 Ok(()),
82 process_instruction(&program_id, &signed_account_infos, memo)
83 );
84
85 assert_eq!(Ok(()), process_instruction(&program_id, &[], memo));
86
87 let unsigned_account_infos = vec![
88 (&pubkey0, false, &mut account0).into_account_info(),
89 (&pubkey1, false, &mut account1).into_account_info(),
90 (&pubkey2, false, &mut account2).into_account_info(),
91 ];
92 assert_eq!(
93 Err(ProgramError::MissingRequiredSignature),
94 process_instruction(&program_id, &unsigned_account_infos, memo)
95 );
96
97 let partially_signed_account_infos = vec![
98 (&pubkey0, true, &mut account0).into_account_info(),
99 (&pubkey1, false, &mut account1).into_account_info(),
100 (&pubkey2, true, &mut account2).into_account_info(),
101 ];
102 assert_eq!(
103 Err(ProgramError::MissingRequiredSignature),
104 process_instruction(&program_id, &partially_signed_account_infos, memo)
105 );
106 }
107}