pchain_runtime/
error.rs

1/*
2    Copyright © 2023, ParallelChain Lab
3    Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
4*/
5
6//! Defines [TransitionError] which is set of error definitions in state transitions.
7//!
8//! Transition Error is not failure code specified in [ExitStatus], which is not included
9//! in the block for transaction failure. The error types are for the purpose of diagnosis.
10
11use pchain_types::blockchain::ExitStatus;
12
13use crate::contract::{FuncError, MethodCallError};
14
15/// Descriptive error definitions of a Transition
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub enum TransitionError {
18    /// Nonce is not current nonce.
19    WrongNonce,
20
21    /// Not enough balance to pay for gas limit.
22    NotEnoughBalanceForGasLimit,
23
24    /// Not enough balance to pay for transfer.
25    NotEnoughBalanceForTransfer,
26
27    /// Gas limit was insufficient to cover pre-execution costs.
28    PreExecutionGasExhausted,
29
30    /// The contract bytecode contains disallowed opcodes.
31    DisallowedOpcode,
32
33    /// Contract cannot be compiled into machine code (it is probably invalid WASM).
34    CannotCompile,
35
36    /// Contract does not export the METHOD_CONTRACT method.
37    NoExportedContractMethod,
38
39    /// Deployment failed for some other reason.
40    OtherDeployError,
41
42    /// Deployment failed because the Contract already exists (CBI version was set for the account)
43    ContractAlreadyExists,
44
45    /// Contract cannot be found in state
46    NoContractcode,
47
48    /// Fail to load Contract from the CBI
49    InvalidCBI,
50
51    /// Gas limit was insufficient to cover execution proper costs.
52    ExecutionProperGasExhausted,
53
54    /// Runtime error during execution proper of the entree smart contract.
55    RuntimeError,
56
57    /// Gas limit was insufficient to cover execution proper costs of an internal transaction.
58    InternalExecutionProperGasExhaustion,
59
60    /// Runtime error during execution proper of an internal transaction.
61    InternalRuntimeError,
62
63    /// Staking Command - Create Pool fails because the pool already exists
64    PoolAlreadyExists,
65
66    /// Staking Command fails for non-existing pool
67    PoolNotExists,
68
69    /// Staking Command - Unstake Deposit fails because the Pool has no stakes.
70    PoolHasNoStakes,
71
72    /// Staking Command fails because pool policy is invalid.
73    /// Scenarios such as
74    /// 1. commission fee is greater than 100
75    /// 2. commission fee is as same as the origin onw
76    InvalidPoolPolicy,
77
78    /// Staking Command - Create Deposits fails because the deposits already exists
79    DepositsAlreadyExists,
80
81    /// Staking Command fails because the deposits does not exist.
82    DepositsNotExists,
83
84    /// Staking Command - Set Deposit Settings fails because the deposit amount
85    InvalidDepositPolicy,
86
87    /// Staking Command fails because the specified amount does not match with the requirement of the operation.
88    /// Scenarios such as
89    /// 1. Stake power has already reached upper limit (deposit amount) for Command - Stake Deposit
90    /// 2. Stake power is not enough to stay in the delegated stakes for Command - Stake Deposit
91    /// 3. Stake power has already reached lower limit for Command - Withdrawal Deposit
92    InvalidStakeAmount,
93
94    /// Transaction commands are empty
95    InvalidCommands,
96
97    /// There is more than 1 NextEpoch Command in a transaction.
98    InvalidNextEpochCommand,
99}
100
101impl From<MethodCallError> for TransitionError {
102    fn from(call_error: MethodCallError) -> Self {
103        match call_error {
104            MethodCallError::GasExhaustion => TransitionError::ExecutionProperGasExhausted,
105            MethodCallError::NoExportedMethod(_) => TransitionError::RuntimeError,
106            MethodCallError::Runtime(e) => {
107                // check for internal errors
108                match e.downcast::<FuncError>() {
109                    Err(_) => TransitionError::RuntimeError,
110                    Ok(FuncError::GasExhaustionError) => {
111                        TransitionError::ExecutionProperGasExhausted
112                    }
113                    Ok(_) => TransitionError::InternalRuntimeError,
114                }
115            }
116        }
117    }
118}
119
120impl<'a> From<&'a TransitionError> for ExitStatus {
121    fn from(value: &'a TransitionError) -> Self {
122        match value {
123            TransitionError::ExecutionProperGasExhausted
124            | TransitionError::InternalExecutionProperGasExhaustion => ExitStatus::GasExhausted,
125            _ => ExitStatus::Failed,
126        }
127    }
128}