Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
context.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
15
16namespace bb::avm2::constraining {
17namespace {
18
19using tracegen::TestTraceContainer;
21using C = Column;
23
24TEST(ContextConstrainingTest, EmptyRow)
25{
26 check_relation<context>(testing::empty_trace());
27}
28
29// This test currently does a lot, consider splitting up the various exit call conditions
30TEST(ContextConstrainingTest, ContextSwitchingCallReturn)
31{
32 constexpr uint32_t top_bytecode_id = 0x12345678;
33 constexpr uint32_t nested_bytecode_id = 0x456789ab;
34
35 TestTraceContainer trace(
36 { {
37 { C::execution_next_context_id, 0 },
38 { C::precomputed_first_row, 1 },
39 // Context Stack Rows
40 { C::context_stack_sel, 1 },
41 { C::context_stack_entered_context_id, 2 },
42 { C::context_stack_context_id, 1 },
43 { C::context_stack_parent_id, 0 },
44 { C::context_stack_next_pc, 2 },
45 { C::context_stack_msg_sender, 0 },
46 { C::context_stack_contract_address, 0 },
47 { C::context_stack_bytecode_id, top_bytecode_id },
48 { C::context_stack_is_static, 0 },
49 { C::context_stack_parent_calldata_addr, 0 },
50 { C::context_stack_parent_calldata_size, 0 },
51 { C::context_stack_parent_l2_gas_limit, 2000 },
52 { C::context_stack_parent_da_gas_limit, 4000 },
53 { C::context_stack_parent_l2_gas_used, 500 },
54 { C::context_stack_parent_da_gas_used, 1500 },
55 },
56 // First Row of execution
57 {
58 { C::execution_sel, 1 },
59 { C::execution_pc, 0 },
60 { C::execution_next_pc, 1 },
61 { C::execution_context_id, 1 },
62 { C::execution_next_context_id, 2 },
63 { C::execution_bytecode_id, top_bytecode_id },
64 { C::execution_is_static, 0 }, // Non-static context
65 { C::execution_parent_l2_gas_limit, 2000 },
66 { C::execution_parent_da_gas_limit, 4000 },
67 { C::execution_parent_l2_gas_used, 500 },
68 { C::execution_parent_da_gas_used, 1500 },
69 { C::execution_enqueued_call_start, 1 },
70 },
71 // CALL
72 {
73 { C::execution_sel, 1 },
74 { C::execution_pc, 1 },
75 { C::execution_next_pc, 2 },
76 { C::execution_sel_execute_call, 1 },
77 { C::execution_sel_execute_static_call, 0 }, // Regular CALL, not STATICCALL
78 { C::execution_sel_enter_call, 1 },
79 { C::execution_context_id, 1 },
80 { C::execution_next_context_id, 2 },
81 { C::execution_bytecode_id, top_bytecode_id }, // Same as previous row (propagated)
82 { C::execution_is_static, 0 }, // Still non-static
83 { C::execution_rop_4_, /*cd offset=*/10 },
84 { C::execution_register_2_, /*contract address=*/0xdeadbeef },
85 { C::execution_register_3_, /*cd size=*/1 },
86 { C::execution_parent_l2_gas_limit, 2000 },
87 { C::execution_parent_da_gas_limit, 4000 },
88 { C::execution_parent_l2_gas_used, 500 },
89 { C::execution_parent_da_gas_used, 1500 },
90 },
91 // First Row in new context
92 {
93 { C::execution_sel, 1 },
94 { C::execution_pc, 0 }, // pc=0 because it is after a CALL
95 { C::execution_next_pc, 20 },
96 { C::execution_context_id, 2 }, // Previous row next_context_id
97 { C::execution_next_context_id, 3 }, // Incremented due to previous call
98 { C::execution_parent_id, 1 }, // Previous row context id
99 { C::execution_is_parent_id_inv, 1 },
100 { C::execution_has_parent_ctx, 1 },
101 { C::execution_contract_address, 0xdeadbeef },
102 { C::execution_bytecode_id, nested_bytecode_id }, // New bytecode_id on entering new context
103 { C::execution_is_static, 0 }, // Remains non-static after regular CALL
104 { C::execution_parent_calldata_addr, 10 },
105 { C::execution_parent_calldata_size, 1 },
106 },
107 // Return Row
108 {
109 { C::execution_sel, 1 },
110 { C::execution_pc, 20 },
111 { C::execution_next_pc, 30 },
112 { C::execution_sel_execute_return, 1 },
113 { C::execution_rop_0_, 500 }, // Return data size offset
114 { C::execution_rop_1_, 600 }, // Return data offset
115 { C::execution_register_0_, 200 }, // Return data size
116 { C::execution_sel_exit_call, 1 },
117 { C::execution_nested_exit_call, 1 },
118 { C::execution_nested_return, 1 },
119 { C::execution_context_id, 2 },
120 { C::execution_next_context_id, 3 },
121 { C::execution_parent_id, 1 },
122 { C::execution_is_parent_id_inv, 1 },
123 { C::execution_has_parent_ctx, 1 },
124 { C::execution_contract_address, 0xdeadbeef },
125 { C::execution_bytecode_id, nested_bytecode_id }, // Propagated within same context
126 { C::execution_parent_calldata_addr, 10 },
127 { C::execution_parent_calldata_size, 1 },
128 },
129 {
130 { C::execution_sel, 1 },
131 { C::execution_next_context_id, 3 },
132 { C::execution_context_id, 1 },
133 { C::execution_parent_id, 0 },
134 { C::execution_last_child_id, 2 }, // Previous context id
135 { C::execution_pc, 2 }, // Based on next_pc of CALL step
136 { C::execution_msg_sender, 0 },
137 { C::execution_contract_address, 0 },
138 { C::execution_bytecode_id, top_bytecode_id }, // Restored from context stack
139 { C::execution_is_static, 0 },
140 { C::execution_parent_calldata_addr, 0 },
141 { C::execution_parent_calldata_size, 0 },
142 { C::execution_last_child_returndata_size, 200 }, // Return data size
143 { C::execution_last_child_returndata_addr, 600 }, // Return data offset
144 { C::execution_parent_l2_gas_limit, 2000 },
145 { C::execution_parent_da_gas_limit, 4000 },
146 { C::execution_parent_l2_gas_used, 500 },
147 { C::execution_parent_da_gas_used, 1500 },
148 },
149 {
150 { C::execution_sel, 0 },
151 { C::execution_last, 1 },
152 } });
153
154 check_relation<context>(trace);
155
156 check_interaction<tracegen::ExecutionTraceBuilder,
160}
161
162TEST(ContextConstrainingTest, ContextSwitchingExceptionalHalt)
163{
164 constexpr uint32_t top_bytecode_id = 0x12345678;
165 constexpr uint32_t nested_bytecode_id = 0x456789ab;
166
167 TestTraceContainer trace(
168 { {
169 { C::execution_next_context_id, 0 },
170 { C::precomputed_first_row, 1 },
171 // Context Stack Rows
172 { C::context_stack_sel, 1 },
173 { C::context_stack_entered_context_id, 2 },
174 { C::context_stack_context_id, 1 },
175 { C::context_stack_parent_id, 0 },
176 { C::context_stack_next_pc, 2 },
177 { C::context_stack_msg_sender, 0 },
178 { C::context_stack_contract_address, 0 },
179 { C::context_stack_bytecode_id, top_bytecode_id },
180 { C::context_stack_is_static, 0 },
181 { C::context_stack_parent_calldata_addr, 0 },
182 { C::context_stack_parent_calldata_size, 0 },
183 { C::context_stack_parent_l2_gas_limit, 2000 },
184 { C::context_stack_parent_da_gas_limit, 4000 },
185 { C::context_stack_parent_l2_gas_used, 500 },
186 { C::context_stack_parent_da_gas_used, 1500 },
187 },
188 // First Row of execution
189 {
190 { C::execution_sel, 1 },
191 { C::execution_pc, 0 },
192 { C::execution_next_pc, 1 },
193 { C::execution_context_id, 1 },
194 { C::execution_next_context_id, 2 },
195 { C::execution_bytecode_id, top_bytecode_id },
196 { C::execution_parent_l2_gas_limit, 2000 },
197 { C::execution_parent_da_gas_limit, 4000 },
198 { C::execution_parent_l2_gas_used, 500 },
199 { C::execution_parent_da_gas_used, 1500 },
200 { C::execution_enqueued_call_start, 1 },
201 },
202 // CALL
203 {
204 { C::execution_sel, 1 },
205 { C::execution_pc, 1 },
206 { C::execution_next_pc, 2 },
207 { C::execution_sel_execute_call, 1 },
208 { C::execution_sel_enter_call, 1 },
209 { C::execution_context_id, 1 },
210 { C::execution_next_context_id, 2 },
211 { C::execution_bytecode_id, top_bytecode_id }, // Same as previous row (propagated)
212 { C::execution_rop_4_, /*cd offset=*/10 },
213 { C::execution_register_2_, /*contract address=*/0xdeadbeef },
214 { C::execution_register_3_, /*cd size=*/1 },
215 { C::execution_parent_l2_gas_limit, 2000 },
216 { C::execution_parent_da_gas_limit, 4000 },
217 { C::execution_parent_l2_gas_used, 500 },
218 { C::execution_parent_da_gas_used, 1500 },
219 },
220 // First Row in new context
221 {
222 { C::execution_sel, 1 },
223 { C::execution_pc, 0 }, // pc=0 because it is after a CALL
224 { C::execution_next_pc, 20 },
225 { C::execution_context_id, 2 }, // Previous row next_context_id
226 { C::execution_next_context_id, 3 }, // Incremented due to previous call
227 { C::execution_parent_id, 1 }, // Previous row context id
228 { C::execution_is_parent_id_inv, 1 },
229 { C::execution_has_parent_ctx, 1 },
230 { C::execution_contract_address, 0xdeadbeef },
231 { C::execution_bytecode_id, nested_bytecode_id }, // New bytecode_id on entering new context
232 { C::execution_parent_calldata_addr, 10 },
233 { C::execution_parent_calldata_size, 1 },
234 },
235 // Exceptional Halt Row
236 {
237 { C::execution_sel, 1 },
238 { C::execution_pc, 20 },
239 { C::execution_next_pc, 30 },
240 { C::execution_sel_execute_return, 1 },
241 { C::execution_rop_0_, 500 }, // Return data size offset
242 { C::execution_rop_1_, 600 }, // Return data offset
243 { C::execution_register_0_, 200 }, // Return data size
244 { C::execution_sel_exit_call, 1 },
245 { C::execution_nested_exit_call, 1 },
246 { C::execution_sel_error, 1 }, // Exceptional Halt
247 { C::execution_context_id, 2 },
248 { C::execution_next_context_id, 3 },
249 { C::execution_parent_id, 1 },
250 { C::execution_is_parent_id_inv, 1 },
251 { C::execution_has_parent_ctx, 1 },
252 { C::execution_contract_address, 0xdeadbeef },
253 { C::execution_bytecode_id, nested_bytecode_id }, // Propagated within same context
254 { C::execution_parent_calldata_addr, 10 },
255 { C::execution_parent_calldata_size, 1 },
256 },
257 {
258 { C::execution_sel, 1 },
259 { C::execution_next_context_id, 3 },
260 { C::execution_context_id, 1 },
261 { C::execution_parent_id, 0 },
262 { C::execution_last_child_id, 2 }, // Previous context id
263 { C::execution_pc, 2 }, // Based on next_pc of CALL step
264 { C::execution_next_pc, 3 },
265 { C::execution_msg_sender, 0 },
266 { C::execution_contract_address, 0 },
267 { C::execution_bytecode_id, top_bytecode_id }, // Restored from context stack
268 { C::execution_is_static, 0 },
269 { C::execution_parent_calldata_addr, 0 },
270 { C::execution_parent_calldata_size, 0 },
271 { C::execution_last_child_returndata_size, 0 }, // Return data size reset
272 { C::execution_last_child_returndata_addr, 0 }, // Return data offset reset
273 { C::execution_parent_l2_gas_limit, 2000 },
274 { C::execution_parent_da_gas_limit, 4000 },
275 { C::execution_parent_l2_gas_used, 500 },
276 { C::execution_parent_da_gas_used, 1500 },
277 },
278 {
279 { C::execution_sel, 0 },
280 { C::execution_last, 1 },
281 } });
282
283 check_relation<context>(trace);
284
285 check_interaction<tracegen::ExecutionTraceBuilder,
289}
290
291TEST(ContextConstrainingTest, GasNextRow)
292{
293 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } },
294 {
295 // First Row of execution
296 { C::execution_sel, 1 },
297 { C::execution_l2_gas_limit, 1000 },
298 { C::execution_da_gas_limit, 2000 },
299 { C::execution_parent_l2_gas_limit, 2000 },
300 { C::execution_parent_da_gas_limit, 4000 },
301 { C::execution_parent_l2_gas_used, 500 },
302 { C::execution_parent_da_gas_used, 1500 },
303 },
304 {
305 // CALL
306 { C::execution_sel, 1 },
307 { C::execution_sel_enter_call, 1 },
308 { C::execution_l2_gas_used, 200 },
309 { C::execution_da_gas_used, 300 },
310 { C::execution_l2_gas_limit, 1000 },
311 { C::execution_da_gas_limit, 2000 },
312 { C::execution_parent_l2_gas_limit, 2000 },
313 { C::execution_parent_da_gas_limit, 4000 },
314 { C::execution_parent_l2_gas_used, 500 },
315 { C::execution_parent_da_gas_used, 1500 },
316 },
317 {
318 // Return
319 { C::execution_sel, 1 },
320 { C::execution_sel_exit_call, 1 },
321 { C::execution_nested_exit_call, 1 },
322 { C::execution_parent_l2_gas_limit, 1000 },
323 { C::execution_parent_da_gas_limit, 2000 },
324 { C::execution_parent_l2_gas_used, 200 },
325 { C::execution_parent_da_gas_used, 300 },
326 },
327 {
328 // After return
329 { C::execution_sel, 1 },
330 { C::execution_l2_gas_limit, 1000 },
331 { C::execution_da_gas_limit, 2000 },
332 { C::execution_parent_l2_gas_limit, 2000 },
333 { C::execution_parent_da_gas_limit, 4000 },
334 },
335 {
336 { C::execution_sel, 0 },
337 { C::execution_last, 1 },
338 } });
339
340 check_relation<context>(trace,
353
354 // Negative test: after return, restore wrong limits
355 trace.set(C::execution_l2_gas_limit, 4, 1001);
357 "L2_GAS_LIMIT_RESTORE_ON_EXIT");
358 trace.set(C::execution_da_gas_limit, 4, 2001);
360 "DA_GAS_LIMIT_RESTORE_ON_EXIT");
361
362 // Negative test: inside a nested call, store wrong parent limit and used
363 trace.set(C::execution_parent_l2_gas_limit, 3, 2001);
365 "PARENT_L2_GAS_LIMIT_STORE_ON_ENTER");
366 trace.set(C::execution_parent_da_gas_limit, 3, 4001);
368 "PARENT_DA_GAS_LIMIT_STORE_ON_ENTER");
369 trace.set(C::execution_parent_l2_gas_used, 3, 201);
371 "PARENT_L2_GAS_USED_STORE_ON_ENTER");
372 trace.set(C::execution_parent_da_gas_used, 3, 301);
374 "PARENT_DA_GAS_USED_STORE_ON_ENTER");
375
376 // Negative test: when no calls have been made, limits, parent limits, and parent used shouldn't change
377 trace.set(C::execution_l2_gas_limit, 2, 1001);
379 "L2_GAS_LIMIT_NEXT_ROW");
380 trace.set(C::execution_da_gas_limit, 2, 2001);
382 "DA_GAS_LIMIT_NEXT_ROW");
383
384 trace.set(C::execution_parent_l2_gas_limit, 2, 2001);
386 "PARENT_L2_GAS_LIMIT_NEXT_ROW");
387 trace.set(C::execution_parent_da_gas_limit, 2, 4001);
389 "PARENT_DA_GAS_LIMIT_NEXT_ROW");
390
391 trace.set(C::execution_parent_l2_gas_used, 2, 501);
393 "PARENT_L2_GAS_USED_NEXT_ROW");
394 trace.set(C::execution_parent_da_gas_used, 2, 1501);
396 "PARENT_DA_GAS_USED_NEXT_ROW");
397}
398
399TEST(ContextConstrainingTest, GasUsedContinuity)
400{
401 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } },
402 {
403 // First Row of execution
404 { C::execution_sel, 1 },
405 { C::execution_l2_gas_used, 100 },
406 { C::execution_da_gas_used, 200 },
407 },
408 {
409 // CALL
410 { C::execution_sel, 1 },
411 { C::execution_sel_enter_call, 1 },
412 { C::execution_l2_gas_used, 110 },
413 { C::execution_da_gas_used, 200 },
414 { C::execution_prev_l2_gas_used, 100 },
415 { C::execution_prev_da_gas_used, 200 },
416 },
417 {
418 // Return
419 { C::execution_sel, 1 },
420 { C::execution_sel_exit_call, 1 },
421 { C::execution_nested_exit_call, 1 },
422 { C::execution_l2_gas_used, 50 },
423 { C::execution_da_gas_used, 60 },
424 { C::execution_parent_l2_gas_used, 110 },
425 { C::execution_parent_da_gas_used, 200 },
426 { C::execution_prev_l2_gas_used, 0 },
427 { C::execution_prev_da_gas_used, 0 },
428 },
429 {
430 // After return
431 { C::execution_sel, 1 },
432 { C::execution_l2_gas_used, 170 },
433 { C::execution_da_gas_used, 260 },
434 { C::execution_prev_l2_gas_used, 160 }, // 110 + 50
435 { C::execution_prev_da_gas_used, 260 }, // 200 + 60
436 },
437 {
438 { C::execution_sel, 0 },
439 { C::execution_last, 1 },
440 } });
441
442 check_relation<context>(trace,
449
450 // Negative test: after return, ingest a wrong value
451 trace.set(C::execution_prev_l2_gas_used, 4, 110);
452
454 "L2_GAS_USED_INGEST_AFTER_EXIT");
455
456 trace.set(C::execution_prev_da_gas_used, 4, 60);
458 "DA_GAS_USED_INGEST_AFTER_EXIT");
459
460 // Negative test: inside a nested call, start with non-zero gas used
461 trace.set(C::execution_prev_l2_gas_used, 3, 110);
463 "L2_GAS_USED_ZERO_AFTER_CALL");
464
465 trace.set(C::execution_prev_da_gas_used, 3, 200);
467 "DA_GAS_USED_ZERO_AFTER_CALL");
468
469 // Negative test: when no calls are made, prev gas used should be gas used of the previous row
470 trace.set(C::execution_prev_l2_gas_used, 2, 0);
472 "L2_GAS_USED_CONTINUITY");
473
474 trace.set(C::execution_prev_da_gas_used, 2, 0);
476 "DA_GAS_USED_CONTINUITY");
477}
478
479TEST(ContextConstrainingTest, TreeStateContinuity)
480{
481 TestTraceContainer trace({ { { C::precomputed_first_row, 1 } },
482 {
483 // First Row of execution
484 { C::execution_sel, 1 },
485 { C::execution_note_hash_tree_root, 10 },
486 { C::execution_note_hash_tree_size, 9 },
487 { C::execution_num_note_hashes_emitted, 8 },
488 { C::execution_nullifier_tree_root, 7 },
489 { C::execution_nullifier_tree_size, 6 },
490 { C::execution_num_nullifiers_emitted, 5 },
491 { C::execution_public_data_tree_root, 4 },
492 { C::execution_public_data_tree_size, 3 },
493 { C::execution_written_public_data_slots_tree_root, 2 },
494 { C::execution_written_public_data_slots_tree_size, 1 },
495 { C::execution_l1_l2_tree_root, 27 },
496 { C::execution_retrieved_bytecodes_tree_root, 26 },
497 { C::execution_retrieved_bytecodes_tree_size, 25 },
498 },
499 {
500 // Second row of execution
501 { C::execution_sel, 1 },
502 { C::execution_prev_note_hash_tree_root, 10 },
503 { C::execution_prev_note_hash_tree_size, 9 },
504 { C::execution_prev_num_note_hashes_emitted, 8 },
505 { C::execution_prev_nullifier_tree_root, 7 },
506 { C::execution_prev_nullifier_tree_size, 6 },
507 { C::execution_prev_num_nullifiers_emitted, 5 },
508 { C::execution_prev_public_data_tree_root, 4 },
509 { C::execution_prev_public_data_tree_size, 3 },
510 { C::execution_prev_written_public_data_slots_tree_root, 2 },
511 { C::execution_prev_written_public_data_slots_tree_size, 1 },
512 { C::execution_l1_l2_tree_root, 27 },
513 { C::execution_prev_retrieved_bytecodes_tree_root, 26 },
514 { C::execution_prev_retrieved_bytecodes_tree_size, 25 },
515 { C::execution_enqueued_call_end, 1 },
516 { C::execution_sel_exit_call, 1 },
517 },
518 {
519 // Third row of execution
520 { C::execution_sel, 1 },
521 { C::execution_prev_note_hash_tree_root, 100 },
522 { C::execution_prev_note_hash_tree_size, 90 },
523 { C::execution_prev_num_note_hashes_emitted, 80 },
524 { C::execution_prev_nullifier_tree_root, 70 },
525 { C::execution_prev_nullifier_tree_size, 60 },
526 { C::execution_prev_num_nullifiers_emitted, 50 },
527 { C::execution_prev_public_data_tree_root, 40 },
528 { C::execution_prev_public_data_tree_size, 30 },
529 { C::execution_prev_written_public_data_slots_tree_root, 20 },
530 { C::execution_prev_written_public_data_slots_tree_size, 10 },
531 { C::execution_l1_l2_tree_root, 27 },
532 { C::execution_prev_retrieved_bytecodes_tree_root, 260 },
533 { C::execution_prev_retrieved_bytecodes_tree_size, 250 },
534 } });
535
536 check_relation<context>(trace,
550
551 // Negative test: change note hash tree root
552 trace.set(C::execution_prev_note_hash_tree_root, 2, 100);
554 "NOTE_HASH_TREE_ROOT_CONTINUITY");
555
556 // Negative test: change note hash tree size
557 trace.set(C::execution_prev_note_hash_tree_size, 2, 100);
559 "NOTE_HASH_TREE_SIZE_CONTINUITY");
560
561 // Negative test: change num note hashes emitted
562 trace.set(C::execution_prev_num_note_hashes_emitted, 2, 10);
564 "NUM_NOTE_HASHES_EMITTED_CONTINUITY");
565
566 // Negative test: change nullifier tree root
567 trace.set(C::execution_prev_nullifier_tree_root, 2, 100);
569 "NULLIFIER_TREE_ROOT_CONTINUITY");
570
571 // Negative test: change nullifier tree size
572 trace.set(C::execution_prev_nullifier_tree_size, 2, 100);
574 "NULLIFIER_TREE_SIZE_CONTINUITY");
575
576 // Negative test: change num nullifiers emitted
577 trace.set(C::execution_prev_num_nullifiers_emitted, 2, 100);
579 "NUM_NULLIFIERS_EMITTED_CONTINUITY");
580
581 // Negative test: change public data tree root
582 trace.set(C::execution_prev_public_data_tree_root, 2, 100);
584 "PUBLIC_DATA_TREE_ROOT_CONTINUITY");
585
586 // Negative test: change public data tree size
587 trace.set(C::execution_prev_public_data_tree_size, 2, 100);
589 "PUBLIC_DATA_TREE_SIZE_CONTINUITY");
590
591 // Negative test: change written public data slots tree root
592 trace.set(C::execution_prev_written_public_data_slots_tree_root, 2, 100);
595 "WRITTEN_PUBLIC_DATA_SLOTS_TREE_ROOT_CONTINUITY");
596
597 // Negative test: change written public data slots tree size
598 trace.set(C::execution_prev_written_public_data_slots_tree_size, 2, 100);
601 "WRITTEN_PUBLIC_DATA_SLOTS_TREE_SIZE_CONTINUITY");
602
603 // Negative test: change l1 l2 tree root
604 trace.set(C::execution_l1_l2_tree_root, 2, 100);
606 "L1_L2_TREE_ROOT_CONTINUITY");
607
608 // Negative test: change retrieved bytecodes tree root
609 trace.set(C::execution_prev_retrieved_bytecodes_tree_root, 2, 100);
611 "RETRIEVED_BYTECODES_TREE_ROOT_CONTINUITY");
612
613 // Negative test: change retrieved bytecodes tree size
614 trace.set(C::execution_prev_retrieved_bytecodes_tree_size, 2, 100);
616 "RETRIEVED_BYTECODES_TREE_SIZE_CONTINUITY");
617}
618
619TEST(ContextConstrainingTest, SideEffectStateContinuity)
620{
621 TestTraceContainer trace({
622 { { C::precomputed_first_row, 1 } },
623 {
624 // First Row of execution
625 { C::execution_sel, 1 },
626 { C::execution_num_unencrypted_log_fields, 10 },
627 { C::execution_num_l2_to_l1_messages, 11 },
628 },
629 {
630 // Second row of execution
631 { C::execution_sel, 1 },
632 { C::execution_prev_num_unencrypted_log_fields, 10 },
633 { C::execution_prev_num_l2_to_l1_messages, 11 },
634 },
635 });
636
637 check_relation<context>(
639
640 // Negative test: change num unencrypted logs
641 trace.set(C::execution_prev_num_unencrypted_log_fields, 2, 100);
643 "NUM_UNENCRYPTED_LOGS_CONTINUITY");
644
645 // Negative test: change num l2 to l1 messages
646 trace.set(C::execution_prev_num_l2_to_l1_messages, 2, 100);
648 "NUM_L2_TO_L1_MESSAGES_CONTINUITY");
649}
650
651TEST(ContextConstrainingTest, BytecodeIdPropagation)
652{
653 TestTraceContainer trace({ // First row - setup
654 {
655 { C::precomputed_first_row, 1 },
656 { C::execution_sel, 1 },
657 { C::execution_context_id, 1 },
658 { C::execution_next_context_id, 1 },
659 { C::execution_bytecode_id, 42 }, // Initial bytecode_id
660 },
661 // Second row - should propagate bytecode_id
662 {
663 { C::execution_sel, 1 },
664 { C::execution_context_id, 1 },
665 { C::execution_next_context_id, 1 },
666 { C::execution_bytecode_id, 42 }, // Same bytecode_id (propagated)
667 } });
668
669 check_relation<context>(trace);
670 // mutate the bytecode_id and confirm that it is a violation
671 trace.set(C::execution_bytecode_id, 1, 99);
673 "BYTECODE_ID_NEXT_ROW"); // Should fail constraint
674}
675
676TEST(ContextConstrainingTest, IsStaticRegularCallFromNonStaticContext)
677{
678 // Non-static context making a regular CALL - should remain non-static
679 TestTraceContainer trace({
680 { { C::precomputed_first_row, 1 } },
681 {
682 { C::execution_sel, 1 },
683 { C::execution_context_id, 1 },
684 { C::execution_next_context_id, 2 },
685 { C::execution_is_static, 0 }, // Non-static context
686 { C::execution_sel_enter_call, 1 },
687 { C::execution_sel_execute_call, 1 }, // Regular CALL
688 { C::execution_sel_execute_static_call, 0 },
689 },
690 {
691 { C::execution_sel, 1 },
692 { C::execution_context_id, 2 },
693 { C::execution_next_context_id, 3 },
694 { C::execution_is_static, 0 }, // Should remain non-static
695 },
696 });
697 check_relation<context>(
699
700 // Negative test: change is_static
701 // regular call from non-static context cannot become static
702 trace.set(C::execution_is_static, 2, 1);
704 "IS_STATIC_IF_STATIC_CALL");
705
706 // reset is_static
707 trace.set(C::execution_is_static, 2, 0);
708}
709
710TEST(ContextConstrainingTest, IsStaticStaticCallFromNonStaticContext)
711{
712 // Non-static context making a STATICCALL - should become static
713 TestTraceContainer trace({
714 { { C::precomputed_first_row, 1 } },
715 {
716 { C::execution_sel, 1 },
717 { C::execution_context_id, 1 },
718 { C::execution_next_context_id, 2 },
719 { C::execution_is_static, 0 }, // Non-static context
720 { C::execution_sel_enter_call, 1 },
721 { C::execution_sel_execute_call, 0 },
722 { C::execution_sel_execute_static_call, 1 }, // STATICCALL
723 },
724 {
725 { C::execution_sel, 1 },
726 { C::execution_context_id, 2 },
727 { C::execution_next_context_id, 3 },
728 { C::execution_is_static, 1 }, // Should become static
729 },
730 });
731 check_relation<context>(
733
734 // Negative test: change is_static
735 // static call from non-static context MUST become static
736 trace.set(C::execution_is_static, 2, 0);
738 "IS_STATIC_IF_STATIC_CALL");
739
740 // reset is_static
741 trace.set(C::execution_is_static, 2, 1);
742}
743
744TEST(ContextConstrainingTest, IsStaticCallFromStaticContext)
745{
746 // Static context making any call - must remain static
747 TestTraceContainer trace({
748 { { C::precomputed_first_row, 1 } },
749 {
750 { C::execution_sel, 1 },
751 { C::execution_context_id, 1 },
752 { C::execution_next_context_id, 2 },
753 { C::execution_is_static, 1 }, // Static context
754 { C::execution_sel_enter_call, 1 },
755 { C::execution_sel_execute_call, 1 }, // Regular CALL
756 { C::execution_sel_execute_static_call, 0 },
757 },
758 {
759 { C::execution_sel, 1 },
760 { C::execution_context_id, 2 },
761 { C::execution_next_context_id, 3 },
762 { C::execution_is_static, 1 }, // Must remain static
763 },
764 });
765 check_relation<context>(
767
768 // Negative test: change is_static
769 // static call from static context MUST remain static
770 trace.set(C::execution_is_static, 2, 0);
772 "IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT");
773
774 // reset is_static
775 trace.set(C::execution_is_static, 2, 1);
776}
777
778TEST(ContextConstrainingTest, IsStaticPropagationWithoutCalls)
779{
780 // is_static propagation without calls
781 TestTraceContainer trace({
782 { { C::precomputed_first_row, 1 } },
783 {
784 { C::execution_sel, 1 },
785 { C::execution_context_id, 1 },
786 { C::execution_next_context_id, 1 },
787 { C::execution_is_static, 1 }, // Static context
788 },
789 {
790 { C::execution_sel, 1 },
791 { C::execution_context_id, 1 },
792 { C::execution_next_context_id, 1 },
793 { C::execution_is_static, 1 }, // Should propagate
794 },
795 });
796 check_relation<context>(trace, context::SR_IS_STATIC_NEXT_ROW);
797
798 // Negative test: change is_static
799 // staticness must propagate without calls
800 trace.set(C::execution_is_static, 2, 0);
801 EXPECT_THROW_WITH_MESSAGE(check_relation<context>(trace, context::SR_IS_STATIC_NEXT_ROW), "IS_STATIC_NEXT_ROW");
802
803 // reset is_static
804 trace.set(C::execution_is_static, 2, 1);
805}
806
807TEST(ContextConstrainingTest, ContextIdPropagation)
808{
809 TestTraceContainer trace({
810 {
811 { C::precomputed_first_row, 1 },
812 },
813 {
814 { C::execution_sel, 1 },
815 { C::execution_enqueued_call_start, 1 },
816 { C::execution_context_id, 1 },
817 { C::execution_next_context_id, 2 },
818 { C::execution_sel_enter_call, 1 },
819 },
820 {
821 { C::execution_sel, 1 },
822 { C::execution_context_id, 2 },
823 { C::execution_next_context_id, 3 },
824 { C::execution_sel_exit_call, 1 },
825 { C::execution_nested_exit_call, 1 },
826 { C::execution_parent_id, 1 },
827 },
828 {
829 { C::execution_sel, 1 },
830 { C::execution_context_id, 1 },
831 { C::execution_next_context_id, 3 },
832 },
833 {
834 { C::execution_sel, 1 },
835 { C::execution_context_id, 1 },
836 { C::execution_next_context_id, 3 },
837 },
838 });
839 check_relation<context>(trace,
845
846 // Negative test: next context id should be context id + 1 on enqueued call start
847 trace.set(C::execution_next_context_id, 1, 3);
849 "ENQUEUED_CALL_START_NEXT_CTX_ID");
850 trace.set(C::execution_next_context_id, 1, 2);
851
852 // Negative test: next context id should increase on external call
853 trace.set(C::execution_next_context_id, 2, 2);
854 EXPECT_THROW_WITH_MESSAGE(check_relation<context>(trace, context::SR_INCR_NEXT_CONTEXT_ID), "INCR_NEXT_CONTEXT_ID");
855 trace.set(C::execution_next_context_id, 2, 3);
856
857 // Negative test: next context id should be propagated
858 trace.set(C::execution_next_context_id, 4, 4);
859 EXPECT_THROW_WITH_MESSAGE(check_relation<context>(trace, context::SR_INCR_NEXT_CONTEXT_ID), "INCR_NEXT_CONTEXT_ID");
860 trace.set(C::execution_next_context_id, 4, 3);
861
862 // Negative test: context id should be propagated
863 trace.set(C::execution_context_id, 4, 2);
864 EXPECT_THROW_WITH_MESSAGE(check_relation<context>(trace, context::SR_CONTEXT_ID_NEXT_ROW), "CONTEXT_ID_NEXT_ROW");
865 trace.set(C::execution_context_id, 4, 1);
866
867 // Negative test: context id should be next context id when entering call
868 trace.set(C::execution_context_id, 2, 1);
869 EXPECT_THROW_WITH_MESSAGE(check_relation<context>(trace, context::SR_CONTEXT_ID_EXT_CALL), "CONTEXT_ID_EXT_CALL");
870 trace.set(C::execution_context_id, 2, 2);
871
872 // Negative test: context id should be restored on exit
873 trace.set(C::execution_context_id, 3, 2);
875 "CONTEXT_ID_NESTED_EXIT");
876 trace.set(C::execution_context_id, 3, 1);
877}
878
879} // namespace
880} // namespace bb::avm2::constraining
static constexpr size_t SR_PARENT_DA_GAS_USED_NEXT_ROW
Definition context.hpp:81
static constexpr size_t SR_INCR_NEXT_CONTEXT_ID
Definition context.hpp:43
static constexpr size_t SR_L1_L2_TREE_ROOT_CONTINUITY
Definition context.hpp:101
static constexpr size_t SR_DA_GAS_USED_INGEST_AFTER_EXIT
Definition context.hpp:90
static constexpr size_t SR_L2_GAS_USED_ZERO_AFTER_CALL
Definition context.hpp:86
static constexpr size_t SR_PARENT_L2_GAS_LIMIT_STORE_ON_ENTER
Definition context.hpp:76
static constexpr size_t SR_PARENT_L2_GAS_USED_STORE_ON_ENTER
Definition context.hpp:80
static constexpr size_t SR_NOTE_HASH_TREE_SIZE_CONTINUITY
Definition context.hpp:92
static constexpr size_t SR_IS_STATIC_IF_CALL_FROM_STATIC_CONTEXT
Definition context.hpp:56
static constexpr size_t SR_RETRIEVED_BYTECODES_TREE_ROOT_CONTINUITY
Definition context.hpp:83
static constexpr size_t SR_WRITTEN_PUBLIC_DATA_SLOTS_TREE_ROOT_CONTINUITY
Definition context.hpp:99
static constexpr size_t SR_L2_GAS_LIMIT_RESTORE_ON_EXIT
Definition context.hpp:72
static constexpr size_t SR_DA_GAS_USED_CONTINUITY
Definition context.hpp:88
static constexpr size_t SR_L2_GAS_USED_INGEST_AFTER_EXIT
Definition context.hpp:87
static constexpr size_t SR_PUBLIC_DATA_TREE_SIZE_CONTINUITY
Definition context.hpp:98
static constexpr size_t SR_PARENT_DA_GAS_USED_STORE_ON_ENTER
Definition context.hpp:82
static constexpr size_t SR_NUM_NOTE_HASHES_EMITTED_CONTINUITY
Definition context.hpp:93
static constexpr size_t SR_PARENT_L2_GAS_LIMIT_NEXT_ROW
Definition context.hpp:75
static constexpr size_t SR_NULLIFIER_TREE_SIZE_CONTINUITY
Definition context.hpp:95
static constexpr size_t SR_CONTEXT_ID_EXT_CALL
Definition context.hpp:45
static constexpr size_t SR_DA_GAS_USED_ZERO_AFTER_CALL
Definition context.hpp:89
static constexpr size_t SR_NUM_L2_TO_L1_MESSAGES_CONTINUITY
Definition context.hpp:103
static constexpr size_t SR_ENQUEUED_CALL_START_NEXT_CTX_ID
Definition context.hpp:42
static constexpr size_t SR_PARENT_DA_GAS_LIMIT_STORE_ON_ENTER
Definition context.hpp:78
static constexpr size_t SR_NOTE_HASH_TREE_ROOT_CONTINUITY
Definition context.hpp:91
static constexpr size_t SR_CONTEXT_ID_NESTED_EXIT
Definition context.hpp:46
static constexpr size_t SR_WRITTEN_PUBLIC_DATA_SLOTS_TREE_SIZE_CONTINUITY
Definition context.hpp:100
static constexpr size_t SR_BYTECODE_ID_NEXT_ROW
Definition context.hpp:52
static constexpr size_t SR_CONTEXT_ID_NEXT_ROW
Definition context.hpp:44
static constexpr size_t SR_RETRIEVED_BYTECODES_TREE_SIZE_CONTINUITY
Definition context.hpp:84
static constexpr size_t SR_PUBLIC_DATA_TREE_ROOT_CONTINUITY
Definition context.hpp:97
static constexpr size_t SR_NUM_NULLIFIERS_EMITTED_CONTINUITY
Definition context.hpp:96
static constexpr size_t SR_L2_GAS_LIMIT_NEXT_ROW
Definition context.hpp:71
static constexpr size_t SR_NUM_UNENCRYPTED_LOGS_CONTINUITY
Definition context.hpp:102
static constexpr size_t SR_DA_GAS_LIMIT_RESTORE_ON_EXIT
Definition context.hpp:74
static constexpr size_t SR_DA_GAS_LIMIT_NEXT_ROW
Definition context.hpp:73
static constexpr size_t SR_PARENT_DA_GAS_LIMIT_NEXT_ROW
Definition context.hpp:77
static constexpr size_t SR_IS_STATIC_IF_STATIC_CALL
Definition context.hpp:55
static constexpr size_t SR_IS_STATIC_NEXT_ROW
Definition context.hpp:54
static constexpr size_t SR_NULLIFIER_TREE_ROOT_CONTINUITY
Definition context.hpp:94
static constexpr size_t SR_PARENT_L2_GAS_USED_NEXT_ROW
Definition context.hpp:79
static constexpr size_t SR_L2_GAS_USED_CONTINUITY
Definition context.hpp:85
void set(Column col, uint32_t row, const FF &value)
TestTraceContainer trace
StrictMock< MockContext > context
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:402
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
lookup_settings< lookup_context_ctx_stack_rollback_settings_ > lookup_context_ctx_stack_rollback_settings
lookup_settings< lookup_context_ctx_stack_return_settings_ > lookup_context_ctx_stack_return_settings
lookup_settings< lookup_context_ctx_stack_call_settings_ > lookup_context_ctx_stack_call_settings
typename Flavor::FF FF