Skip to main content

arc_malachitebft_network/
channel.rs

1use core::fmt;
2
3use libp2p::gossipsub;
4use libp2p_broadcast as broadcast;
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Copy)]
8pub struct ChannelNames {
9    pub consensus: &'static str,
10    pub proposal_parts: &'static str,
11    pub sync: &'static str,
12    pub liveness: &'static str,
13}
14
15impl Default for ChannelNames {
16    fn default() -> Self {
17        Self {
18            consensus: "/consensus",
19            proposal_parts: "/proposal_parts",
20            sync: "/sync",
21            liveness: "/liveness",
22        }
23    }
24}
25
26#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub enum Channel {
28    Consensus,
29    Liveness,
30    ProposalParts,
31    Sync,
32}
33
34impl Channel {
35    pub fn all() -> &'static [Channel] {
36        &[
37            Channel::Consensus,
38            Channel::ProposalParts,
39            Channel::Sync,
40            Channel::Liveness,
41        ]
42    }
43
44    pub fn consensus() -> &'static [Channel] {
45        &[
46            Channel::Consensus,
47            Channel::ProposalParts,
48            Channel::Liveness,
49        ]
50    }
51
52    pub fn to_gossipsub_topic(self, channel_names: ChannelNames) -> gossipsub::IdentTopic {
53        gossipsub::IdentTopic::new(self.as_str(channel_names))
54    }
55
56    pub fn to_broadcast_topic(self, channel_names: ChannelNames) -> broadcast::Topic {
57        broadcast::Topic::new(self.as_str(channel_names).as_bytes())
58    }
59
60    pub fn as_str(&self, channel_names: ChannelNames) -> &'static str {
61        match self {
62            Channel::Consensus => channel_names.consensus,
63            Channel::ProposalParts => channel_names.proposal_parts,
64            Channel::Sync => channel_names.sync,
65            Channel::Liveness => channel_names.liveness,
66        }
67    }
68
69    pub fn has_gossipsub_topic(
70        topic_hash: &gossipsub::TopicHash,
71        channel_names: ChannelNames,
72    ) -> bool {
73        Self::all()
74            .iter()
75            .any(|channel| &channel.to_gossipsub_topic(channel_names).hash() == topic_hash)
76    }
77
78    pub fn has_broadcast_topic(topic: &broadcast::Topic, channel_names: ChannelNames) -> bool {
79        Self::all()
80            .iter()
81            .any(|channel| &channel.to_broadcast_topic(channel_names) == topic)
82    }
83
84    pub fn from_gossipsub_topic_hash(
85        topic: &gossipsub::TopicHash,
86        channel_names: ChannelNames,
87    ) -> Option<Self> {
88        if topic == &Self::Consensus.to_gossipsub_topic(channel_names).hash() {
89            Some(Self::Consensus)
90        } else if topic == &Self::ProposalParts.to_gossipsub_topic(channel_names).hash() {
91            Some(Self::ProposalParts)
92        } else if topic == &Self::Sync.to_gossipsub_topic(channel_names).hash() {
93            Some(Self::Sync)
94        } else if topic == &Self::Liveness.to_gossipsub_topic(channel_names).hash() {
95            Some(Self::Liveness)
96        } else {
97            None
98        }
99    }
100
101    pub fn from_broadcast_topic(
102        topic: &broadcast::Topic,
103        channel_names: ChannelNames,
104    ) -> Option<Self> {
105        if topic == &Self::Consensus.to_broadcast_topic(channel_names) {
106            Some(Self::Consensus)
107        } else if topic == &Self::ProposalParts.to_broadcast_topic(channel_names) {
108            Some(Self::ProposalParts)
109        } else if topic == &Self::Sync.to_broadcast_topic(channel_names) {
110            Some(Self::Sync)
111        } else if topic == &Self::Liveness.to_broadcast_topic(channel_names) {
112            Some(Self::Liveness)
113        } else {
114            None
115        }
116    }
117}
118
119impl fmt::Display for Channel {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121        write!(f, "{self:?}")
122    }
123}