1use bytes::{Buf, BufMut, Bytes, BytesMut};
2use commonware_codec::{Decode, EncodeSize, Error, Read, Write};
3use commonware_consensus::{simplex::types, Block};
4use commonware_cryptography::{certificate, Digest};
5
6const HEADER_LENGTH_BYTES: usize = 4;
7
8fn write_block_data<B>(header: &B, body: &[u8], buf: &mut impl BufMut)
9where
10 B: Write + EncodeSize,
11{
12 let header_len =
13 u32::try_from(header.encode_size()).expect("header block encoding exceeds u32 length");
14 buf.put_u32(header_len);
15 header.write(buf);
16 buf.put_slice(body);
17}
18
19pub fn encode_block_data<B>(header: &B, body: &[u8]) -> Bytes
20where
21 B: Write + EncodeSize,
22{
23 let mut buf = BytesMut::with_capacity(HEADER_LENGTH_BYTES + header.encode_size() + body.len());
24 write_block_data(header, body, &mut buf);
25 buf.freeze()
26}
27
28#[derive(Clone, Debug, PartialEq, Eq)]
34pub struct BlockData<B> {
35 pub header: B,
36 pub body: Bytes,
37}
38
39impl<B> BlockData<B> {
40 pub fn new(header: B) -> Self {
41 Self {
42 header,
43 body: Bytes::new(),
44 }
45 }
46
47 pub fn with_body(header: B, body: impl Into<Bytes>) -> Self {
48 Self {
49 header,
50 body: body.into(),
51 }
52 }
53}
54
55impl<B> Write for BlockData<B>
56where
57 B: Write + EncodeSize,
58{
59 fn write(&self, buf: &mut impl BufMut) {
60 write_block_data(&self.header, &self.body, buf);
61 }
62}
63
64impl<B> Read for BlockData<B>
65where
66 B: Read,
67{
68 type Cfg = <B as Read>::Cfg;
69
70 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
71 if buf.remaining() < HEADER_LENGTH_BYTES {
72 return Err(Error::Invalid(
73 "exoware_simplex::BlockData",
74 "missing header length",
75 ));
76 }
77 let header_len = buf.get_u32() as usize;
78 if buf.remaining() < header_len {
79 return Err(Error::Invalid(
80 "exoware_simplex::BlockData",
81 "header length exceeds remaining bytes",
82 ));
83 }
84 let header = B::decode_cfg(buf.copy_to_bytes(header_len), cfg)?;
85 let body = buf.copy_to_bytes(buf.remaining());
86 Ok(Self { header, body })
87 }
88}
89
90impl<B> EncodeSize for BlockData<B>
91where
92 B: EncodeSize,
93{
94 fn encode_size(&self) -> usize {
95 HEADER_LENGTH_BYTES + self.header.encode_size() + self.body.len()
96 }
97}
98
99#[derive(Clone, Debug)]
101pub struct Notarized<B, S: certificate::Scheme, D: Digest> {
102 pub proof: types::Notarization<S, D>,
103 pub header: B,
104}
105
106impl<B, S, D> PartialEq for Notarized<B, S, D>
107where
108 B: PartialEq,
109 S: certificate::Scheme,
110 D: Digest,
111{
112 fn eq(&self, other: &Self) -> bool {
113 self.proof == other.proof && self.header == other.header
114 }
115}
116
117impl<B, S, D> Eq for Notarized<B, S, D>
118where
119 B: Eq,
120 S: certificate::Scheme,
121 D: Digest,
122{
123}
124
125impl<B, S, D> Notarized<B, S, D>
126where
127 B: Block<Digest = D>,
128 S: certificate::Scheme,
129 D: Digest,
130{
131 pub fn new(proof: types::Notarization<S, D>, header: B) -> Result<Self, Error> {
132 if proof.proposal.payload != header.digest() {
133 return Err(Error::Invalid(
134 "exoware_simplex::Notarized",
135 "proof payload does not match header digest",
136 ));
137 }
138 Ok(Self { proof, header })
139 }
140}
141
142impl<B, S, D> Write for Notarized<B, S, D>
143where
144 B: Block<Digest = D>,
145 S: certificate::Scheme,
146 D: Digest,
147{
148 fn write(&self, buf: &mut impl BufMut) {
149 self.proof.write(buf);
150 self.header.write(buf);
151 }
152}
153
154impl<B, S, D> Read for Notarized<B, S, D>
155where
156 B: Block<Digest = D>,
157 S: certificate::Scheme,
158 D: Digest,
159 <S::Certificate as Read>::Cfg: Clone,
160{
161 type Cfg = (<S::Certificate as Read>::Cfg, <B as Read>::Cfg);
162
163 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
164 let (proof, header) = <(types::Notarization<S, D>, B) as Read>::read_cfg(buf, cfg)?;
165 Self::new(proof, header)
166 }
167}
168
169impl<B, S, D> EncodeSize for Notarized<B, S, D>
170where
171 B: Block<Digest = D>,
172 S: certificate::Scheme,
173 D: Digest,
174{
175 fn encode_size(&self) -> usize {
176 self.proof.encode_size() + self.header.encode_size()
177 }
178}
179
180#[derive(Clone, Debug)]
182pub struct Finalized<B, S: certificate::Scheme, D: Digest> {
183 pub proof: types::Finalization<S, D>,
184 pub header: B,
185}
186
187impl<B, S, D> PartialEq for Finalized<B, S, D>
188where
189 B: PartialEq,
190 S: certificate::Scheme,
191 D: Digest,
192{
193 fn eq(&self, other: &Self) -> bool {
194 self.proof == other.proof && self.header == other.header
195 }
196}
197
198impl<B, S, D> Eq for Finalized<B, S, D>
199where
200 B: Eq,
201 S: certificate::Scheme,
202 D: Digest,
203{
204}
205
206impl<B, S, D> Finalized<B, S, D>
207where
208 B: Block<Digest = D>,
209 S: certificate::Scheme,
210 D: Digest,
211{
212 pub fn new(proof: types::Finalization<S, D>, header: B) -> Result<Self, Error> {
213 if proof.proposal.payload != header.digest() {
214 return Err(Error::Invalid(
215 "exoware_simplex::Finalized",
216 "proof payload does not match header digest",
217 ));
218 }
219 Ok(Self { proof, header })
220 }
221}
222
223impl<B, S, D> Write for Finalized<B, S, D>
224where
225 B: Block<Digest = D>,
226 S: certificate::Scheme,
227 D: Digest,
228{
229 fn write(&self, buf: &mut impl BufMut) {
230 self.proof.write(buf);
231 self.header.write(buf);
232 }
233}
234
235impl<B, S, D> Read for Finalized<B, S, D>
236where
237 B: Block<Digest = D>,
238 S: certificate::Scheme,
239 D: Digest,
240 <S::Certificate as Read>::Cfg: Clone,
241{
242 type Cfg = (<S::Certificate as Read>::Cfg, <B as Read>::Cfg);
243
244 fn read_cfg(buf: &mut impl Buf, cfg: &Self::Cfg) -> Result<Self, Error> {
245 let (proof, header) = <(types::Finalization<S, D>, B) as Read>::read_cfg(buf, cfg)?;
246 Self::new(proof, header)
247 }
248}
249
250impl<B, S, D> EncodeSize for Finalized<B, S, D>
251where
252 B: Block<Digest = D>,
253 S: certificate::Scheme,
254 D: Digest,
255{
256 fn encode_size(&self) -> usize {
257 self.proof.encode_size() + self.header.encode_size()
258 }
259}
260
261#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
262pub struct UploadSummary {
263 pub headers: usize,
264 pub blocks: usize,
265 pub notarizations: usize,
266 pub finalizations: usize,
267 pub finalized_height_indexes: usize,
268}
269
270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
271pub struct UploadReceipt {
272 pub store_sequence_number: u64,
273 pub summary: UploadSummary,
274}