Solana基础 - 如何在 Solana 程序中验证账户

2025-03-19 15:36:14

由于 Solana 中的程序是无状态的,因此作为程序创建者,我们必须确保传递的帐户尽可能得到验证,以避免任何恶意帐户进入。可以进行的基本检查包括

  1. 检查预期签名者帐户是否确实已签名
  2. 检查预期状态帐户是否已被检查为可写
  3. 检查预期状态账户的所有者是否是被调用的程序 ID
  4. 如果第一次初始化状态,请检查账户是否已经初始化。
  5. 检查传递的任何跨程序 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

当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »