1use crate::consensus::{Finalization, Notarization, Scheme};
2use bytes::{Buf, BufMut};
3use commonware_codec::{varint::UInt, EncodeSize, Error, Read, ReadExt, Write};
4use commonware_cryptography::{sha256::Digest, Committable, Digestible, Hasher, Sha256};
5use rand::rngs::OsRng;
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct Block {
9 pub parent: Digest,
11
12 pub height: u64,
14
15 pub timestamp: u64,
17
18 digest: Digest,
20}
21
22impl Block {
23 fn compute_digest(parent: &Digest, height: u64, timestamp: u64) -> Digest {
24 let mut hasher = Sha256::new();
25 hasher.update(parent);
26 hasher.update(&height.to_be_bytes());
27 hasher.update(×tamp.to_be_bytes());
28 hasher.finalize()
29 }
30
31 pub fn new(parent: Digest, height: u64, timestamp: u64) -> Self {
32 let digest = Self::compute_digest(&parent, height, timestamp);
33 Self {
34 parent,
35 height,
36 timestamp,
37 digest,
38 }
39 }
40}
41
42impl Write for Block {
43 fn write(&self, writer: &mut impl BufMut) {
44 self.parent.write(writer);
45 UInt(self.height).write(writer);
46 UInt(self.timestamp).write(writer);
47 }
48}
49
50impl Read for Block {
51 type Cfg = ();
52
53 fn read_cfg(reader: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
54 let parent = Digest::read(reader)?;
55 let height = UInt::read(reader)?.into();
56 let timestamp = UInt::read(reader)?.into();
57
58 let digest = Self::compute_digest(&parent, height, timestamp);
60 Ok(Self {
61 parent,
62 height,
63 timestamp,
64
65 digest,
66 })
67 }
68}
69
70impl EncodeSize for Block {
71 fn encode_size(&self) -> usize {
72 self.parent.encode_size()
73 + UInt(self.height).encode_size()
74 + UInt(self.timestamp).encode_size()
75 }
76}
77
78impl Digestible for Block {
79 type Digest = Digest;
80
81 fn digest(&self) -> Digest {
82 self.digest
83 }
84}
85
86impl Committable for Block {
87 type Commitment = Digest;
88
89 fn commitment(&self) -> Digest {
90 self.digest
91 }
92}
93
94#[derive(Clone, Debug, PartialEq, Eq)]
95pub struct Notarized {
96 pub proof: Notarization,
97 pub block: Block,
98}
99
100impl Notarized {
101 pub fn new(proof: Notarization, block: Block) -> Self {
102 Self { proof, block }
103 }
104
105 pub fn verify(&self, scheme: &Scheme, namespace: &[u8]) -> bool {
106 self.proof.verify(&mut OsRng, scheme, namespace)
107 }
108}
109
110impl Write for Notarized {
111 fn write(&self, buf: &mut impl BufMut) {
112 self.proof.write(buf);
113 self.block.write(buf);
114 }
115}
116
117impl Read for Notarized {
118 type Cfg = ();
119
120 fn read_cfg(buf: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
121 let proof = Notarization::read(buf)?;
122 let block = Block::read(buf)?;
123
124 if proof.proposal.payload != block.digest() {
126 return Err(Error::Invalid(
127 "types::Notarized",
128 "Proof payload does not match block digest",
129 ));
130 }
131 Ok(Self { proof, block })
132 }
133}
134
135impl EncodeSize for Notarized {
136 fn encode_size(&self) -> usize {
137 self.proof.encode_size() + self.block.encode_size()
138 }
139}
140
141#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct Finalized {
143 pub proof: Finalization,
144 pub block: Block,
145}
146
147impl Finalized {
148 pub fn new(proof: Finalization, block: Block) -> Self {
149 Self { proof, block }
150 }
151
152 pub fn verify(&self, scheme: &Scheme, namespace: &[u8]) -> bool {
153 self.proof.verify(&mut OsRng, scheme, namespace)
154 }
155}
156
157impl Write for Finalized {
158 fn write(&self, buf: &mut impl BufMut) {
159 self.proof.write(buf);
160 self.block.write(buf);
161 }
162}
163
164impl Read for Finalized {
165 type Cfg = ();
166
167 fn read_cfg(buf: &mut impl Buf, _: &Self::Cfg) -> Result<Self, Error> {
168 let proof = Finalization::read(buf)?;
169 let block = Block::read(buf)?;
170
171 if proof.proposal.payload != block.digest() {
173 return Err(Error::Invalid(
174 "types::Finalized",
175 "Proof payload does not match block digest",
176 ));
177 }
178 Ok(Self { proof, block })
179 }
180}
181
182impl EncodeSize for Finalized {
183 fn encode_size(&self) -> usize {
184 self.proof.encode_size() + self.block.encode_size()
185 }
186}
187
188impl commonware_consensus::Block for Block {
189 fn parent(&self) -> Digest {
190 self.parent
191 }
192
193 fn height(&self) -> u64 {
194 self.height
195 }
196}