110 lines
3.5 KiB
Rust
110 lines
3.5 KiB
Rust
//! Program state processor
|
|
|
|
use solana_program::{
|
|
account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError,
|
|
pubkey::Pubkey,
|
|
};
|
|
use std::str::from_utf8;
|
|
|
|
/// Instruction processor
|
|
pub fn process_instruction(
|
|
_program_id: &Pubkey,
|
|
accounts: &[AccountInfo],
|
|
input: &[u8],
|
|
) -> ProgramResult {
|
|
let account_info_iter = &mut accounts.iter();
|
|
let mut missing_required_signature = false;
|
|
for account_info in account_info_iter {
|
|
if let Some(address) = account_info.signer_key() {
|
|
msg!("Signed by {:?}", address);
|
|
} else {
|
|
missing_required_signature = true;
|
|
}
|
|
}
|
|
if missing_required_signature {
|
|
return Err(ProgramError::MissingRequiredSignature);
|
|
}
|
|
|
|
let memo = from_utf8(input).map_err(|err| {
|
|
msg!("Invalid UTF-8, from byte {}", err.valid_up_to());
|
|
ProgramError::InvalidInstructionData
|
|
})?;
|
|
msg!("Memo (len {}): {:?}", memo.len(), memo);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use solana_program::{
|
|
account_info::IntoAccountInfo, program_error::ProgramError, pubkey::Pubkey,
|
|
};
|
|
use solana_sdk::account::Account;
|
|
|
|
#[test]
|
|
fn test_utf8_memo() {
|
|
let program_id = Pubkey::new(&[0; 32]);
|
|
|
|
let string = b"letters and such";
|
|
assert_eq!(Ok(()), process_instruction(&program_id, &[], string));
|
|
|
|
let emoji = "🐆".as_bytes();
|
|
let bytes = [0xF0, 0x9F, 0x90, 0x86];
|
|
assert_eq!(emoji, bytes);
|
|
assert_eq!(Ok(()), process_instruction(&program_id, &[], emoji));
|
|
|
|
let mut bad_utf8 = bytes;
|
|
bad_utf8[3] = 0xFF; // Invalid UTF-8 byte
|
|
assert_eq!(
|
|
Err(ProgramError::InvalidInstructionData),
|
|
process_instruction(&program_id, &[], &bad_utf8)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_signers() {
|
|
let program_id = Pubkey::new(&[0; 32]);
|
|
let memo = "🐆".as_bytes();
|
|
|
|
let pubkey0 = Pubkey::new_unique();
|
|
let pubkey1 = Pubkey::new_unique();
|
|
let pubkey2 = Pubkey::new_unique();
|
|
let mut account0 = Account::default();
|
|
let mut account1 = Account::default();
|
|
let mut account2 = Account::default();
|
|
|
|
let signed_account_infos = vec![
|
|
(&pubkey0, true, &mut account0).into_account_info(),
|
|
(&pubkey1, true, &mut account1).into_account_info(),
|
|
(&pubkey2, true, &mut account2).into_account_info(),
|
|
];
|
|
assert_eq!(
|
|
Ok(()),
|
|
process_instruction(&program_id, &signed_account_infos, memo)
|
|
);
|
|
|
|
assert_eq!(Ok(()), process_instruction(&program_id, &[], memo));
|
|
|
|
let unsigned_account_infos = vec![
|
|
(&pubkey0, false, &mut account0).into_account_info(),
|
|
(&pubkey1, false, &mut account1).into_account_info(),
|
|
(&pubkey2, false, &mut account2).into_account_info(),
|
|
];
|
|
assert_eq!(
|
|
Err(ProgramError::MissingRequiredSignature),
|
|
process_instruction(&program_id, &unsigned_account_infos, memo)
|
|
);
|
|
|
|
let partially_signed_account_infos = vec![
|
|
(&pubkey0, true, &mut account0).into_account_info(),
|
|
(&pubkey1, false, &mut account1).into_account_info(),
|
|
(&pubkey2, true, &mut account2).into_account_info(),
|
|
];
|
|
assert_eq!(
|
|
Err(ProgramError::MissingRequiredSignature),
|
|
process_instruction(&program_id, &partially_signed_account_infos, memo)
|
|
);
|
|
}
|
|
}
|