hotshot_new_protocol/
utils.rs1use alloy::primitives::U256;
2use anyhow::{anyhow, ensure};
3use committable::Committable;
4use hotshot_types::{
5 PeerConfig,
6 data::Leaf2,
7 message::UpgradeLock,
8 stake_table::StakeTableEntries,
9 traits::node_implementation::NodeType,
10 vote::{Certificate, HasViewNumber},
11};
12
13use crate::message::Certificate2;
14
15pub async fn verify_leaf_chain_with_cert2<T: NodeType>(
27 mut leaf_chain: Vec<Leaf2<T>>,
28 stake_table: &[PeerConfig<T>],
29 success_threshold: U256,
30 expected_height: u64,
31 upgrade_lock: &UpgradeLock<T>,
32 cert2: Certificate2<T>,
33) -> anyhow::Result<Leaf2<T>> {
34 leaf_chain.sort_by_key(|l| l.view_number());
35 leaf_chain.reverse();
36
37 ensure!(!leaf_chain.is_empty(), "empty leaf chain");
38
39 let stake_table_entries = StakeTableEntries::<T>::from(stake_table.to_vec()).0;
40
41 cert2.is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)?;
42
43 ensure!(
44 cert2.data.leaf_commit == leaf_chain[0].commit(),
45 "cert2 does not match the newest leaf in the chain"
46 );
47 ensure!(
48 cert2.data.block_number == leaf_chain[0].height(),
49 "cert2 block number does not match the newest leaf"
50 );
51 ensure!(
52 cert2.view_number() == leaf_chain[0].view_number(),
53 "cert2 view does not match the newest leaf"
54 );
55
56 if leaf_chain[0].height() == expected_height {
57 return Ok(leaf_chain[0].clone());
58 }
59
60 let mut current = &leaf_chain[0];
61 for leaf in leaf_chain[1..].iter() {
62 let justify_qc = current.justify_qc();
63 if justify_qc.view_number() != leaf.view_number()
64 || justify_qc.data().leaf_commit != leaf.commit()
65 {
66 tracing::warn!(
67 view = ?leaf.view_number(),
68 expected_view = ?justify_qc.view_number(),
69 "leaf is off the leafchain path; expected only after a view timeout"
70 );
71 continue;
72 }
73 ensure!(
74 current.parent_commitment() == leaf.commit(),
75 "current leaf parent commitment does not match parent leaf"
76 );
77 ensure!(
78 leaf.height().checked_add(1) == Some(current.height()),
79 "leaf heights do not chain"
80 );
81 justify_qc.is_valid_cert(&stake_table_entries, success_threshold, upgrade_lock)?;
82 if leaf.height() == expected_height {
83 return Ok(leaf.clone());
84 }
85 current = leaf;
86 }
87
88 Err(anyhow!(
89 "expected height was not found in the cert2-finalized chain"
90 ))
91}