1use std::{
10 hash::{Hash, Hasher},
11 ops::Deref,
12 sync::Arc,
13};
14
15use anyhow::{anyhow, ensure};
16use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
17use bincode::{
18 DefaultOptions, Options,
19 config::{
20 FixintEncoding, LittleEndian, RejectTrailing, WithOtherEndian, WithOtherIntEncoding,
21 WithOtherLimit, WithOtherTrailing,
22 },
23};
24use committable::{Commitment, Committable};
25use digest::OutputSizeUser;
26use serde::{Deserialize, Serialize};
27use sha2::Digest;
28use tagged_base64::tagged;
29use typenum::Unsigned;
30use vbs::version::Version;
31use versions::EPOCH_VERSION;
32
33use crate::{
34 data::{EpochNumber, Leaf2, VidCommitment, ViewNumber},
35 epoch_membership::EpochMembershipCoordinator,
36 message::UpgradeLock,
37 simple_certificate::QuorumCertificate2,
38 simple_vote::HasEpoch,
39 stake_table::StakeTableEntries,
40 traits::{ValidatedState, node_implementation::NodeType},
41 vote::{Certificate, HasViewNumber},
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<EpochNumber>,
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<EpochNumber>,
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>(
108 mut leaf_chain: Vec<Leaf2<T>>,
109 coordinator: &EpochMembershipCoordinator<T>,
110 expected_height: u64,
111 upgrade_lock: &UpgradeLock<T>,
112) -> anyhow::Result<Leaf2<T>> {
113 let epoch_height = *coordinator.epoch_height();
114 let validate_qc = |qc: QuorumCertificate2<T>, certified_height: u64| -> anyhow::Result<()> {
118 let epoch = EpochNumber::new(epoch_from_block_number(certified_height, epoch_height));
119 ensure!(
120 qc.data.epoch() == Some(epoch),
121 "QC claims epoch {:?} but certifies the leaf at height {certified_height} in epoch \
122 {epoch}",
123 qc.data.epoch(),
124 );
125 if let Some(block_number) = qc.data.block_number {
126 ensure!(
127 block_number == certified_height,
128 "QC claims block number {block_number} but certifies the leaf at height \
129 {certified_height}"
130 );
131 }
132 let membership = coordinator
133 .stake_table_for_epoch(Some(epoch))
134 .map_err(|err| anyhow!("no stake table available for epoch {epoch}: {err:?}"))?;
135 let entries = StakeTableEntries::<T>::from_iter(membership.stake_table()).0;
136 qc.is_valid_cert(&entries, membership.success_threshold(), upgrade_lock)?;
137 Ok(())
138 };
139
140 leaf_chain.sort_by_key(|l| l.view_number());
142 leaf_chain.reverse();
144
145 if leaf_chain.len() < 3 {
147 return Err(anyhow!("Leaf chain is not long enough for a decide"));
148 }
149
150 let newest_leaf = leaf_chain.first().unwrap();
151 let parent = &leaf_chain[1];
152 let grand_parent = &leaf_chain[2];
153
154 if newest_leaf.justify_qc().view_number() != parent.view_number()
156 || parent.justify_qc().view_number() != grand_parent.view_number()
157 {
158 return Err(anyhow!("Leaf views do not chain"));
159 }
160 if newest_leaf.justify_qc().data.leaf_commit != parent.commit()
161 || parent.justify_qc().data().leaf_commit != grand_parent.commit()
162 {
163 return Err(anyhow!("Leaf commits do not chain"));
164 }
165 if parent.view_number() != grand_parent.view_number() + 1 {
166 return Err(anyhow::anyhow!(
167 "Decide rule failed, parent does not directly extend grandparent"
168 ));
169 }
170
171 validate_qc(newest_leaf.justify_qc(), parent.height())?;
173 let mut last_leaf = parent;
174 for leaf in leaf_chain.iter().skip(2) {
175 ensure!(last_leaf.justify_qc().view_number() == leaf.view_number());
176 ensure!(last_leaf.justify_qc().data().leaf_commit == leaf.commit());
177 validate_qc(last_leaf.justify_qc(), leaf.height())?;
178 if leaf.height() == expected_height {
179 return Ok(leaf.clone());
180 }
181 last_leaf = leaf;
182 }
183 Err(anyhow!("Epoch Root was not found in the decided chain"))
184}
185
186impl<TYPES: NodeType> ViewInner<TYPES> {
187 #[must_use]
189 pub fn leaf_and_state(&self) -> Option<(LeafCommitment<TYPES>, &Arc<TYPES::ValidatedState>)> {
190 if let Self::Leaf { leaf, state, .. } = self {
191 Some((*leaf, state))
192 } else {
193 None
194 }
195 }
196
197 #[must_use]
199 pub fn leaf_commitment(&self) -> Option<LeafCommitment<TYPES>> {
200 if let Self::Leaf { leaf, .. } = self {
201 Some(*leaf)
202 } else {
203 None
204 }
205 }
206
207 #[must_use]
209 pub fn state(&self) -> Option<&Arc<TYPES::ValidatedState>> {
210 if let Self::Leaf { state, .. } = self {
211 Some(state)
212 } else {
213 None
214 }
215 }
216
217 #[must_use]
219 pub fn state_and_delta(&self) -> StateAndDelta<TYPES> {
220 if let Self::Leaf { state, delta, .. } = self {
221 (Some(Arc::clone(state)), delta.clone())
222 } else {
223 (None, None)
224 }
225 }
226
227 #[must_use]
229 pub fn payload_commitment(&self) -> Option<VidCommitment> {
230 if let Self::Da {
231 payload_commitment, ..
232 } = self
233 {
234 Some(*payload_commitment)
235 } else {
236 None
237 }
238 }
239
240 pub fn epoch(&self) -> Option<Option<EpochNumber>> {
243 match self {
244 Self::Da { epoch, .. } | Self::Leaf { epoch, .. } => Some(*epoch),
245 Self::Failed => None,
246 }
247 }
248}
249
250impl<TYPES: NodeType> Deref for View<TYPES> {
251 type Target = ViewInner<TYPES>;
252
253 fn deref(&self) -> &Self::Target {
254 &self.view_inner
255 }
256}
257
258#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
260#[serde(bound = "")]
261pub struct View<TYPES: NodeType> {
262 pub view_inner: ViewInner<TYPES>,
264}
265
266#[derive(Debug, Clone)]
268pub struct RoundFinishedEvent {
269 pub view_number: ViewNumber,
271}
272
273#[derive(Copy, Clone, Debug)]
275pub enum Terminator<T> {
276 Exclusive(T),
278 Inclusive(T),
280}
281
282type Sha256Digest = [u8; <sha2::Sha256 as OutputSizeUser>::OutputSize::USIZE];
284
285#[tagged("BUILDER_COMMITMENT")]
286#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
287pub struct BuilderCommitment(Sha256Digest);
290
291impl BuilderCommitment {
292 pub fn from_bytes(data: impl AsRef<[u8]>) -> Self {
294 Self(sha2::Sha256::digest(data.as_ref()).into())
295 }
296
297 pub fn from_raw_digest(digest: impl Into<Sha256Digest>) -> Self {
299 Self(digest.into())
300 }
301}
302
303impl AsRef<Sha256Digest> for BuilderCommitment {
304 fn as_ref(&self) -> &Sha256Digest {
305 &self.0
306 }
307}
308
309type BincodeOpts = WithOtherTrailing<
310 WithOtherIntEncoding<
311 WithOtherEndian<WithOtherLimit<DefaultOptions, bincode::config::Infinite>, LittleEndian>,
312 FixintEncoding,
313 >,
314 RejectTrailing,
315>;
316
317#[must_use]
323pub fn bincode_opts() -> BincodeOpts {
324 bincode::DefaultOptions::new()
325 .with_no_limit()
326 .with_little_endian()
327 .with_fixint_encoding()
328 .reject_trailing_bytes()
329}
330
331#[must_use]
333pub fn epoch_from_block_number(block_number: u64, epoch_height: u64) -> u64 {
334 if epoch_height == 0 {
335 0
336 } else if block_number == 0 {
337 1
338 } else if block_number.is_multiple_of(epoch_height) {
339 block_number / epoch_height
340 } else {
341 block_number / epoch_height + 1
342 }
343}
344
345#[must_use]
350pub fn root_block_in_epoch(epoch: u64, epoch_height: u64) -> u64 {
351 if epoch_height == 0 || epoch < 1 {
352 0
353 } else {
354 epoch_height * epoch - 5
355 }
356}
357
358#[must_use]
362pub fn transition_block_for_epoch(epoch: u64, epoch_height: u64) -> u64 {
363 if epoch_height == 0 || epoch < 1 {
364 0
365 } else {
366 epoch_height * epoch - 3
367 }
368}
369
370#[must_use]
373pub fn option_epoch_from_block_number(
374 with_epoch: bool,
375 block_number: u64,
376 epoch_height: u64,
377) -> Option<EpochNumber> {
378 if with_epoch {
379 if epoch_height == 0 {
380 None
381 } else if block_number == 0 {
382 Some(1u64)
383 } else if block_number.is_multiple_of(epoch_height) {
384 Some(block_number / epoch_height)
385 } else {
386 Some(block_number / epoch_height + 1)
387 }
388 .map(EpochNumber::new)
389 } else {
390 None
391 }
392}
393
394#[must_use]
396pub fn genesis_epoch_from_version(base: Version) -> Option<EpochNumber> {
397 (base >= EPOCH_VERSION).then(|| EpochNumber::new(1))
398}
399
400#[must_use]
402pub fn mnemonic<H: Hash>(bytes: H) -> String {
403 let mut state = std::collections::hash_map::DefaultHasher::new();
404 bytes.hash(&mut state);
405 mnemonic::to_string(state.finish().to_le_bytes())
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
411pub enum EpochTransitionIndicator {
412 InTransition,
414 NotInTransition,
416}
417
418#[must_use]
420pub fn is_transition_block(block_number: u64, epoch_height: u64) -> bool {
421 if block_number == 0 || epoch_height == 0 {
422 false
423 } else {
424 (block_number + 3).is_multiple_of(epoch_height)
425 }
426}
427#[must_use]
429pub fn is_first_transition_block(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 - 2
434 }
435}
436#[must_use]
438pub fn is_epoch_transition(block_number: u64, epoch_height: u64) -> bool {
439 if block_number == 0 || epoch_height == 0 {
440 false
441 } else {
442 block_number % epoch_height >= epoch_height - 3 || block_number.is_multiple_of(epoch_height)
443 }
444}
445
446#[must_use]
448pub fn is_last_block(block_number: u64, epoch_height: u64) -> bool {
449 if block_number == 0 || epoch_height == 0 {
450 false
451 } else {
452 block_number.is_multiple_of(epoch_height)
453 }
454}
455
456#[must_use]
462pub fn is_middle_transition_block(block_number: u64, epoch_height: u64) -> bool {
463 if block_number == 0 || epoch_height == 0 {
464 false
465 } else {
466 let blocks_left = epoch_height - (block_number % epoch_height);
467 blocks_left == 1 || blocks_left == 2
468 }
469}
470
471#[must_use]
474pub fn is_epoch_root(block_number: u64, epoch_height: u64) -> bool {
475 if block_number == 0 || epoch_height == 0 {
476 false
477 } else {
478 (block_number + 5).is_multiple_of(epoch_height)
479 }
480}
481
482#[must_use]
484pub fn is_ge_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
492pub fn is_gt_epoch_root(block_number: u64, epoch_height: u64) -> bool {
494 if block_number == 0 || epoch_height == 0 {
495 false
496 } else {
497 block_number.is_multiple_of(epoch_height) || block_number % epoch_height > epoch_height - 5
498 }
499}
500
501#[cfg(test)]
502mod test {
503 use super::*;
504
505 #[test]
506 fn test_epoch_from_block_number() {
507 let epoch = epoch_from_block_number(0, 10);
509 assert_eq!(1, epoch);
510
511 let epoch = epoch_from_block_number(1, 10);
512 assert_eq!(1, epoch);
513
514 let epoch = epoch_from_block_number(10, 10);
515 assert_eq!(1, epoch);
516
517 let epoch = epoch_from_block_number(11, 10);
518 assert_eq!(2, epoch);
519
520 let epoch = epoch_from_block_number(20, 10);
521 assert_eq!(2, epoch);
522
523 let epoch = epoch_from_block_number(21, 10);
524 assert_eq!(3, epoch);
525
526 let epoch = epoch_from_block_number(21, 0);
527 assert_eq!(0, epoch);
528 }
529
530 #[test]
531 fn test_is_last_block_in_epoch() {
532 assert!(!is_epoch_transition(5, 10));
533 assert!(!is_epoch_transition(6, 10));
534 assert!(is_epoch_transition(7, 10));
535 assert!(is_epoch_transition(8, 10));
536 assert!(is_epoch_transition(9, 10));
537 assert!(is_epoch_transition(10, 10));
538 assert!(!is_epoch_transition(11, 10));
539
540 assert!(!is_epoch_transition(10, 0));
541 }
542
543 #[test]
544 fn test_is_epoch_root() {
545 assert!(is_epoch_root(5, 10));
546 assert!(!is_epoch_root(6, 10));
547 assert!(!is_epoch_root(7, 10));
548 assert!(!is_epoch_root(8, 10));
549 assert!(!is_epoch_root(9, 10));
550 assert!(!is_epoch_root(10, 10));
551 assert!(!is_epoch_root(11, 10));
552
553 assert!(!is_epoch_transition(10, 0));
554 }
555
556 #[test]
557 fn test_root_block_in_epoch() {
558 let epoch = 3;
560 let epoch_height = 10;
561 let epoch_root_block_number = root_block_in_epoch(3, epoch_height);
562
563 assert!(is_epoch_root(25, epoch_height));
564
565 assert_eq!(epoch_root_block_number, 25);
566
567 assert_eq!(
568 epoch,
569 epoch_from_block_number(epoch_root_block_number, epoch_height)
570 );
571 }
572}