1use dpp::bls_signatures::BlsError;
2use dpp::consensus::ConsensusError;
3use tenderdash_abci::proto::abci::ExtendVoteExtension;
4use tenderdash_abci::proto::types::VoteExtension;
5
6#[derive(Debug, thiserror::Error)]
9pub enum AbciError {
10 #[error("invalid state: {0}")]
12 InvalidState(String),
13 #[error("request does not match current block: {0}")]
15 RequestForWrongBlockReceived(String),
16 #[error("votes extensions mismatch: got {got:?}, expected {expected:?}")]
18 #[allow(missing_docs)]
19 VoteExtensionMismatchReceived {
20 got: Vec<VoteExtension>,
21 expected: Vec<ExtendVoteExtension>,
22 },
23 #[error("one of votes extension signatures is invalid")]
25 VoteExtensionsSignatureInvalid,
26 #[error("invalid votes extensions verification")]
28 InvalidVoteExtensionsVerification,
29 #[error("cannot load withdrawal transactions: {0}")]
31 WithdrawalTransactionsDBLoadError(String),
32 #[error("finalize block received before processing from Tenderdash: {0}")]
34 FinalizeBlockReceivedBeforeProcessing(String),
35 #[error("wrong block from Tenderdash: {0}")]
37 WrongBlockReceived(String),
38 #[error("wrong finalize block from Tenderdash: {0}")]
40 WrongFinalizeBlockReceived(String),
41 #[error("data received from Tenderdash could not be converted: {0}")]
44 BadRequestDataSize(String),
45 #[error("bad request received from Tenderdash: {0}")]
47 BadRequest(String),
48
49 #[error("bad initialization: {0}")]
51 BadInitialization(String),
52
53 #[error("bad commit signature: {0}")]
55 BadCommitSignature(String),
56
57 #[error("invalid chain lock: {0}")]
59 InvalidChainLock(String),
60
61 #[error("chain lock is for a block not known by core: {0}")]
63 ChainLockedBlockNotKnownByCore(String),
64
65 #[error("tenderdash: {0}")]
67 Tenderdash(#[from] tenderdash_abci::Error),
68
69 #[error("tenderdash data: {0}")]
71 TenderdashProto(tenderdash_abci::proto::Error),
72
73 #[error("bls error from user message: {0}")]
75 BlsErrorFromUserMessage(BlsError),
76
77 #[error("bls error from Tenderdash for threshold mechanisms: {1}: {0}")]
79 BlsErrorOfTenderdashThresholdMechanism(BlsError, String),
80
81 #[error("ABCI version mismatch. Tenderdash requires ABCI protobuf definitions version {tenderdash}, our version is {drive}")]
83 AbciVersionMismatch {
84 tenderdash: String,
86 drive: String,
88 },
89
90 #[error("invalid state transition error: {0}")]
92 InvalidStateTransition(#[from] ConsensusError),
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn invalid_state_display() {
101 let err = AbciError::InvalidState("bad state".to_string());
102 assert_eq!(err.to_string(), "invalid state: bad state");
103 }
104
105 #[test]
106 fn request_for_wrong_block_received_display() {
107 let err = AbciError::RequestForWrongBlockReceived("wrong block".to_string());
108 assert_eq!(
109 err.to_string(),
110 "request does not match current block: wrong block"
111 );
112 }
113
114 #[test]
115 fn vote_extension_mismatch_received_display() {
116 let err = AbciError::VoteExtensionMismatchReceived {
117 got: vec![],
118 expected: vec![],
119 };
120 assert_eq!(
121 err.to_string(),
122 "votes extensions mismatch: got [], expected []"
123 );
124 }
125
126 #[test]
127 fn vote_extensions_signature_invalid_display() {
128 let err = AbciError::VoteExtensionsSignatureInvalid;
129 assert_eq!(
130 err.to_string(),
131 "one of votes extension signatures is invalid"
132 );
133 }
134
135 #[test]
136 fn invalid_vote_extensions_verification_display() {
137 let err = AbciError::InvalidVoteExtensionsVerification;
138 assert_eq!(err.to_string(), "invalid votes extensions verification");
139 }
140
141 #[test]
142 fn withdrawal_transactions_db_load_error_display() {
143 let err = AbciError::WithdrawalTransactionsDBLoadError("db fail".to_string());
144 assert_eq!(
145 err.to_string(),
146 "cannot load withdrawal transactions: db fail"
147 );
148 }
149
150 #[test]
151 fn finalize_block_received_before_processing_display() {
152 let err = AbciError::FinalizeBlockReceivedBeforeProcessing("not processed yet".to_string());
153 assert_eq!(
154 err.to_string(),
155 "finalize block received before processing from Tenderdash: not processed yet"
156 );
157 }
158
159 #[test]
160 fn wrong_block_received_display() {
161 let err = AbciError::WrongBlockReceived("bad block".to_string());
162 assert_eq!(err.to_string(), "wrong block from Tenderdash: bad block");
163 }
164
165 #[test]
166 fn wrong_finalize_block_received_display() {
167 let err = AbciError::WrongFinalizeBlockReceived("bad finalize".to_string());
168 assert_eq!(
169 err.to_string(),
170 "wrong finalize block from Tenderdash: bad finalize"
171 );
172 }
173
174 #[test]
175 fn bad_request_data_size_display() {
176 let err = AbciError::BadRequestDataSize("size mismatch".to_string());
177 assert_eq!(
178 err.to_string(),
179 "data received from Tenderdash could not be converted: size mismatch"
180 );
181 }
182
183 #[test]
184 fn bad_request_display() {
185 let err = AbciError::BadRequest("invalid request".to_string());
186 assert_eq!(
187 err.to_string(),
188 "bad request received from Tenderdash: invalid request"
189 );
190 }
191
192 #[test]
193 fn bad_initialization_display() {
194 let err = AbciError::BadInitialization("init failed".to_string());
195 assert_eq!(err.to_string(), "bad initialization: init failed");
196 }
197
198 #[test]
199 fn bad_commit_signature_display() {
200 let err = AbciError::BadCommitSignature("sig mismatch".to_string());
201 assert_eq!(err.to_string(), "bad commit signature: sig mismatch");
202 }
203
204 #[test]
205 fn invalid_chain_lock_display() {
206 let err = AbciError::InvalidChainLock("lock invalid".to_string());
207 assert_eq!(err.to_string(), "invalid chain lock: lock invalid");
208 }
209
210 #[test]
211 fn chain_locked_block_not_known_by_core_display() {
212 let err = AbciError::ChainLockedBlockNotKnownByCore("unknown block".to_string());
213 assert_eq!(
214 err.to_string(),
215 "chain lock is for a block not known by core: unknown block"
216 );
217 }
218
219 #[test]
220 fn abci_version_mismatch_display() {
221 let err = AbciError::AbciVersionMismatch {
222 tenderdash: "1.0".to_string(),
223 drive: "2.0".to_string(),
224 };
225 assert!(err.to_string().contains("1.0"));
226 assert!(err.to_string().contains("2.0"));
227 }
228
229 #[test]
230 fn invalid_state_transition_display() {
231 let consensus_error = ConsensusError::DefaultError;
232 let err = AbciError::InvalidStateTransition(consensus_error);
233 assert_eq!(
234 err.to_string(),
235 "invalid state transition error: default error"
236 );
237 }
238
239 #[test]
240 fn tenderdash_proto_display() {
241 let proto_err = tenderdash_abci::proto::Error::try_from_protobuf("proto fail".to_string());
242 let err = AbciError::TenderdashProto(proto_err);
243 assert!(err.to_string().contains("proto fail"));
244 }
245
246 #[test]
247 fn error_debug_format_is_not_empty() {
248 let err = AbciError::InvalidState("test".to_string());
249 let debug = format!("{:?}", err);
250 assert!(!debug.is_empty());
251 assert!(debug.contains("InvalidState"));
252 }
253
254 #[test]
255 fn consensus_error_converts_to_abci_error() {
256 let consensus_err = ConsensusError::DefaultError;
257 let abci_err: AbciError = consensus_err.into();
258 assert!(matches!(abci_err, AbciError::InvalidStateTransition(_)));
259 }
260}