1use std::{
10 hash::{Hash, Hasher},
11 ops::Deref,
12 sync::Arc,
13};
14
15use alloy::primitives::U256;
16use anyhow::{anyhow, ensure};
17use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
18use bincode::{
19 config::{
20 FixintEncoding, LittleEndian, RejectTrailing, WithOtherEndian, WithOtherIntEncoding,
21 WithOtherLimit, WithOtherTrailing,
22 },
23 DefaultOptions, Options,
24};
25use committable::{Commitment, Committable};
26use digest::OutputSizeUser;
27use serde::{Deserialize, Serialize};
28use sha2::Digest;
29use tagged_base64::tagged;
30use typenum::Unsigned;
31use vbs::version::StaticVersionType;
32
33use crate::{
34 data::{Leaf2, VidCommitment},
35 stake_table::StakeTableEntries,
36 traits::{
37 node_implementation::{ConsensusTime, NodeType, Versions},
38 ValidatedState,
39 },
40 vote::{Certificate, HasViewNumber},
41 PeerConfig,
42};
43
44#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
46#[serde(bound = "")]
47pub enum ViewInner<TYPES: NodeType> {
48 Da {
54 payload_commitment: VidCommitment,
56 epoch: Option<TYPES::Epoch>,
58 },
59 Leaf {
61 leaf: LeafCommitment<TYPES>,
63 state: Arc<TYPES::ValidatedState>,
65 delta: Option<Arc<<TYPES::ValidatedState as ValidatedState<TYPES>>::Delta>>,
67 epoch: Option<TYPES::Epoch>,
69 },
70 Failed,
72}
73impl<TYPES: NodeType> Clone for ViewInner<TYPES> {
74 fn clone(&self) -> Self {
75 match self {
76 Self::Da {
77 payload_commitment,
78 epoch,
79 } => Self::Da {
80 payload_commitment: *payload_commitment,
81 epoch: *epoch,
82 },
83 Self::Leaf {
84 leaf,
85 state,
86 delta,
87 epoch,
88 } => Self::Leaf {
89 leaf: *leaf,
90 state: Arc::clone(state),
91 delta: delta.clone(),
92 epoch: *epoch,
93 },
94 Self::Failed => Self::Failed,
95 }
96 }
97}
98pub type LeafCommitment<TYPES> = Commitment<Leaf2<TYPES>>;
100
101pub type StateAndDelta<TYPES> = (
103 Option<Arc<<TYPES as NodeType>::ValidatedState>>,
104 Option<Arc<<<TYPES as NodeType>::ValidatedState as ValidatedState<TYPES>>::Delta>>,
105);
106
107pub async fn verify_leaf_chain<T: NodeType, V: Versions>(
108 mut leaf_chain: Vec<Leaf2<T>>,
109 stake_table: &[PeerConfig<T>],
110 success_threshold: U256,
111 expected_height: u64,
112 upgrade_lock: &crate::message::UpgradeLock<T, V>,
113) -> anyhow::Result<Leaf2<T>> {
114 leaf_chain.sort_by_key(|l| l.view_number());
116 leaf_chain.reverse();
118
119 if leaf_chain.len() < 3 {
121 return Err(anyhow!("Leaf chain is not long enough for a decide"));
122 }
123
124 let newest_leaf = leaf_chain.first().unwrap();
125 let parent = &leaf_chain[1];
126 let grand_parent = &leaf_chain[2];
127
128 if newest_leaf.justify_qc().view_number() != parent.view_number()
130 || parent.justify_qc().view_number() != grand_parent.view_number()
131 {
132 return Err(anyhow!("Leaf views do not chain"));
133 }
134 if newest_leaf.justify_qc().data.leaf_commit != parent.commit()
135 || parent.justify_qc().data().leaf_commit != grand_parent.commit()
136 {
137 return Err(anyhow!("Leaf commits do not chain"));
138 }
139 if parent.view_number() != grand_parent.view_number() + 1 {
140 return Err(anyhow::anyhow!(
141 "Decide rule failed, parent does not directly extend grandparent"
142 ));
143 }
144
145 let stake_table_entries = StakeTableEntries::<T>::from(stake_table.to_vec()).0;
147
148 newest_leaf
150 .justify_qc()
151 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
152 .await?;
153 parent
154 .justify_qc()
155 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
156 .await?;
157 grand_parent
158 .justify_qc()
159 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
160 .await?;
161
162 let mut last_leaf = parent;
164 for leaf in leaf_chain.iter().skip(2) {
165 ensure!(last_leaf.justify_qc().view_number() == leaf.view_number());
166 ensure!(last_leaf.justify_qc().data().leaf_commit == leaf.commit());
167 leaf.justify_qc()
168 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
169 .await?;
170 if leaf.height() == expected_height {
171 return Ok(leaf.clone());
172 }
173 last_leaf = leaf;
174 }
175 Err(anyhow!("Epoch Root was not found in the decided chain"))
176}
177
178impl<TYPES: NodeType> ViewInner<TYPES> {
179 #[must_use]
181 pub fn leaf_and_state(&self) -> Option<(LeafCommitment<TYPES>, &Arc<TYPES::ValidatedState>)> {
182 if let Self::Leaf { leaf, state, .. } = self {
183 Some((*leaf, state))
184 } else {
185 None
186 }
187 }
188
189 #[must_use]
191 pub fn leaf_commitment(&self) -> Option<LeafCommitment<TYPES>> {
192 if let Self::Leaf { leaf, .. } = self {
193 Some(*leaf)
194 } else {
195 None
196 }
197 }
198
199 #[must_use]
201 pub fn state(&self) -> Option<&Arc<TYPES::ValidatedState>> {
202 if let Self::Leaf { state, .. } = self {
203 Some(state)
204 } else {
205 None
206 }
207 }
208
209 #[must_use]
211 pub fn state_and_delta(&self) -> StateAndDelta<TYPES> {
212 if let Self::Leaf { state, delta, .. } = self {
213 (Some(Arc::clone(state)), delta.clone())
214 } else {
215 (None, None)
216 }
217 }
218
219 #[must_use]
221 pub fn payload_commitment(&self) -> Option<VidCommitment> {
222 if let Self::Da {
223 payload_commitment, ..
224 } = self
225 {
226 Some(*payload_commitment)
227 } else {
228 None
229 }
230 }
231
232 pub fn epoch(&self) -> Option<Option<TYPES::Epoch>> {
235 match self {
236 Self::Da { epoch, .. } | Self::Leaf { epoch, .. } => Some(*epoch),
237 Self::Failed => None,
238 }
239 }
240}
241
242impl<TYPES: NodeType> Deref for View<TYPES> {
243 type Target = ViewInner<TYPES>;
244
245 fn deref(&self) -> &Self::Target {
246 &self.view_inner
247 }
248}
249
250#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
252#[serde(bound = "")]
253pub struct View<TYPES: NodeType> {
254 pub view_inner: ViewInner<TYPES>,
256}
257
258#[derive(Debug, Clone)]
260pub struct RoundFinishedEvent<TYPES: NodeType> {
261 pub view_number: TYPES::View,
263}
264
265#[derive(Copy, Clone, Debug)]
267pub enum Terminator<T> {
268 Exclusive(T),
270 Inclusive(T),
272}
273
274type Sha256Digest = [u8; <sha2::Sha256 as OutputSizeUser>::OutputSize::USIZE];
276
277#[tagged("BUILDER_COMMITMENT")]
278#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
279pub struct BuilderCommitment(Sha256Digest);
282
283impl BuilderCommitment {
284 pub fn from_bytes(data: impl AsRef<[u8]>) -> Self {
286 Self(sha2::Sha256::digest(data.as_ref()).into())
287 }
288
289 pub fn from_raw_digest(digest: impl Into<Sha256Digest>) -> Self {
291 Self(digest.into())
292 }
293}
294
295impl AsRef<Sha256Digest> for BuilderCommitment {
296 fn as_ref(&self) -> &Sha256Digest {
297 &self.0
298 }
299}
300
301#[allow(clippy::type_complexity)]
307#[must_use]
308#[allow(clippy::type_complexity)]
309pub fn bincode_opts() -> WithOtherTrailing<
310 WithOtherIntEncoding<
311 WithOtherEndian<WithOtherLimit<DefaultOptions, bincode::config::Infinite>, LittleEndian>,
312 FixintEncoding,
313 >,
314 RejectTrailing,
315> {
316 bincode::DefaultOptions::new()
317 .with_no_limit()
318 .with_little_endian()
319 .with_fixint_encoding()
320 .reject_trailing_bytes()
321}
322
323#[must_use]
325pub fn epoch_from_block_number(block_number: u64, epoch_height: u64) -> u64 {
326 if epoch_height == 0 {
327 0
328 } else if block_number == 0 {
329 1
330 } else if block_number % epoch_height == 0 {
331 block_number / epoch_height
332 } else {
333 block_number / epoch_height + 1
334 }
335}
336
337#[must_use]
342pub fn root_block_in_epoch(epoch: u64, epoch_height: u64) -> u64 {
343 if epoch_height == 0 || epoch < 1 {
344 0
345 } else {
346 epoch_height * epoch - 5
347 }
348}
349
350#[must_use]
354pub fn transition_block_for_epoch(epoch: u64, epoch_height: u64) -> u64 {
355 if epoch_height == 0 || epoch < 1 {
356 0
357 } else {
358 epoch_height * epoch - 3
359 }
360}
361
362#[must_use]
365pub fn option_epoch_from_block_number<TYPES: NodeType>(
366 with_epoch: bool,
367 block_number: u64,
368 epoch_height: u64,
369) -> Option<TYPES::Epoch> {
370 if with_epoch {
371 if epoch_height == 0 {
372 None
373 } else if block_number == 0 {
374 Some(1u64)
375 } else if block_number % epoch_height == 0 {
376 Some(block_number / epoch_height)
377 } else {
378 Some(block_number / epoch_height + 1)
379 }
380 .map(TYPES::Epoch::new)
381 } else {
382 None
383 }
384}
385
386#[must_use]
388pub fn genesis_epoch_from_version<V: Versions, TYPES: NodeType>() -> Option<TYPES::Epoch> {
389 (V::Base::VERSION >= V::Epochs::VERSION).then(|| TYPES::Epoch::new(1))
390}
391
392#[must_use]
394pub fn mnemonic<H: Hash>(bytes: H) -> String {
395 let mut state = std::collections::hash_map::DefaultHasher::new();
396 bytes.hash(&mut state);
397 mnemonic::to_string(state.finish().to_le_bytes())
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
403pub enum EpochTransitionIndicator {
404 InTransition,
406 NotInTransition,
408}
409
410#[must_use]
412pub fn is_transition_block(block_number: u64, epoch_height: u64) -> bool {
413 if block_number == 0 || epoch_height == 0 {
414 false
415 } else {
416 (block_number + 3) % epoch_height == 0
417 }
418}
419#[must_use]
421pub fn is_first_transition_block(block_number: u64, epoch_height: u64) -> bool {
422 if block_number == 0 || epoch_height == 0 {
423 false
424 } else {
425 block_number % epoch_height == epoch_height - 2
426 }
427}
428#[must_use]
430pub fn is_epoch_transition(block_number: u64, epoch_height: u64) -> bool {
431 if block_number == 0 || epoch_height == 0 {
432 false
433 } else {
434 block_number % epoch_height >= epoch_height - 3 || block_number % epoch_height == 0
435 }
436}
437
438#[must_use]
440pub fn is_last_block(block_number: u64, epoch_height: u64) -> bool {
441 if block_number == 0 || epoch_height == 0 {
442 false
443 } else {
444 block_number % epoch_height == 0
445 }
446}
447
448#[must_use]
454pub fn is_middle_transition_block(block_number: u64, epoch_height: u64) -> bool {
455 if block_number == 0 || epoch_height == 0 {
456 false
457 } else {
458 let blocks_left = epoch_height - (block_number % epoch_height);
459 blocks_left == 1 || blocks_left == 2
460 }
461}
462
463#[must_use]
466pub fn is_epoch_root(block_number: u64, epoch_height: u64) -> bool {
467 if block_number == 0 || epoch_height == 0 {
468 false
469 } else {
470 (block_number + 5) % epoch_height == 0
471 }
472}
473
474#[must_use]
476pub fn is_ge_epoch_root(block_number: u64, epoch_height: u64) -> bool {
477 if block_number == 0 || epoch_height == 0 {
478 false
479 } else {
480 block_number % epoch_height == 0 || block_number % epoch_height >= epoch_height - 5
481 }
482}
483
484pub fn is_gt_epoch_root(block_number: u64, epoch_height: u64) -> bool {
486 if block_number == 0 || epoch_height == 0 {
487 false
488 } else {
489 block_number % epoch_height == 0 || block_number % epoch_height > epoch_height - 5
490 }
491}
492
493#[cfg(test)]
494mod test {
495 use super::*;
496
497 #[test]
498 fn test_epoch_from_block_number() {
499 let epoch = epoch_from_block_number(0, 10);
501 assert_eq!(1, epoch);
502
503 let epoch = epoch_from_block_number(1, 10);
504 assert_eq!(1, epoch);
505
506 let epoch = epoch_from_block_number(10, 10);
507 assert_eq!(1, epoch);
508
509 let epoch = epoch_from_block_number(11, 10);
510 assert_eq!(2, epoch);
511
512 let epoch = epoch_from_block_number(20, 10);
513 assert_eq!(2, epoch);
514
515 let epoch = epoch_from_block_number(21, 10);
516 assert_eq!(3, epoch);
517
518 let epoch = epoch_from_block_number(21, 0);
519 assert_eq!(0, epoch);
520 }
521
522 #[test]
523 fn test_is_last_block_in_epoch() {
524 assert!(!is_epoch_transition(5, 10));
525 assert!(!is_epoch_transition(6, 10));
526 assert!(is_epoch_transition(7, 10));
527 assert!(is_epoch_transition(8, 10));
528 assert!(is_epoch_transition(9, 10));
529 assert!(is_epoch_transition(10, 10));
530 assert!(!is_epoch_transition(11, 10));
531
532 assert!(!is_epoch_transition(10, 0));
533 }
534
535 #[test]
536 fn test_is_epoch_root() {
537 assert!(is_epoch_root(5, 10));
538 assert!(!is_epoch_root(6, 10));
539 assert!(!is_epoch_root(7, 10));
540 assert!(!is_epoch_root(8, 10));
541 assert!(!is_epoch_root(9, 10));
542 assert!(!is_epoch_root(10, 10));
543 assert!(!is_epoch_root(11, 10));
544
545 assert!(!is_epoch_transition(10, 0));
546 }
547
548 #[test]
549 fn test_root_block_in_epoch() {
550 let epoch = 3;
552 let epoch_height = 10;
553 let epoch_root_block_number = root_block_in_epoch(3, epoch_height);
554
555 assert!(is_epoch_root(25, epoch_height));
556
557 assert_eq!(epoch_root_block_number, 25);
558
559 assert_eq!(
560 epoch,
561 epoch_from_block_number(epoch_root_block_number, epoch_height)
562 );
563 }
564}