cairo_vm/vm/errors/
vm_errors.rs

1// The `(*.0).0` syntax of thiserror falsely triggers this clippy warning
2#![allow(clippy::explicit_auto_deref)]
3
4use crate::types::builtin_name::BuiltinName;
5use crate::{stdlib::prelude::*, Felt252};
6
7use thiserror::Error;
8
9use crate::{
10    types::{
11        errors::math_errors::MathError,
12        relocatable::{MaybeRelocatable, Relocatable},
13    },
14    vm::errors::{
15        exec_scope_errors::ExecScopeError, hint_errors::HintError, memory_errors::MemoryError,
16        runner_errors::RunnerError, trace_errors::TraceError,
17    },
18};
19
20pub const HINT_ERROR_STR: &str = "Got an exception while executing a hint: ";
21
22#[derive(Debug, Error)]
23pub enum VirtualMachineError {
24    #[error(transparent)]
25    RunnerError(#[from] RunnerError),
26    #[error(transparent)]
27    Memory(#[from] MemoryError),
28    #[error(transparent)]
29    Math(#[from] MathError),
30    #[error(transparent)]
31    TracerError(#[from] TraceError),
32    #[error(transparent)]
33    MainScopeError(#[from] ExecScopeError),
34    #[error(transparent)]
35    Other(anyhow::Error),
36    #[error("Instruction should be an int")]
37    InvalidInstructionEncoding,
38    #[error("Invalid op1_register value: {0}")]
39    InvalidOp1Reg(u128),
40    #[error("In immediate mode, off2 should be 1")]
41    ImmShouldBe1,
42    #[error("op0 must be known in double dereference")]
43    UnknownOp0,
44    #[error("Invalid ap_update value: {0}")]
45    InvalidApUpdate(u128),
46    #[error("Invalid pc_update value: {0}")]
47    InvalidPcUpdate(u128),
48    #[error("Res.UNCONSTRAINED cannot be used with ApUpdate.ADD")]
49    UnconstrainedResAdd,
50    #[error("Res.UNCONSTRAINED cannot be used with PcUpdate.JUMP")]
51    UnconstrainedResJump,
52    #[error("Res.UNCONSTRAINED cannot be used with PcUpdate.JUMP_REL")]
53    UnconstrainedResJumpRel,
54    #[error("Res.UNCONSTRAINED cannot be used with Opcode.ASSERT_EQ")]
55    UnconstrainedResAssertEq,
56    #[error("A relocatable value as Res cannot be used with PcUpdate.JUMP_REL")]
57    JumpRelNotInt,
58    #[error(
59        "Failed to compute Res.MUL: Could not complete computation of non pure values {} * {}", (*.0).0, (*.0).1
60    )]
61    ComputeResRelocatableMul(Box<(MaybeRelocatable, MaybeRelocatable)>),
62    #[error(
63        "Failed to compute operand, attempted to use {0} for an OpcodeExtension that is neither Stone nor QM31Operation"
64    )]
65    InvalidTypedOperationOpcodeExtension(Box<str>),
66    #[error("Couldn't compute operand {}. Unknown value for memory cell {}", (*.0).0, (*.0).1)]
67    FailedToComputeOperands(Box<(String, Relocatable)>),
68    #[error("An ASSERT_EQ instruction failed: {} != {}.", (*.0).0, (*.0).1)]
69    DiffAssertValues(Box<(MaybeRelocatable, MaybeRelocatable)>),
70    #[error("Call failed to write return-pc (inconsistent op0): {} != {}. Did you forget to increment ap?", (*.0).0, (*.0).1)]
71    CantWriteReturnPc(Box<(MaybeRelocatable, MaybeRelocatable)>),
72    #[error("Call failed to write return-fp (inconsistent dst): {} != {}. Did you forget to increment ap?", (*.0).0, (*.0).1)]
73    CantWriteReturnFp(Box<(MaybeRelocatable, MaybeRelocatable)>),
74    #[error("Couldn't get or load dst")]
75    NoDst,
76    #[error("Invalid res value: {0}")]
77    InvalidRes(u128),
78    #[error("Invalid opcode value: {0}")]
79    InvalidOpcode(u128),
80    #[error("Invalid opcode extension value: {0}")]
81    InvalidOpcodeExtension(u128),
82    #[error("Inconsistent auto-deduction for {}, expected {}, got {:?}", (*.0).0, (*.0).1, (*.0).2)]
83    InconsistentAutoDeduction(Box<(BuiltinName, MaybeRelocatable, Option<MaybeRelocatable>)>),
84    #[error("Expected output builtin to be present")]
85    NoOutputBuiltin,
86    #[error("Expected range_check builtin to be present")]
87    NoRangeCheckBuiltin,
88    #[error("Expected ecdsa builtin to be present")]
89    NoSignatureBuiltin,
90    #[error("Expected {0} to be present")]
91    NoModBuiltin(BuiltinName),
92    #[error("Failed to compare {} and {}, cant compare a relocatable to an integer value", (*.0).0, (*.0).1)]
93    DiffTypeComparison(Box<(MaybeRelocatable, MaybeRelocatable)>),
94    #[error("Failed to compare {} and  {}, cant compare two relocatable values of different segment indexes", (*.0).0, (*.0).1)]
95    DiffIndexComp(Box<(Relocatable, Relocatable)>),
96    #[error("Expected integer, found: {0:?}")]
97    ExpectedIntAtRange(Box<Option<MaybeRelocatable>>),
98    #[error("Could not convert slice to array")]
99    SliceToArrayError,
100    #[error("Failed to compile hint: {0}")]
101    CompileHintFail(Box<str>),
102    #[error("op1_addr is Op1Addr.IMM, but no immediate was given")]
103    NoImm,
104    #[error("Execution reached the end of the program. Requested remaining steps: {0}.")]
105    EndOfProgram(usize),
106    #[error("Could not reach the end of the program. RunResources has no remaining steps.")]
107    UnfinishedExecution,
108    #[error("Current run is not finished")]
109    RunNotFinished,
110    #[error("{HINT_ERROR_STR}{}", (*.0).1)]
111    Hint(Box<(usize, HintError)>),
112    #[error("Unexpected Failure")]
113    Unexpected,
114    #[error("Out of bounds access to builtin segment")]
115    OutOfBoundsBuiltinSegmentAccess,
116    #[error("Out of bounds access to program segment")]
117    OutOfBoundsProgramSegmentAccess,
118    #[error("Security Error: Invalid Memory Value: temporary address not relocated: {0}")]
119    InvalidMemoryValueTemporaryAddress(Box<Relocatable>),
120    #[error("accessed_addresses is None.")]
121    MissingAccessedAddresses,
122    #[error("Failed to write the output builtin content")]
123    FailedToWriteOutput,
124    #[error("Failed to find index {0} in the vm's relocation table")]
125    RelocationNotFound(usize),
126    #[error("{} batch size is not {}", (*.0).0, (*.0).1)]
127    ModBuiltinBatchSize(Box<(BuiltinName, usize)>),
128    #[error("Initial FP should have been initialized")]
129    MissingInitialFp,
130    #[error("Return FP address should be in memory: {0}")]
131    MissingReturnFp(Box<Relocatable>),
132    #[error("Return FP { } should equal expected final FP { }", (*.0).0, (*.0).1)]
133    MismatchReturnFP(Box<(Relocatable, Relocatable)>),
134    #[error("Return FP { } offset should equal expected final FP { } offset", (*.0).0, (*.0).1)]
135    MismatchReturnFPOffset(Box<(Relocatable, Relocatable)>),
136    #[error("Return FP felt { } should equal expected final FP { } offset", (*.0).0, (*.0).1)]
137    MismatchReturnFPFelt(Box<(Felt252, Relocatable)>),
138    #[error("Blake2s opcode invalid operand: op{0} does not point to {1} u32 numbers.")]
139    Blake2sInvalidOperand(u8, u8),
140    #[error("Blake2s opcode invalid flags {0}")]
141    InvalidBlake2sFlags(u128),
142    #[error("QM31 add mul opcode invalid flags {0}")]
143    InvalidQM31AddMulFlags(u128),
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    // Test to catch possible enum size regressions
152    fn test_vm_error_size() {
153        let size = crate::stdlib::mem::size_of::<VirtualMachineError>();
154        assert!(size <= 32, "{size}")
155    }
156}