Skip to main content

tycho_collator/mempool/
state_update_context.rs

1use std::sync::Arc;
2
3use anyhow::Result;
4use tycho_network::PeerId;
5use tycho_types::cell::HashBytes;
6use tycho_types::models::{
7    BlockId, ConsensusConfig, ConsensusInfo, ValidatorDescription, ValidatorSet,
8};
9
10use super::MempoolAnchorId;
11
12#[derive(Debug)]
13pub struct StateUpdateContext {
14    pub mc_block_id: BlockId,
15    pub mc_block_chain_time: u64,
16    pub top_processed_to_anchor_id: MempoolAnchorId,
17    pub consensus_info: ConsensusInfo,
18    pub consensus_config: ConsensusConfig,
19    pub shuffle_validators: bool,
20    pub prev_validator_set: Option<(HashBytes, Arc<ValidatorSet>)>,
21    pub current_validator_set: (HashBytes, Arc<ValidatorSet>),
22    pub next_validator_set: Option<(HashBytes, Arc<ValidatorSet>)>,
23}
24
25/// Contains all data needed to deterministically derive all v(sub)sets
26#[derive(PartialEq, Eq)]
27pub struct VSetsId<'a> {
28    prev_vset_switch_round: u32,
29    prev_shuffle_mc_validators: bool,
30    prev_validator_set: Option<&'a HashBytes>,
31
32    vset_switch_round: u32,
33    shuffle_validators: bool,
34    current_validator_set: &'a HashBytes,
35
36    next_validator_set: Option<&'a HashBytes>,
37}
38
39impl StateUpdateContext {
40    /// equality by vid means all contained and derived v(sub)sets are the same
41    pub fn vid(&self) -> VSetsId<'_> {
42        VSetsId {
43            prev_vset_switch_round: self.consensus_info.prev_vset_switch_round,
44            prev_shuffle_mc_validators: self.consensus_info.prev_shuffle_mc_validators,
45            prev_validator_set: self.prev_validator_set.as_ref().map(|(hash, _)| hash),
46
47            vset_switch_round: self.consensus_info.vset_switch_round,
48            shuffle_validators: self.shuffle_validators,
49            current_validator_set: &self.current_validator_set.0,
50
51            next_validator_set: self.next_validator_set.as_ref().map(|(hash, _)| hash),
52        }
53    }
54
55    /// Preserves blockchain config peer order to pass into mempool
56    pub fn prev_v_set(&self) -> Vec<PeerId> {
57        Self::peer_ids((self.prev_validator_set.iter()).flat_map(|(_, v_set)| v_set.list.iter()))
58    }
59
60    /// Preserves blockchain config peer order to pass into mempool
61    pub fn curr_v_set(&self) -> Vec<PeerId> {
62        Self::peer_ids(self.current_validator_set.1.list.iter())
63    }
64
65    /// Preserves blockchain config peer order to pass into mempool
66    pub fn next_v_set(&self) -> Vec<PeerId> {
67        Self::peer_ids((self.next_validator_set.iter()).flat_map(|(_, v_set)| v_set.list.iter()))
68    }
69
70    /// Preserves shuffled peer order to pass into mempool;
71    /// contains `validator_idx` peer position in original blockchain config
72    pub fn prev_v_subset(&self) -> Result<Vec<(PeerId, u16)>> {
73        let Some((_, prev_validator_set)) = self.prev_validator_set.as_ref() else {
74            return Ok(Vec::new());
75        };
76        Self::compute_subset(
77            prev_validator_set,
78            self.consensus_info.prev_vset_switch_round,
79            self.consensus_info.prev_shuffle_mc_validators,
80        )
81        .ok_or_else(|| anyhow::anyhow!("failed to compute previous validator subset"))
82    }
83
84    /// Preserves shuffled peer order to pass into mempool;
85    /// contains `validator_idx` peer position in original blockchain config
86    pub fn curr_v_subset(&self) -> Result<Vec<(PeerId, u16)>> {
87        Self::compute_subset(
88            &self.current_validator_set.1,
89            self.consensus_info.vset_switch_round,
90            self.shuffle_validators,
91        )
92        .ok_or_else(|| anyhow::anyhow!("failed to compute current validator subset"))
93    }
94
95    // NOTE: do not try to calculate subset from next set
96    //  because it is impossible without known future `switch_round`
97
98    fn compute_subset(
99        validator_set: &ValidatorSet,
100        switch_round: u32,
101        shuffle_validators: bool,
102    ) -> Option<Vec<(PeerId, u16)>> {
103        let (v_subset, _) =
104            validator_set.compute_mc_subset_indexed(switch_round, shuffle_validators)?;
105        let peer_idxs = v_subset
106            .into_iter()
107            .map(|desc| (PeerId(desc.public_key.0), desc.validator_idx))
108            .collect();
109        Some(peer_idxs)
110    }
111
112    fn peer_ids<'a>(iter: impl Iterator<Item = &'a ValidatorDescription>) -> Vec<PeerId> {
113        iter.map(|descr| PeerId(descr.public_key.0)).collect()
114    }
115}
116
117pub struct DebugStateUpdateContext<'a>(pub &'a StateUpdateContext);
118impl std::fmt::Debug for DebugStateUpdateContext<'_> {
119    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120        f.debug_struct("StateUpdateContext")
121            .field("mc_block_id", &self.0.mc_block_id.as_short_id())
122            .field("mc_block_chain_time", &self.0.mc_block_chain_time)
123            .field(
124                "top_processed_to_anchor_id",
125                &self.0.top_processed_to_anchor_id,
126            )
127            .field("consensus_info", &self.0.consensus_info)
128            .field("consensus_config", &self.0.consensus_config)
129            .field("shuffle_validators", &self.0.shuffle_validators)
130            .field(
131                "prev_validator_set.hash",
132                &self.0.prev_validator_set.as_ref().map(|s| s.0),
133            )
134            .field(
135                "current_validator_set.hash",
136                &self.0.current_validator_set.0,
137            )
138            .field(
139                "next_validator_set.hash",
140                &self.0.next_validator_set.as_ref().map(|s| s.0),
141            )
142            .finish()
143    }
144}