1use consensus_config::{AuthorityIndex, Epoch, Stake};
6use fastcrypto::error::FastCryptoError;
7use strum_macros::IntoStaticStr;
8use thiserror::Error;
9use typed_store::TypedStoreError;
10
11use crate::{
12 block::{BlockRef, Round},
13 commit::{Commit, CommitIndex},
14};
15
16#[derive(Clone, Debug, Error, IntoStaticStr)]
19pub(crate) enum ConsensusError {
20 #[error("Error deserializing block: {0}")]
21 MalformedBlock(bcs::Error),
22
23 #[error("Error deserializing commit: {0}")]
24 MalformedCommit(bcs::Error),
25
26 #[error("Error serializing: {0}")]
27 SerializationFailure(bcs::Error),
28
29 #[error("Block contains a transaction that is too large: {size} > {limit}")]
30 TransactionTooLarge { size: usize, limit: usize },
31
32 #[error("Block contains too many transactions: {count} > {limit}")]
33 TooManyTransactions { count: usize, limit: usize },
34
35 #[error("Block contains too many transaction bytes: {size} > {limit}")]
36 TooManyTransactionBytes { size: usize, limit: usize },
37
38 #[error("Unexpected block authority {0} from peer {1}")]
39 UnexpectedAuthority(AuthorityIndex, AuthorityIndex),
40
41 #[error("Block has wrong epoch: expected {expected}, actual {actual}")]
42 WrongEpoch { expected: Epoch, actual: Epoch },
43
44 #[error("Genesis blocks should only be generated from Committee!")]
45 UnexpectedGenesisBlock,
46
47 #[error("Genesis blocks should not be queried!")]
48 UnexpectedGenesisBlockRequested,
49
50 #[error(
51 "Expected {requested} but received {received} blocks returned from authority {authority}"
52 )]
53 UnexpectedNumberOfBlocksFetched {
54 authority: AuthorityIndex,
55 requested: usize,
56 received: usize,
57 },
58
59 #[error("Unexpected block returned while fetching missing blocks")]
60 UnexpectedFetchedBlock {
61 index: AuthorityIndex,
62 block_ref: BlockRef,
63 },
64
65 #[error(
66 "Unexpected block {block_ref} returned while fetching last own block from peer {index}"
67 )]
68 UnexpectedLastOwnBlock {
69 index: AuthorityIndex,
70 block_ref: BlockRef,
71 },
72
73 #[error(
74 "Too many blocks have been returned from authority {0} when requesting to fetch missing blocks"
75 )]
76 TooManyFetchedBlocksReturned(AuthorityIndex),
77
78 #[error("Too many blocks have been requested from authority {0}")]
79 TooManyFetchBlocksRequested(AuthorityIndex),
80
81 #[error("Too many authorities have been provided from authority {0}")]
82 TooManyAuthoritiesProvided(AuthorityIndex),
83
84 #[error(
85 "Provided size of highest accepted rounds parameter, {0}, is different than committee size, {1}"
86 )]
87 InvalidSizeOfHighestAcceptedRounds(usize, usize),
88
89 #[error("Invalid authority index: {index} > {max}")]
90 InvalidAuthorityIndex { index: AuthorityIndex, max: usize },
91
92 #[error(
93 "Invalid ancestor authority index: block {block_authority}, ancestor {ancestor_index} > {max}"
94 )]
95 InvalidAncestorAuthorityIndex {
96 block_authority: AuthorityIndex,
97 ancestor_index: AuthorityIndex,
98 max: usize,
99 },
100
101 #[error("Failed to deserialize signature: {0}")]
102 MalformedSignature(FastCryptoError),
103
104 #[error("Failed to verify the block's signature: {0}")]
105 SignatureVerificationFailure(FastCryptoError),
106
107 #[error("Synchronizer for fetching blocks directly from ([{0}],{1}) is saturated")]
108 SynchronizerSaturated(AuthorityIndex, String),
109
110 #[error("Block {block_ref:?} rejected: {reason}")]
111 BlockRejected { block_ref: BlockRef, reason: String },
112
113 #[error(
114 "Ancestor is in wrong position: block {block_authority}, ancestor {ancestor_authority}, position {position}"
115 )]
116 InvalidAncestorPosition {
117 block_authority: AuthorityIndex,
118 ancestor_authority: AuthorityIndex,
119 position: usize,
120 },
121
122 #[error("Ancestor's round ({ancestor}) should be lower than the block's round ({block})")]
123 InvalidAncestorRound { ancestor: Round, block: Round },
124
125 #[error("Ancestor {0} not found among genesis blocks!")]
126 InvalidGenesisAncestor(BlockRef),
127
128 #[error("Too many ancestors in the block: {0} > {1}")]
129 TooManyAncestors(usize, usize),
130
131 #[error("Ancestors from the same authority {0}")]
132 DuplicatedAncestorsAuthority(AuthorityIndex),
133
134 #[error("Insufficient stake from parents: {parent_stakes} < {quorum}")]
135 InsufficientParentStakes { parent_stakes: Stake, quorum: Stake },
136
137 #[error("Invalid transaction: {0}")]
138 InvalidTransaction(String),
139
140 #[error("Ancestors max timestamp {max_timestamp_ms} > block timestamp {block_timestamp_ms}")]
141 InvalidBlockTimestamp {
142 max_timestamp_ms: u64,
143 block_timestamp_ms: u64,
144 },
145
146 #[error("Received no commit from peer {peer}")]
147 NoCommitReceived { peer: AuthorityIndex },
148
149 #[error(
150 "Received unexpected start commit from peer {peer}: requested {start}, received {commit:?}"
151 )]
152 UnexpectedStartCommit {
153 peer: AuthorityIndex,
154 start: CommitIndex,
155 commit: Box<Commit>,
156 },
157
158 #[error(
159 "Received unexpected commit sequence from peer {peer}: {prev_commit:?}, {curr_commit:?}"
160 )]
161 UnexpectedCommitSequence {
162 peer: AuthorityIndex,
163 prev_commit: Box<Commit>,
164 curr_commit: Box<Commit>,
165 },
166
167 #[error("Not enough votes ({stake}) on end commit from peer {peer}: {commit:?}")]
168 NotEnoughCommitVotes {
169 stake: Stake,
170 peer: AuthorityIndex,
171 commit: Box<Commit>,
172 },
173
174 #[error("Received unexpected block from peer {peer}: {requested:?} vs {received:?}")]
175 UnexpectedBlockForCommit {
176 peer: AuthorityIndex,
177 requested: BlockRef,
178 received: BlockRef,
179 },
180
181 #[error(
182 "Unexpected certified commit index and last committed index. Expected next commit index to be {expected_commit_index}, but found {commit_index}"
183 )]
184 UnexpectedCertifiedCommitIndex {
185 expected_commit_index: CommitIndex,
186 commit_index: CommitIndex,
187 },
188
189 #[error("RocksDB failure: {0}")]
190 RocksDBFailure(#[from] TypedStoreError),
191
192 #[error("Network config error: {0:?}")]
193 NetworkConfig(String),
194
195 #[error("Failed to connect as client: {0:?}")]
196 NetworkClientConnection(String),
197
198 #[error("Failed to send request: {0:?}")]
199 NetworkRequest(String),
200
201 #[error("Request timeout: {0:?}")]
202 NetworkRequestTimeout(String),
203
204 #[error("Consensus has shut down!")]
205 Shutdown,
206}
207
208impl ConsensusError {
209 pub fn name(&self) -> &'static str {
212 self.into()
213 }
214}
215
216pub type ConsensusResult<T> = Result<T, ConsensusError>;
217
218#[macro_export]
219macro_rules! bail {
220 ($e:expr) => {
221 return Err($e);
222 };
223}
224
225#[macro_export(local_inner_macros)]
226macro_rules! ensure {
227 ($cond:expr, $e:expr) => {
228 if !($cond) {
229 bail!($e);
230 }
231 };
232}
233
234#[cfg(test)]
235mod test {
236 use super::*;
237 #[test]
241 fn test_error_name() {
242 {
243 let error = ConsensusError::InvalidAncestorRound {
244 ancestor: 10,
245 block: 11,
246 };
247 let error: &'static str = error.into();
248 assert_eq!(error, "InvalidAncestorRound");
249 }
250 {
251 let error = ConsensusError::InvalidAuthorityIndex {
252 index: AuthorityIndex::new_for_test(3),
253 max: 10,
254 };
255 assert_eq!(error.name(), "InvalidAuthorityIndex");
256 }
257 {
258 let error = ConsensusError::InsufficientParentStakes {
259 parent_stakes: 5,
260 quorum: 20,
261 };
262 assert_eq!(error.name(), "InsufficientParentStakes");
263 }
264 }
265}