1use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
2
3use super::{
4 DeferredError, Digest, IntegrityError, MAX_DEFERRED_ELEMENTS, Node, NodeType, PrecompileError,
5 PrecompileRegistry, PrecompileWitness, TRUE_DIGEST, Tag,
6};
7
8#[derive(Debug, Clone)]
14pub struct DeferredState {
15 registry: Arc<PrecompileRegistry>,
16 nodes: BTreeMap<Digest, Node>,
17 pub(super) root: Digest,
18 evals: BTreeMap<Digest, Digest>,
19 remaining_elements: usize,
20}
21
22impl Default for DeferredState {
23 fn default() -> Self {
24 Self::new(Arc::new(PrecompileRegistry::new()))
25 .expect("empty registry initialization cannot fail")
26 }
27}
28
29impl DeferredState {
30 pub fn new(registry: Arc<PrecompileRegistry>) -> Result<Self, PrecompileError> {
31 let mut state = Self::empty(registry);
32 state.initialize_precompile_nodes()?;
33 Ok(state)
34 }
35
36 fn empty(registry: Arc<PrecompileRegistry>) -> Self {
38 let mut nodes = BTreeMap::new();
39 nodes.insert(TRUE_DIGEST, Node::TRUE);
40
41 let mut evals = BTreeMap::new();
42 evals.insert(TRUE_DIGEST, TRUE_DIGEST);
43
44 Self {
45 registry,
46 nodes,
47 root: TRUE_DIGEST,
48 evals,
49 remaining_elements: MAX_DEFERRED_ELEMENTS,
50 }
51 }
52
53 fn initialize_precompile_nodes(&mut self) -> Result<(), PrecompileError> {
56 let init_nodes = self.registry.init_nodes();
57 let init_digests: Vec<Digest> = init_nodes.iter().map(Node::digest).collect();
58
59 for node in init_nodes {
62 self.registry.validate_node(&node)?;
63 self.insert_node(node)?;
64 }
65
66 for digest in init_digests {
67 self.evaluate_digest(digest)?;
68 }
69
70 Ok(())
71 }
72
73 pub fn extend_precompiles(
81 &mut self,
82 precompiles: PrecompileRegistry,
83 ) -> Result<(), PrecompileError> {
84 let mut next = self.clone();
85 Arc::make_mut(&mut next.registry).merge(precompiles);
86 next.initialize_precompile_nodes()?;
87
88 *self = next;
89 Ok(())
90 }
91
92 pub fn registry(&self) -> &PrecompileRegistry {
93 &self.registry
94 }
95
96 pub fn root(&self) -> Digest {
98 self.root
99 }
100
101 pub fn get_node(&self, digest: &Digest) -> Option<&Node> {
102 self.nodes.get(digest)
103 }
104
105 pub fn get_canonical_digest(&self, digest: Digest) -> Option<Digest> {
111 let canonical_digest = self.evals.get(&digest).copied()?;
112 self.nodes.contains_key(&canonical_digest).then_some(canonical_digest)
113 }
114
115 pub fn get_canonical_node(&self, digest: Digest) -> Option<(Digest, &Node)> {
120 let canonical_digest = self.get_canonical_digest(digest)?;
121 self.nodes.get(&canonical_digest).map(|node| (canonical_digest, node))
122 }
123
124 pub fn require_canonical_node(
129 &self,
130 digest: Digest,
131 ) -> Result<(Digest, &Node), PrecompileError> {
132 self.get_canonical_node(digest).ok_or(PrecompileError::MissingNode)
133 }
134
135 pub fn num_elements(&self) -> usize {
137 self.nodes
138 .iter()
139 .filter_map(|(digest, node)| {
140 (*digest != TRUE_DIGEST).then_some(node.storage_felt_len())
141 })
142 .sum()
143 }
144
145 pub fn remaining_elements(&self) -> usize {
146 self.remaining_elements
147 }
148
149 pub fn decode(&self, tag: Tag) -> Result<NodeType, PrecompileError> {
154 self.registry.decode_node_type(tag)
155 }
156
157 pub fn register(&mut self, node: Node) -> Result<Digest, PrecompileError> {
166 self.validate_node_for_insertion(&node)?;
167 let digest = self.insert_node(node)?;
168 self.evaluate_digest(digest)?;
169 Ok(digest)
170 }
171
172 pub fn log_statement(&mut self, statement_digest: Digest) -> Result<Digest, PrecompileError> {
178 let prev_root = self.root;
179
180 self.require_true_eval(prev_root)?;
181 self.require_true_eval(statement_digest)?;
182
183 let and_node = Node::and(prev_root, statement_digest);
184 let new_root = and_node.digest();
185 self.insert_node(and_node)?;
186 self.root = new_root;
187 self.record_eval(new_root, Node::TRUE)?;
188 Ok(new_root)
189 }
190
191 pub fn log_verified_statement(
198 &mut self,
199 statement_digest: Digest,
200 expected_new_root: Digest,
201 ) -> Result<Digest, PrecompileError> {
202 let actual_new_root = Node::and(self.root, statement_digest).digest();
203 if actual_new_root != expected_new_root {
204 return Err(DeferredError::InvalidDeferredRootTransition {
205 expected: expected_new_root,
206 actual: actual_new_root,
207 }
208 .into());
209 }
210
211 self.log_statement(statement_digest)
212 }
213
214 pub fn evaluate_digest(&mut self, digest: Digest) -> Result<Digest, PrecompileError> {
220 let node = self.nodes.get(&digest).ok_or(PrecompileError::MissingNode)?.clone();
221 if let Some(canonical_digest) = self.evals.get(&digest) {
222 if self.nodes.contains_key(canonical_digest) {
223 return Ok(*canonical_digest);
224 }
225 return Err(PrecompileError::MissingNode);
226 }
227
228 self.validate_node_for_insertion(&node)?;
229 let canonical = if node.tag() == Tag::TRUE {
230 Node::TRUE
231 } else if node.tag() == Tag::AND {
232 let (lhs, rhs) = node.payload().as_join()?;
233 for child in [lhs, rhs] {
234 self.require_true_eval(child)?;
235 }
236 Node::TRUE
237 } else if node.tag() == Tag::CHUNKS {
238 node
239 } else {
240 let registry = Arc::clone(&self.registry);
241 let mut context = DeferredContext::new(self);
242 registry.evaluate(&node, &mut context)?
243 };
244
245 self.record_eval(digest, canonical)?;
246 self.evals.get(&digest).copied().ok_or(PrecompileError::MissingNode)
247 }
248
249 pub fn into_witness(self) -> Result<Option<PrecompileWitness>, IntegrityError> {
254 if self.root == TRUE_DIGEST {
255 return Ok(None);
256 }
257 PrecompileWitness::from_state(&self).map(Some)
258 }
259
260 fn validate_node_for_insertion(&self, node: &Node) -> Result<NodeType, PrecompileError> {
261 let node_type = self.registry.validate_node(node)?;
262 for child in node.children() {
263 if child != TRUE_DIGEST && !self.nodes.contains_key(&child) {
264 return Err(PrecompileError::MissingNode);
265 }
266 }
267 Ok(node_type)
268 }
269
270 fn insert_node(&mut self, node: Node) -> Result<Digest, PrecompileError> {
271 let digest = node.digest();
272 match self.nodes.get(&digest) {
273 Some(existing) if existing == &node => Ok(digest),
274 Some(_) => Err(DeferredError::ConflictingNode.into()),
275 None => {
276 let required = node.storage_felt_len();
277 self.remaining_elements = self.remaining_elements.checked_sub(required).ok_or(
278 DeferredError::DeferredStateTooLarge {
279 num_elements: required,
280 max: self.remaining_elements,
281 },
282 )?;
283 self.nodes.insert(digest, node);
284 Ok(digest)
285 },
286 }
287 }
288
289 fn record_eval(
292 &mut self,
293 input_digest: Digest,
294 canonical: Node,
295 ) -> Result<(), PrecompileError> {
296 if !self.nodes.contains_key(&input_digest) {
297 return Err(PrecompileError::MissingNode);
298 }
299 self.validate_node_for_insertion(&canonical)?;
300 let canonical_digest = self.insert_node(canonical)?;
301 match self.evals.get(&input_digest) {
302 Some(existing) if *existing == canonical_digest => Ok(()),
303 Some(_) => Err(DeferredError::ConflictingNode.into()),
304 None => {
305 self.evals.insert(input_digest, canonical_digest);
306 Ok(())
307 },
308 }
309 }
310
311 fn require_true_eval(&mut self, digest: Digest) -> Result<(), PrecompileError> {
312 if self.evaluate_digest(digest)? != TRUE_DIGEST {
313 return Err(PrecompileError::AssertionFailed);
314 }
315 Ok(())
316 }
317}
318
319pub struct DeferredContext<'a> {
327 state: &'a mut DeferredState,
328}
329
330impl<'a> DeferredContext<'a> {
331 pub(crate) fn new(state: &'a mut DeferredState) -> Self {
333 Self { state }
334 }
335
336 pub fn get_node(&self, digest: &Digest) -> Option<&Node> {
340 self.state.get_node(digest)
341 }
342
343 pub fn evaluate_digest(&mut self, digest: Digest) -> Result<Digest, PrecompileError> {
349 self.state.evaluate_digest(digest)
350 }
351
352 pub fn evaluate_digest_pair(
354 &mut self,
355 lhs: Digest,
356 rhs: Digest,
357 ) -> Result<(Digest, Digest), PrecompileError> {
358 Ok((self.evaluate_digest(lhs)?, self.evaluate_digest(rhs)?))
359 }
360
361 pub fn ensure_equal(&mut self, lhs: Digest, rhs: Digest) -> Result<(), PrecompileError> {
363 let (lhs, rhs) = self.evaluate_digest_pair(lhs, rhs)?;
364 if lhs != rhs {
365 return Err(PrecompileError::AssertionFailed);
366 }
367 Ok(())
368 }
369
370 pub fn register(&mut self, node: Node) -> Result<Digest, PrecompileError> {
375 self.state.register(node)
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382 use crate::{
383 Felt, ZERO,
384 deferred::{Payload, Precompile, precompile_id},
385 };
386
387 #[derive(Debug, Clone, Copy)]
388 struct RejectingPrecompile;
389
390 impl Precompile for RejectingPrecompile {
391 fn name(&self) -> &'static str {
392 "rejecting-registration-fixture"
393 }
394
395 fn id(&self) -> Felt {
396 precompile_id(self.name())
397 }
398
399 fn decode(&self, args: [Felt; 3]) -> Option<NodeType> {
400 (args == [ZERO; 3]).then_some(NodeType::Data)
401 }
402
403 fn evaluate(
404 &self,
405 _args: [Felt; 3],
406 _payload: &Payload,
407 _context: &mut DeferredContext<'_>,
408 ) -> Result<Node, PrecompileError> {
409 Err(PrecompileError::AssertionFailed)
410 }
411 }
412
413 #[test]
414 fn construction_uses_the_fixed_deferred_element_limit() {
415 let state = DeferredState::new(Arc::new(PrecompileRegistry::new())).unwrap();
416 let default_state = DeferredState::default();
417
418 assert_eq!(state.num_elements(), 0);
419 assert_eq!(state.remaining_elements(), MAX_DEFERRED_ELEMENTS);
420 assert_eq!(default_state.remaining_elements(), MAX_DEFERRED_ELEMENTS);
421 }
422
423 #[test]
424 fn register_eagerly_propagates_precompile_evaluation_errors() {
425 let precompile = RejectingPrecompile;
426 let tag =
427 Tag::precompile(precompile.id(), [ZERO; 3]).expect("fixture id is precompile-owned");
428 let registry = Arc::new(PrecompileRegistry::new().with_precompile(precompile));
429 let mut state = DeferredState::new(registry).unwrap();
430 let node = Node::value(tag, [ZERO; 8]).unwrap();
431 let digest = node.digest();
432
433 let error = state.register(node).unwrap_err();
434
435 assert!(matches!(error.root(), PrecompileError::AssertionFailed));
436 assert_eq!(state.get_canonical_digest(digest), None);
437 }
438}