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}