1use std::fmt::{self, Error, Formatter};
2
3use borsh::{BorshDeserialize, BorshSerialize};
4use near_account_id::AccountId;
5use near_rpc_error_macro::RpcError;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
9pub enum VMError {
10 FunctionCallError(FunctionCallError),
11 ExternalError(Vec<u8>),
13 InconsistentStateError(InconsistentStateError),
16 CacheError(CacheError),
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize)]
22pub enum FunctionCallError {
23 CompilationError(CompilationError),
25 LinkError {
27 msg: String,
28 },
29 MethodResolveError(MethodResolveError),
31 WasmTrap(WasmTrap),
33 WasmUnknownError {
34 debug_message: String,
35 },
36 HostError(HostError),
37 _EVMError,
40 Nondeterministic(String),
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
49pub enum FunctionCallErrorSer {
50 CompilationError(CompilationError),
52 LinkError {
54 msg: String,
55 },
56 MethodResolveError(MethodResolveError),
58 WasmTrap(WasmTrap),
60 WasmUnknownError,
61 HostError(HostError),
62 _EVMError,
65 ExecutionError(String),
66}
67
68#[derive(
69 Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
70)]
71pub enum CacheError {
72 ReadError,
73 WriteError,
74 DeserializationError,
75 SerializationError { hash: [u8; 32] },
76}
77#[derive(
79 Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
80)]
81pub enum WasmTrap {
82 Unreachable,
84 IncorrectCallIndirectSignature,
86 MemoryOutOfBounds,
88 CallIndirectOOB,
90 IllegalArithmetic,
92 MisalignedAtomicAccess,
94 IndirectCallToNull,
96 StackOverflow,
98 GenericTrap,
100}
101
102#[derive(
103 Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
104)]
105pub enum MethodResolveError {
106 MethodEmptyName,
107 MethodNotFound,
108 MethodInvalidSignature,
109}
110
111#[derive(
112 Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
113)]
114pub enum CompilationError {
115 CodeDoesNotExist { account_id: AccountId },
116 PrepareError(PrepareError),
117 WasmerCompileError { msg: String },
118 UnsupportedCompiler { msg: String },
119}
120
121#[derive(
122 Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
123)]
124pub enum PrepareError {
126 Serialization,
128 Deserialization,
130 InternalMemoryDeclared,
132 GasInstrumentation,
136 StackHeightInstrumentation,
140 Instantiate,
145 Memory,
147}
148
149#[derive(
150 Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize, RpcError,
151)]
152pub enum HostError {
153 BadUTF16,
155 BadUTF8,
157 GasExceeded,
159 GasLimitExceeded,
161 BalanceExceeded,
163 EmptyMethodName,
165 GuestPanic { panic_msg: String },
167 IntegerOverflow,
169 InvalidPromiseIndex { promise_idx: u64 },
171 CannotAppendActionToJointPromise,
173 CannotReturnJointPromise,
175 InvalidPromiseResultIndex { result_idx: u64 },
177 InvalidRegisterId { register_id: u64 },
179 IteratorWasInvalidated { iterator_index: u64 },
181 MemoryAccessViolation,
183 InvalidReceiptIndex { receipt_index: u64 },
185 InvalidIteratorIndex { iterator_index: u64 },
187 InvalidAccountId,
189 InvalidMethodName,
191 InvalidPublicKey,
193 ProhibitedInView { method_name: String },
195 NumberOfLogsExceeded { limit: u64 },
197 KeyLengthExceeded { length: u64, limit: u64 },
199 ValueLengthExceeded { length: u64, limit: u64 },
201 TotalLogLengthExceeded { length: u64, limit: u64 },
203 NumberPromisesExceeded { number_of_promises: u64, limit: u64 },
205 NumberInputDataDependenciesExceeded { number_of_input_data_dependencies: u64, limit: u64 },
207 ReturnedValueLengthExceeded { length: u64, limit: u64 },
209 ContractSizeExceeded { size: u64, limit: u64 },
211 Deprecated { method_name: String },
213 ECRecoverError { msg: String },
215 #[cfg(feature = "protocol_feature_alt_bn128")]
217 AltBn128DeserializationError { msg: String },
218 #[cfg(feature = "protocol_feature_alt_bn128")]
220 AltBn128SerializationError { msg: String },
221}
222
223#[derive(Debug, Clone, PartialEq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)]
224pub enum VMLogicError {
225 HostError(HostError),
227 ExternalError(Vec<u8>),
229 InconsistentStateError(InconsistentStateError),
231}
232
233impl std::error::Error for VMLogicError {}
234
235#[derive(Debug, Clone, PartialEq, Eq, BorshDeserialize, BorshSerialize, Deserialize, Serialize)]
238pub enum InconsistentStateError {
239 StorageError(String),
240 IntegerOverflow,
242}
243
244impl From<HostError> for VMLogicError {
245 fn from(err: HostError) -> Self {
246 VMLogicError::HostError(err)
247 }
248}
249
250impl From<InconsistentStateError> for VMLogicError {
251 fn from(err: InconsistentStateError) -> Self {
252 VMLogicError::InconsistentStateError(err)
253 }
254}
255
256impl From<PrepareError> for VMError {
257 fn from(err: PrepareError) -> Self {
258 VMError::FunctionCallError(FunctionCallError::CompilationError(
259 CompilationError::PrepareError(err),
260 ))
261 }
262}
263
264impl From<&VMLogicError> for VMError {
265 fn from(err: &VMLogicError) -> Self {
266 match err {
267 VMLogicError::HostError(h) => {
268 VMError::FunctionCallError(FunctionCallError::HostError(h.clone()))
269 }
270 VMLogicError::ExternalError(s) => VMError::ExternalError(s.clone()),
271 VMLogicError::InconsistentStateError(e) => VMError::InconsistentStateError(e.clone()),
272 }
273 }
274}
275
276impl fmt::Display for VMLogicError {
277 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
278 write!(f, "{:?}", self)
279 }
280}
281
282impl fmt::Display for PrepareError {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
284 use PrepareError::*;
285 match self {
286 Serialization => write!(f, "Error happened while serializing the module."),
287 Deserialization => write!(f, "Error happened while deserializing the module."),
288 InternalMemoryDeclared => {
289 write!(f, "Internal memory declaration has been found in the module.")
290 }
291 GasInstrumentation => write!(f, "Gas instrumentation failed."),
292 StackHeightInstrumentation => write!(f, "Stack instrumentation failed."),
293 Instantiate => write!(f, "Error happened during instantiation."),
294 Memory => write!(f, "Error creating memory"),
295 }
296 }
297}
298
299impl fmt::Display for FunctionCallError {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
301 match self {
302 FunctionCallError::CompilationError(e) => e.fmt(f),
303 FunctionCallError::MethodResolveError(e) => e.fmt(f),
304 FunctionCallError::HostError(e) => e.fmt(f),
305 FunctionCallError::LinkError { msg } => write!(f, "{}", msg),
306 FunctionCallError::WasmTrap(trap) => write!(f, "WebAssembly trap: {}", trap),
307 FunctionCallError::WasmUnknownError { debug_message } => {
308 write!(f, "Unknown error during Wasm contract execution: {}", debug_message)
309 }
310 FunctionCallError::Nondeterministic(msg) => {
311 write!(f, "Nondeterministic error during contract execution: {}", msg)
312 }
313 FunctionCallError::_EVMError => unreachable!(),
314 }
315 }
316}
317
318impl fmt::Display for WasmTrap {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
320 match self {
321 WasmTrap::Unreachable => write!(f, "An `unreachable` opcode was executed."),
322 WasmTrap::IncorrectCallIndirectSignature => {
323 write!(f, "Call indirect incorrect signature trap.")
324 }
325 WasmTrap::MemoryOutOfBounds => write!(f, "Memory out of bounds trap."),
326 WasmTrap::CallIndirectOOB => write!(f, "Call indirect out of bounds trap."),
327 WasmTrap::IllegalArithmetic => {
328 write!(f, "An arithmetic exception, e.g. divided by zero.")
329 }
330 WasmTrap::MisalignedAtomicAccess => write!(f, "Misaligned atomic access trap."),
331 WasmTrap::GenericTrap => write!(f, "Generic trap."),
332 WasmTrap::StackOverflow => write!(f, "Stack overflow."),
333 WasmTrap::IndirectCallToNull => write!(f, "Indirect call to null."),
334 }
335 }
336}
337
338impl fmt::Display for CompilationError {
339 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
340 match self {
341 CompilationError::CodeDoesNotExist { account_id } => {
342 write!(f, "cannot find contract code for account {}", account_id)
343 }
344 CompilationError::PrepareError(p) => write!(f, "PrepareError: {}", p),
345 CompilationError::WasmerCompileError { msg } => {
346 write!(f, "Wasmer compilation error: {}", msg)
347 }
348 CompilationError::UnsupportedCompiler { msg } => {
349 write!(f, "Unsupported compiler: {}", msg)
350 }
351 }
352 }
353}
354
355impl fmt::Display for MethodResolveError {
356 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
357 fmt::Debug::fmt(self, f)
358 }
359}
360
361impl fmt::Display for VMError {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
363 match self {
364 VMError::FunctionCallError(err) => fmt::Display::fmt(err, f),
365 VMError::ExternalError(_err) => write!(f, "Serialized ExternalError"),
366 VMError::InconsistentStateError(err) => fmt::Display::fmt(err, f),
367 VMError::CacheError(err) => write!(f, "Cache error: {:?}", err),
368 }
369 }
370}
371
372impl std::fmt::Display for InconsistentStateError {
373 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
374 match self {
375 InconsistentStateError::StorageError(err) => write!(f, "Storage error: {:?}", err),
376 InconsistentStateError::IntegerOverflow => write!(
377 f,
378 "Math operation with a value from the state resulted in a integer overflow.",
379 ),
380 }
381 }
382}
383
384impl std::fmt::Display for HostError {
385 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
386 use HostError::*;
387 match self {
388 BadUTF8 => write!(f, "String encoding is bad UTF-8 sequence."),
389 BadUTF16 => write!(f, "String encoding is bad UTF-16 sequence."),
390 GasExceeded => write!(f, "Exceeded the prepaid gas."),
391 GasLimitExceeded => write!(f, "Exceeded the maximum amount of gas allowed to burn per contract."),
392 BalanceExceeded => write!(f, "Exceeded the account balance."),
393 EmptyMethodName => write!(f, "Tried to call an empty method name."),
394 GuestPanic { panic_msg } => write!(f, "Smart contract panicked: {}", panic_msg),
395 IntegerOverflow => write!(f, "Integer overflow."),
396 InvalidIteratorIndex { iterator_index } => write!(f, "Iterator index {:?} does not exist", iterator_index),
397 InvalidPromiseIndex { promise_idx } => write!(f, "{:?} does not correspond to existing promises", promise_idx),
398 CannotAppendActionToJointPromise => write!(f, "Actions can only be appended to non-joint promise."),
399 CannotReturnJointPromise => write!(f, "Returning joint promise is currently prohibited."),
400 InvalidPromiseResultIndex { result_idx } => write!(f, "Accessed invalid promise result index: {:?}", result_idx),
401 InvalidRegisterId { register_id } => write!(f, "Accessed invalid register id: {:?}", register_id),
402 IteratorWasInvalidated { iterator_index } => write!(f, "Iterator {:?} was invalidated after its creation by performing a mutable operation on trie", iterator_index),
403 MemoryAccessViolation => write!(f, "Accessed memory outside the bounds."),
404 InvalidReceiptIndex { receipt_index } => write!(f, "VM Logic returned an invalid receipt index: {:?}", receipt_index),
405 InvalidAccountId => write!(f, "VM Logic returned an invalid account id"),
406 InvalidMethodName => write!(f, "VM Logic returned an invalid method name"),
407 InvalidPublicKey => write!(f, "VM Logic provided an invalid public key"),
408 ProhibitedInView { method_name } => write!(f, "{} is not allowed in view calls", method_name),
409 NumberOfLogsExceeded { limit } => write!(f, "The number of logs will exceed the limit {}", limit),
410 KeyLengthExceeded { length, limit } => write!(f, "The length of a storage key {} exceeds the limit {}", length, limit),
411 ValueLengthExceeded { length, limit } => write!(f, "The length of a storage value {} exceeds the limit {}", length, limit),
412 TotalLogLengthExceeded{ length, limit } => write!(f, "The length of a log message {} exceeds the limit {}", length, limit),
413 NumberPromisesExceeded { number_of_promises, limit } => write!(f, "The number of promises within a FunctionCall {} exceeds the limit {}", number_of_promises, limit),
414 NumberInputDataDependenciesExceeded { number_of_input_data_dependencies, limit } => write!(f, "The number of input data dependencies {} exceeds the limit {}", number_of_input_data_dependencies, limit),
415 ReturnedValueLengthExceeded { length, limit } => write!(f, "The length of a returned value {} exceeds the limit {}", length, limit),
416 ContractSizeExceeded { size, limit } => write!(f, "The size of a contract code in DeployContract action {} exceeds the limit {}", size, limit),
417 Deprecated {method_name}=> write!(f, "Attempted to call deprecated host function {}", method_name),
418 #[cfg(feature = "protocol_feature_alt_bn128")]
419 AltBn128DeserializationError { msg } => write!(f, "AltBn128 deserialization error: {}", msg),
420 #[cfg(feature = "protocol_feature_alt_bn128")]
421 AltBn128SerializationError { msg } => write!(f, "AltBn128 serialization error: {}", msg),
422 ECRecoverError { msg } => write!(f, "ECDSA recover error: {}", msg),
423 }
424 }
425}
426
427pub mod hex_format {
428 use hex::{decode, encode};
429
430 use serde::de;
431 use serde::{Deserialize, Deserializer, Serializer};
432
433 pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
434 where
435 S: Serializer,
436 T: AsRef<[u8]>,
437 {
438 serializer.serialize_str(&encode(data))
439 }
440
441 pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
442 where
443 D: Deserializer<'de>,
444 T: From<Vec<u8>>,
445 {
446 let s = String::deserialize(deserializer)?;
447 decode(&s).map_err(|err| de::Error::custom(err.to_string())).map(Into::into)
448 }
449}
450
451#[cfg(test)]
452mod tests {
453 use crate::{CompilationError, FunctionCallError, MethodResolveError, PrepareError, VMError};
454
455 #[test]
456 fn test_display() {
457 assert_eq!(
459 VMError::FunctionCallError(FunctionCallError::MethodResolveError(
460 MethodResolveError::MethodInvalidSignature
461 ))
462 .to_string(),
463 "MethodInvalidSignature"
464 );
465 assert_eq!(
466 VMError::FunctionCallError(FunctionCallError::CompilationError(
467 CompilationError::PrepareError(PrepareError::StackHeightInstrumentation)
468 ))
469 .to_string(),
470 "PrepareError: Stack instrumentation failed."
471 );
472 }
473}