Skip to main content

fedimint_server/consensus/aleph_bft/
mod.rs

1pub mod backup;
2pub mod data_provider;
3pub mod finalization_handler;
4pub mod keychain;
5pub mod network;
6pub mod spawner;
7
8use aleph_bft::NodeIndex;
9use fedimint_core::PeerId;
10
11/// Convert an aleph-bft `NodeIndex` into a `PeerId`, if it can represent one.
12///
13/// `NodeIndex` wraps a `usize` and its decoder accepts any `u64` verbatim, so
14/// every index embedded in a message received from a peer is chosen by that
15/// peer and may not correspond to any peer at all. Callers have to handle
16/// `None` instead of panicking, since a panic in the consensus task shuts down
17/// the entire node.
18pub fn to_peer_id(node_index: NodeIndex) -> Option<PeerId> {
19    u16::try_from(usize::from(node_index))
20        .ok()
21        .map(PeerId::from)
22}
23
24pub fn to_node_index(peer_id: PeerId) -> NodeIndex {
25    usize::from(u16::from(peer_id)).into()
26}
27
28#[cfg(test)]
29mod tests {
30    use aleph_bft::NodeIndex;
31    use fedimint_core::PeerId;
32
33    use super::{to_node_index, to_peer_id};
34
35    #[test]
36    fn to_peer_id_roundtrips_valid_indices() {
37        for peer_id in [PeerId::from(0), PeerId::from(3), PeerId::from(u16::MAX)] {
38            assert_eq!(to_peer_id(to_node_index(peer_id)), Some(peer_id));
39        }
40    }
41
42    #[test]
43    fn to_peer_id_rejects_out_of_range_indices() {
44        // A malicious peer can embed an arbitrary u64 in a message it sends us, so
45        // this must not panic and take the consensus session down with it.
46        for index in [usize::from(u16::MAX) + 1, u32::MAX as usize, usize::MAX] {
47            assert_eq!(to_peer_id(NodeIndex(index)), None);
48        }
49    }
50}