1use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
2
3use super::{
4 DeferredError, DeferredStateWire, Digest, IntegrityError, MAX_DEFERRED_ELEMENTS, Node,
5 NodeType, PrecompileError, PrecompileRegistry, TRUE_DIGEST, Tag,
6};
7
8#[derive(Debug, Clone)]
16pub struct DeferredState {
17 registry: Arc<PrecompileRegistry>,
18 nodes: BTreeMap<Digest, Node>,
19 pub(super) root: Digest,
20 evals: BTreeMap<Digest, Digest>,
21 remaining_elements: usize,
22}
23
24impl Default for DeferredState {
25 fn default() -> Self {
26 Self::new(Arc::new(PrecompileRegistry::new()))
27 .expect("empty registry initialization cannot fail")
28 }
29}
30
31impl DeferredState {
32 pub fn new(registry: Arc<PrecompileRegistry>) -> Result<Self, PrecompileError> {
33 let mut state = Self::empty(registry);
34 state.initialize_precompile_nodes()?;
35 Ok(state)
36 }
37
38 fn empty(registry: Arc<PrecompileRegistry>) -> Self {
40 let mut nodes = BTreeMap::new();
41 nodes.insert(TRUE_DIGEST, Node::TRUE);
42
43 let mut evals = BTreeMap::new();
44 evals.insert(TRUE_DIGEST, TRUE_DIGEST);
45
46 Self {
47 registry,
48 nodes,
49 root: TRUE_DIGEST,
50 evals,
51 remaining_elements: MAX_DEFERRED_ELEMENTS,
52 }
53 }
54
55 fn initialize_precompile_nodes(&mut self) -> Result<(), PrecompileError> {
58 let init_nodes = self.registry.init_nodes();
59 let init_digests: Vec<Digest> = init_nodes.iter().map(Node::digest).collect();
60
61 for node in init_nodes {
64 self.registry.validate_node(&node)?;
65 self.insert_node(node)?;
66 }
67
68 for digest in init_digests {
69 self.evaluate_digest(digest)?;
70 }
71
72 Ok(())
73 }
74
75 pub fn extend_precompiles(
83 &mut self,
84 precompiles: PrecompileRegistry,
85 ) -> Result<(), PrecompileError> {
86 let mut next = self.clone();
87 Arc::make_mut(&mut next.registry).merge(precompiles);
88 next.initialize_precompile_nodes()?;
89
90 *self = next;
91 Ok(())
92 }
93
94 pub fn registry(&self) -> &PrecompileRegistry {
95 &self.registry
96 }
97
98 pub fn root(&self) -> Digest {
100 self.root
101 }
102
103 pub fn get_node(&self, digest: &Digest) -> Option<&Node> {
104 self.nodes.get(digest)
105 }
106
107 pub fn get_canonical_digest(&self, digest: Digest) -> Option<Digest> {
113 let canonical_digest = self.evals.get(&digest).copied()?;
114 self.nodes.contains_key(&canonical_digest).then_some(canonical_digest)
115 }
116
117 pub fn get_canonical_node(&self, digest: Digest) -> Option<(Digest, &Node)> {
122 let canonical_digest = self.get_canonical_digest(digest)?;
123 self.nodes.get(&canonical_digest).map(|node| (canonical_digest, node))
124 }
125
126 pub fn require_canonical_node(
131 &self,
132 digest: Digest,
133 ) -> Result<(Digest, &Node), PrecompileError> {
134 self.get_canonical_node(digest).ok_or(PrecompileError::MissingNode)
135 }
136
137 pub fn nodes(&self) -> &BTreeMap<Digest, Node> {
138 &self.nodes
139 }
140
141 pub(crate) fn compact(self) -> Result<Self, PrecompileError> {
146 let root = self.root;
147 let mut compacted = Self::new(Arc::clone(&self.registry))?;
148 compacted.import_reachable_from(&self, root)?;
149 compacted.root = root;
150 Ok(compacted)
151 }
152
153 pub(crate) fn merge(mut self, other: Self) -> Result<Self, PrecompileError> {
159 let other_root = other.root();
160 self.import_reachable_from(&other, other_root)?;
161 self.log_statement(other_root)?;
162 Ok(self)
163 }
164
165 pub fn num_elements(&self) -> usize {
167 self.nodes
168 .iter()
169 .filter_map(|(digest, node)| {
170 (*digest != TRUE_DIGEST).then_some(node.storage_felt_len())
171 })
172 .sum()
173 }
174
175 pub fn remaining_elements(&self) -> usize {
176 self.remaining_elements
177 }
178
179 pub fn decode(&self, tag: Tag) -> Result<NodeType, PrecompileError> {
184 self.registry.decode_node_type(tag)
185 }
186
187 pub fn register(&mut self, node: Node) -> Result<Digest, PrecompileError> {
196 self.validate_node_for_insertion(&node)?;
197 let digest = self.insert_node(node)?;
198 self.evaluate_digest(digest)?;
199 Ok(digest)
200 }
201
202 pub fn log_statement(&mut self, statement_digest: Digest) -> Result<Digest, PrecompileError> {
208 let prev_root = self.root;
209
210 self.require_true_eval(prev_root)?;
211 self.require_true_eval(statement_digest)?;
212
213 let and_node = Node::and(prev_root, statement_digest);
214 let new_root = and_node.digest();
215 self.insert_node(and_node)?;
216 self.root = new_root;
217 self.record_eval(new_root, Node::TRUE)?;
218 Ok(new_root)
219 }
220
221 pub fn log_verified_statement(
228 &mut self,
229 statement_digest: Digest,
230 expected_new_root: Digest,
231 ) -> Result<Digest, PrecompileError> {
232 let actual_new_root = Node::and(self.root, statement_digest).digest();
233 if actual_new_root != expected_new_root {
234 return Err(DeferredError::InvalidDeferredRootTransition {
235 expected: expected_new_root,
236 actual: actual_new_root,
237 }
238 .into());
239 }
240
241 self.log_statement(statement_digest)
242 }
243
244 pub fn evaluate_digest(&mut self, digest: Digest) -> Result<Digest, PrecompileError> {
250 let node = self.nodes.get(&digest).ok_or(PrecompileError::MissingNode)?.clone();
251 if let Some(canonical_digest) = self.evals.get(&digest) {
252 if self.nodes.contains_key(canonical_digest) {
253 return Ok(*canonical_digest);
254 }
255 return Err(PrecompileError::MissingNode);
256 }
257
258 self.validate_node_for_insertion(&node)?;
259 let canonical = if node.tag() == Tag::TRUE {
260 Node::TRUE
261 } else if node.tag() == Tag::AND {
262 let (lhs, rhs) = node.payload().as_join()?;
263 for child in [lhs, rhs] {
264 self.require_true_eval(child)?;
265 }
266 Node::TRUE
267 } else if node.tag() == Tag::CHUNKS {
268 node
269 } else {
270 let registry = Arc::clone(&self.registry);
271 let mut context = DeferredContext::new(self);
272 registry.evaluate(&node, &mut context)?
273 };
274
275 self.record_eval(digest, canonical)?;
276 self.evals.get(&digest).copied().ok_or(PrecompileError::MissingNode)
277 }
278
279 pub fn to_wire(&self) -> Result<DeferredStateWire, IntegrityError> {
286 DeferredStateWire::from_state(self)
287 }
288
289 pub fn from_wire(
297 registry: Arc<PrecompileRegistry>,
298 wire: &DeferredStateWire,
299 ) -> Result<Self, IntegrityError> {
300 wire.rehydrate(registry)
301 }
302
303 fn import_reachable_from(
304 &mut self,
305 source: &DeferredState,
306 root: Digest,
307 ) -> Result<(), PrecompileError> {
308 let mut pending = alloc::vec![(root, false)];
309 while let Some((digest, children_imported)) = pending.pop() {
310 if digest == TRUE_DIGEST {
311 continue;
312 }
313
314 let node = source.nodes.get(&digest).ok_or(PrecompileError::MissingNode)?;
315 if let Some(existing) = self.nodes.get(&digest) {
316 if existing != node {
317 return Err(DeferredError::ConflictingNode.into());
318 }
319 continue;
320 }
321
322 if children_imported {
323 self.register(node.clone())?;
324 } else {
325 pending.push((digest, true));
326 pending.extend(node.children().map(|child| (child, false)));
327 }
328 }
329 Ok(())
330 }
331
332 fn validate_node_for_insertion(&self, node: &Node) -> Result<NodeType, PrecompileError> {
333 let node_type = self.registry.validate_node(node)?;
334 for child in node.children() {
335 if child != TRUE_DIGEST && !self.nodes.contains_key(&child) {
336 return Err(PrecompileError::MissingNode);
337 }
338 }
339 Ok(node_type)
340 }
341
342 fn insert_node(&mut self, node: Node) -> Result<Digest, PrecompileError> {
343 let digest = node.digest();
344 match self.nodes.get(&digest) {
345 Some(existing) if existing == &node => Ok(digest),
346 Some(_) => Err(DeferredError::ConflictingNode.into()),
347 None => {
348 let required = node.storage_felt_len();
349 self.remaining_elements = self.remaining_elements.checked_sub(required).ok_or(
350 DeferredError::DeferredStateTooLarge {
351 num_elements: required,
352 max: self.remaining_elements,
353 },
354 )?;
355 self.nodes.insert(digest, node);
356 Ok(digest)
357 },
358 }
359 }
360
361 fn record_eval(
364 &mut self,
365 input_digest: Digest,
366 canonical: Node,
367 ) -> Result<(), PrecompileError> {
368 if !self.nodes.contains_key(&input_digest) {
369 return Err(PrecompileError::MissingNode);
370 }
371 self.validate_node_for_insertion(&canonical)?;
372 let canonical_digest = self.insert_node(canonical)?;
373 match self.evals.get(&input_digest) {
374 Some(existing) if *existing == canonical_digest => Ok(()),
375 Some(_) => Err(DeferredError::ConflictingNode.into()),
376 None => {
377 self.evals.insert(input_digest, canonical_digest);
378 Ok(())
379 },
380 }
381 }
382
383 fn require_true_eval(&mut self, digest: Digest) -> Result<(), PrecompileError> {
384 if self.evaluate_digest(digest)? != TRUE_DIGEST {
385 return Err(PrecompileError::AssertionFailed);
386 }
387 Ok(())
388 }
389}
390
391pub struct DeferredContext<'a> {
401 state: &'a mut DeferredState,
402}
403
404impl<'a> DeferredContext<'a> {
405 pub(crate) fn new(state: &'a mut DeferredState) -> Self {
407 Self { state }
408 }
409
410 pub fn get_node(&self, digest: &Digest) -> Option<&Node> {
414 self.state.get_node(digest)
415 }
416
417 pub fn evaluate_digest(&mut self, digest: Digest) -> Result<Digest, PrecompileError> {
423 self.state.evaluate_digest(digest)
424 }
425
426 pub fn evaluate_digest_pair(
428 &mut self,
429 lhs: Digest,
430 rhs: Digest,
431 ) -> Result<(Digest, Digest), PrecompileError> {
432 Ok((self.evaluate_digest(lhs)?, self.evaluate_digest(rhs)?))
433 }
434
435 pub fn ensure_equal(&mut self, lhs: Digest, rhs: Digest) -> Result<(), PrecompileError> {
437 let (lhs, rhs) = self.evaluate_digest_pair(lhs, rhs)?;
438 if lhs != rhs {
439 return Err(PrecompileError::AssertionFailed);
440 }
441 Ok(())
442 }
443
444 pub fn register(&mut self, node: Node) -> Result<Digest, PrecompileError> {
449 self.state.register(node)
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456 use crate::{
457 Felt, ZERO,
458 deferred::{Payload, Precompile, precompile_id},
459 };
460
461 #[derive(Debug, Clone, Copy)]
462 struct RejectingPrecompile;
463
464 impl Precompile for RejectingPrecompile {
465 fn name(&self) -> &'static str {
466 "rejecting-registration-fixture"
467 }
468
469 fn id(&self) -> Felt {
470 precompile_id(self.name())
471 }
472
473 fn decode(&self, args: [Felt; 3]) -> Option<NodeType> {
474 (args == [ZERO; 3]).then_some(NodeType::Data)
475 }
476
477 fn evaluate(
478 &self,
479 _args: [Felt; 3],
480 _payload: &Payload,
481 _context: &mut DeferredContext<'_>,
482 ) -> Result<Node, PrecompileError> {
483 Err(PrecompileError::AssertionFailed)
484 }
485 }
486
487 #[test]
488 fn construction_uses_the_fixed_deferred_element_limit() {
489 let state = DeferredState::new(Arc::new(PrecompileRegistry::new())).unwrap();
490 let default_state = DeferredState::default();
491
492 assert_eq!(state.num_elements(), 0);
493 assert_eq!(state.remaining_elements(), MAX_DEFERRED_ELEMENTS);
494 assert_eq!(default_state.remaining_elements(), MAX_DEFERRED_ELEMENTS);
495 }
496
497 #[test]
498 fn register_eagerly_propagates_precompile_evaluation_errors() {
499 let precompile = RejectingPrecompile;
500 let tag =
501 Tag::precompile(precompile.id(), [ZERO; 3]).expect("fixture id is precompile-owned");
502 let registry = Arc::new(PrecompileRegistry::new().with_precompile(precompile));
503 let mut state = DeferredState::new(registry).unwrap();
504 let node = Node::value(tag, [ZERO; 8]).unwrap();
505 let digest = node.digest();
506
507 let error = state.register(node).unwrap_err();
508
509 assert!(matches!(error.root(), PrecompileError::AssertionFailed));
510 assert_eq!(state.get_canonical_digest(digest), None);
511 }
512
513 fn framework_state(statement_depth: usize) -> DeferredState {
514 let mut state = DeferredState::default();
515 let mut statement = TRUE_DIGEST;
516 for _ in 0..statement_depth {
517 statement = state.register(Node::and(statement, TRUE_DIGEST)).unwrap();
518 }
519 state.log_statement(statement).unwrap();
520 state
521 }
522
523 #[test]
524 fn merge_reduces_roots_in_order_and_deduplicates_nodes() {
525 let first = framework_state(1);
526 let second = framework_state(2);
527 let first_root = first.root();
528 let second_root = second.root();
529 let total_nodes = first.nodes().len() + second.nodes().len();
530
531 let merged = first.merge(second).unwrap();
532
533 assert_eq!(merged.root(), Node::and(first_root, second_root).digest());
534 assert!(merged.nodes().len() < total_nodes);
535 }
536
537 #[test]
538 fn merge_preserves_order_and_duplicate_multiplicity() {
539 let first = framework_state(1);
540 let second = framework_state(2);
541 let first_root = first.root();
542 let second_root = second.root();
543
544 let ordered = first.clone().merge(second.clone()).unwrap();
545 let reordered = second.merge(first.clone()).unwrap();
546 let duplicate = first.clone().merge(first).unwrap();
547
548 assert_eq!(ordered.root(), Node::and(first_root, second_root).digest());
549 assert_eq!(reordered.root(), Node::and(second_root, first_root).digest());
550 assert_eq!(duplicate.root(), Node::and(first_root, first_root).digest());
551 assert_ne!(ordered.root(), reordered.root());
552 assert_ne!(duplicate.root(), first_root);
553 }
554
555 #[test]
556 fn merge_enforces_the_combined_element_limit() {
557 let mut first = framework_state(1);
558 let second = framework_state(2);
559 first.remaining_elements = 0;
560
561 let error = first.merge(second).unwrap_err();
562
563 assert!(matches!(
564 error.root(),
565 PrecompileError::Other(DeferredError::DeferredStateTooLarge { .. })
566 ));
567 }
568
569 #[test]
570 fn merge_combines_exact_roots_without_filtering_true() {
571 let settled = DeferredState::default();
572 let unsettled = framework_state(1);
573 let unsettled_root = unsettled.root();
574
575 let merged = settled.merge(unsettled).unwrap();
576
577 assert_eq!(merged.root(), Node::and(TRUE_DIGEST, unsettled_root).digest());
578 }
579}