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