Skip to main content

fedimint_hbbft/broadcast/
message.rs

1use std::fmt::{self, Debug};
2
3use hex_fmt::HexFmt;
4use rand::distributions::{Distribution, Standard};
5use rand::{self, seq::SliceRandom, Rng};
6use serde::{Deserialize, Serialize};
7
8use super::merkle::{Digest, MerkleTree, Proof};
9
10/// The three kinds of message sent during the reliable broadcast stage of the
11/// consensus algorithm.
12#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
13pub enum Message {
14    /// A share of the value, sent from the sender to another validator.
15    Value(Proof<Vec<u8>>),
16    /// A copy of the value received from the sender, multicast by a validator.
17    Echo(Proof<Vec<u8>>),
18    /// Indicates that the sender knows that every node will eventually be able to decode.
19    Ready(Digest),
20    /// Indicates that this node has enough shares to decode the message with given Merkle root.
21    CanDecode(Digest),
22    /// Indicates that sender can send an Echo for given Merkle root.
23    EchoHash(Digest),
24}
25
26// A random generation impl is provided for test cases. Unfortunately `#[cfg(test)]` does not work
27// for integration tests.
28impl Distribution<Message> for Standard {
29    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Message {
30        let message_type = *["value", "echo", "ready", "can_decode", "echo_hash"]
31            .choose(rng)
32            .unwrap();
33
34        // Create a random buffer for our proof.
35        let mut buffer: [u8; 32] = [0; 32];
36        rng.fill_bytes(&mut buffer);
37
38        // Generate a dummy proof to fill broadcast messages with.
39        let tree = MerkleTree::from_vec(vec![buffer.to_vec()]);
40        let proof = tree.proof(0).unwrap();
41
42        match message_type {
43            "value" => Message::Value(proof),
44            "echo" => Message::Echo(proof),
45            "ready" => Message::Ready([b'r'; 32]),
46            "can_decode" => Message::Ready([b'r'; 32]),
47            "echo_hash" => Message::Ready([b'r'; 32]),
48            _ => unreachable!(),
49        }
50    }
51}
52
53impl Debug for Message {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match *self {
56            Message::Value(ref v) => f.debug_tuple("Value").field(&HexProof(v)).finish(),
57            Message::Echo(ref v) => f.debug_tuple("Echo").field(&HexProof(v)).finish(),
58            Message::Ready(ref b) => write!(f, "Ready({:0.10})", HexFmt(b)),
59            Message::CanDecode(ref b) => write!(f, "CanDecode({:0.10})", HexFmt(b)),
60            Message::EchoHash(ref b) => write!(f, "EchoHash({:0.10})", HexFmt(b)),
61        }
62    }
63}
64/// Wrapper for a `Proof`, to print the bytes as a shortened hexadecimal number.
65pub struct HexProof<'a, T>(pub &'a Proof<T>);
66
67impl<'a, T: AsRef<[u8]>> fmt::Debug for HexProof<'a, T> {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        write!(
70            f,
71            "Proof {{ #{}, root_hash: {:0.10}, value: {:0.10}, .. }}",
72            &self.0.index(),
73            HexFmt(self.0.root_hash()),
74            HexFmt(self.0.value())
75        )
76    }
77}