Solana基础 - 如何在 Solana 程序中验证账户
由于 Solana 中的程序是无状态的,因此作为程序创建者,我们必须确保传递的帐户尽可能得到验证,以避免任何恶意帐户进入。可以进行的基本检查包括
- 检查预期签名者帐户是否确实已签名
- 检查预期状态帐户是否已被检查为可写
- 检查预期状态账户的所有者是否是被调用的程序 ID
- 如果第一次初始化状态,请检查账户是否已经初始化。
- 检查传递的任何跨程序 ID(无论何时需要)是否符合预期。
初始化HelloState账户的基本指令,但使用上述检查,定义如下
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
account_info::{next_account_info, AccountInfo},
clock::Clock,
entrypoint,
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
pubkey::Pubkey,
rent::Rent,
system_program::ID as SYSTEM_PROGRAM_ID,
sysvar::Sysvar,
};
entrypoint!(process_instruction);
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct HelloState {
is_initialized: bool,
}
// Accounts required
/// 1. [signer] Payer
/// 2. [writable] Hello state account
/// 3. [] System Program
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
let accounts_iter = &mut accounts.iter();
// Payer account
let payer_account = next_account_info(accounts_iter)?;
// Hello state account
let hello_state_account = next_account_info(accounts_iter)?;
// System Program
let system_program = next_account_info(accounts_iter)?;
let rent = Rent::get()?;
// 检查付款人账户是否是签名者
if !payer_account.is_signer {
return Err(ProgramError::MissingRequiredSignature);
}
// 检查 Hello State 账户是否免租
if !rent.is_exempt(hello_state_account.lamports(), 1) {
return Err(ProgramError::AccountNotRentExempt);
}
// 检查 hello 状态帐户是否可写
if !hello_state_account.is_writable {
return Err(ProgramError::InvalidAccountData);
}
// 检查 hello 状态账户的所有者是否是当前程序
if hello_state_account.owner.ne(&program_id) {
return Err(ProgramError::IllegalOwner);
}
// 检查系统程序是否有效
if system_program.key.ne(&SYSTEM_PROGRAM_ID) {
return Err(ProgramError::IncorrectProgramId);
}
let mut hello_state = HelloState::try_from_slice(&hello_state_account.data.borrow())?;
// 检查状态是否已初始化
if hello_state.is_initialized {
return Err(ProgramError::AccountAlreadyInitialized);
}
hello_state.is_initialized = true;
hello_state.serialize(&mut &mut hello_state_account.data.borrow_mut()[..])?;
msg!("Account initialized :)");
Ok(())
}https://solana.com/zh/developers/cookbook/programs/verify-accounts