Skip to main content

wanning_core/
error.rs

1//! 核心错误类型。
2//!
3//! 语义分层,别混淆:
4//! - **业务拒绝**不是错误——是 [`crate::gate::GateDecision::Deny`],属于闸的正常输出,
5//!   必须落 WAL、必须给出 reason。
6//! - [`CoreError`] 只表示**调用方用错了 API / 配置非法 / 状态被破坏**,此时闸拒绝继续,
7//!   fail-closed(宁可停,不可放)。
8
9use std::fmt;
10
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub enum CoreError {
13    /// 委托注册被拒:字段非法(空 id / 预算为 0 / 有效期倒挂等)。fail-closed:宁可注册失败。
14    InvalidDelegation(String),
15    /// 意图非法:金额或 nonce 为 0、必填字段为空。
16    InvalidIntent(String),
17    /// 引用了不存在的委托(撤销/查询)。
18    UnknownDelegation(String),
19    /// 委托 id 重复注册。
20    DuplicateDelegation(String),
21    /// 账本累计溢出(u64)。状态异常,fail-closed:宁可报错也不回绕把巨额记成小额。
22    LedgerOverflow(String),
23    /// 在闸未放行的情况下调用了 `commit`(API 误用,程序员错误)。
24    /// 正常流程是 evaluate → (写审计) → commit;直接 commit 会被这里拦下。
25    CommitRejected(String),
26    /// WAL 打开/读写失败。
27    WalIo(String),
28    /// 单写者锁被占:同一份 WAL 已有另一个活着的写进程。fail-closed 拒启——
29    /// 两个闸共写一份审计 = 预算硬上限失效、同一 nonce 跨进程放行两次。
30    WalLocked { path: String, message: String },
31    /// WAL 里有一行读不懂(半行 JSON / 空行 / 未知结构)。**绝不静默跳过**。
32    WalBadLine { line: u64, message: String },
33    /// WAL 完整性链断裂(`seq` 与物理行号不符 / `prev` 与按前文重算的链值不符)。
34    /// 这是日志被改(改字段/删行/重排/复制)的痕迹,fail-closed 拒读拒续写。
35    WalChainBroken { line: u64, message: String },
36    /// 回放时重算结果与记录不一致(日志被改 / 实时与回放口径漂移)。fail-closed 停机。
37    WalMismatch { line: u64, message: String },
38    /// 审计锚点文件非法:格式/字段读不懂,或 MAC 与所有者密钥对不上(锚点不是
39    /// 所有者签的,或锚点本身被改)。fail-closed:不可信的锚点比没有锚点更危险。
40    AnchorInvalid(String),
41    /// 当前 WAL 与合法锚点不符:整体截尾(行数不足)或被锚定的前缀内容被改。
42    /// 这是 W-21 完整性链已知边界(尾行篡改/截尾本地验不住)的抓法。
43    AnchorMismatch(String),
44}
45
46impl fmt::Display for CoreError {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        match self {
49            CoreError::InvalidDelegation(m) => write!(f, "委托注册被拒(非法配置): {m}"),
50            CoreError::InvalidIntent(m) => write!(f, "消费意图非法: {m}"),
51            CoreError::UnknownDelegation(id) => write!(f, "未知委托: {id}"),
52            CoreError::DuplicateDelegation(id) => write!(f, "委托重复注册: {id}"),
53            CoreError::LedgerOverflow(m) => write!(f, "账本溢出(状态异常,fail-closed): {m}"),
54            CoreError::CommitRejected(m) => write!(f, "commit 被拒(闸未放行,API 误用): {m}"),
55            CoreError::WalIo(m) => write!(f, "审计日志 IO 失败(fail-closed): {m}"),
56            CoreError::WalLocked { path, message } => {
57                write!(
58                    f,
59                    "审计日志单写者锁被占(fail-closed 拒启): {message}[锁文件: {path}]"
60                )
61            }
62            CoreError::WalBadLine { line, message } => {
63                write!(
64                    f,
65                    "审计日志第 {line} 行损坏(fail-closed,不静默跳过): {message}"
66                )
67            }
68            CoreError::WalChainBroken { line, message } => {
69                write!(
70                    f,
71                    "审计日志第 {line} 行完整性链断裂(fail-closed): {message}"
72                )
73            }
74            CoreError::WalMismatch { line, message } => {
75                write!(
76                    f,
77                    "审计日志第 {line} 行回放对账不一致(fail-closed): {message}"
78                )
79            }
80            CoreError::AnchorInvalid(m) => {
81                write!(f, "审计锚点文件不可信(fail-closed): {m}")
82            }
83            CoreError::AnchorMismatch(m) => {
84                write!(f, "审计日志与所有者锚点不符——审计被动过(fail-closed): {m}")
85            }
86        }
87    }
88}
89
90impl std::error::Error for CoreError {}