darkfid/
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::collections::HashMap;
20
21use tinyjson::JsonValue;
22
23use darkfi::rpc::jsonrpc::{ErrorCode::ServerError, JsonError, JsonResponse, JsonResult};
24
25/// Custom RPC errors available for darkfid.
26/// Please sort them sensefully.
27pub enum RpcError {
28    // Transaction-related errors
29    TxSimulationFail = -32110,
30    TxGasCalculationFail = -32111,
31
32    // State-related errors,
33    NotSynced = -32120,
34    UnknownBlockHeight = -32121,
35
36    // Parsing errors
37    ParseError = -32190,
38
39    // Contract-related errors
40    ContractZkasDbNotFound = -32200,
41    ContractStateNotFound = -32201,
42    ContractStateKeyNotFound = -32202,
43    ContractWasmNotFound = -32203,
44
45    // Miner configuration errors
46    MinerInvalidWalletConfig = -32301,
47    MinerInvalidRecipient = -32302,
48    MinerInvalidRecipientPrefix = -32303,
49    MinerInvalidSpendHook = -32304,
50    MinerInvalidUserData = -32305,
51
52    // Stratum errors
53    MinerMissingLogin = -32306,
54    MinerInvalidLogin = -32307,
55    MinerMissingPassword = -32308,
56    MinerInvalidPassword = -32309,
57    MinerMissingAgent = -32310,
58    MinerInvalidAgent = -32311,
59    MinerMissingAlgo = -32312,
60    MinerInvalidAlgo = -32313,
61    MinerRandomXNotSupported = -32314,
62    MinerMissingClientId = -32315,
63    MinerInvalidClientId = -32316,
64    MinerUnknownClient = -32317,
65    MinerMissingJobId = -32318,
66    MinerInvalidJobId = -32319,
67    MinerMissingNonce = -32320,
68    MinerInvalidNonce = -32321,
69    MinerMissingResult = -32322,
70    MinerInvalidResult = -32323,
71
72    // Merge mining errors
73    MinerMissingAddress = -32324,
74    MinerInvalidAddress = -32325,
75    MinerMissingAuxHash = -32326,
76    MinerInvalidAuxHash = -32327,
77    MinerMissingHeight = -32328,
78    MinerInvalidHeight = -32329,
79    MinerMissingPrevId = -32330,
80    MinerInvalidPrevId = -32331,
81    MinerMissingAuxBlob = -32332,
82    MinerInvalidAuxBlob = -32333,
83    MinerMissingBlob = -32334,
84    MinerInvalidBlob = -32335,
85    MinerMissingMerkleProof = -32336,
86    MinerInvalidMerkleProof = -32337,
87    MinerMissingPath = -32338,
88    MinerInvalidPath = -32339,
89    MinerMissingSeedHash = -32340,
90    MinerInvalidSeedHash = -32341,
91    MinerMerkleProofConstructionFailed = -32342,
92    MinerMoneroPowDataConstructionFailed = -32343,
93}
94
95fn to_tuple(e: RpcError) -> (i32, String) {
96    let msg = match e {
97        // Transaction-related errors
98        RpcError::TxSimulationFail => "Failed simulating transaction state change",
99        RpcError::TxGasCalculationFail => "Failed to calculate transaction's gas",
100
101        // State-related errors
102        RpcError::NotSynced => "Blockchain is not synced",
103        RpcError::UnknownBlockHeight => "Did not find block height",
104
105        // Parsing errors
106        RpcError::ParseError => "Parse error",
107
108        // Contract-related errors
109        RpcError::ContractZkasDbNotFound => "zkas database not found for given contract",
110        RpcError::ContractStateNotFound => "Records not found for given contract state",
111        RpcError::ContractStateKeyNotFound => "Value not found for given contract state key",
112        RpcError::ContractWasmNotFound => "wasm bincode not found for given contract",
113
114        // Miner configuration errors
115        RpcError::MinerInvalidWalletConfig => "Request wallet configuration is invalid",
116        RpcError::MinerInvalidRecipient => "Request recipient wallet address is invalid",
117        RpcError::MinerInvalidRecipientPrefix => {
118            "Request recipient wallet address prefix is invalid"
119        }
120        RpcError::MinerInvalidSpendHook => "Request spend hook is invalid",
121        RpcError::MinerInvalidUserData => "Request user data is invalid",
122
123        // Stratum errors
124        RpcError::MinerMissingLogin => "Request is missing the login",
125        RpcError::MinerInvalidLogin => "Request login is invalid",
126        RpcError::MinerMissingPassword => "Request is missing the password",
127        RpcError::MinerInvalidPassword => "Request password is invalid",
128        RpcError::MinerMissingAgent => "Request is missing the agent",
129        RpcError::MinerInvalidAgent => "Request agent is invalid",
130        RpcError::MinerMissingAlgo => "Request is missing the algo",
131        RpcError::MinerInvalidAlgo => "Request algo is invalid",
132        RpcError::MinerRandomXNotSupported => "Request doesn't support rx/0",
133        RpcError::MinerMissingClientId => "Request is missing the client ID",
134        RpcError::MinerInvalidClientId => "Request client ID is invalid",
135        RpcError::MinerUnknownClient => "Request client is unknown",
136        RpcError::MinerMissingJobId => "Request is missing the job ID",
137        RpcError::MinerInvalidJobId => "Request job ID is invalid",
138        RpcError::MinerMissingNonce => "Request is missing the nonce",
139        RpcError::MinerInvalidNonce => "Request nonce is invalid",
140        RpcError::MinerMissingResult => "Request is missing the result",
141        RpcError::MinerInvalidResult => "Request nonce is result",
142
143        // Merge mining errors
144        RpcError::MinerMissingAddress => {
145            "Request is missing the recipient wallet address configuration"
146        }
147        RpcError::MinerInvalidAddress => {
148            "Request recipient wallet address configuration is invalid"
149        }
150        RpcError::MinerMissingAuxHash => "Request is missing the merge mining job (aux_hash)",
151        RpcError::MinerInvalidAuxHash => "Request merge mining job (aux_hash) is invalid",
152        RpcError::MinerMissingHeight => "Request is missing the Monero height",
153        RpcError::MinerInvalidHeight => "Request Monero height is invalid",
154        RpcError::MinerMissingPrevId => "Request is missing the hash of the previous Monero block",
155        RpcError::MinerInvalidPrevId => "Request hash of the previous Monero block is invalid",
156        RpcError::MinerMissingAuxBlob => "Request is missing the merge mining blob",
157        RpcError::MinerInvalidAuxBlob => "Request merge mining bob is invalid",
158        RpcError::MinerMissingBlob => "Request is missing the Monero block template",
159        RpcError::MinerInvalidBlob => "Request Monero block template is invalid",
160        RpcError::MinerMissingMerkleProof => "Request is missing the Merkle proof",
161        RpcError::MinerInvalidMerkleProof => "Request Merkle proof is invalid",
162        RpcError::MinerMissingPath => "Request is missing the Merkle proof path",
163        RpcError::MinerInvalidPath => "Request Merkle proof path is invalid",
164        RpcError::MinerMissingSeedHash => "Request is missing the RandomX seed key",
165        RpcError::MinerInvalidSeedHash => "Request RandomX seed key is invalid",
166        RpcError::MinerMerkleProofConstructionFailed => {
167            "failed constructing aux chain Merkle proof"
168        }
169        RpcError::MinerMoneroPowDataConstructionFailed => "Failed constructing Monero PoW data",
170    };
171
172    (e as i32, msg.to_string())
173}
174
175pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult {
176    let (code, default_msg) = to_tuple(e);
177
178    if let Some(message) = msg {
179        return JsonError::new(ServerError(code), Some(message.to_string()), id).into()
180    }
181
182    JsonError::new(ServerError(code), Some(default_msg), id).into()
183}
184
185pub fn miner_status_response(id: u16, status: &str) -> JsonResult {
186    JsonResponse::new(
187        JsonValue::from(HashMap::from([(
188            "status".to_string(),
189            JsonValue::from(String::from(status)),
190        )])),
191        id,
192    )
193    .into()
194}