fuel_asm/panic_reason.rs
1use core::fmt;
2
3macro_rules! enum_from {
4 (
5 $(#[$meta:meta])* $vis:vis enum $name:ident {
6 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
7 }
8 ) => {
9 $(#[$meta])*
10 $vis enum $name {
11 $($(#[$vmeta])* $vname $(= $val)?,)*
12 }
13
14 impl From<u8> for $name {
15 fn from(v: u8) -> Self {
16 match v {
17 $(x if x == $name::$vname as u8 => $name::$vname,)*
18 _ => $name::UnknownPanicReason,
19 }
20 }
21 }
22 }
23}
24
25enum_from! {
26 #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, strum::EnumIter)]
27 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
28 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29 #[repr(u8)]
30 #[non_exhaustive]
31 /// Panic reason representation for the interpreter.
32 pub enum PanicReason {
33 #[default]
34 /// The byte can't be mapped to any known `PanicReason`.
35 UnknownPanicReason = 0x00,
36 /// Found `RVRT` instruction.
37 Revert = 0x01,
38 /// Execution ran out of gas.
39 OutOfGas = 0x02,
40 /// The transaction validity is violated.
41 TransactionValidity = 0x03,
42 /// Attempt to write outside interpreter memory boundaries.
43 MemoryOverflow = 0x04,
44 /// Overflow while executing arithmetic operation.
45 /// These errors are ignored using the WRAPPING flag.
46 ArithmeticOverflow = 0x05,
47 /// Designed contract was not found in the storage.
48 ContractNotFound = 0x06,
49 /// Memory ownership rules are violated.
50 MemoryOwnership = 0x07,
51 /// The asset ID balance isn't enough for the instruction.
52 NotEnoughBalance = 0x08,
53 /// The interpreter is expected to be in internal context.
54 ExpectedInternalContext = 0x09,
55 /// The queried asset ID was not found in the state.
56 AssetIdNotFound = 0x0a,
57 /// The provided input is not found in the transaction.
58 InputNotFound = 0x0b,
59 /// The provided output is not found in the transaction.
60 OutputNotFound = 0x0c,
61 /// The provided witness is not found in the transaction.
62 WitnessNotFound = 0x0d,
63 /// The transaction maturity is not valid for this request.
64 TransactionMaturity = 0x0e,
65 /// The metadata identifier is invalid.
66 InvalidMetadataIdentifier = 0x0f,
67 /// The call structure is not valid.
68 MalformedCallStructure = 0x10,
69 /// The provided register does not allow write operations.
70 ReservedRegisterNotWritable = 0x11,
71 /// The execution resulted in an erroneous state of the interpreter.
72 InvalidFlags = 0x12,
73 /// The provided immediate value is not valid for this instruction.
74 InvalidImmediateValue = 0x13,
75 /// The provided transaction input is not of type `Coin`.
76 ExpectedCoinInput = 0x14,
77 /// `ECAL` instruction failed.
78 EcalError = 0x15,
79 /// Two segments of the interpreter memory should not intersect for write operations.
80 MemoryWriteOverlap = 0x16,
81 /// The requested contract is not listed in the transaction inputs.
82 ContractNotInInputs = 0x17,
83 /// The internal asset ID balance overflowed with the provided instruction.
84 InternalBalanceOverflow = 0x18,
85 /// The maximum allowed contract size is violated.
86 ContractMaxSize = 0x19,
87 /// This instruction expects the stack area to be unallocated for this call.
88 ExpectedUnallocatedStack = 0x1a,
89 /// The maximum allowed number of static contracts was reached for this transaction.
90 MaxStaticContractsReached = 0x1b,
91 /// The requested transfer amount cannot be zero.
92 TransferAmountCannotBeZero = 0x1c,
93 /// The provided transaction output should be of type `Variable`.
94 ExpectedOutputVariable = 0x1d,
95 /// The expected context of the stack parent is internal.
96 ExpectedParentInternalContext = 0x1e,
97 /// The predicate returned non `1`. The `1` means successful verification
98 /// of the predicate, all other values means unsuccessful.
99 PredicateReturnedNonOne = 0x1f,
100 /// The contract ID is already deployed and can't be overwritten.
101 ContractIdAlreadyDeployed = 0x20,
102 /// The loaded contract mismatch expectations.
103 ContractMismatch = 0x21,
104 /// Attempting to send message data longer than `MAX_MESSAGE_DATA_LENGTH`
105 MessageDataTooLong = 0x22,
106 /// Mathematically invalid arguments where given to an arithmetic instruction.
107 /// For instance, division by zero produces this.
108 /// These errors are ignored using the UNSAFEMATH flag.
109 ArithmeticError = 0x23,
110 /// The contract instruction is not allowed in predicates.
111 ContractInstructionNotAllowed = 0x24,
112 /// Transfer of zero coins is not allowed.
113 TransferZeroCoins = 0x25,
114 /// Attempted to execute an invalid instruction
115 InvalidInstruction = 0x26,
116 /// Memory outside $is..$ssp range is not executable
117 MemoryNotExecutable = 0x27,
118 /// The policy is not set.
119 PolicyIsNotSet = 0x28,
120 /// The policy is not found across policies.
121 PolicyNotFound = 0x29,
122 /// Receipt context is full
123 TooManyReceipts = 0x2a,
124 /// Balance of a contract overflowed
125 BalanceOverflow = 0x2b,
126 /// Block height value is invalid, typically because it is too large
127 InvalidBlockHeight = 0x2c,
128 /// Attempt to use sequential memory instructions with too large slot count,
129 /// typically because it cannot fit into usize
130 TooManySlots = 0x2d,
131 /// Caller of this internal context is also expected to be internal,
132 /// i.e. $fp->$fp must be non-zero.
133 ExpectedNestedCaller = 0x2e,
134 /// During memory growth, the stack overlapped with the heap
135 MemoryGrowthOverlap = 0x2f,
136 /// Attempting to read or write uninitialized memory.
137 /// Also occurs when boundary crosses from stack to heap.
138 UninitalizedMemoryAccess = 0x30,
139 /// Overriding consensus parameters is not allowed.
140 OverridingConsensusParameters = 0x31,
141 /// The storage doesn't know about the hash of the state transition bytecode.
142 UnknownStateTransactionBytecodeRoot = 0x32,
143 /// Overriding the state transition bytecode is not allowed.
144 OverridingStateTransactionBytecode = 0x33,
145 /// The bytecode is already uploaded and cannot be uploaded again.
146 BytecodeAlreadyUploaded = 0x34,
147 /// The part of the bytecode is not sequentially connected to the previous parts.
148 ThePartIsNotSequentiallyConnected = 0x35,
149 /// The requested blob is not found.
150 BlobNotFound = 0x36,
151 /// The blob was already
152 BlobIdAlreadyUploaded = 0x37,
153 /// Active gas costs do not define the cost for this instruction.
154 GasCostNotDefined = 0x38,
155 /// The curve id is not supported.
156 UnsupportedCurveId = 0x39,
157 /// The operation type is not supported.
158 UnsupportedOperationType = 0x3a,
159 /// Read alt_bn_128 curve point is invalid.
160 InvalidEllipticCurvePoint = 0x3b,
161 /// Given input contract does not exist.
162 InputContractDoesNotExist = 0x3c,
163 }
164}
165
166impl fmt::Display for PanicReason {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 write!(f, "{self:?}")
169 }
170}
171
172impl From<core::array::TryFromSliceError> for PanicReason {
173 fn from(_: core::array::TryFromSliceError) -> Self {
174 Self::MemoryOverflow
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use strum::IntoEnumIterator;
182
183 #[test]
184 fn test_u8_panic_reason_round_trip() {
185 let last_known_panic_reason: u8 = PanicReason::iter().last().unwrap() as u8 + 1;
186 let reason = PanicReason::from(0);
187 assert_eq!(reason, PanicReason::UnknownPanicReason);
188
189 for i in 1..last_known_panic_reason {
190 let reason = PanicReason::from(i);
191 let i2 = reason as u8;
192 assert_eq!(i, i2);
193 }
194 for i in last_known_panic_reason..=255 {
195 let reason = PanicReason::from(i);
196 let i2 = reason as u8;
197 assert_eq!(PanicReason::UnknownPanicReason as u8, i2);
198 }
199 }
200}