alto_types/
block.rs

1use crate::{Finalization, Notarization};
2use bytes::{Buf, BufMut};
3use commonware_cryptography::{bls12381::PublicKey, sha256::Digest, Hasher, Sha256};
4use commonware_utils::{Array, SizedSerialize};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
7pub struct Block {
8    /// The parent block's digest.
9    pub parent: Digest,
10
11    /// The height of the block in the blockchain.
12    pub height: u64,
13
14    /// The timestamp of the block (in milliseconds since the Unix epoch).
15    pub timestamp: u64,
16
17    /// Pre-computed digest of the block.
18    digest: Digest,
19}
20
21impl Block {
22    fn compute_digest(parent: &Digest, height: u64, timestamp: u64) -> Digest {
23        let mut hasher = Sha256::new();
24        hasher.update(parent);
25        hasher.update(&height.to_be_bytes());
26        hasher.update(&timestamp.to_be_bytes());
27        hasher.finalize()
28    }
29
30    pub fn new(parent: Digest, height: u64, timestamp: u64) -> Self {
31        let digest = Self::compute_digest(&parent, height, timestamp);
32        Self {
33            parent,
34            height,
35            timestamp,
36            digest,
37        }
38    }
39
40    pub fn serialize(&self) -> Vec<u8> {
41        let mut bytes = Vec::with_capacity(Self::SERIALIZED_LEN);
42        bytes.extend_from_slice(&self.parent);
43        bytes.put_u64(self.height);
44        bytes.put_u64(self.timestamp);
45        bytes
46    }
47
48    pub fn deserialize(mut bytes: &[u8]) -> Option<Self> {
49        // Parse the block
50        if bytes.len() != Self::SERIALIZED_LEN {
51            return None;
52        }
53        let parent = Digest::read_from(&mut bytes).ok()?;
54        let height = bytes.get_u64();
55        let timestamp = bytes.get_u64();
56
57        // Return block
58        let digest = Self::compute_digest(&parent, height, timestamp);
59        Some(Self {
60            parent,
61            height,
62            timestamp,
63            digest,
64        })
65    }
66
67    pub fn digest(&self) -> Digest {
68        self.digest.clone()
69    }
70}
71
72impl SizedSerialize for Block {
73    const SERIALIZED_LEN: usize =
74        Digest::SERIALIZED_LEN + u64::SERIALIZED_LEN + u64::SERIALIZED_LEN;
75}
76
77pub struct Notarized {
78    pub proof: Notarization,
79    pub block: Block,
80}
81
82impl Notarized {
83    pub fn new(proof: Notarization, block: Block) -> Self {
84        Self { proof, block }
85    }
86
87    pub fn serialize(&self) -> Vec<u8> {
88        let block = self.block.serialize();
89        let mut bytes = Vec::with_capacity(Notarization::SERIALIZED_LEN + block.len());
90        bytes.extend_from_slice(&self.proof.serialize());
91        bytes.extend_from_slice(&block);
92        bytes
93    }
94
95    pub fn deserialize(public: Option<&PublicKey>, bytes: &[u8]) -> Option<Self> {
96        // Deserialize the proof and block
97        let (proof, block) = bytes.split_at_checked(Notarization::SERIALIZED_LEN)?;
98        let proof = Notarization::deserialize(public, proof)?;
99        let block = Block::deserialize(block)?;
100
101        // Ensure the proof is for the block
102        if proof.payload != block.digest() {
103            return None;
104        }
105        Some(Self { proof, block })
106    }
107}
108
109pub struct Finalized {
110    pub proof: Finalization,
111    pub block: Block,
112}
113
114impl Finalized {
115    pub fn new(proof: Finalization, block: Block) -> Self {
116        Self { proof, block }
117    }
118
119    pub fn serialize(&self) -> Vec<u8> {
120        let block = self.block.serialize();
121        let mut bytes = Vec::with_capacity(Finalization::SERIALIZED_LEN + block.len());
122        bytes.extend_from_slice(&self.proof.serialize());
123        bytes.extend_from_slice(&block);
124        bytes
125    }
126
127    pub fn deserialize(public: Option<&PublicKey>, bytes: &[u8]) -> Option<Self> {
128        // Deserialize the proof and block
129        let (proof, block) = bytes.split_at_checked(Finalization::SERIALIZED_LEN)?;
130        let proof = Finalization::deserialize(public, proof)?;
131        let block = Block::deserialize(block)?;
132
133        // Ensure the proof is for the block
134        if proof.payload != block.digest() {
135            return None;
136        }
137        Some(Self { proof, block })
138    }
139}