LogoAnchor 中文文档

自定义错误

学习如何在 Anchor 程序中实现自定义错误处理。

在 Anchor 程序中,所有指令处理程序都返回一个自定义的 Result<T> 类型,允许你通过 Ok(T) 处理成功执行,并通过 Err(Error) 处理错误情况。


pub fn custom_instruction(ctx: Context<CustomInstruction>) -> Result<()> {
    // --snip--
    Ok(())
}

在 Anchor 程序中,Result<T> 类型是一个类型别名,它封装了标准的 Rust Result<T, E>。在这种情况下,T 表示成功的返回类型,而 E 则是 Anchor 的自定义 Error 类型。

pub type Result<T> = std::result::Result<T, error::Error>;

Anchor 错误

当 Anchor 程序中发生错误时,它会返回一个自定义的 Error 类型,定义为:

#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    AnchorError(Box<AnchorError>),
    ProgramError(Box<ProgramErrorWithOrigin>),
}

Anchor 程序中的 Error 类型可以是以下两种变体之一:

  1. ProgramErrorWithOrigin:一种自定义类型,它封装了标准的 Solana ProgramError 类型。这些错误来自 solana_program crate。
#[derive(Debug)]
pub struct ProgramErrorWithOrigin {
    pub program_error: ProgramError,
    pub error_origin: Optional<ErrorOrigin>,
    pub compared_values: Optional<ComparedValues>,
}
  1. AnchorError:由 Anchor 框架定义的错误。
#[derive(Debug)]
pub struct AnchorError {
    pub error_name: String,
    pub error_code_number: u32,
    pub error_msg: String,
    pub error_origin: Optional<ErrorOrigin>,
    pub compared_values: Optional<ComparedValues>,
}

AnchorError 可以看作是具有以下两种类别:

  1. 内部 Anchor 错误 - 这些是 Anchor 框架内置的错误。它们在 ErrorCode 枚举中定义。

  2. 自定义程序错误 - 这些是开发者定义的特定于程序的错误,用于处理自定义错误情况。

AnchorErrorerror_code_number 具有以下编号方案:

错误代码描述
>= 100指令错误代码
>= 1000IDL 错误代码
>= 2000约束错误代码
>= 3000账户错误代码
>= 4100杂项错误代码
= 5000已弃用的错误代码
>= 6000自定义用户错误的起始点

使用

Anchor 提供了一种通过 error_code 属性定义自定义错误的便捷方法。实现细节可以在这里找到。

当你使用 error_code 属性定义一个枚举时,Anchor 会自动:

  • 从 6000 开始分配错误代码
  • 生成必要的错误处理样板代码
  • 启用通过 msg 属性使用自定义错误消息
#[error_code]
pub enum MyError {
    #[msg("我的自定义错误消息")]
    MyCustomError,
    #[msg("我的第二个自定义错误消息")]
    MySecondCustomError,
}

err!

要抛出错误,请使用 err! 宏。err! 宏提供了一种便捷的方式从程序中返回自定义错误。在底层,err! 使用 error! 宏来构建 AnchorError。实现可以在这里找到。

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData, data: MyAccount) - Result<() {
        if data.data = 100 {


            return err!(MyError::DataTooLarge);
        }
        ctx.accounts.my_account.set_inner(data);
        Ok(())
    }
}
 
 
#[error_code]
pub enum MyError {
    #[msg("MyAccount 只能保存小于 100 的数据")]
    DataTooLarge
}

require!

require! 宏提供了一种更简洁的方式来处理错误条件。它结合了条件检查和条件为假时返回错误的功能。以下是我们如何使用 require! 重写前面的示例:

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData, data: MyAccount) - Result<() {


        require!(data.data < 100, MyError::DataTooLarge);
        ctx.accounts.my_account.set_inner(data);
        Ok(())
    }
}
 
 
#[error_code]
pub enum MyError {
    #[msg("MyAccount 只能保存小于 100 的数据")]
    DataTooLarge
}

Anchor 提供了几个 "require" 宏来满足不同的验证需求。你可以在这里找到这些宏的实现。

描述
require!确保条件为真,否则返回给定的错误。
require_eq!确保两个 NON-PUBKEY 值相等。
require_neq!确保两个 NON-PUBKEY 值不相等。
require_keys_eq!确保两个 pubkeys 值相等。
require_keys_neq!确保两个 pubkeys 值不相等。
require_gt!确保第一个 NON-PUBKEY 值大于第二个 NON-PUBKEY 值。
require_gte!确保第一个 NON-PUBKEY 值大于或等于第二个 NON-PUBKEY 值。

示例

以下是一个简单的示例,演示了如何在 Anchor 程序中定义和处理自定义错误。下面的程序验证输入金额是否在可接受范围内,展示了如何:

  • 定义带有消息的自定义错误类型
  • 使用 require! 宏检查条件并返回错误
lib.rs
use anchor_lang::prelude::*;
 
declare_id!("9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV");
 
#[program]
pub mod custom_error {
    use super::*;
 
    pub fn validate_amount(_ctx: Context<ValidateAmount, amount: u64) - Result<() {


        require!(amount = 10, CustomError::AmountTooSmall);
        require!(amount <= 100, CustomError::AmountTooLarge);
 
        msg!("金额验证成功: {}", amount);
        Ok(())
    }
}
 
#[derive(Accounts)]
pub struct ValidateAmount {}
 
#[error_code]
pub enum CustomError {
    #[msg("金额必须大于或等于 10")]
    AmountTooSmall,
    #[msg("金额必须小于或等于 100")]
    AmountTooLarge,
}

当程序错误发生时,Anchor 的 TypeScript 客户端 SDK 返回一个详细的错误响应,其中包含有关错误的信息。以下是一个错误响应的示例,展示了结构和可用字段:

错误响应
{
  errorLogs: [
    'Program log: AnchorError thrown in programs/custom-error/src/lib.rs:11. Error Code: AmountTooLarge. Error Number: 6001. Error Message: 金额必须小于或等于 100.'
  ],
  logs: [
    'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV invoke [1]',
    'Program log: Instruction: ValidateAmount',
    'Program log: AnchorError thrown in programs/custom-error/src/lib.rs:11. Error Code: AmountTooLarge. Error Number: 6001. Error Message: 金额必须小于或等于 100.',
    'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV consumed 2153 of 200000 compute units',
    'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV failed: custom program error: 0x1771'
  ],
  error: {
    errorCode: { code: 'AmountTooLarge', number: 6001 },
    errorMessage: '金额必须小于或等于 100',
    comparedValues: undefined,
    origin: { file: 'programs/custom-error/src/lib.rs', line: 11 }
  },
  _programErrorStack: ProgramErrorStack {
    stack: [
      [PublicKey [PublicKey(9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV)]]
    ]
  }
}

有关更全面的示例,你还可以参考 Anchor 仓库中的错误测试程序

On this page

在GitHub上编辑