1use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
2
3use super::{
4 DeferredError, DeferredStateWire, Digest, IntegrityError, Node, NodeType, PrecompileError,
5 PrecompileRegistry, TRUE_DIGEST, Tag,
6};
7
8#[derive(Debug, Clone)]
17pub struct DeferredState {
18 registry: Arc<PrecompileRegistry>,
19 nodes: BTreeMap<Digest, Node>,
20 pub(super) root: Digest,
21 evals: BTreeMap<Digest, Digest>,
22 remaining_elements: usize,
23}
24
25impl Default for DeferredState {
26 fn default() -> Self {
27 Self::new(Arc::new(PrecompileRegistry::new()), usize::MAX)
28 .expect("empty registry initialization cannot fail")
29 }
30}
31
32impl DeferredState {
33 pub fn new(
34 registry: Arc<PrecompileRegistry>,
35 max_elements: usize,
36 ) -> Result<Self, PrecompileError> {
37 let mut state = Self::empty(registry, max_elements);
38 state.initialize_precompile_nodes()?;
39 Ok(state)
40 }
41
42 fn empty(registry: Arc<PrecompileRegistry>, max_elements: usize) -> Self {
44 let mut nodes = BTreeMap::new();
45 nodes.insert(TRUE_DIGEST, Node::TRUE);
46
47 let mut evals = BTreeMap::new();
48 evals.insert(TRUE_DIGEST, TRUE_DIGEST);
49
50 Self {
51 registry,
52 nodes,
53 root: TRUE_DIGEST,
54 evals,
55 remaining_elements: max_elements,
56 }
57 }
58
59 fn initialize_precompile_nodes(&mut self) -> Result<(), PrecompileError> {
62 let init_nodes = self.registry.init_nodes();
63 let init_digests: Vec<Digest> = init_nodes.iter().map(Node::digest).collect();
64
65 for node in init_nodes {
68 self.registry.validate_node(&node)?;
69 self.insert_node(node)?;
70 }
71
72 for digest in init_digests {
73 self.evaluate_digest(digest)?;
74 }
75
76 Ok(())
77 }
78
79 pub fn extend_precompiles(
87 &mut self,
88 precompiles: PrecompileRegistry,
89 ) -> Result<(), PrecompileError> {
90 let mut next = self.clone();
91 Arc::make_mut(&mut next.registry).merge(precompiles);
92 next.initialize_precompile_nodes()?;
93
94 *self = next;
95 Ok(())
96 }
97
98 pub fn registry(&self) -> &PrecompileRegistry {
99 &self.registry
100 }
101
102 pub fn root(&self) -> Digest {
104 self.root
105 }
106
107 pub fn get_node(&self, digest: &Digest) -> Option<&Node> {
108 self.nodes.get(digest)
109 }
110
111 pub fn get_canonical_digest(&self, digest: Digest) -> Option<Digest> {
117 let canonical_digest = self.evals.get(&digest).copied()?;
118 self.nodes.contains_key(&canonical_digest).then_some(canonical_digest)
119 }
120
121 pub fn get_canonical_node(&self, digest: Digest) -> Option<(Digest, &Node)> {
126 let canonical_digest = self.get_canonical_digest(digest)?;
127 self.nodes.get(&canonical_digest).map(|node| (canonical_digest, node))
128 }
129
130 pub fn require_canonical_node(
135 &self,
136 digest: Digest,
137 ) -> Result<(Digest, &Node), PrecompileError> {
138 self.get_canonical_node(digest).ok_or(PrecompileError::MissingNode)
139 }
140
141 pub fn nodes(&self) -> &BTreeMap<Digest, Node> {
142 &self.nodes
143 }
144
145 pub fn remaining_elements(&self) -> usize {
146 self.remaining_elements
147 }
148
149 pub fn set_max_elements(&mut self, max_elements: usize) {
156 let used_elements = self
157 .nodes
158 .iter()
159 .filter_map(|(digest, node)| {
160 (*digest != TRUE_DIGEST).then_some(node.storage_felt_len())
161 })
162 .sum::<usize>();
163 self.remaining_elements = max_elements.saturating_sub(used_elements);
164 }
165
166 pub fn decode(&self, tag: Tag) -> Result<NodeType, PrecompileError> {
171 self.registry.decode_node_type(tag)
172 }
173
174 pub fn register(&mut self, node: Node) -> Result<Digest, PrecompileError> {
183 self.validate_node_for_insertion(&node)?;
184 let digest = self.insert_node(node)?;
185 self.evaluate_digest(digest)?;
186 Ok(digest)
187 }
188
189 pub fn log_statement(&mut self, statement_digest: Digest) -> Result<Digest, PrecompileError> {
195 let prev_root = self.root;
196
197 self.require_true_eval(prev_root)?;
198 self.require_true_eval(statement_digest)?;
199
200 let and_node = Node::and(prev_root, statement_digest);
201 let new_root = and_node.digest();
202 self.insert_node(and_node)?;
203 self.root = new_root;
204 self.record_eval(new_root, Node::TRUE)?;
205 Ok(new_root)
206 }
207
208 pub fn log_verified_statement(
215 &mut self,
216 statement_digest: Digest,
217 expected_new_root: Digest,
218 ) -> Result<Digest, PrecompileError> {
219 let actual_new_root = Node::and(self.root, statement_digest).digest();
220 if actual_new_root != expected_new_root {
221 return Err(DeferredError::InvalidDeferredRootTransition {
222 expected: expected_new_root,
223 actual: actual_new_root,
224 }
225 .into());
226 }
227
228 self.log_statement(statement_digest)
229 }
230
231 pub fn evaluate_digest(&mut self, digest: Digest) -> Result<Digest, PrecompileError> {
237 let node = self.nodes.get(&digest).ok_or(PrecompileError::MissingNode)?.clone();
238 if let Some(canonical_digest) = self.evals.get(&digest) {
239 if self.nodes.contains_key(canonical_digest) {
240 return Ok(*canonical_digest);
241 }
242 return Err(PrecompileError::MissingNode);
243 }
244
245 self.validate_node_for_insertion(&node)?;
246 let canonical = if node.tag() == Tag::TRUE {
247 Node::TRUE
248 } else if node.tag() == Tag::AND {
249 let (lhs, rhs) = node.payload().as_join()?;
250 for child in [lhs, rhs] {
251 self.require_true_eval(child)?;
252 }
253 Node::TRUE
254 } else if node.tag() == Tag::CHUNKS {
255 node
256 } else {
257 let registry = Arc::clone(&self.registry);
258 let mut context = DeferredContext::new(self);
259 registry.evaluate(&node, &mut context)?
260 };
261
262 self.record_eval(digest, canonical)?;
263 self.evals.get(&digest).copied().ok_or(PrecompileError::MissingNode)
264 }
265
266 pub fn to_wire(&self) -> Result<DeferredStateWire, IntegrityError> {
272 DeferredStateWire::from_state(self)
273 }
274
275 pub fn from_wire(
283 registry: Arc<PrecompileRegistry>,
284 wire: &DeferredStateWire,
285 max_elements: usize,
286 ) -> Result<Self, IntegrityError> {
287 wire.rehydrate(registry, max_elements)
288 }
289
290 fn validate_node_for_insertion(&self, node: &Node) -> Result<NodeType, PrecompileError> {
291 let node_type = self.registry.validate_node(node)?;
292 for child in node.children() {
293 if child != TRUE_DIGEST && !self.nodes.contains_key(&child) {
294 return Err(PrecompileError::MissingNode);
295 }
296 }
297 Ok(node_type)
298 }
299
300 fn insert_node(&mut self, node: Node) -> Result<Digest, PrecompileError> {
301 let digest = node.digest();
302 match self.nodes.get(&digest) {
303 Some(existing) if existing == &node => Ok(digest),
304 Some(_) => Err(DeferredError::ConflictingNode.into()),
305 None => {
306 let required = node.storage_felt_len();
307 self.remaining_elements = self.remaining_elements.checked_sub(required).ok_or(
308 DeferredError::DeferredStateTooLarge {
309 num_elements: required,
310 max: self.remaining_elements,
311 },
312 )?;
313 self.nodes.insert(digest, node);
314 Ok(digest)
315 },
316 }
317 }
318
319 fn record_eval(
322 &mut self,
323 input_digest: Digest,
324 canonical: Node,
325 ) -> Result<(), PrecompileError> {
326 if !self.nodes.contains_key(&input_digest) {
327 return Err(PrecompileError::MissingNode);
328 }
329 self.validate_node_for_insertion(&canonical)?;
330 let canonical_digest = self.insert_node(canonical)?;
331 match self.evals.get(&input_digest) {
332 Some(existing) if *existing == canonical_digest => Ok(()),
333 Some(_) => Err(DeferredError::ConflictingNode.into()),
334 None => {
335 self.evals.insert(input_digest, canonical_digest);
336 Ok(())
337 },
338 }
339 }
340
341 fn require_true_eval(&mut self, digest: Digest) -> Result<(), PrecompileError> {
342 if self.evaluate_digest(digest)? != TRUE_DIGEST {
343 return Err(PrecompileError::AssertionFailed);
344 }
345 Ok(())
346 }
347}
348
349pub struct DeferredContext<'a> {
359 state: &'a mut DeferredState,
360}
361
362impl<'a> DeferredContext<'a> {
363 pub(crate) fn new(state: &'a mut DeferredState) -> Self {
365 Self { state }
366 }
367
368 pub fn get_node(&self, digest: &Digest) -> Option<&Node> {
372 self.state.get_node(digest)
373 }
374
375 pub fn evaluate_digest(&mut self, digest: Digest) -> Result<Digest, PrecompileError> {
381 self.state.evaluate_digest(digest)
382 }
383
384 pub fn evaluate_digest_pair(
386 &mut self,
387 lhs: Digest,
388 rhs: Digest,
389 ) -> Result<(Digest, Digest), PrecompileError> {
390 Ok((self.evaluate_digest(lhs)?, self.evaluate_digest(rhs)?))
391 }
392
393 pub fn ensure_equal(&mut self, lhs: Digest, rhs: Digest) -> Result<(), PrecompileError> {
395 let (lhs, rhs) = self.evaluate_digest_pair(lhs, rhs)?;
396 if lhs != rhs {
397 return Err(PrecompileError::AssertionFailed);
398 }
399 Ok(())
400 }
401
402 pub fn register(&mut self, node: Node) -> Result<Digest, PrecompileError> {
407 self.state.register(node)
408 }
409}
410
411#[cfg(test)]
412mod tests {
413 use super::*;
414 use crate::{
415 Felt, ZERO,
416 deferred::{Payload, Precompile, precompile_id},
417 };
418
419 #[derive(Debug, Clone, Copy)]
420 struct RejectingPrecompile;
421
422 impl Precompile for RejectingPrecompile {
423 fn name(&self) -> &'static str {
424 "rejecting-registration-fixture"
425 }
426
427 fn id(&self) -> Felt {
428 precompile_id(self.name())
429 }
430
431 fn decode(&self, args: [Felt; 3]) -> Option<NodeType> {
432 (args == [ZERO; 3]).then_some(NodeType::Data)
433 }
434
435 fn evaluate(
436 &self,
437 _args: [Felt; 3],
438 _payload: &Payload,
439 _context: &mut DeferredContext<'_>,
440 ) -> Result<Node, PrecompileError> {
441 Err(PrecompileError::AssertionFailed)
442 }
443 }
444
445 #[test]
446 fn register_eagerly_propagates_precompile_evaluation_errors() {
447 let precompile = RejectingPrecompile;
448 let tag =
449 Tag::precompile(precompile.id(), [ZERO; 3]).expect("fixture id is precompile-owned");
450 let registry = Arc::new(PrecompileRegistry::new().with_precompile(precompile));
451 let mut state = DeferredState::new(registry, usize::MAX).unwrap();
452 let node = Node::value(tag, [ZERO; 8]).unwrap();
453 let digest = node.digest();
454
455 let error = state.register(node).unwrap_err();
456
457 assert!(matches!(error.root(), PrecompileError::AssertionFailed));
458 assert_eq!(state.get_canonical_digest(digest), None);
459 }
460}