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 DefaultOptions, Options,
20 config::{
21 FixintEncoding, LittleEndian, RejectTrailing, WithOtherEndian, WithOtherIntEncoding,
22 WithOtherLimit, WithOtherTrailing,
23 },
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::Version;
32use versions::EPOCH_VERSION;
33
34use crate::{
35 PeerConfig,
36 data::{EpochNumber, Leaf2, VidCommitment, ViewNumber},
37 stake_table::StakeTableEntries,
38 traits::{ValidatedState, node_implementation::NodeType},
39 vote::{Certificate, HasViewNumber},
40};
41
42#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
44#[serde(bound = "")]
45pub enum ViewInner<TYPES: NodeType> {
46 Da {
52 payload_commitment: VidCommitment,
54 epoch: Option<EpochNumber>,
56 },
57 Leaf {
59 leaf: LeafCommitment<TYPES>,
61 state: Arc<TYPES::ValidatedState>,
63 delta: Option<Arc<<TYPES::ValidatedState as ValidatedState<TYPES>>::Delta>>,
65 epoch: Option<EpochNumber>,
67 },
68 Failed,
70}
71impl<TYPES: NodeType> Clone for ViewInner<TYPES> {
72 fn clone(&self) -> Self {
73 match self {
74 Self::Da {
75 payload_commitment,
76 epoch,
77 } => Self::Da {
78 payload_commitment: *payload_commitment,
79 epoch: *epoch,
80 },
81 Self::Leaf {
82 leaf,
83 state,
84 delta,
85 epoch,
86 } => Self::Leaf {
87 leaf: *leaf,
88 state: Arc::clone(state),
89 delta: delta.clone(),
90 epoch: *epoch,
91 },
92 Self::Failed => Self::Failed,
93 }
94 }
95}
96pub type LeafCommitment<TYPES> = Commitment<Leaf2<TYPES>>;
98
99pub type StateAndDelta<TYPES> = (
101 Option<Arc<<TYPES as NodeType>::ValidatedState>>,
102 Option<Arc<<<TYPES as NodeType>::ValidatedState as ValidatedState<TYPES>>::Delta>>,
103);
104
105pub async fn verify_leaf_chain<T: NodeType>(
106 mut leaf_chain: Vec<Leaf2<T>>,
107 stake_table: &[PeerConfig<T>],
108 success_threshold: U256,
109 expected_height: u64,
110 upgrade_lock: &crate::message::UpgradeLock<T>,
111) -> anyhow::Result<Leaf2<T>> {
112 leaf_chain.sort_by_key(|l| l.view_number());
114 leaf_chain.reverse();
116
117 if leaf_chain.len() < 3 {
119 return Err(anyhow!("Leaf chain is not long enough for a decide"));
120 }
121
122 let newest_leaf = leaf_chain.first().unwrap();
123 let parent = &leaf_chain[1];
124 let grand_parent = &leaf_chain[2];
125
126 if newest_leaf.justify_qc().view_number() != parent.view_number()
128 || parent.justify_qc().view_number() != grand_parent.view_number()
129 {
130 return Err(anyhow!("Leaf views do not chain"));
131 }
132 if newest_leaf.justify_qc().data.leaf_commit != parent.commit()
133 || parent.justify_qc().data().leaf_commit != grand_parent.commit()
134 {
135 return Err(anyhow!("Leaf commits do not chain"));
136 }
137 if parent.view_number() != grand_parent.view_number() + 1 {
138 return Err(anyhow::anyhow!(
139 "Decide rule failed, parent does not directly extend grandparent"
140 ));
141 }
142
143 let stake_table_entries = StakeTableEntries::<T>::from(stake_table.to_vec()).0;
145
146 newest_leaf
148 .justify_qc()
149 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
150 .await?;
151 parent
152 .justify_qc()
153 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
154 .await?;
155 grand_parent
156 .justify_qc()
157 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
158 .await?;
159
160 let mut last_leaf = parent;
162 for leaf in leaf_chain.iter().skip(2) {
163 ensure!(last_leaf.justify_qc().view_number() == leaf.view_number());
164 ensure!(last_leaf.justify_qc().data().leaf_commit == leaf.commit());
165 leaf.justify_qc()
166 .is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)
167 .await?;
168 if leaf.height() == expected_height {
169 return Ok(leaf.clone());
170 }
171 last_leaf = leaf;
172 }
173 Err(anyhow!("Epoch Root was not found in the decided chain"))
174}
175
176impl<TYPES: NodeType> ViewInner<TYPES> {
177 #[must_use]
179 pub fn leaf_and_state(&self) -> Option<(LeafCommitment<TYPES>, &Arc<TYPES::ValidatedState>)> {
180 if let Self::Leaf { leaf, state, .. } = self {
181 Some((*leaf, state))
182 } else {
183 None
184 }
185 }
186
187 #[must_use]
189 pub fn leaf_commitment(&self) -> Option<LeafCommitment<TYPES>> {
190 if let Self::Leaf { leaf, .. } = self {
191 Some(*leaf)
192 } else {
193 None
194 }
195 }
196
197 #[must_use]
199 pub fn state(&self) -> Option<&Arc<TYPES::ValidatedState>> {
200 if let Self::Leaf { state, .. } = self {
201 Some(state)
202 } else {
203 None
204 }
205 }
206
207 #[must_use]
209 pub fn state_and_delta(&self) -> StateAndDelta<TYPES> {
210 if let Self::Leaf { state, delta, .. } = self {
211 (Some(Arc::clone(state)), delta.clone())
212 } else {
213 (None, None)
214 }
215 }
216
217 #[must_use]
219 pub fn payload_commitment(&self) -> Option<VidCommitment> {
220 if let Self::Da {
221 payload_commitment, ..
222 } = self
223 {
224 Some(*payload_commitment)
225 } else {
226 None
227 }
228 }
229
230 pub fn epoch(&self) -> Option<Option<EpochNumber>> {
233 match self {
234 Self::Da { epoch, .. } | Self::Leaf { epoch, .. } => Some(*epoch),
235 Self::Failed => None,
236 }
237 }
238}
239
240impl<TYPES: NodeType> Deref for View<TYPES> {
241 type Target = ViewInner<TYPES>;
242
243 fn deref(&self) -> &Self::Target {
244 &self.view_inner
245 }
246}
247
248#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
250#[serde(bound = "")]
251pub struct View<TYPES: NodeType> {
252 pub view_inner: ViewInner<TYPES>,
254}
255
256#[derive(Debug, Clone)]
258pub struct RoundFinishedEvent {
259 pub view_number: ViewNumber,
261}
262
263#[derive(Copy, Clone, Debug)]
265pub enum Terminator<T> {
266 Exclusive(T),
268 Inclusive(T),
270}
271
272type Sha256Digest = [u8; <sha2::Sha256 as OutputSizeUser>::OutputSize::USIZE];
274
275#[tagged("BUILDER_COMMITMENT")]
276#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
277pub struct BuilderCommitment(Sha256Digest);
280
281impl BuilderCommitment {
282 pub fn from_bytes(data: impl AsRef<[u8]>) -> Self {
284 Self(sha2::Sha256::digest(data.as_ref()).into())
285 }
286
287 pub fn from_raw_digest(digest: impl Into<Sha256Digest>) -> Self {
289 Self(digest.into())
290 }
291}
292
293impl AsRef<Sha256Digest> for BuilderCommitment {
294 fn as_ref(&self) -> &Sha256Digest {
295 &self.0
296 }
297}
298
299type BincodeOpts = WithOtherTrailing<
300 WithOtherIntEncoding<
301 WithOtherEndian<WithOtherLimit<DefaultOptions, bincode::config::Infinite>, LittleEndian>,
302 FixintEncoding,
303 >,
304 RejectTrailing,
305>;
306
307#[must_use]
313pub fn bincode_opts() -> BincodeOpts {
314 bincode::DefaultOptions::new()
315 .with_no_limit()
316 .with_little_endian()
317 .with_fixint_encoding()
318 .reject_trailing_bytes()
319}
320
321#[must_use]
323pub fn epoch_from_block_number(block_number: u64, epoch_height: u64) -> u64 {
324 if epoch_height == 0 {
325 0
326 } else if block_number == 0 {
327 1
328 } else if block_number.is_multiple_of(epoch_height) {
329 block_number / epoch_height
330 } else {
331 block_number / epoch_height + 1
332 }
333}
334
335#[must_use]
340pub fn root_block_in_epoch(epoch: u64, epoch_height: u64) -> u64 {
341 if epoch_height == 0 || epoch < 1 {
342 0
343 } else {
344 epoch_height * epoch - 5
345 }
346}
347
348#[must_use]
352pub fn transition_block_for_epoch(epoch: u64, epoch_height: u64) -> u64 {
353 if epoch_height == 0 || epoch < 1 {
354 0
355 } else {
356 epoch_height * epoch - 3
357 }
358}
359
360#[must_use]
363pub fn option_epoch_from_block_number(
364 with_epoch: bool,
365 block_number: u64,
366 epoch_height: u64,
367) -> Option<EpochNumber> {
368 if with_epoch {
369 if epoch_height == 0 {
370 None
371 } else if block_number == 0 {
372 Some(1u64)
373 } else if block_number.is_multiple_of(epoch_height) {
374 Some(block_number / epoch_height)
375 } else {
376 Some(block_number / epoch_height + 1)
377 }
378 .map(EpochNumber::new)
379 } else {
380 None
381 }
382}
383
384#[must_use]
386pub fn genesis_epoch_from_version(base: Version) -> Option<EpochNumber> {
387 (base >= EPOCH_VERSION).then(|| EpochNumber::new(1))
388}
389
390#[must_use]
392pub fn mnemonic<H: Hash>(bytes: H) -> String {
393 let mut state = std::collections::hash_map::DefaultHasher::new();
394 bytes.hash(&mut state);
395 mnemonic::to_string(state.finish().to_le_bytes())
396}
397
398#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
401pub enum EpochTransitionIndicator {
402 InTransition,
404 NotInTransition,
406}
407
408#[must_use]
410pub fn is_transition_block(block_number: u64, epoch_height: u64) -> bool {
411 if block_number == 0 || epoch_height == 0 {
412 false
413 } else {
414 (block_number + 3).is_multiple_of(epoch_height)
415 }
416}
417#[must_use]
419pub fn is_first_transition_block(block_number: u64, epoch_height: u64) -> bool {
420 if block_number == 0 || epoch_height == 0 {
421 false
422 } else {
423 block_number % epoch_height == epoch_height - 2
424 }
425}
426#[must_use]
428pub fn is_epoch_transition(block_number: u64, epoch_height: u64) -> bool {
429 if block_number == 0 || epoch_height == 0 {
430 false
431 } else {
432 block_number % epoch_height >= epoch_height - 3 || block_number.is_multiple_of(epoch_height)
433 }
434}
435
436#[must_use]
438pub fn is_last_block(block_number: u64, epoch_height: u64) -> bool {
439 if block_number == 0 || epoch_height == 0 {
440 false
441 } else {
442 block_number.is_multiple_of(epoch_height)
443 }
444}
445
446#[must_use]
452pub fn is_middle_transition_block(block_number: u64, epoch_height: u64) -> bool {
453 if block_number == 0 || epoch_height == 0 {
454 false
455 } else {
456 let blocks_left = epoch_height - (block_number % epoch_height);
457 blocks_left == 1 || blocks_left == 2
458 }
459}
460
461#[must_use]
464pub fn is_epoch_root(block_number: u64, epoch_height: u64) -> bool {
465 if block_number == 0 || epoch_height == 0 {
466 false
467 } else {
468 (block_number + 5).is_multiple_of(epoch_height)
469 }
470}
471
472#[must_use]
474pub fn is_ge_epoch_root(block_number: u64, epoch_height: u64) -> bool {
475 if block_number == 0 || epoch_height == 0 {
476 false
477 } else {
478 block_number.is_multiple_of(epoch_height) || block_number % epoch_height >= epoch_height - 5
479 }
480}
481
482pub fn is_gt_epoch_root(block_number: u64, epoch_height: u64) -> bool {
484 if block_number == 0 || epoch_height == 0 {
485 false
486 } else {
487 block_number.is_multiple_of(epoch_height) || block_number % epoch_height > epoch_height - 5
488 }
489}
490
491#[cfg(test)]
492mod test {
493 use super::*;
494
495 #[test]
496 fn test_epoch_from_block_number() {
497 let epoch = epoch_from_block_number(0, 10);
499 assert_eq!(1, epoch);
500
501 let epoch = epoch_from_block_number(1, 10);
502 assert_eq!(1, epoch);
503
504 let epoch = epoch_from_block_number(10, 10);
505 assert_eq!(1, epoch);
506
507 let epoch = epoch_from_block_number(11, 10);
508 assert_eq!(2, epoch);
509
510 let epoch = epoch_from_block_number(20, 10);
511 assert_eq!(2, epoch);
512
513 let epoch = epoch_from_block_number(21, 10);
514 assert_eq!(3, epoch);
515
516 let epoch = epoch_from_block_number(21, 0);
517 assert_eq!(0, epoch);
518 }
519
520 #[test]
521 fn test_is_last_block_in_epoch() {
522 assert!(!is_epoch_transition(5, 10));
523 assert!(!is_epoch_transition(6, 10));
524 assert!(is_epoch_transition(7, 10));
525 assert!(is_epoch_transition(8, 10));
526 assert!(is_epoch_transition(9, 10));
527 assert!(is_epoch_transition(10, 10));
528 assert!(!is_epoch_transition(11, 10));
529
530 assert!(!is_epoch_transition(10, 0));
531 }
532
533 #[test]
534 fn test_is_epoch_root() {
535 assert!(is_epoch_root(5, 10));
536 assert!(!is_epoch_root(6, 10));
537 assert!(!is_epoch_root(7, 10));
538 assert!(!is_epoch_root(8, 10));
539 assert!(!is_epoch_root(9, 10));
540 assert!(!is_epoch_root(10, 10));
541 assert!(!is_epoch_root(11, 10));
542
543 assert!(!is_epoch_transition(10, 0));
544 }
545
546 #[test]
547 fn test_root_block_in_epoch() {
548 let epoch = 3;
550 let epoch_height = 10;
551 let epoch_root_block_number = root_block_in_epoch(3, epoch_height);
552
553 assert!(is_epoch_root(25, epoch_height));
554
555 assert_eq!(epoch_root_block_number, 25);
556
557 assert_eq!(
558 epoch,
559 epoch_from_block_number(epoch_root_block_number, epoch_height)
560 );
561 }
562}