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