darkfi_sdk/
error.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::result::Result as ResultGeneric;
20
21pub type GenericResult<T> = ResultGeneric<T, ContractError>;
22pub type ContractResult = ResultGeneric<(), ContractError>;
23
24/// Error codes available in the contract.
25#[derive(Debug, Clone, thiserror::Error)]
26pub enum ContractError {
27    /// Allows on-chain programs to implement contract-specific error types and
28    /// see them returned by the runtime. A contract-specific error may be any
29    /// type that is represented as or serialized to an u32 integer.
30    #[error("Custom contract error: {0:#x}")]
31    Custom(u32),
32
33    #[error("Internal error")]
34    Internal,
35
36    #[error("IO error: {0}")]
37    IoError(String),
38
39    #[error("Error setting return value")]
40    SetRetvalError,
41
42    #[error("Error checking if nullifier exists")]
43    NullifierExistCheck,
44
45    #[error("Error checking merkle root validity")]
46    ValidMerkleCheck,
47
48    #[error("Update already set")]
49    UpdateAlreadySet,
50
51    #[error("Db init failed")]
52    DbInitFailed,
53
54    #[error("Caller access was denied")]
55    CallerAccessDenied,
56
57    #[error("Db not found")]
58    DbNotFound,
59
60    #[error("Db set failed")]
61    DbSetFailed,
62
63    #[error("Db del failed")]
64    DbDelFailed,
65
66    #[error("Db lookup failed")]
67    DbLookupFailed,
68
69    #[error("Db get failed")]
70    DbGetFailed,
71
72    #[error("Db get empty")]
73    DbGetEmpty,
74
75    #[error("Db contains_key failed")]
76    DbContainsKeyFailed,
77
78    #[error("Invalid function call")]
79    InvalidFunction,
80
81    #[error("SMT: put failed with storage backend")]
82    SmtPutFailed,
83
84    #[error("SMT: rm failed with storage backend")]
85    SmtDelFailed,
86
87    #[error("Error retrieving system time")]
88    GetSystemTimeFailed,
89
90    // Provide feedback when the data sent is too large. For example,
91    // if a user tries to send > u32::MAX bytes, we can limit the
92    // size and present this error.
93    #[error("Data too large")]
94    DataTooLarge,
95
96    #[error("Hex string is not properly formatted")]
97    HexFmtErr,
98}
99
100/// Builtin return values occupy the upper 32 bits
101macro_rules! to_builtin {
102    ($error:expr) => {
103        i64::MIN + $error
104    };
105}
106
107pub const CUSTOM_ZERO: i64 = to_builtin!(1);
108pub const INTERNAL_ERROR: i64 = to_builtin!(2);
109pub const SET_RETVAL_ERROR: i64 = to_builtin!(3);
110pub const IO_ERROR: i64 = to_builtin!(4);
111pub const NULLIFIER_EXIST_CHECK: i64 = to_builtin!(5);
112pub const VALID_MERKLE_CHECK: i64 = to_builtin!(6);
113pub const UPDATE_ALREADY_SET: i64 = to_builtin!(7);
114pub const DB_INIT_FAILED: i64 = to_builtin!(8);
115pub const CALLER_ACCESS_DENIED: i64 = to_builtin!(9);
116pub const DB_NOT_FOUND: i64 = to_builtin!(10);
117pub const DB_SET_FAILED: i64 = to_builtin!(11);
118pub const DB_LOOKUP_FAILED: i64 = to_builtin!(12);
119pub const DB_GET_FAILED: i64 = to_builtin!(13);
120pub const DB_GET_EMPTY: i64 = to_builtin!(14);
121pub const DB_CONTAINS_KEY_FAILED: i64 = to_builtin!(15);
122pub const INVALID_FUNCTION: i64 = to_builtin!(16);
123pub const DB_DEL_FAILED: i64 = to_builtin!(17);
124pub const SMT_PUT_FAILED: i64 = to_builtin!(18);
125pub const SMT_DEL_FAILED: i64 = to_builtin!(19);
126pub const GET_SYSTEM_TIME_FAILED: i64 = to_builtin!(20);
127pub const DATA_TOO_LARGE: i64 = to_builtin!(21);
128pub const HEX_FMT_ERR: i64 = to_builtin!(22);
129
130impl From<ContractError> for i64 {
131    fn from(err: ContractError) -> Self {
132        match err {
133            ContractError::Internal => INTERNAL_ERROR,
134            ContractError::IoError(_) => IO_ERROR,
135            ContractError::SetRetvalError => SET_RETVAL_ERROR,
136            ContractError::NullifierExistCheck => NULLIFIER_EXIST_CHECK,
137            ContractError::ValidMerkleCheck => VALID_MERKLE_CHECK,
138            ContractError::UpdateAlreadySet => UPDATE_ALREADY_SET,
139            ContractError::DbInitFailed => DB_INIT_FAILED,
140            ContractError::CallerAccessDenied => CALLER_ACCESS_DENIED,
141            ContractError::DbNotFound => DB_NOT_FOUND,
142            ContractError::DbSetFailed => DB_SET_FAILED,
143            ContractError::DbLookupFailed => DB_LOOKUP_FAILED,
144            ContractError::DbGetFailed => DB_GET_FAILED,
145            ContractError::DbGetEmpty => DB_GET_EMPTY,
146            ContractError::DbContainsKeyFailed => DB_CONTAINS_KEY_FAILED,
147            ContractError::InvalidFunction => INVALID_FUNCTION,
148            ContractError::DbDelFailed => DB_DEL_FAILED,
149            ContractError::SmtPutFailed => SMT_PUT_FAILED,
150            ContractError::SmtDelFailed => SMT_DEL_FAILED,
151            ContractError::GetSystemTimeFailed => GET_SYSTEM_TIME_FAILED,
152            ContractError::DataTooLarge => DATA_TOO_LARGE,
153            ContractError::HexFmtErr => HEX_FMT_ERR,
154            ContractError::Custom(error) => {
155                if error == 0 {
156                    CUSTOM_ZERO
157                } else {
158                    error as i64
159                }
160            }
161        }
162    }
163}
164
165impl From<i64> for ContractError {
166    fn from(error: i64) -> Self {
167        match error {
168            CUSTOM_ZERO => Self::Custom(0),
169            INTERNAL_ERROR => Self::Internal,
170            SET_RETVAL_ERROR => Self::SetRetvalError,
171            IO_ERROR => Self::IoError("Unknown".to_string()),
172            NULLIFIER_EXIST_CHECK => Self::NullifierExistCheck,
173            VALID_MERKLE_CHECK => Self::ValidMerkleCheck,
174            UPDATE_ALREADY_SET => Self::UpdateAlreadySet,
175            DB_INIT_FAILED => Self::DbInitFailed,
176            CALLER_ACCESS_DENIED => Self::CallerAccessDenied,
177            DB_NOT_FOUND => Self::DbNotFound,
178            DB_SET_FAILED => Self::DbSetFailed,
179            DB_LOOKUP_FAILED => Self::DbLookupFailed,
180            DB_GET_FAILED => Self::DbGetFailed,
181            DB_GET_EMPTY => Self::DbGetEmpty,
182            DB_CONTAINS_KEY_FAILED => Self::DbContainsKeyFailed,
183            INVALID_FUNCTION => Self::InvalidFunction,
184            DB_DEL_FAILED => Self::DbDelFailed,
185            SMT_PUT_FAILED => Self::SmtPutFailed,
186            SMT_DEL_FAILED => Self::SmtDelFailed,
187            GET_SYSTEM_TIME_FAILED => Self::GetSystemTimeFailed,
188            DATA_TOO_LARGE => Self::DataTooLarge,
189            HEX_FMT_ERR => Self::HexFmtErr,
190            _ => Self::Custom(error as u32),
191        }
192    }
193}
194
195impl From<std::io::Error> for ContractError {
196    fn from(err: std::io::Error) -> Self {
197        Self::IoError(format!("{}", err))
198    }
199}
200
201impl From<bs58::decode::Error> for ContractError {
202    fn from(err: bs58::decode::Error) -> Self {
203        Self::IoError(format!("{}", err))
204    }
205}
206
207/// Main result type used by DarkTree.
208pub type DarkTreeResult<T> = ResultGeneric<T, DarkTreeError>;
209
210/// General DarkTree related errors.
211#[derive(Debug, Clone, thiserror::Error)]
212pub enum DarkTreeError {
213    #[error("Invalid DarkLeaf index found: {0} (Expected: {1}")]
214    InvalidLeafIndex(usize, usize),
215
216    #[error("Invalid DarkLeaf parent index found for leaf: {0}")]
217    InvalidLeafParentIndex(usize),
218
219    #[error("Invalid DarkLeaf children index found for leaf: {0}")]
220    InvalidLeafChildrenIndexes(usize),
221
222    #[error("Invalid DarkTree min capacity found: {0} (Expected: >= 1)")]
223    InvalidMinCapacity(usize),
224
225    #[error("DarkTree min capacity has not been exceeded")]
226    MinCapacityNotExceeded,
227
228    #[error("Invalid DarkTree max capacity found: {0} (Expected: >= {1})")]
229    InvalidMaxCapacity(usize, usize),
230
231    #[error("DarkTree max capacity has been exceeded")]
232    MaxCapacityExceeded,
233}