drive_abci/abci/
error.rs

1use dpp::bls_signatures::BlsError;
2use dpp::consensus::ConsensusError;
3use tenderdash_abci::proto::abci::ExtendVoteExtension;
4use tenderdash_abci::proto::types::VoteExtension;
5
6// @append_only
7/// Error returned within ABCI server
8#[derive(Debug, thiserror::Error)]
9pub enum AbciError {
10    /// Invalid system state
11    #[error("invalid state: {0}")]
12    InvalidState(String),
13    /// Request does not match currently processed block
14    #[error("request does not match current block: {0}")]
15    RequestForWrongBlockReceived(String),
16    /// Withdrawal votes extensions mismatch
17    #[error("votes extensions mismatch: got {got:?}, expected {expected:?}")]
18    #[allow(missing_docs)]
19    VoteExtensionMismatchReceived {
20        got: Vec<VoteExtension>,
21        expected: Vec<ExtendVoteExtension>,
22    },
23    /// Vote extensions signature is invalid
24    #[error("one of votes extension signatures is invalid")]
25    VoteExtensionsSignatureInvalid,
26    /// Invalid votes extensions verification
27    #[error("invalid votes extensions verification")]
28    InvalidVoteExtensionsVerification,
29    /// Cannot load withdrawal transactions
30    #[error("cannot load withdrawal transactions: {0}")]
31    WithdrawalTransactionsDBLoadError(String),
32    /// Wrong finalize block received
33    #[error("finalize block received before processing from Tenderdash: {0}")]
34    FinalizeBlockReceivedBeforeProcessing(String),
35    /// Wrong finalize block received
36    #[error("wrong block from Tenderdash: {0}")]
37    WrongBlockReceived(String),
38    /// Wrong finalize block received
39    #[error("wrong finalize block from Tenderdash: {0}")]
40    WrongFinalizeBlockReceived(String),
41    /// Bad request received from Tenderdash that can't be translated to the correct size
42    /// This often happens if a Vec<> can not be translated into a \[u8;32\]
43    #[error("data received from Tenderdash could not be converted: {0}")]
44    BadRequestDataSize(String),
45    /// Bad request received from Tenderdash
46    #[error("bad request received from Tenderdash: {0}")]
47    BadRequest(String),
48
49    /// Bad initialization from Tenderdash
50    #[error("bad initialization: {0}")]
51    BadInitialization(String),
52
53    /// Bad commit signature from Tenderdash
54    #[error("bad commit signature: {0}")]
55    BadCommitSignature(String),
56
57    /// The chain lock received was invalid
58    #[error("invalid chain lock: {0}")]
59    InvalidChainLock(String),
60
61    /// The chain lock received was invalid
62    #[error("chain lock is for a block not known by core: {0}")]
63    ChainLockedBlockNotKnownByCore(String),
64
65    /// Error returned by Tenderdash-abci library
66    #[error("tenderdash: {0}")]
67    Tenderdash(#[from] tenderdash_abci::Error),
68
69    /// Error occurred during protobuf data manipulation
70    #[error("tenderdash data: {0}")]
71    TenderdashProto(tenderdash_abci::proto::Error),
72
73    /// Error occurred during signature verification or deserializing a BLS primitive
74    #[error("bls error from user message: {0}")]
75    BlsErrorFromUserMessage(BlsError),
76
77    /// Error occurred related to threshold signing, either of commit
78    #[error("bls error from Tenderdash for threshold mechanisms: {1}: {0}")]
79    BlsErrorOfTenderdashThresholdMechanism(BlsError, String),
80
81    /// Incompatibility version Error on info handshake between Drive ABCI and Tenderdash
82    #[error("ABCI version mismatch. Tenderdash requires ABCI protobuf definitions version {tenderdash}, our version is {drive}")]
83    AbciVersionMismatch {
84        /// ABCI version in Tenderdash
85        tenderdash: String,
86        /// ABCI version in Drive ABCI
87        drive: String,
88    },
89
90    /// Generic with code should only be used in tests
91    #[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}