Skip to main content

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}