aleph_bft/network/
mod.rs

1use crate::{alerts::AlertMessage, Data, Hasher, PartialMultisignature, Recipient, Signature};
2use codec::{Decode, Encode};
3use std::fmt::Debug;
4
5mod hub;
6mod unit;
7
8pub use hub::Hub;
9pub use unit::UnitMessage;
10
11pub type UnitMessageTo<H, D, S> = (UnitMessage<H, D, S>, Recipient);
12
13#[derive(Clone, Eq, PartialEq, Debug, Decode, Encode)]
14pub(crate) enum NetworkDataInner<H: Hasher, D: Data, S: Signature, MS: PartialMultisignature> {
15    Units(UnitMessage<H, D, S>),
16    Alert(AlertMessage<H, D, S, MS>),
17}
18
19impl<H: Hasher, D: Data, S: Signature, MS: PartialMultisignature> NetworkDataInner<H, D, S, MS> {
20    pub(crate) fn included_data(&self) -> Vec<D> {
21        match self {
22            Self::Units(message) => message.included_data(),
23            Self::Alert(message) => message.included_data(),
24        }
25    }
26}
27
28/// NetworkData is the opaque format for all data that a committee member needs to send to other nodes.
29#[derive(Clone, Eq, PartialEq, Debug, Decode, Encode)]
30pub struct NetworkData<H: Hasher, D: Data, S: Signature, MS: PartialMultisignature>(
31    pub(crate) NetworkDataInner<H, D, S, MS>,
32);
33
34impl<H: Hasher, D: Data, S: Signature, MS: PartialMultisignature> NetworkData<H, D, S, MS> {
35    /// Returns all the Data in the network message that might end up in the ordering as a result
36    /// of accepting this message. Useful for ensuring data availability, if Data only represents
37    /// the objects the user wants to order, and facilitates access to the Data before it is
38    /// ordered for optimization purposes.
39    pub fn included_data(&self) -> Vec<D> {
40        self.0.included_data()
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use crate::{
47        alerts::AlertMessage,
48        network::{
49            NetworkDataInner::{Alert, Units},
50            UnitMessage,
51        },
52        units::{ControlHash, FullUnit, PreUnit, UncheckedSignedUnit, UnitCoord},
53        Hasher, NodeIndex, Round, Signed,
54    };
55    use aleph_bft_mock::{Data, Hasher64, Keychain, PartialMultisignature, Signature};
56    use aleph_bft_types::NodeMap;
57    use codec::{Decode, Encode};
58
59    fn test_unchecked_unit(
60        creator: NodeIndex,
61        round: Round,
62        data: Data,
63    ) -> UncheckedSignedUnit<Hasher64, Data, Signature> {
64        let control_hash = ControlHash::new(&NodeMap::with_size(7.into()));
65        let pu = PreUnit::new(creator, round, control_hash);
66        let signable = FullUnit::new(pu, Some(data), 0);
67        Signed::sign(signable, &Keychain::new(0.into(), creator)).into_unchecked()
68    }
69
70    type TestNetworkData = super::NetworkData<Hasher64, Data, Signature, PartialMultisignature>;
71    impl TestNetworkData {
72        fn new(
73            inner: super::NetworkDataInner<Hasher64, Data, Signature, PartialMultisignature>,
74        ) -> Self {
75            super::NetworkData::<Hasher64, Data, Signature, PartialMultisignature>(inner)
76        }
77    }
78
79    #[test]
80    fn decoding_network_data_units_new_unit() {
81        use UnitMessage::Unit;
82
83        let uu = test_unchecked_unit(5.into(), 43, 1729);
84        let included_data = uu.as_signable().included_data();
85        let nd = TestNetworkData::new(Units(Unit(uu.clone())));
86        let decoded = TestNetworkData::decode(&mut &nd.encode()[..]);
87        assert!(decoded.is_ok(), "Bug in encode/decode for Unit");
88        let decoded = decoded.unwrap();
89        assert_eq!(
90            decoded.included_data(),
91            included_data,
92            "data decoded incorrectly"
93        );
94        if let Units(Unit(decoded_unchecked)) = decoded.0 {
95            assert_eq!(
96                uu.as_signable(),
97                decoded_unchecked.as_signable(),
98                "decoded should equal encoded"
99            );
100        } else {
101            panic!("Decoded Unit as something else");
102        }
103    }
104
105    #[test]
106    fn decoding_network_data_units_request_coord() {
107        use UnitMessage::CoordRequest;
108
109        let ni = 7.into();
110        let uc = UnitCoord::new(3, 13.into());
111        let nd = TestNetworkData::new(Units(CoordRequest(ni, uc)));
112        let decoded = TestNetworkData::decode(&mut &nd.encode()[..]);
113        assert!(decoded.is_ok(), "Bug in encode/decode for CoordRequest");
114        let decoded = decoded.unwrap();
115        assert!(
116            decoded.included_data().is_empty(),
117            "data returned from a coord request"
118        );
119        if let Units(CoordRequest(dni, duc)) = decoded.0 {
120            assert!(ni == dni && uc == duc, "decoded should equal encoded");
121        } else {
122            panic!("Decoded CoordRequest as something else");
123        }
124    }
125
126    #[test]
127    fn decoding_network_data_units_request_parents() {
128        use UnitMessage::ParentsRequest;
129
130        let ni = 7.into();
131        let h = 43.using_encoded(Hasher64::hash);
132        let nd = TestNetworkData::new(Units(ParentsRequest(ni, h)));
133        let decoded = TestNetworkData::decode(&mut &nd.encode()[..]);
134        assert!(decoded.is_ok(), "Bug in encode/decode for ParentsRequest");
135        let decoded = decoded.unwrap();
136        assert!(
137            decoded.included_data().is_empty(),
138            "data returned from a parent request"
139        );
140        if let Units(ParentsRequest(dni, dh)) = decoded.0 {
141            assert!(ni == dni && h == dh, "decoded should equal encoded");
142        } else {
143            panic!("Decoded ParentsRequest as something else");
144        }
145    }
146
147    #[test]
148    fn decoding_network_data_units_response_parents() {
149        use UnitMessage::ParentsResponse;
150
151        let h = 43.using_encoded(Hasher64::hash);
152        let p1 = test_unchecked_unit(5.into(), 43, 1729);
153        let p2 = test_unchecked_unit(13.into(), 43, 1729);
154        let p3 = test_unchecked_unit(17.into(), 43, 1729);
155        let included_data: Vec<Data> = p1
156            .as_signable()
157            .included_data()
158            .into_iter()
159            .chain(p2.as_signable().included_data())
160            .chain(p3.as_signable().included_data())
161            .collect();
162        let parents = vec![p1, p2, p3];
163
164        let nd = TestNetworkData::new(Units(ParentsResponse(h, parents.clone())));
165        let decoded = TestNetworkData::decode(&mut &nd.encode()[..]);
166        assert!(decoded.is_ok(), "Bug in encode/decode for ParentsResponse");
167        let decoded = decoded.unwrap();
168        assert_eq!(
169            decoded.included_data(),
170            included_data,
171            "data decoded incorrectly"
172        );
173        if let Units(ParentsResponse(dh, dparents)) = decoded.0 {
174            assert_eq!(h, dh, "decoded should equal encoded");
175            assert_eq!(
176                parents.len(),
177                dparents.len(),
178                "decoded should equal encoded"
179            );
180            for (p, dp) in parents.iter().zip(dparents.iter()) {
181                assert_eq!(
182                    p.as_signable(),
183                    dp.as_signable(),
184                    "decoded should equal encoded"
185                );
186            }
187        } else {
188            panic!("Decoded ParentsResponse as something else");
189        }
190    }
191
192    #[test]
193    fn decoding_network_data_alert_fork_alert() {
194        use AlertMessage::ForkAlert;
195
196        let forker = 9.into();
197        let f1 = test_unchecked_unit(forker, 10, 0);
198        let f2 = test_unchecked_unit(forker, 10, 1);
199        let lu1 = test_unchecked_unit(forker, 11, 0);
200        let lu2 = test_unchecked_unit(forker, 12, 0);
201        let mut included_data = lu1.as_signable().included_data();
202        included_data.extend(lu2.as_signable().included_data());
203        let sender: NodeIndex = 7.into();
204        let alert = crate::alerts::Alert::new(sender, (f1, f2), vec![lu1, lu2]);
205
206        let nd = TestNetworkData::new(Alert(ForkAlert(
207            Signed::sign(alert.clone(), &Keychain::new(0.into(), sender)).into_unchecked(),
208        )));
209        let decoded = TestNetworkData::decode(&mut &nd.encode()[..]);
210        assert!(decoded.is_ok(), "Bug in encode/decode for ForkAlert");
211        let decoded = decoded.unwrap();
212        assert_eq!(
213            decoded.included_data(),
214            included_data,
215            "data decoded incorrectly"
216        );
217        if let Alert(ForkAlert(unchecked_alert)) = decoded.0 {
218            assert_eq!(
219                &alert,
220                unchecked_alert.as_signable(),
221                "decoded should equal encoded"
222            )
223        } else {
224            panic!("Decoded ForkAlert as something else");
225        }
226    }
227}