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