Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
execution.test.cpp
Go to the documentation of this file.
2
3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
5
6#include <memory>
7
41
42namespace bb::avm2::simulation {
43namespace {
44
45using ::testing::_;
46using ::testing::NiceMock;
47using ::testing::Return;
48using ::testing::ReturnRef;
49using ::testing::StrictMock;
50using ::testing::Throw;
51
52// TODO(fcarreiro): This is a hack to get the gas tracker for testing.
53class TestingExecution : public Execution {
54 public:
55 using Execution::Execution;
56
57 void set_gas_tracker(GasTrackerInterface& gas_tracker) { this->testing_gas_tracker = &gas_tracker; }
58
59 GasTrackerInterface& get_gas_tracker() override { return *testing_gas_tracker; }
60
61 private:
62 GasTrackerInterface* testing_gas_tracker;
63};
64
65class ExecutionSimulationTest : public ::testing::Test {
66 protected:
67 ExecutionSimulationTest()
68 {
69 ON_CALL(context, get_memory).WillByDefault(ReturnRef(memory));
70 ON_CALL(context, get_bytecode_manager).WillByDefault(ReturnRef(bytecode_manager));
71 execution.set_gas_tracker(gas_tracker);
72 }
73
74 StrictMock<MockAlu> alu;
75 StrictMock<MockBitwise> bitwise;
76 StrictMock<MockMemory> memory;
77 StrictMock<MockExecutionComponentsProvider> execution_components;
78 StrictMock<MockContext> context;
79 StrictMock<MockDataCopy> data_copy;
80 StrictMock<MockInternalCallStackManager> internal_call_stack_manager;
81 StrictMock<MockKeccakF1600> keccakf1600;
82 StrictMock<MockGetContractInstance> get_contract_instance;
83 EventEmitter<ExecutionEvent> execution_event_emitter;
84 EventEmitter<ContextStackEvent> context_stack_event_emitter;
85 InstructionInfoDB instruction_info_db; // Using the real thing.
86 StrictMock<MockContextProvider> context_provider;
87 StrictMock<MockExecutionIdManager> execution_id_manager;
88 StrictMock<MockGasTracker> gas_tracker;
89 StrictMock<MockHighLevelMerkleDB> merkle_db;
90 StrictMock<MockGreaterThan> greater_than;
91 StrictMock<MockPoseidon2> poseidon2;
92 StrictMock<MockEcc> ecc;
93 StrictMock<MockToRadix> to_radix;
94 StrictMock<MockEmitUnencryptedLog> emit_unencrypted_log;
95 StrictMock<MockBytecodeManager> bytecode_manager;
96 StrictMock<MockSha256> sha256;
97 TestingExecution execution = TestingExecution(alu,
98 bitwise,
100 poseidon2,
101 ecc,
102 to_radix,
103 sha256,
104 execution_components,
108 execution_event_emitter,
109 context_stack_event_emitter,
110 keccakf1600,
111 greater_than,
112 get_contract_instance,
113 emit_unencrypted_log,
114 merkle_db);
115};
116
117// NOTE: MemoryAddresses x, y used in the below tests like: execution.fn(context, x, y, ..) are just unchecked arbitrary
118// addresses. We test the MemoryValues and destination addresses.
119
120TEST_F(ExecutionSimulationTest, Add)
121{
122 MemoryValue a = MemoryValue::from<uint32_t>(4);
123 MemoryValue b = MemoryValue::from<uint32_t>(5);
124
125 EXPECT_CALL(context, get_memory);
126 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
127 EXPECT_CALL(alu, add(a, b)).WillOnce(Return(MemoryValue::from<uint32_t>(9)));
128 EXPECT_CALL(memory, set(6, MemoryValue::from<uint32_t>(9)));
129 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
130
131 execution.add(context, 4, 5, 6);
132}
133
134TEST_F(ExecutionSimulationTest, Sub)
135{
136 MemoryValue a = MemoryValue::from<uint64_t>(5);
137 MemoryValue b = MemoryValue::from<uint64_t>(3);
138
139 EXPECT_CALL(context, get_memory);
140 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
141 EXPECT_CALL(alu, sub(a, b)).WillOnce(Return(MemoryValue::from<uint64_t>(2)));
142 EXPECT_CALL(memory, set(3, MemoryValue::from<uint64_t>(2)));
143 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
144
145 execution.sub(context, 1, 2, 3);
146}
147
148TEST_F(ExecutionSimulationTest, Mul)
149{
151 auto a = MemoryValue::from<uint128_t>(max);
152 auto b = MemoryValue::from<uint128_t>(max - 3);
153
154 EXPECT_CALL(context, get_memory);
155 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
156 EXPECT_CALL(alu, mul(a, b)).WillOnce(Return(MemoryValue::from<uint128_t>(4)));
157 EXPECT_CALL(memory, set(3, MemoryValue::from<uint128_t>(4)));
158 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
159
160 execution.mul(context, 1, 2, 3);
161}
162
163TEST_F(ExecutionSimulationTest, Div)
164{
165 auto a = MemoryValue::from<uint128_t>(6);
166 auto b = MemoryValue::from<uint128_t>(3);
167
168 EXPECT_CALL(context, get_memory);
169 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
170 EXPECT_CALL(alu, div(a, b)).WillOnce(Return(MemoryValue::from<uint128_t>(2)));
171 EXPECT_CALL(memory, set(3, MemoryValue::from<uint128_t>(2)));
172 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
173
174 execution.div(context, 1, 2, 3);
175}
176
177TEST_F(ExecutionSimulationTest, FDiv)
178{
179 auto a = MemoryValue::from<FF>(FF::modulus - 4);
180 auto b = MemoryValue::from<FF>(2);
181
182 EXPECT_CALL(context, get_memory);
183 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
184 EXPECT_CALL(alu, fdiv(a, b)).WillOnce(Return(MemoryValue::from<FF>(FF::modulus - 2)));
185 EXPECT_CALL(memory, set(3, MemoryValue::from<FF>(FF::modulus - 2)));
186 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
187
188 execution.fdiv(context, 1, 2, 3);
189}
190
191TEST_F(ExecutionSimulationTest, Shl)
192{
193 auto a = MemoryValue::from<uint32_t>(64);
194 auto b = MemoryValue::from<uint32_t>(2);
195
196 EXPECT_CALL(context, get_memory);
197 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
198 EXPECT_CALL(alu, shl(a, b)).WillOnce(Return(MemoryValue::from<uint32_t>(256)));
199 EXPECT_CALL(memory, set(3, MemoryValue::from<uint32_t>(256)));
200 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
201
202 execution.shl(context, 1, 2, 3);
203}
204
205TEST_F(ExecutionSimulationTest, Shr)
206{
207 auto a = MemoryValue::from<uint64_t>(64);
208 auto b = MemoryValue::from<uint64_t>(2);
209
210 EXPECT_CALL(context, get_memory);
211 EXPECT_CALL(memory, get).Times(2).WillOnce(ReturnRef(a)).WillOnce(ReturnRef(b));
212 EXPECT_CALL(alu, shr(a, b)).WillOnce(Return(MemoryValue::from<uint64_t>(16)));
213 EXPECT_CALL(memory, set(3, MemoryValue::from<uint64_t>(16)));
214 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
215
216 execution.shr(context, 1, 2, 3);
217}
218
219// TODO(MW): Add alu tests here for other ops
220
221TEST_F(ExecutionSimulationTest, Call)
222{
223 FF zero = 0;
224 AztecAddress parent_address = 0xdeadbeef;
225 AztecAddress nested_address = 0xc0ffee;
226 MemoryValue nested_address_value = MemoryValue::from<FF>(nested_address);
227 MemoryValue l2_gas_allocated = MemoryValue::from<uint32_t>(6);
228 MemoryValue da_gas_allocated = MemoryValue::from<uint32_t>(7);
229 MemoryValue cd_size = MemoryValue::from<uint32_t>(8);
230 AppendOnlyTreeSnapshot written_public_data_slots_tree_snapshot = AppendOnlyTreeSnapshot{
231 .root = 0x12345678,
232 .nextAvailableLeafIndex = 10,
233 };
234 TreeStates tree_states = TreeStates {
235 .noteHashTree = {
236 .tree = {
237 .root = 10,
238 .nextAvailableLeafIndex = 9,
239 },
240 .counter = 8,
241 },
242 .nullifierTree = {
243 .tree = {
244 .root = 7,
245 .nextAvailableLeafIndex = 6,
246 },
247 .counter = 5,
248 },
249 .l1ToL2MessageTree = {
250 .tree = {
251 .root = 4,
252 .nextAvailableLeafIndex = 3,
253 },
254 .counter = 0,
255 },
256 .publicDataTree = {
257 .tree = {
258 .root = 2,
259 .nextAvailableLeafIndex = 1,
260 },
261 .counter = 1,
262 }
263 };
264
265 SideEffectStates side_effect_states = SideEffectStates{ .numUnencryptedLogs = 1, .numL2ToL1Messages = 2 };
266
267 EXPECT_CALL(gas_tracker, compute_gas_limit_for_call(Gas{ 6, 7 })).WillOnce(Return(Gas{ 2, 3 }));
268 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
269
270 // Context snapshotting
271 EXPECT_CALL(context, get_context_id);
272 EXPECT_CALL(context, get_parent_id);
273 EXPECT_CALL(context, get_bytecode_manager).WillOnce(ReturnRef(bytecode_manager));
274 EXPECT_CALL(bytecode_manager, try_get_bytecode_id);
275 EXPECT_CALL(context, get_next_pc);
276 EXPECT_CALL(context, get_is_static).WillRepeatedly(Return(false));
277 EXPECT_CALL(context, get_msg_sender).WillOnce(ReturnRef(parent_address));
278 EXPECT_CALL(context, get_transaction_fee).WillOnce(ReturnRef(zero));
279 EXPECT_CALL(context, get_parent_cd_addr);
280 EXPECT_CALL(context, get_parent_cd_size);
281 EXPECT_CALL(context, get_parent_gas_used);
282 EXPECT_CALL(context, get_parent_gas_limit);
283 EXPECT_CALL(context, get_written_public_data_slots_tree_snapshot)
284 .WillOnce(Return(written_public_data_slots_tree_snapshot));
285 EXPECT_CALL(context, get_side_effect_states).WillRepeatedly(ReturnRef(side_effect_states));
286
287 EXPECT_CALL(context, get_phase).WillOnce(Return(TransactionPhase::APP_LOGIC));
288
289 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_states));
290
291 EXPECT_CALL(context, get_memory);
292 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(parent_address));
293 EXPECT_CALL(memory, get(1)).WillOnce(ReturnRef(l2_gas_allocated)); // l2_gas_offset
294 EXPECT_CALL(memory, get(2)).WillOnce(ReturnRef(da_gas_allocated)); // da_gas_offset
295 EXPECT_CALL(memory, get(3)).WillOnce(ReturnRef(nested_address_value)); // contract_address
296 EXPECT_CALL(memory, get(4)).WillOnce(ReturnRef(cd_size)); // cd_size
297
298 auto nested_context = std::make_unique<NiceMock<MockContext>>();
299 ON_CALL(*nested_context, halted())
300 .WillByDefault(Return(true)); // We just want the recursive call to return immediately.
301
302 EXPECT_CALL(context_provider,
303 make_nested_context(nested_address,
304 parent_address,
305 _,
306 _,
307 _,
308 _,
309 _,
310 Gas{ 2, 3 },
311 side_effect_states,
313 .WillOnce(Return(std::move(nested_context)));
314
315 execution.call(context,
316 /*l2_gas_offset=*/1,
317 /*da_gas_offset=*/2,
318 /*addr=*/3,
319 /*cd_size_offset=*/4,
320 /*cd_offset=*/5);
321}
322
323// Test staticness propagation for external calls (CALL vs STATICCALL)
324TEST_F(ExecutionSimulationTest, ExternalCallStaticnessPropagation)
325{
326 // Common test data setup
327 FF zero = 0;
328 AztecAddress parent_address = 0xdeadbeef;
329 AztecAddress nested_address = 0xc0ffee;
330 MemoryValue nested_address_value = MemoryValue::from<FF>(nested_address);
331 MemoryValue l2_gas_allocated = MemoryValue::from<uint32_t>(6);
332 MemoryValue da_gas_allocated = MemoryValue::from<uint32_t>(7);
333 MemoryValue cd_size = MemoryValue::from<uint32_t>(8);
334 AppendOnlyTreeSnapshot written_public_data_slots_tree_snapshot = AppendOnlyTreeSnapshot{
335 .root = 0x12345678,
336 .nextAvailableLeafIndex = 10,
337 };
338 TreeStates tree_states =
339 TreeStates{ .noteHashTree = { .tree = { .root = 10, .nextAvailableLeafIndex = 9 }, .counter = 8 },
340 .nullifierTree = { .tree = { .root = 7, .nextAvailableLeafIndex = 6 }, .counter = 5 },
341 .l1ToL2MessageTree = { .tree = { .root = 4, .nextAvailableLeafIndex = 3 }, .counter = 0 },
342 .publicDataTree = { .tree = { .root = 2, .nextAvailableLeafIndex = 1 }, .counter = 1 } };
343 SideEffectStates side_effect_states = SideEffectStates{ .numUnencryptedLogs = 1, .numL2ToL1Messages = 2 };
344
345 auto setup_context_expectations = [&](bool parent_is_static) {
346 EXPECT_CALL(gas_tracker, compute_gas_limit_for_call(Gas{ 6, 7 })).WillOnce(Return(Gas{ 2, 3 }));
347 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
348 EXPECT_CALL(context, get_context_id);
349 EXPECT_CALL(context, get_parent_id);
350 EXPECT_CALL(context, get_bytecode_manager).WillOnce(ReturnRef(bytecode_manager));
351 EXPECT_CALL(bytecode_manager, try_get_bytecode_id);
352 EXPECT_CALL(context, get_next_pc);
353 EXPECT_CALL(context, get_is_static).WillRepeatedly(Return(parent_is_static));
354 EXPECT_CALL(context, get_msg_sender).WillOnce(ReturnRef(parent_address));
355 EXPECT_CALL(context, get_transaction_fee).WillOnce(ReturnRef(zero));
356 EXPECT_CALL(context, get_parent_cd_addr);
357 EXPECT_CALL(context, get_parent_cd_size);
358 EXPECT_CALL(context, get_parent_gas_used);
359 EXPECT_CALL(context, get_parent_gas_limit);
360 EXPECT_CALL(context, get_written_public_data_slots_tree_snapshot)
361 .WillOnce(Return(written_public_data_slots_tree_snapshot));
362 EXPECT_CALL(context, get_side_effect_states).WillRepeatedly(ReturnRef(side_effect_states));
363 EXPECT_CALL(context, get_phase).WillOnce(Return(TransactionPhase::APP_LOGIC));
364 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_states));
365 EXPECT_CALL(context, get_memory);
366 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(parent_address));
367 EXPECT_CALL(memory, get(1)).WillOnce(ReturnRef(l2_gas_allocated));
368 EXPECT_CALL(memory, get(2)).WillOnce(ReturnRef(da_gas_allocated));
369 EXPECT_CALL(memory, get(3)).WillOnce(ReturnRef(nested_address_value));
370 EXPECT_CALL(memory, get(4)).WillOnce(ReturnRef(cd_size));
371 };
372
373 auto create_nested_context = []() {
375 ON_CALL(*nested, halted()).WillByDefault(Return(true));
376 return nested;
377 };
378
379 // Test Case 1: Non-static context + CALL -> nested context is non-static
380 setup_context_expectations(false);
381 EXPECT_CALL(context_provider,
382 make_nested_context(nested_address,
383 parent_address,
384 _,
385 _,
386 _,
387 _,
388 /*is_static=*/false,
389 Gas{ 2, 3 },
390 side_effect_states,
392 .WillOnce(Return(create_nested_context()));
393 execution.call(context, 1, 2, 3, 4, 5);
394
395 // Test Case 2: Non-static context + STATICCALL -> nested context is static
396 setup_context_expectations(false);
397 EXPECT_CALL(context_provider,
398 make_nested_context(nested_address,
399 parent_address,
400 _,
401 _,
402 _,
403 _,
404 /*is_static=*/true,
405 Gas{ 2, 3 },
406 side_effect_states,
408 .WillOnce(Return(create_nested_context()));
409 execution.static_call(context, 1, 2, 3, 4, 5);
410
411 // Test Case 3: Static context + CALL -> nested context remains static
412 setup_context_expectations(true);
413 EXPECT_CALL(context_provider,
414 make_nested_context(nested_address,
415 parent_address,
416 _,
417 _,
418 _,
419 _,
420 /*is_static=*/true,
421 Gas{ 2, 3 },
422 side_effect_states,
424 .WillOnce(Return(create_nested_context()));
425 execution.call(context, 1, 2, 3, 4, 5);
426
427 // Test Case 4: Static context + STATICCALL -> nested context remains static
428 setup_context_expectations(true);
429 EXPECT_CALL(context_provider,
430 make_nested_context(nested_address,
431 parent_address,
432 _,
433 _,
434 _,
435 _,
436 /*is_static=*/true,
437 Gas{ 2, 3 },
438 side_effect_states,
440 .WillOnce(Return(create_nested_context()));
441 execution.static_call(context, 1, 2, 3, 4, 5);
442}
443
444TEST_F(ExecutionSimulationTest, InternalCall)
445{
446 uint32_t return_pc = 500; // This is next pc that we should return to after the internal call.
447 uint32_t pc_loc = 11; // This is the pc of the internal call
448
449 NiceMock<MockInternalCallStackManager> internal_call_stack_manager;
450 ON_CALL(context, get_internal_call_stack_manager).WillByDefault(ReturnRef(internal_call_stack_manager));
451
452 // ==== Internal Call
453 // Get manager
454 EXPECT_CALL(context, get_internal_call_stack_manager());
455 // Store the return pc (i.e. context.get_next_pc())
456 EXPECT_CALL(context, get_next_pc()).WillOnce(Return(return_pc));
457 EXPECT_CALL(internal_call_stack_manager, push(return_pc));
458 // Set next pc to the parameter pc_loc
459 EXPECT_CALL(context, set_next_pc(pc_loc));
460 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
461
462 execution.internal_call(context, pc_loc);
463
464 // ==== Internal Return
465 // Get manager
466 EXPECT_CALL(context, get_internal_call_stack_manager());
467 // Pop the return pc from the stack
468 EXPECT_CALL(internal_call_stack_manager, pop()).WillOnce(Return(return_pc));
469 // Set the next pc to the return pc
470 EXPECT_CALL(context, set_next_pc(return_pc));
471 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
472
473 execution.internal_return(context);
474}
475
476TEST_F(ExecutionSimulationTest, GetEnvVarAddress)
477{
478 AztecAddress addr = 0xdeadbeef;
479 EXPECT_CALL(context, get_address).WillOnce(ReturnRef(addr));
480 EXPECT_CALL(context, get_memory);
481 EXPECT_CALL(memory, set(1, MemoryValue::from<FF>(addr)));
482 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
483
484 execution.get_env_var(context, 1, static_cast<uint8_t>(EnvironmentVariable::ADDRESS));
485}
486
487TEST_F(ExecutionSimulationTest, GetEnvVarChainId)
488{
489 GlobalVariables globals;
490 globals.chainId = 1;
491 EXPECT_CALL(context, get_globals).WillOnce(ReturnRef(globals));
492 EXPECT_CALL(context, get_memory);
493 EXPECT_CALL(memory, set(1, MemoryValue::from<FF>(1)));
494 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
495
496 execution.get_env_var(context, 1, static_cast<uint8_t>(EnvironmentVariable::CHAINID));
497}
498
499TEST_F(ExecutionSimulationTest, GetEnvVarIsStaticCall)
500{
501 EXPECT_CALL(context, get_is_static).WillOnce(Return(true));
502 EXPECT_CALL(context, get_memory);
503 EXPECT_CALL(memory, set(1, MemoryValue::from<uint1_t>(1)));
504 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
505
506 execution.get_env_var(context, 1, static_cast<uint8_t>(EnvironmentVariable::ISSTATICCALL));
507}
508
509TEST_F(ExecutionSimulationTest, GetEnvVarInvalidEnum)
510{
511 EXPECT_CALL(context, get_memory);
512 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
513
514 EXPECT_THROW(execution.get_env_var(context, 1, 255), std::runtime_error);
515}
516
517// Trivial test at the moment.
518// TODO: Attempt to have infra to call execution.execute() with a JUMP and a second instruction
519// and check the pc value for the second instruction is correct.
520TEST_F(ExecutionSimulationTest, Jump)
521{
522 EXPECT_CALL(context, set_next_pc(120));
523 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
524
525 execution.jump(context, 120);
526}
527
528TEST_F(ExecutionSimulationTest, SuccessCopyTrue)
529{
530 EXPECT_CALL(context, get_memory);
531 EXPECT_CALL(context, get_last_success).WillOnce(Return(true));
532 EXPECT_CALL(memory, set(10, MemoryValue::from<uint1_t>(1)));
533 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
534
535 execution.success_copy(context, 10);
536}
537
538TEST_F(ExecutionSimulationTest, SuccessCopyFalse)
539{
540 EXPECT_CALL(context, get_memory);
541 EXPECT_CALL(context, get_last_success).WillOnce(Return(false));
542 EXPECT_CALL(memory, set(10, MemoryValue::from<uint1_t>(0)));
543 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
544
545 execution.success_copy(context, 10);
546}
547
548TEST_F(ExecutionSimulationTest, RdSize)
549{
550 EXPECT_CALL(context, get_memory);
551 EXPECT_CALL(context, get_last_rd_size).WillOnce(Return(42));
552 EXPECT_CALL(memory, set(10, MemoryValue::from<uint32_t>(42)));
553 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
554
555 execution.rd_size(context, /*dst_addr=*/10);
556}
557
558TEST_F(ExecutionSimulationTest, DebugLogEnabled)
559{
560 // Setup test data
561 MemoryAddress message_offset = 100;
562 MemoryAddress fields_offset = 200;
563 MemoryAddress fields_size_offset = 300;
564 uint16_t message_size = 5;
565 bool is_debug_logging_enabled = true;
566
567 // Create test message data (ASCII characters)
568 MemoryValue message_data[] = {
569 MemoryValue::from<FF>('H'), // 'H'
570 MemoryValue::from<FF>('e'), // 'e'
571 MemoryValue::from<FF>('l'), // 'l'
572 MemoryValue::from<FF>('l'), // 'l'
573 MemoryValue::from<FF>('o'), // 'o'
574 };
575
576 // Create test fields data
577 MemoryValue field1 = MemoryValue::from<FF>(42);
578 MemoryValue field2 = MemoryValue::from<FF>(123);
579 MemoryValue fields_size = MemoryValue::from<uint32_t>(2);
580
581 EXPECT_CALL(context, get_memory);
582 EXPECT_CALL(memory, get(fields_size_offset)).WillOnce(ReturnRef(fields_size));
583 EXPECT_CALL(memory, get(message_offset + 0)).WillOnce(ReturnRef(message_data[0]));
584 EXPECT_CALL(memory, get(message_offset + 1)).WillOnce(ReturnRef(message_data[1]));
585 EXPECT_CALL(memory, get(message_offset + 2)).WillOnce(ReturnRef(message_data[2]));
586 EXPECT_CALL(memory, get(message_offset + 3)).WillOnce(ReturnRef(message_data[3]));
587 EXPECT_CALL(memory, get(message_offset + 4)).WillOnce(ReturnRef(message_data[4]));
588 EXPECT_CALL(memory, get(fields_offset + 0)).WillOnce(ReturnRef(field1));
589 EXPECT_CALL(memory, get(fields_offset + 1)).WillOnce(ReturnRef(field2));
590 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
591
592 execution.debug_log(
593 context, message_offset, fields_offset, fields_size_offset, message_size, is_debug_logging_enabled);
594}
595
596TEST_F(ExecutionSimulationTest, DebugLogDisabled)
597{
598 // Setup test data
599 MemoryAddress message_offset = 100;
600 MemoryAddress fields_offset = (1UL << 32) - 50;
601 MemoryAddress fields_size_offset = (1UL << 32) - 50;
602 uint16_t message_size = 1UL << 15;
603 bool is_debug_logging_enabled = false;
604
605 // When debug logging is disabled, only gas should be consumed
606 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
607
608 execution.debug_log(
609 context, message_offset, fields_offset, fields_size_offset, message_size, is_debug_logging_enabled);
610}
611
612TEST_F(ExecutionSimulationTest, DebugLogMessageTruncation)
613{
614 // Setup test data with message size larger than the 100 character limit
615 MemoryAddress message_offset = 100;
616 MemoryAddress fields_offset = 200;
617 MemoryAddress fields_size_offset = 300;
618 uint16_t message_size = 150; // Larger than the 100 character limit
619 bool is_debug_logging_enabled = true;
620
621 // Create test fields data
622 MemoryValue fields_size = MemoryValue::from<uint32_t>(0);
623
624 EXPECT_CALL(context, get_memory);
625 EXPECT_CALL(memory, get(fields_size_offset)).WillOnce(ReturnRef(fields_size));
626
627 // Expect only 100 memory reads for the message (truncated)
628 for (uint32_t i = 0; i < 100; ++i) {
629 MemoryValue char_val = MemoryValue::from<FF>('A' + (i % 26));
630 EXPECT_CALL(memory, get(message_offset + i)).WillOnce(ReturnRef(char_val));
631 }
632
633 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
634
635 execution.debug_log(
636 context, message_offset, fields_offset, fields_size_offset, message_size, is_debug_logging_enabled);
637}
638
639TEST_F(ExecutionSimulationTest, DebugLogExceptionHandling)
640{
641 // Setup test data
642 MemoryAddress message_offset = 100;
643 MemoryAddress fields_offset = 200;
644 MemoryAddress fields_size_offset = 300;
645 uint16_t message_size = 5;
646 bool is_debug_logging_enabled = true;
647
648 // Make memory.get throw an exception to test error handling
649 EXPECT_CALL(context, get_memory);
650 EXPECT_CALL(memory, get(fields_size_offset)).WillOnce(Throw(std::runtime_error("Memory access error")));
651 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
652
653 // The debug_log method should not throw, it should catch the exception and continue
654 EXPECT_NO_THROW(execution.debug_log(
655 context, message_offset, fields_offset, fields_size_offset, message_size, is_debug_logging_enabled));
656}
657
658TEST_F(ExecutionSimulationTest, Sload)
659{
660 MemoryAddress slot_addr = 27;
662 AztecAddress address = 0xdeadbeef;
663 auto slot = MemoryValue::from<FF>(42);
664
665 EXPECT_CALL(context, get_memory);
666
667 EXPECT_CALL(memory, get(slot_addr)).WillOnce(ReturnRef(slot));
668 EXPECT_CALL(context, get_address).WillOnce(ReturnRef(address));
669 EXPECT_CALL(merkle_db, storage_read(address, slot.as<FF>())).WillOnce(Return(7));
670
671 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<FF>(7)));
672 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
673
674 execution.sload(context, slot_addr, dst_addr);
675}
676
677TEST_F(ExecutionSimulationTest, SStore)
678{
679 MemoryAddress slot_addr = 27;
680 MemoryAddress value_addr = 10;
681 AztecAddress address = 0xdeadbeef;
682 auto slot = MemoryValue::from<FF>(42);
683 auto value = MemoryValue::from<FF>(7);
684 TreeStates tree_state = {};
685 EXPECT_CALL(context, get_memory);
686
687 EXPECT_CALL(memory, get(slot_addr)).WillOnce(ReturnRef(slot));
688 EXPECT_CALL(memory, get(value_addr)).WillOnce(ReturnRef(value));
689 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
690 EXPECT_CALL(merkle_db, was_storage_written(address, slot.as<FF>())).WillOnce(Return(false));
691 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
692 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 1 }));
693
694 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
695
696 EXPECT_CALL(merkle_db, storage_write(address, slot.as<FF>(), value.as<FF>(), false));
697
698 execution.sstore(context, value_addr, slot_addr);
699}
700
701TEST_F(ExecutionSimulationTest, SStoreDuringStaticCall)
702{
703 MemoryAddress slot_addr = 27;
704 MemoryAddress value_addr = 10;
705 AztecAddress address = 0xdeadbeef;
706 auto slot = MemoryValue::from<FF>(42);
707 auto value = MemoryValue::from<FF>(7);
708 EXPECT_CALL(context, get_memory);
709
710 EXPECT_CALL(memory, get(slot_addr)).WillOnce(ReturnRef(slot));
711 EXPECT_CALL(memory, get(value_addr)).WillOnce(ReturnRef(value));
712 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
713 EXPECT_CALL(merkle_db, was_storage_written(address, slot.as<FF>())).WillOnce(Return(false));
714 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 1 }));
715
716 EXPECT_CALL(context, get_is_static).WillOnce(Return(true));
717 EXPECT_THROW_WITH_MESSAGE(execution.sstore(context, value_addr, slot_addr),
718 "SSTORE: Cannot write to storage in static context");
719}
720
721TEST_F(ExecutionSimulationTest, SStoreLimitReached)
722{
723 MemoryAddress slot_addr = 27;
724 MemoryAddress value_addr = 10;
725 AztecAddress address = 0xdeadbeef;
726 auto slot = MemoryValue::from<FF>(42);
727 auto value = MemoryValue::from<FF>(7);
728 TreeStates tree_state = {};
729 tree_state.publicDataTree.counter = MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX;
730 EXPECT_CALL(context, get_memory);
731
732 EXPECT_CALL(memory, get(slot_addr)).WillOnce(ReturnRef(slot));
733 EXPECT_CALL(memory, get(value_addr)).WillOnce(ReturnRef(value));
734 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
735 EXPECT_CALL(merkle_db, was_storage_written(address, slot.as<FF>())).WillOnce(Return(false));
736 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
737 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 1 }));
738
739 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
740
741 EXPECT_THROW_WITH_MESSAGE(execution.sstore(context, value_addr, slot_addr),
742 "SSTORE: Maximum number of data writes reached");
743}
744
745TEST_F(ExecutionSimulationTest, SStoreLimitReachedSquashed)
746{
747 MemoryAddress slot_addr = 27;
748 MemoryAddress value_addr = 10;
749 AztecAddress address = 0xdeadbeef;
750 auto slot = MemoryValue::from<FF>(42);
751 auto value = MemoryValue::from<FF>(7);
752 TreeStates tree_state = {};
753 tree_state.publicDataTree.counter = MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX;
754 EXPECT_CALL(context, get_memory);
755
756 EXPECT_CALL(memory, get(slot_addr)).WillOnce(ReturnRef(slot));
757 EXPECT_CALL(memory, get(value_addr)).WillOnce(ReturnRef(value));
758 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
759 // has been written before, so it does not count against the limit.
760 EXPECT_CALL(merkle_db, was_storage_written(address, slot.as<FF>())).WillOnce(Return(true));
761 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
762
763 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
764
765 EXPECT_CALL(merkle_db, storage_write(address, slot.as<FF>(), value.as<FF>(), false));
766
767 execution.sstore(context, value_addr, slot_addr);
768}
769
770TEST_F(ExecutionSimulationTest, NoteHashExists)
771{
772 MemoryAddress unique_note_hash_addr = 10;
773 MemoryAddress leaf_index_addr = 11;
775
776 auto unique_note_hash = MemoryValue::from<FF>(42);
777 auto leaf_index = MemoryValue::from<uint64_t>(7);
778
779 EXPECT_CALL(context, get_memory);
780 EXPECT_CALL(memory, get(unique_note_hash_addr)).WillOnce(ReturnRef(unique_note_hash));
781 EXPECT_CALL(memory, get(leaf_index_addr)).WillOnce(ReturnRef(leaf_index));
782
783 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
784
785 EXPECT_CALL(greater_than, gt(NOTE_HASH_TREE_LEAF_COUNT, leaf_index.as<uint64_t>())).WillOnce(Return(true));
786
787 EXPECT_CALL(merkle_db, note_hash_exists(leaf_index.as<uint64_t>(), unique_note_hash.as<FF>()))
788 .WillOnce(Return(true));
789
790 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<uint1_t>(1)));
791
792 execution.note_hash_exists(context, unique_note_hash_addr, leaf_index_addr, dst_addr);
793}
794
795TEST_F(ExecutionSimulationTest, NoteHashExistsOutOfRange)
796{
797 MemoryAddress unique_note_hash_addr = 10;
798 MemoryAddress leaf_index_addr = 11;
800
801 auto unique_note_hash = MemoryValue::from<FF>(42);
802 auto leaf_index = MemoryValue::from<uint64_t>(NOTE_HASH_TREE_LEAF_COUNT + 1);
803
804 EXPECT_CALL(context, get_memory);
805 EXPECT_CALL(memory, get(unique_note_hash_addr)).WillOnce(ReturnRef(unique_note_hash));
806 EXPECT_CALL(memory, get(leaf_index_addr)).WillOnce(ReturnRef(leaf_index));
807
808 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
809
810 EXPECT_CALL(greater_than, gt(NOTE_HASH_TREE_LEAF_COUNT, leaf_index.as<uint64_t>())).WillOnce(Return(false));
811
812 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<uint1_t>(0)));
813
814 execution.note_hash_exists(context, unique_note_hash_addr, leaf_index_addr, dst_addr);
815}
816
817TEST_F(ExecutionSimulationTest, EmitNoteHash)
818{
819 MemoryAddress note_hash_addr = 10;
820
821 auto note_hash = MemoryValue::from<FF>(42);
822 AztecAddress address = 0xdeadbeef;
823 TreeStates tree_state = {};
824
825 EXPECT_CALL(context, get_memory);
826 EXPECT_CALL(memory, get(note_hash_addr)).WillOnce(ReturnRef(note_hash));
827 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
828
829 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
830
831 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
832 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
833 EXPECT_CALL(merkle_db, note_hash_write(address, note_hash.as<FF>()));
834
835 execution.emit_note_hash(context, note_hash_addr);
836}
837
838TEST_F(ExecutionSimulationTest, EmitNoteHashDuringStaticCall)
839{
840 MemoryAddress note_hash_addr = 10;
841
842 auto note_hash = MemoryValue::from<FF>(42);
843 AztecAddress address = 0xdeadbeef;
844
845 EXPECT_CALL(context, get_memory);
846 EXPECT_CALL(memory, get(note_hash_addr)).WillOnce(ReturnRef(note_hash));
847 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
848
849 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
850
851 EXPECT_CALL(context, get_is_static).WillOnce(Return(true));
852 EXPECT_THROW_WITH_MESSAGE(execution.emit_note_hash(context, note_hash_addr),
853 "EMITNOTEHASH: Cannot emit note hash in static context");
854}
855
856TEST_F(ExecutionSimulationTest, EmitNoteHashLimitReached)
857{
858 MemoryAddress note_hash_addr = 10;
859
860 auto note_hash = MemoryValue::from<FF>(42);
861 AztecAddress address = 0xdeadbeef;
862 TreeStates tree_state = {};
863 tree_state.noteHashTree.counter = MAX_NOTE_HASHES_PER_TX;
864
865 EXPECT_CALL(context, get_memory);
866 EXPECT_CALL(memory, get(note_hash_addr)).WillOnce(ReturnRef(note_hash));
867 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
868
869 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
870
871 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
872 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
873
874 EXPECT_THROW_WITH_MESSAGE(execution.emit_note_hash(context, note_hash_addr),
875 "EMITNOTEHASH: Maximum number of note hashes reached");
876}
877
878TEST_F(ExecutionSimulationTest, L1ToL2MessageExists)
879{
880 MemoryAddress msg_hash_addr = 10;
881 MemoryAddress leaf_index_addr = 11;
883
884 auto msg_hash = MemoryValue::from<FF>(42);
885 auto leaf_index = MemoryValue::from<uint64_t>(7);
886
887 EXPECT_CALL(context, get_memory);
888 EXPECT_CALL(memory, get(msg_hash_addr)).WillOnce(ReturnRef(msg_hash));
889 EXPECT_CALL(memory, get(leaf_index_addr)).WillOnce(ReturnRef(leaf_index));
890
891 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
892
893 EXPECT_CALL(greater_than, gt(L1_TO_L2_MSG_TREE_LEAF_COUNT, leaf_index.as<uint64_t>())).WillOnce(Return(true));
894
895 EXPECT_CALL(merkle_db, l1_to_l2_msg_exists(leaf_index.as<uint64_t>(), msg_hash.as<FF>())).WillOnce(Return(true));
896
897 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<uint1_t>(1)));
898
899 execution.l1_to_l2_message_exists(context, msg_hash_addr, leaf_index_addr, dst_addr);
900}
901
902TEST_F(ExecutionSimulationTest, L1ToL2MessageExistsOutOfRange)
903{
904 MemoryAddress msg_hash_addr = 10;
905 MemoryAddress leaf_index_addr = 11;
907
908 auto msg_hash = MemoryValue::from<FF>(42);
909 auto leaf_index = MemoryValue::from<uint64_t>(L1_TO_L2_MSG_TREE_LEAF_COUNT + 1);
910
911 EXPECT_CALL(context, get_memory);
912 EXPECT_CALL(memory, get(msg_hash_addr)).WillOnce(ReturnRef(msg_hash));
913 EXPECT_CALL(memory, get(leaf_index_addr)).WillOnce(ReturnRef(leaf_index));
914
915 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
916
917 EXPECT_CALL(greater_than, gt(L1_TO_L2_MSG_TREE_LEAF_COUNT, leaf_index.as<uint64_t>())).WillOnce(Return(false));
918
919 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<uint1_t>(0)));
920
921 execution.l1_to_l2_message_exists(context, msg_hash_addr, leaf_index_addr, dst_addr);
922}
923
924TEST_F(ExecutionSimulationTest, NullifierExists)
925{
926 MemoryAddress nullifier_offset = 10;
927 MemoryAddress address_offset = 11;
928 MemoryAddress exists_offset = 12;
929
930 auto nullifier = MemoryValue::from<FF>(42);
931 auto address = MemoryValue::from<FF>(7);
932
933 EXPECT_CALL(context, get_memory);
934 EXPECT_CALL(memory, get(nullifier_offset)).WillOnce(ReturnRef(nullifier));
935 EXPECT_CALL(memory, get(address_offset)).WillOnce(ReturnRef(address));
936
937 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
938
939 EXPECT_CALL(merkle_db, nullifier_exists(address.as_ff(), nullifier.as_ff())).WillOnce(Return(true));
940
941 EXPECT_CALL(memory, set(exists_offset, MemoryValue::from<uint1_t>(1)));
942
943 execution.nullifier_exists(context, nullifier_offset, address_offset, exists_offset);
944}
945
946TEST_F(ExecutionSimulationTest, EmitNullifier)
947{
948 MemoryAddress nullifier_addr = 10;
949
950 auto nullifier = MemoryValue::from<FF>(42);
951 AztecAddress address = 0xdeadbeef;
952 TreeStates tree_state = {};
953
954 EXPECT_CALL(context, get_memory);
955 EXPECT_CALL(memory, get(nullifier_addr)).WillOnce(ReturnRef(nullifier));
956 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
957
958 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
959
960 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
961 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
962 EXPECT_CALL(merkle_db, nullifier_write(address, nullifier.as_ff())).WillOnce(Return(true)); // success
963
964 execution.emit_nullifier(context, nullifier_addr);
965}
966
967TEST_F(ExecutionSimulationTest, EmitNullifierDuringStaticCall)
968{
969 MemoryAddress nullifier_addr = 10;
970
971 auto nullifier = MemoryValue::from<FF>(42);
972 AztecAddress address = 0xdeadbeef;
973
974 EXPECT_CALL(context, get_memory);
975 EXPECT_CALL(memory, get(nullifier_addr)).WillOnce(ReturnRef(nullifier));
976 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
977
978 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
979
980 EXPECT_CALL(context, get_is_static).WillOnce(Return(true));
981 EXPECT_THROW_WITH_MESSAGE(execution.emit_nullifier(context, nullifier_addr),
982 "EMITNULLIFIER: Cannot emit nullifier in static context");
983}
984
985TEST_F(ExecutionSimulationTest, EmitNullifierLimitReached)
986{
987 MemoryAddress nullifier_addr = 10;
988
989 auto nullifier = MemoryValue::from<FF>(42);
990 AztecAddress address = 0xdeadbeef;
991 TreeStates tree_state = {};
992 tree_state.nullifierTree.counter = MAX_NULLIFIERS_PER_TX;
993
994 EXPECT_CALL(context, get_memory);
995 EXPECT_CALL(memory, get(nullifier_addr)).WillOnce(ReturnRef(nullifier));
996 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
997
998 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
999
1000 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
1001 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
1002
1003 EXPECT_THROW_WITH_MESSAGE(execution.emit_nullifier(context, nullifier_addr),
1004 "EMITNULLIFIER: Maximum number of nullifiers reached");
1005}
1006
1007TEST_F(ExecutionSimulationTest, EmitNullifierCollision)
1008{
1009 MemoryAddress nullifier_addr = 10;
1010
1011 auto nullifier = MemoryValue::from<FF>(42);
1012 AztecAddress address = 0xdeadbeef;
1013 TreeStates tree_state = {};
1014
1015 EXPECT_CALL(context, get_memory);
1016 EXPECT_CALL(memory, get(nullifier_addr)).WillOnce(ReturnRef(nullifier));
1017 EXPECT_CALL(context, get_address).WillRepeatedly(ReturnRef(address));
1018
1019 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1020
1021 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
1022 EXPECT_CALL(merkle_db, get_tree_state).WillOnce(Return(tree_state));
1023 EXPECT_CALL(merkle_db, nullifier_write(address, nullifier.as<FF>())).WillOnce(Return(false)); // collision
1024
1025 EXPECT_THROW_WITH_MESSAGE(execution.emit_nullifier(context, nullifier_addr), "EMITNULLIFIER: Nullifier collision");
1026}
1027
1028TEST_F(ExecutionSimulationTest, Set)
1029{
1031 uint8_t dst_tag = static_cast<uint8_t>(MemoryTag::U8);
1032 FF value = 7;
1033
1034 EXPECT_CALL(context, get_memory);
1035 EXPECT_CALL(alu, truncate(value, static_cast<MemoryTag>(dst_tag))).WillOnce(Return(MemoryValue::from<uint8_t>(7)));
1036 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<uint8_t>(7)));
1037 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1038
1039 execution.set(context, dst_addr, dst_tag, value);
1040}
1041
1042TEST_F(ExecutionSimulationTest, Cast)
1043{
1044 MemoryAddress src_addr = 9;
1046 uint8_t dst_tag = static_cast<uint8_t>(MemoryTag::U1);
1047 MemoryValue value = MemoryValue::from<uint64_t>(7);
1048
1049 EXPECT_CALL(context, get_memory).WillOnce(ReturnRef(memory));
1050 EXPECT_CALL(memory, get(src_addr)).WillOnce(ReturnRef(value));
1051
1052 EXPECT_CALL(alu, truncate(value.as_ff(), static_cast<MemoryTag>(dst_tag)))
1053 .WillOnce(Return(MemoryValue::from<uint1_t>(1)));
1054 EXPECT_CALL(memory, set(dst_addr, MemoryValue::from<uint1_t>(1)));
1055 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1056
1057 execution.cast(context, src_addr, dst_addr, dst_tag);
1058}
1059
1060TEST_F(ExecutionSimulationTest, Poseidon2Perm)
1061{
1062 MemoryAddress src_address = 10;
1063 MemoryAddress dst_address = 20;
1064
1065 EXPECT_CALL(context, get_memory);
1066 EXPECT_CALL(gas_tracker, consume_gas);
1067 EXPECT_CALL(poseidon2, permutation(_, src_address, dst_address));
1068
1069 execution.poseidon2_permutation(context, src_address, dst_address);
1070}
1071
1072TEST_F(ExecutionSimulationTest, EccAdd)
1073{
1074 MemoryAddress p_x_addr = 10;
1075 MemoryAddress p_y_addr = 15;
1076 MemoryAddress p_is_inf_addr = 25;
1077 MemoryAddress q_x_addr = 20;
1078 MemoryAddress q_y_addr = 30;
1079 MemoryAddress q_is_inf_addr = 35;
1081
1082 MemoryValue p_x = MemoryValue::from<FF>(FF("0x04c95d1b26d63d46918a156cae92db1bcbc4072a27ec81dc82ea959abdbcf16a"));
1083 MemoryValue p_y = MemoryValue::from<FF>(FF("0x035b6dd9e63c1370462c74775765d07fc21fd1093cc988149d3aa763bb3dbb60"));
1084 EmbeddedCurvePoint p(p_x.as_ff(), p_y, false);
1085
1086 MemoryValue q_x = MemoryValue::from<FF>(FF("0x009242167ec31949c00cbe441cd36757607406e87844fa2c8c4364a4403e66d7"));
1087 MemoryValue q_y = MemoryValue::from<FF>(FF("0x0fe3016d64cfa8045609f375284b6b739b5fa282e4cbb75cc7f1687ecc7420e3"));
1088 EmbeddedCurvePoint q(q_x.as_ff(), q_y.as_ff(), false);
1089
1090 // Mock the context and memory interactions
1091 MemoryValue zero = MemoryValue::from<uint1_t>(0);
1092 EXPECT_CALL(context, get_memory).WillRepeatedly(ReturnRef(memory));
1093 EXPECT_CALL(Const(memory), get(p_x_addr)).WillOnce(ReturnRef(p_x));
1094 EXPECT_CALL(memory, get(p_y_addr)).WillOnce(ReturnRef(p_y));
1095 EXPECT_CALL(memory, get(p_is_inf_addr)).WillOnce(ReturnRef(zero)); // p is not infinity
1096 EXPECT_CALL(memory, get(q_x_addr)).WillOnce(ReturnRef(q_x));
1097 EXPECT_CALL(memory, get(q_y_addr)).WillOnce(ReturnRef(q_y));
1098 EXPECT_CALL(memory, get(q_is_inf_addr)).WillOnce(ReturnRef(zero)); // q is not infinity
1099
1100 EXPECT_CALL(gas_tracker, consume_gas);
1101
1102 // Mock the ECC add operation
1103 EXPECT_CALL(ecc, add(_, _, _, dst_addr));
1104
1105 // Execute the ECC add operation
1106 execution.ecc_add(context, p_x_addr, p_y_addr, p_is_inf_addr, q_x_addr, q_y_addr, q_is_inf_addr, dst_addr);
1107}
1108
1109TEST_F(ExecutionSimulationTest, ToRadixBE)
1110{
1111 MemoryAddress value_addr = 5;
1112 MemoryAddress radix_addr = 6;
1113 MemoryAddress num_limbs_addr = 7;
1114 MemoryAddress is_output_bits_addr = 8;
1115
1117 MemoryValue value = MemoryValue::from<FF>(42069);
1118 MemoryValue radix = MemoryValue::from<uint32_t>(16);
1119 std::vector<MemoryValue> be_limbs = { MemoryValue::from<uint8_t>(0xa4),
1120 MemoryValue::from<uint8_t>(0x55),
1121 MemoryValue::from<uint8_t>(0x00) };
1122 MemoryValue num_limbs = MemoryValue::from<uint32_t>(3);
1123 MemoryValue is_output_bits = MemoryValue::from<uint1_t>(false);
1124 uint32_t num_p_limbs = 64;
1125
1126 EXPECT_CALL(context, get_memory).WillOnce(ReturnRef(memory));
1127 EXPECT_CALL(memory, get(value_addr)).WillOnce(ReturnRef(value));
1128 EXPECT_CALL(memory, get(radix_addr)).WillOnce(ReturnRef(radix));
1129 EXPECT_CALL(memory, get(num_limbs_addr)).WillOnce(ReturnRef(num_limbs));
1130 EXPECT_CALL(memory, get(is_output_bits_addr)).WillOnce(ReturnRef(is_output_bits));
1131
1132 EXPECT_CALL(greater_than, gt(radix.as<uint32_t>(), /*max_radix/*/ 256)).WillOnce(Return(false));
1133 EXPECT_CALL(greater_than, gt(num_limbs.as<uint32_t>(), num_p_limbs)).WillOnce(Return(false));
1134
1135 EXPECT_CALL(gas_tracker, consume_gas);
1136 EXPECT_CALL(to_radix, to_be_radix);
1137
1138 execution.to_radix_be(context, value_addr, radix_addr, num_limbs_addr, is_output_bits_addr, dst_addr);
1139}
1140
1141TEST_F(ExecutionSimulationTest, EmitUnencryptedLog)
1142{
1143 MemoryAddress log_offset = 10;
1144 MemoryAddress log_size_offset = 20;
1145 MemoryValue first_field = MemoryValue::from<FF>(42);
1146 MemoryValue log_size = MemoryValue::from<uint32_t>(10);
1147 AztecAddress address = 0xdeadbeef;
1148
1149 EXPECT_CALL(context, get_memory);
1150 EXPECT_CALL(memory, get(log_offset)).WillOnce(ReturnRef(first_field));
1151 EXPECT_CALL(memory, get(log_size_offset)).WillOnce(ReturnRef(log_size));
1152
1153 EXPECT_CALL(context, get_address).WillOnce(ReturnRef(address));
1154
1155 EXPECT_CALL(emit_unencrypted_log, emit_unencrypted_log(_, _, address, log_offset, log_size.as<uint32_t>()));
1156
1157 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, log_size.as<uint32_t>() }));
1158
1159 execution.emit_unencrypted_log(context, log_offset, log_size_offset);
1160}
1161
1162TEST_F(ExecutionSimulationTest, SendL2ToL1Msg)
1163{
1164 MemoryAddress recipient_addr = 10;
1165 MemoryAddress content_addr = 11;
1166
1167 auto recipient = MemoryValue::from<FF>(42);
1168 auto content = MemoryValue::from<FF>(27);
1169
1170 SideEffectStates side_effects_states = {};
1171 side_effects_states.numL2ToL1Messages = MAX_L2_TO_L1_MSGS_PER_TX - 1;
1172 SideEffectStates side_effects_states_after = side_effects_states;
1173 side_effects_states_after.numL2ToL1Messages++;
1174
1175 EXPECT_CALL(context, get_memory);
1176
1177 EXPECT_CALL(memory, get(recipient_addr)).WillOnce(ReturnRef(recipient));
1178 EXPECT_CALL(memory, get(content_addr)).WillOnce(ReturnRef(content));
1179
1180 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1181
1182 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
1183
1184 EXPECT_CALL(context, get_side_effect_states).WillOnce(ReturnRef(side_effects_states));
1185 EXPECT_CALL(context, set_side_effect_states(side_effects_states_after));
1186
1187 execution.send_l2_to_l1_msg(context, recipient_addr, content_addr);
1188}
1189
1190TEST_F(ExecutionSimulationTest, SendL2ToL1MsgStaticCall)
1191{
1192 MemoryAddress recipient_addr = 10;
1193 MemoryAddress content_addr = 11;
1194
1195 auto recipient = MemoryValue::from<FF>(42);
1196 auto content = MemoryValue::from<FF>(27);
1197
1198 SideEffectStates side_effects_states = {};
1199 side_effects_states.numL2ToL1Messages = MAX_L2_TO_L1_MSGS_PER_TX - 1;
1200
1201 EXPECT_CALL(context, get_memory);
1202
1203 EXPECT_CALL(memory, get(recipient_addr)).WillOnce(ReturnRef(recipient));
1204 EXPECT_CALL(memory, get(content_addr)).WillOnce(ReturnRef(content));
1205
1206 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1207
1208 EXPECT_CALL(context, get_is_static).WillOnce(Return(true));
1209
1210 EXPECT_CALL(context, get_side_effect_states).WillOnce(ReturnRef(side_effects_states));
1211
1212 EXPECT_THROW_WITH_MESSAGE(execution.send_l2_to_l1_msg(context, recipient_addr, content_addr),
1213 "SENDL2TOL1MSG: Cannot send L2 to L1 message in static context");
1214}
1215
1216TEST_F(ExecutionSimulationTest, SendL2ToL1MsgLimitReached)
1217{
1218 MemoryAddress recipient_addr = 10;
1219 MemoryAddress content_addr = 11;
1220
1221 auto recipient = MemoryValue::from<FF>(42);
1222 auto content = MemoryValue::from<FF>(27);
1223
1224 SideEffectStates side_effects_states = {};
1225 side_effects_states.numL2ToL1Messages = MAX_L2_TO_L1_MSGS_PER_TX;
1226
1227 EXPECT_CALL(context, get_memory);
1228
1229 EXPECT_CALL(memory, get(recipient_addr)).WillOnce(ReturnRef(recipient));
1230 EXPECT_CALL(memory, get(content_addr)).WillOnce(ReturnRef(content));
1231
1232 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1233
1234 EXPECT_CALL(context, get_is_static).WillOnce(Return(false));
1235
1236 EXPECT_CALL(context, get_side_effect_states).WillOnce(ReturnRef(side_effects_states));
1237
1238 EXPECT_THROW_WITH_MESSAGE(execution.send_l2_to_l1_msg(context, recipient_addr, content_addr),
1239 "SENDL2TOL1MSG: Maximum number of L2 to L1 messages reached");
1240}
1241
1242TEST_F(ExecutionSimulationTest, Sha256Compression)
1243{
1244 MemoryAddress state_address = 10;
1245 MemoryAddress input_address = 20;
1246 MemoryAddress dst_address = 50;
1247
1248 EXPECT_CALL(context, get_memory);
1249 EXPECT_CALL(gas_tracker, consume_gas(Gas{ 0, 0 }));
1250 EXPECT_CALL(sha256, compression(_, state_address, input_address, dst_address));
1251
1252 execution.sha256_compression(context, dst_address, state_address, input_address);
1253}
1254
1255} // namespace
1256
1257} // namespace bb::avm2::simulation
MemoryTag dst_tag
#define NOTE_HASH_TREE_LEAF_COUNT
#define L1_TO_L2_MSG_TREE_LEAF_COUNT
#define MAX_L2_TO_L1_MSGS_PER_TX
#define MAX_NOTE_HASHES_PER_TX
#define MAX_NULLIFIERS_PER_TX
#define MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
StrictMock< MockHighLevelMerkleDB > merkle_db
Applies the Poseidon2 permutation function from https://eprint.iacr.org/2023/323 ....
ExecutionIdManager execution_id_manager
uint32_t dst_addr
GreaterThan gt
StrictMock< MockContext > context
FF a
FF b
InstructionInfoDB instruction_info_db
smt_circuit::STerm shr(smt_circuit::STerm v0, smt_circuit::STerm v1, smt_solver::Solver *solver)
Right shift operation.
Definition helpers.cpp:40
smt_circuit::STerm shl(smt_circuit::STerm v0, smt_circuit::STerm v1, smt_solver::Solver *solver)
Left shift operation without truncation.
Definition helpers.cpp:34
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TaggedValue MemoryValue
StandardAffinePoint< AvmFlavorSettings::EmbeddedCurve::AffineElement > EmbeddedCurvePoint
Definition field.hpp:12
uint256_t get_tag_max_value(ValueTag tag)
uint32_t MemoryAddress
ValueTag MemoryTag
Sha256Hash sha256(const ByteContainer &input)
Definition sha256.cpp:142
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:123
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
unsigned __int128 uint128_t
Definition serialize.hpp:44
bb::crypto::Poseidon2< bb::crypto::Poseidon2Bn254ScalarFieldParams > poseidon2
Bitwise bitwise
DataCopy data_copy
MemoryStore memory
NiceMock< MockContextProvider > context_provider
NiceMock< MockExecution > execution