darkfi_sdk/
error.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 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    #[error("Numcast: cast failed")]
100    NumCastError,
101
102    #[error("Monotree error: {0}")]
103    MonotreeError(String),
104}
105
106/// Builtin return values occupy the upper 32 bits
107macro_rules! to_builtin {
108    ($error:expr) => {
109        i64::MIN + $error
110    };
111}
112
113pub const CUSTOM_ZERO: i64 = to_builtin!(1);
114pub const INTERNAL_ERROR: i64 = to_builtin!(2);
115pub const SET_RETVAL_ERROR: i64 = to_builtin!(3);
116pub const IO_ERROR: i64 = to_builtin!(4);
117pub const NULLIFIER_EXIST_CHECK: i64 = to_builtin!(5);
118pub const VALID_MERKLE_CHECK: i64 = to_builtin!(6);
119pub const UPDATE_ALREADY_SET: i64 = to_builtin!(7);
120pub const DB_INIT_FAILED: i64 = to_builtin!(8);
121pub const CALLER_ACCESS_DENIED: i64 = to_builtin!(9);
122pub const DB_NOT_FOUND: i64 = to_builtin!(10);
123pub const DB_SET_FAILED: i64 = to_builtin!(11);
124pub const DB_LOOKUP_FAILED: i64 = to_builtin!(12);
125pub const DB_GET_FAILED: i64 = to_builtin!(13);
126pub const DB_GET_EMPTY: i64 = to_builtin!(14);
127pub const DB_CONTAINS_KEY_FAILED: i64 = to_builtin!(15);
128pub const INVALID_FUNCTION: i64 = to_builtin!(16);
129pub const DB_DEL_FAILED: i64 = to_builtin!(17);
130pub const SMT_PUT_FAILED: i64 = to_builtin!(18);
131pub const SMT_DEL_FAILED: i64 = to_builtin!(19);
132pub const GET_SYSTEM_TIME_FAILED: i64 = to_builtin!(20);
133pub const DATA_TOO_LARGE: i64 = to_builtin!(21);
134pub const HEX_FMT_ERR: i64 = to_builtin!(22);
135pub const NUM_CAST_ERR: i64 = to_builtin!(23);
136pub const MONOTREE_ERROR: i64 = to_builtin!(24);
137
138impl From<ContractError> for i64 {
139    fn from(err: ContractError) -> Self {
140        match err {
141            ContractError::Internal => INTERNAL_ERROR,
142            ContractError::IoError(_) => IO_ERROR,
143            ContractError::SetRetvalError => SET_RETVAL_ERROR,
144            ContractError::NullifierExistCheck => NULLIFIER_EXIST_CHECK,
145            ContractError::ValidMerkleCheck => VALID_MERKLE_CHECK,
146            ContractError::UpdateAlreadySet => UPDATE_ALREADY_SET,
147            ContractError::DbInitFailed => DB_INIT_FAILED,
148            ContractError::CallerAccessDenied => CALLER_ACCESS_DENIED,
149            ContractError::DbNotFound => DB_NOT_FOUND,
150            ContractError::DbSetFailed => DB_SET_FAILED,
151            ContractError::DbLookupFailed => DB_LOOKUP_FAILED,
152            ContractError::DbGetFailed => DB_GET_FAILED,
153            ContractError::DbGetEmpty => DB_GET_EMPTY,
154            ContractError::DbContainsKeyFailed => DB_CONTAINS_KEY_FAILED,
155            ContractError::InvalidFunction => INVALID_FUNCTION,
156            ContractError::DbDelFailed => DB_DEL_FAILED,
157            ContractError::SmtPutFailed => SMT_PUT_FAILED,
158            ContractError::SmtDelFailed => SMT_DEL_FAILED,
159            ContractError::GetSystemTimeFailed => GET_SYSTEM_TIME_FAILED,
160            ContractError::DataTooLarge => DATA_TOO_LARGE,
161            ContractError::HexFmtErr => HEX_FMT_ERR,
162            ContractError::NumCastError => NUM_CAST_ERR,
163            ContractError::MonotreeError(_) => MONOTREE_ERROR,
164            ContractError::Custom(error) => {
165                if error == 0 {
166                    CUSTOM_ZERO
167                } else {
168                    error as i64
169                }
170            }
171        }
172    }
173}
174
175impl From<i64> for ContractError {
176    fn from(error: i64) -> Self {
177        match error {
178            CUSTOM_ZERO => Self::Custom(0),
179            INTERNAL_ERROR => Self::Internal,
180            SET_RETVAL_ERROR => Self::SetRetvalError,
181            IO_ERROR => Self::IoError("Unknown".to_string()),
182            NULLIFIER_EXIST_CHECK => Self::NullifierExistCheck,
183            VALID_MERKLE_CHECK => Self::ValidMerkleCheck,
184            UPDATE_ALREADY_SET => Self::UpdateAlreadySet,
185            DB_INIT_FAILED => Self::DbInitFailed,
186            CALLER_ACCESS_DENIED => Self::CallerAccessDenied,
187            DB_NOT_FOUND => Self::DbNotFound,
188            DB_SET_FAILED => Self::DbSetFailed,
189            DB_LOOKUP_FAILED => Self::DbLookupFailed,
190            DB_GET_FAILED => Self::DbGetFailed,
191            DB_GET_EMPTY => Self::DbGetEmpty,
192            DB_CONTAINS_KEY_FAILED => Self::DbContainsKeyFailed,
193            INVALID_FUNCTION => Self::InvalidFunction,
194            DB_DEL_FAILED => Self::DbDelFailed,
195            SMT_PUT_FAILED => Self::SmtPutFailed,
196            SMT_DEL_FAILED => Self::SmtDelFailed,
197            GET_SYSTEM_TIME_FAILED => Self::GetSystemTimeFailed,
198            DATA_TOO_LARGE => Self::DataTooLarge,
199            HEX_FMT_ERR => Self::HexFmtErr,
200            NUM_CAST_ERR => Self::NumCastError,
201            MONOTREE_ERROR => Self::MonotreeError("Unknown".to_string()),
202            _ => Self::Custom(error as u32),
203        }
204    }
205}
206
207impl From<std::io::Error> for ContractError {
208    fn from(err: std::io::Error) -> Self {
209        Self::IoError(format!("{err}"))
210    }
211}
212
213impl From<bs58::decode::Error> for ContractError {
214    fn from(err: bs58::decode::Error) -> Self {
215        Self::IoError(format!("{err}"))
216    }
217}
218
219/// Main result type used by DarkTree.
220pub type DarkTreeResult<T> = ResultGeneric<T, DarkTreeError>;
221
222/// General DarkTree related errors.
223#[derive(Debug, Clone, thiserror::Error)]
224pub enum DarkTreeError {
225    #[error("Invalid DarkLeaf index found: {0} (Expected: {1}")]
226    InvalidLeafIndex(usize, usize),
227
228    #[error("Invalid DarkLeaf parent index found for leaf: {0}")]
229    InvalidLeafParentIndex(usize),
230
231    #[error("Invalid DarkLeaf children index found for leaf: {0}")]
232    InvalidLeafChildrenIndexes(usize),
233
234    #[error("Invalid DarkTree min capacity found: {0} (Expected: >= 1)")]
235    InvalidMinCapacity(usize),
236
237    #[error("DarkTree min capacity has not been exceeded")]
238    MinCapacityNotExceeded,
239
240    #[error("Invalid DarkTree max capacity found: {0} (Expected: >= {1})")]
241    InvalidMaxCapacity(usize, usize),
242
243    #[error("DarkTree max capacity has been exceeded")]
244    MaxCapacityExceeded,
245}