1use alloc::vec::Vec;
6use serde::{Deserialize, Serialize};
7
8use crate::dag::DAGSegment;
9use crate::hash::Hash;
10use crate::seal::{AnchorRef, SealRef};
11
12pub const MAX_PROOF_BYTES: usize = 64 * 1024;
14
15pub const MAX_FINALITY_DATA: usize = 4 * 1024;
17
18pub const MAX_SIGNATURES_TOTAL_SIZE: usize = 1024 * 1024;
20
21#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23pub struct InclusionProof {
24 pub proof_bytes: Vec<u8>,
26 pub block_hash: Hash,
28 pub position: u64,
30}
31
32impl InclusionProof {
33 pub fn new(
43 proof_bytes: Vec<u8>,
44 block_hash: Hash,
45 position: u64,
46 ) -> Result<Self, &'static str> {
47 if proof_bytes.len() > MAX_PROOF_BYTES {
48 return Err("proof_bytes exceeds maximum allowed size (64KB)");
49 }
50 Ok(Self {
51 proof_bytes,
52 block_hash,
53 position,
54 })
55 }
56
57 pub fn new_unchecked(proof_bytes: Vec<u8>, block_hash: Hash, position: u64) -> Self {
63 Self {
64 proof_bytes,
65 block_hash,
66 position,
67 }
68 }
69
70 pub fn is_confirmed(&self, _required_depth: u32) -> bool {
72 true
74 }
75}
76
77#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
79pub struct FinalityProof {
80 pub finality_data: Vec<u8>,
82 pub confirmations: u64,
84 pub is_deterministic: bool,
86}
87
88impl FinalityProof {
89 pub fn new(
99 finality_data: Vec<u8>,
100 confirmations: u64,
101 is_deterministic: bool,
102 ) -> Result<Self, &'static str> {
103 if finality_data.len() > MAX_FINALITY_DATA {
104 return Err("finality_data exceeds maximum allowed size (4KB)");
105 }
106 Ok(Self {
107 finality_data,
108 confirmations,
109 is_deterministic,
110 })
111 }
112
113 pub fn new_unchecked(
118 finality_data: Vec<u8>,
119 confirmations: u64,
120 is_deterministic: bool,
121 ) -> Self {
122 Self {
123 finality_data,
124 confirmations,
125 is_deterministic,
126 }
127 }
128}
129
130#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
132pub struct ProofBundle {
133 pub transition_dag: DAGSegment,
135 pub signatures: Vec<Vec<u8>>,
137 pub seal_ref: SealRef,
139 pub anchor_ref: AnchorRef,
141 pub inclusion_proof: InclusionProof,
143 pub finality_proof: FinalityProof,
145}
146
147impl ProofBundle {
148 pub fn new(
161 transition_dag: DAGSegment,
162 signatures: Vec<Vec<u8>>,
163 seal_ref: SealRef,
164 anchor_ref: AnchorRef,
165 inclusion_proof: InclusionProof,
166 finality_proof: FinalityProof,
167 ) -> Result<Self, &'static str> {
168 let total_sig_size: usize = signatures.iter().map(|s| s.len()).sum();
170 if total_sig_size > MAX_SIGNATURES_TOTAL_SIZE {
171 return Err("total signatures size exceeds maximum allowed (1MB)");
172 }
173 Ok(Self {
174 transition_dag,
175 signatures,
176 seal_ref,
177 anchor_ref,
178 inclusion_proof,
179 finality_proof,
180 })
181 }
182
183 pub fn new_unchecked(
188 transition_dag: DAGSegment,
189 signatures: Vec<Vec<u8>>,
190 seal_ref: SealRef,
191 anchor_ref: AnchorRef,
192 inclusion_proof: InclusionProof,
193 finality_proof: FinalityProof,
194 ) -> Self {
195 Self {
196 transition_dag,
197 signatures,
198 seal_ref,
199 anchor_ref,
200 inclusion_proof,
201 finality_proof,
202 }
203 }
204
205 pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
207 bincode::serialize(self)
208 }
209
210 pub fn from_bytes(bytes: &[u8]) -> Result<Self, bincode::Error> {
212 const MAX_SIZE: usize = 10 * 1024 * 1024; if bytes.len() > MAX_SIZE {
214 return Err(bincode::ErrorKind::Custom(format!(
215 "ProofBundle too large: {} bytes (max {})",
216 bytes.len(),
217 MAX_SIZE
218 ))
219 .into());
220 }
221 bincode::deserialize(bytes)
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn test_inclusion_proof_creation() {
231 let proof = InclusionProof::new(vec![0xAB; 64], Hash::new([1u8; 32]), 42).unwrap();
232 assert_eq!(proof.position, 42);
233 }
234
235 #[test]
236 fn test_finality_proof_creation() {
237 let proof = FinalityProof::new(vec![0xCD; 32], 6, false).unwrap();
238 assert_eq!(proof.confirmations, 6);
239 assert!(!proof.is_deterministic);
240 }
241
242 #[test]
243 fn test_proof_bundle_serialization() {
244 let bundle = ProofBundle::new(
245 DAGSegment::new(vec![], Hash::zero()),
246 vec![vec![0xAB; 64]],
247 SealRef::new(vec![1, 2, 3], Some(42)).unwrap(),
248 AnchorRef::new(vec![4, 5, 6], 100, vec![]).unwrap(),
249 InclusionProof::new(vec![], Hash::zero(), 0).unwrap(),
250 FinalityProof::new(vec![], 6, false).unwrap(),
251 )
252 .unwrap();
253
254 let bytes = bundle.to_bytes().unwrap();
255 let restored = ProofBundle::from_bytes(&bytes).unwrap();
256 assert_eq!(bundle, restored);
257 }
258
259 #[test]
260 fn test_inclusion_proof_too_large() {
261 let large_proof = vec![0u8; MAX_PROOF_BYTES + 1];
262 let result = InclusionProof::new(large_proof, Hash::zero(), 0);
263 assert!(result.is_err());
264 }
265
266 #[test]
267 fn test_finality_proof_too_large() {
268 let large_data = vec![0u8; MAX_FINALITY_DATA + 1];
269 let result = FinalityProof::new(large_data, 6, false);
270 assert!(result.is_err());
271 }
272
273 #[test]
274 fn test_proof_bundle_signatures_too_large() {
275 let large_sigs = vec![vec![0u8; MAX_SIGNATURES_TOTAL_SIZE / 2 + 1]; 2];
276 let result = ProofBundle::new(
277 DAGSegment::new(vec![], Hash::zero()),
278 large_sigs,
279 SealRef::new(vec![1, 2, 3], Some(42)).unwrap(),
280 AnchorRef::new(vec![4, 5, 6], 100, vec![]).unwrap(),
281 InclusionProof::new(vec![], Hash::zero(), 0).unwrap(),
282 FinalityProof::new(vec![], 6, false).unwrap(),
283 );
284 assert!(result.is_err());
285 }
286}