alea_verifier/errors.rs
1use anchor_lang::prelude::*;
2
3/// Alea error codes. Codes 6000-6009 are assigned in declaration order
4/// and are part of the v1 CPI interface per ADR 0028 — never renumber,
5/// never remove (reserved even if unreachable, see NoSquareRoot).
6///
7/// Canonical source: `build-spec/program/spec.md §"Error Codes"`.
8/// Consumer SDKs (TS `@alea-drand/sdk` and Rust `alea-sdk`) map these 1:1.
9///
10/// # Anchor framework error codes to be aware of (not Alea-custom)
11///
12/// T2.AA (Codex C LOW) — Anchor 0.30.1 emits distinct framework codes
13/// for different failure modes on `UpdateConfig`. Consumers and
14/// monitoring must handle both:
15///
16/// - **2001 `ConstraintHasOne`**: `has_one = authority` mismatch —
17/// the `authority` account's pubkey does not equal `config.authority`.
18/// Fires AFTER account deserialization, BEFORE handler body.
19///
20/// - **3010 `AccountNotSigner`**: `authority: Signer<'info>` present
21/// but the account was passed without a signature. Fires during
22/// account resolution, EARLIER than 2001.
23///
24/// These are distinct failure modes: wrong key (2001) vs no signature
25/// (3010). Tests + monitoring should not conflate them.
26#[error_code]
27pub enum AleaError {
28 #[msg("BLS signature verification failed")]
29 InvalidSignature, // 6000 — alt_bn128_pairing Ok but result != GT_ONE
30
31 #[msg("Signature bytes are not a valid G1 point (y² != x³ + 3 mod p)")]
32 InvalidG1Point, // 6001 — pre-pairing on_curve_g1 check failed (T2.48)
33
34 #[msg("Round number must be greater than 0")]
35 RoundZero, // 6002 — drand has no valid beacon for round 0
36
37 #[msg("Reserved (unreachable in v1) — do not treat as retryable")]
38 InvalidFieldElement, // 6003 — T2.J: reserved per ADR 0028;
39 // unreachable in v1 (hash_to_field uses
40 // from_be_bytes_mod_order, no range check
41 // needed). Retained for future use if a
42 // future instruction adds a canonical-Fq
43 // guard. Consumers: if observed in prod,
44 // treat as non-retryable PairingError-class;
45 // do not loop.
46 #[msg("Square root does not exist for this field element")]
47 NoSquareRoot, // 6004 — T1.05: ACTIVATED. Emitted when
48 // hash_round_to_g1 returns None (all 3
49 // SVDW candidates fail try_sqrt_curve).
50 // SVDW theorem guarantees at least one
51 // is a QR, so in practice this signals
52 // a constant corruption or syscall oracle
53 // regression (not attacker-reachable
54 // under honest drand input).
55 #[msg("Public key bytes are not a valid G2 point")]
56 InvalidG2Point, // 6005 — UNREACHABLE under ADR 0027 fallback
57 // path (byte-for-byte hardcoded pubkey is
58 // strictly stronger than subgroup check
59 // for this single-chain deployment).
60 // Reserved per ADR 0028 CPI stability.
61 #[msg("Pairing check syscall failed")]
62 PairingError, // 6006 — alt_bn128_pairing returned Err OR
63 // output length != 32 (tri-state None
64 // branch). T1.05: g1_add also maps here
65 // when alt_bn128_addition syscall fails.
66 #[msg("chain_hash does not match EXPECTED_EVMNET_CHAIN_HASH (wrong-chain deployment)")]
67 WrongChainHash, // 6007 — ADR 0031 chain-hash guard
68
69 #[msg("pubkey_g2 does not match EXPECTED_EVMNET_G2_PUBKEY (ADR 0027 fallback path)")]
70 WrongPubkey, // 6008 — fallback G2 validation path (OPEN-ITEMS #4 RESOLVED)
71
72 #[msg("CPI consumer: get_return_data returned None (program upgrade mismatch?)")]
73 ReturnDataMissing, // 6009 — UNREACHABLE under Pattern A (ADR
74 // 0030 resolved Phase 2 Wave 10 P0#12).
75 // Retained per ADR 0028 CPI stability.
76 #[msg("genesis_time does not match EXPECTED_EVMNET_GENESIS_TIME")]
77 InvalidGenesisTime, // 6010 — T2.E (Wave E): byte-equality guard
78 // against evmnet constant. Appended per
79 // ADR 0028 append-only rule.
80 #[msg("period does not match EXPECTED_EVMNET_PERIOD")]
81 InvalidPeriod, // 6011 — T2.E (Wave E): byte-equality guard
82 // against evmnet constant. Appended per
83 // ADR 0028 append-only rule.
84 #[msg("initialize authority must equal the program's upgrade_authority_address")]
85 UnauthorizedInit, // 6012 — Wave X+1 (Codex Session C HIGH,
86 // 2026-04-17): FENDER-002 hardening at
87 // the program level. The `initialize`
88 // handler requires the signer's pubkey
89 // to equal the BPFLoaderUpgradeable
90 // ProgramData.upgrade_authority_address,
91 // closing the deploy-to-init front-run
92 // window that the prior `scripts/
93 // initialize.ts` operational mitigation
94 // could not close (Solana cannot bundle
95 // program deploy + first-init in a
96 // single tx — deploy is itself multi-tx
97 // upload). Appended per ADR 0028
98 // append-only rule.
99}