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, election::Membership, 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 first_epoch = coordinator.membership().first_epoch();
115 let validate_qc = |qc: &QuorumCertificate2<T>, certified_height: u64| -> anyhow::Result<()> {
119 let epoch = EpochNumber::new(epoch_from_block_number(certified_height, epoch_height));
120 let membership = match qc.data.epoch() {
121 None => {
125 ensure!(
126 epoch <= first_epoch,
127 "QC claims no epoch but certifies the leaf at height {certified_height} in \
128 epoch {epoch}, after the first epoch {first_epoch}"
129 );
130 coordinator.stake_table_for_epoch(None)
131 },
132 Some(claimed) => {
133 ensure!(
134 claimed == epoch,
135 "QC claims epoch {claimed} but certifies the leaf at height \
136 {certified_height} in epoch {epoch}"
137 );
138 coordinator.stake_table_for_epoch(Some(epoch))
139 },
140 }
141 .map_err(|err| anyhow!("no stake table available for epoch {epoch}: {err:?}"))?;
142 if let Some(block_number) = qc.data.block_number {
143 ensure!(
144 block_number == certified_height,
145 "QC claims block number {block_number} but certifies the leaf at height \
146 {certified_height}"
147 );
148 }
149 let entries = StakeTableEntries::<T>::from_iter(membership.stake_table()).0;
150 qc.is_valid_cert(&entries, membership.success_threshold(), upgrade_lock)?;
151 Ok(())
152 };
153
154 leaf_chain.sort_by_key(|l| l.view_number());
156 leaf_chain.reverse();
158
159 if leaf_chain.len() < 3 {
161 return Err(anyhow!("Leaf chain is not long enough for a decide"));
162 }
163
164 let newest_leaf = leaf_chain.first().unwrap();
165 let parent = &leaf_chain[1];
166 let grand_parent = &leaf_chain[2];
167
168 if newest_leaf.justify_qc().view_number() != parent.view_number()
170 || parent.justify_qc().view_number() != grand_parent.view_number()
171 {
172 return Err(anyhow!("Leaf views do not chain"));
173 }
174 if newest_leaf.justify_qc().data.leaf_commit != parent.commit()
175 || parent.justify_qc().data().leaf_commit != grand_parent.commit()
176 {
177 return Err(anyhow!("Leaf commits do not chain"));
178 }
179 if parent.view_number() != grand_parent.view_number() + 1 {
180 return Err(anyhow::anyhow!(
181 "Decide rule failed, parent does not directly extend grandparent"
182 ));
183 }
184
185 validate_qc(newest_leaf.justify_qc(), parent.height())?;
187 let mut last_leaf = parent;
188 for leaf in leaf_chain.iter().skip(2) {
189 ensure!(last_leaf.justify_qc().view_number() == leaf.view_number());
190 ensure!(last_leaf.justify_qc().data().leaf_commit == leaf.commit());
191 validate_qc(last_leaf.justify_qc(), leaf.height())?;
192 if leaf.height() == expected_height {
193 return Ok(leaf.clone());
194 }
195 last_leaf = leaf;
196 }
197 Err(anyhow!("Epoch Root was not found in the decided chain"))
198}
199
200impl<TYPES: NodeType> ViewInner<TYPES> {
201 #[must_use]
203 pub fn leaf_and_state(&self) -> Option<(LeafCommitment<TYPES>, &Arc<TYPES::ValidatedState>)> {
204 if let Self::Leaf { leaf, state, .. } = self {
205 Some((*leaf, state))
206 } else {
207 None
208 }
209 }
210
211 #[must_use]
213 pub fn leaf_commitment(&self) -> Option<LeafCommitment<TYPES>> {
214 if let Self::Leaf { leaf, .. } = self {
215 Some(*leaf)
216 } else {
217 None
218 }
219 }
220
221 #[must_use]
223 pub fn state(&self) -> Option<&Arc<TYPES::ValidatedState>> {
224 if let Self::Leaf { state, .. } = self {
225 Some(state)
226 } else {
227 None
228 }
229 }
230
231 #[must_use]
233 pub fn state_and_delta(&self) -> StateAndDelta<TYPES> {
234 if let Self::Leaf { state, delta, .. } = self {
235 (Some(Arc::clone(state)), delta.clone())
236 } else {
237 (None, None)
238 }
239 }
240
241 #[must_use]
243 pub fn payload_commitment(&self) -> Option<VidCommitment> {
244 if let Self::Da {
245 payload_commitment, ..
246 } = self
247 {
248 Some(*payload_commitment)
249 } else {
250 None
251 }
252 }
253
254 pub fn epoch(&self) -> Option<Option<EpochNumber>> {
257 match self {
258 Self::Da { epoch, .. } | Self::Leaf { epoch, .. } => Some(*epoch),
259 Self::Failed => None,
260 }
261 }
262}
263
264impl<TYPES: NodeType> Deref for View<TYPES> {
265 type Target = ViewInner<TYPES>;
266
267 fn deref(&self) -> &Self::Target {
268 &self.view_inner
269 }
270}
271
272#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
274#[serde(bound = "")]
275pub struct View<TYPES: NodeType> {
276 pub view_inner: ViewInner<TYPES>,
278}
279
280#[derive(Debug, Clone)]
282pub struct RoundFinishedEvent {
283 pub view_number: ViewNumber,
285}
286
287type Sha256Digest = [u8; <sha2::Sha256 as OutputSizeUser>::OutputSize::USIZE];
289
290#[tagged("BUILDER_COMMITMENT")]
291#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
292pub struct BuilderCommitment(Sha256Digest);
295
296impl BuilderCommitment {
297 pub fn from_bytes(data: impl AsRef<[u8]>) -> Self {
299 Self(sha2::Sha256::digest(data.as_ref()).into())
300 }
301
302 pub fn from_raw_digest(digest: impl Into<Sha256Digest>) -> Self {
304 Self(digest.into())
305 }
306
307 pub fn empty() -> Self {
310 Self::from_bytes([])
311 }
312}
313
314impl AsRef<Sha256Digest> for BuilderCommitment {
315 fn as_ref(&self) -> &Sha256Digest {
316 &self.0
317 }
318}
319
320type BincodeOpts = WithOtherTrailing<
321 WithOtherIntEncoding<
322 WithOtherEndian<WithOtherLimit<DefaultOptions, bincode::config::Infinite>, LittleEndian>,
323 FixintEncoding,
324 >,
325 RejectTrailing,
326>;
327
328#[must_use]
334pub fn bincode_opts() -> BincodeOpts {
335 bincode::DefaultOptions::new()
336 .with_no_limit()
337 .with_little_endian()
338 .with_fixint_encoding()
339 .reject_trailing_bytes()
340}
341
342#[must_use]
344pub fn epoch_from_block_number(block_number: u64, epoch_height: u64) -> u64 {
345 if epoch_height == 0 {
346 0
347 } else if block_number == 0 {
348 1
349 } else if block_number.is_multiple_of(epoch_height) {
350 block_number / epoch_height
351 } else {
352 block_number / epoch_height + 1
353 }
354}
355
356#[must_use]
361pub fn root_block_in_epoch(epoch: u64, epoch_height: u64) -> u64 {
362 if epoch_height == 0 || epoch < 1 {
363 0
364 } else {
365 epoch_height * epoch - 5
366 }
367}
368
369#[must_use]
373pub fn transition_block_for_epoch(epoch: u64, epoch_height: u64) -> u64 {
374 if epoch_height == 0 || epoch < 1 {
375 0
376 } else {
377 epoch_height * epoch - 3
378 }
379}
380
381#[must_use]
384pub fn option_epoch_from_block_number(
385 with_epoch: bool,
386 block_number: u64,
387 epoch_height: u64,
388) -> Option<EpochNumber> {
389 if with_epoch {
390 if epoch_height == 0 {
391 None
392 } else if block_number == 0 {
393 Some(1u64)
394 } else if block_number.is_multiple_of(epoch_height) {
395 Some(block_number / epoch_height)
396 } else {
397 Some(block_number / epoch_height + 1)
398 }
399 .map(EpochNumber::new)
400 } else {
401 None
402 }
403}
404
405#[must_use]
407pub fn genesis_epoch_from_version(base: Version) -> Option<EpochNumber> {
408 (base >= EPOCH_VERSION).then(|| EpochNumber::new(1))
409}
410
411#[must_use]
413pub fn mnemonic<H: Hash>(bytes: H) -> String {
414 let mut state = std::collections::hash_map::DefaultHasher::new();
415 bytes.hash(&mut state);
416 mnemonic::to_string(state.finish().to_le_bytes())
417}
418
419#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
422pub enum EpochTransitionIndicator {
423 InTransition,
425 NotInTransition,
427}
428
429#[must_use]
431pub fn is_transition_block(block_number: u64, epoch_height: u64) -> bool {
432 if block_number == 0 || epoch_height == 0 {
433 false
434 } else {
435 (block_number + 3).is_multiple_of(epoch_height)
436 }
437}
438#[must_use]
440pub fn is_first_transition_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 == epoch_height - 2
445 }
446}
447#[must_use]
449pub fn is_epoch_transition(block_number: u64, epoch_height: u64) -> bool {
450 if block_number == 0 || epoch_height == 0 {
451 false
452 } else {
453 block_number % epoch_height >= epoch_height - 3 || block_number.is_multiple_of(epoch_height)
454 }
455}
456
457#[must_use]
459pub fn is_last_block(block_number: u64, epoch_height: u64) -> bool {
460 if block_number == 0 || epoch_height == 0 {
461 false
462 } else {
463 block_number.is_multiple_of(epoch_height)
464 }
465}
466
467#[must_use]
473pub fn is_middle_transition_block(block_number: u64, epoch_height: u64) -> bool {
474 if block_number == 0 || epoch_height == 0 {
475 false
476 } else {
477 let blocks_left = epoch_height - (block_number % epoch_height);
478 blocks_left == 1 || blocks_left == 2
479 }
480}
481
482#[must_use]
485pub fn is_epoch_root(block_number: u64, epoch_height: u64) -> bool {
486 if block_number == 0 || epoch_height == 0 {
487 false
488 } else {
489 (block_number + 5).is_multiple_of(epoch_height)
490 }
491}
492
493#[must_use]
495pub fn is_ge_epoch_root(block_number: u64, epoch_height: u64) -> bool {
496 if block_number == 0 || epoch_height == 0 {
497 false
498 } else {
499 block_number.is_multiple_of(epoch_height) || block_number % epoch_height >= epoch_height - 5
500 }
501}
502
503pub fn is_gt_epoch_root(block_number: u64, epoch_height: u64) -> bool {
505 if block_number == 0 || epoch_height == 0 {
506 false
507 } else {
508 block_number.is_multiple_of(epoch_height) || block_number % epoch_height > epoch_height - 5
509 }
510}
511
512#[cfg(test)]
513mod test {
514 use super::*;
515
516 #[test]
517 fn test_epoch_from_block_number() {
518 let epoch = epoch_from_block_number(0, 10);
520 assert_eq!(1, epoch);
521
522 let epoch = epoch_from_block_number(1, 10);
523 assert_eq!(1, epoch);
524
525 let epoch = epoch_from_block_number(10, 10);
526 assert_eq!(1, epoch);
527
528 let epoch = epoch_from_block_number(11, 10);
529 assert_eq!(2, epoch);
530
531 let epoch = epoch_from_block_number(20, 10);
532 assert_eq!(2, epoch);
533
534 let epoch = epoch_from_block_number(21, 10);
535 assert_eq!(3, epoch);
536
537 let epoch = epoch_from_block_number(21, 0);
538 assert_eq!(0, epoch);
539 }
540
541 #[test]
542 fn test_is_last_block_in_epoch() {
543 assert!(!is_epoch_transition(5, 10));
544 assert!(!is_epoch_transition(6, 10));
545 assert!(is_epoch_transition(7, 10));
546 assert!(is_epoch_transition(8, 10));
547 assert!(is_epoch_transition(9, 10));
548 assert!(is_epoch_transition(10, 10));
549 assert!(!is_epoch_transition(11, 10));
550
551 assert!(!is_epoch_transition(10, 0));
552 }
553
554 #[test]
555 fn test_is_epoch_root() {
556 assert!(is_epoch_root(5, 10));
557 assert!(!is_epoch_root(6, 10));
558 assert!(!is_epoch_root(7, 10));
559 assert!(!is_epoch_root(8, 10));
560 assert!(!is_epoch_root(9, 10));
561 assert!(!is_epoch_root(10, 10));
562 assert!(!is_epoch_root(11, 10));
563
564 assert!(!is_epoch_transition(10, 0));
565 }
566
567 #[test]
568 fn test_root_block_in_epoch() {
569 let epoch = 3;
571 let epoch_height = 10;
572 let epoch_root_block_number = root_block_in_epoch(3, epoch_height);
573
574 assert!(is_epoch_root(25, epoch_height));
575
576 assert_eq!(epoch_root_block_number, 25);
577
578 assert_eq!(
579 epoch,
580 epoch_from_block_number(epoch_root_block_number, epoch_height)
581 );
582 }
583}