Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
fuzz.test.cpp
Go to the documentation of this file.
1#include <gtest/gtest.h>
2#include <iostream>
3
13
14using namespace bb::avm2::fuzzer;
15
17
19{
20 for (auto& function : PREDEFINED_FUNCTIONS) {
21 try {
22 context.register_contract_from_bytecode(function);
23 } catch (...) {
24 std::cout << "Failed to register predefined function: " << function.size() << std::endl;
25 continue;
26 }
27 }
28}
29
30class FuzzTest : public ::testing::Test {
31 protected:
32 void SetUp() override
33 {
35 if (ws_mgr == nullptr) {
37 }
38 ws_mgr->fork();
41 }
42
43 void TearDown() override { ws_mgr->reset_world_state(); }
44
45 SimulatorResult simulate_with_default_tx(std::vector<uint8_t>& bytecode, std::vector<FF> calldata)
46 {
48
49 auto contract_address = context.register_contract_from_bytecode(bytecode);
50 FuzzerContractDB contract_db = context.get_contract_db();
51
53 FF fee_required_da = FF(tx.effective_gas_fees.fee_per_da_gas) * FF(tx.gas_settings.gas_limits.da_gas);
54 FF fee_required_l2 = FF(tx.effective_gas_fees.fee_per_l2_gas) * FF(tx.gas_settings.gas_limits.l2_gas);
55 ws_mgr->write_fee_payer_balance(tx.fee_payer, fee_required_da + fee_required_l2);
56 auto cpp_simulator = CppSimulator();
57
58 auto result = cpp_simulator.simulate(*ws_mgr, contract_db, tx);
59
60 ws_mgr->revert();
61
62 return result;
63 }
64
66};
67
68namespace arithmetic {
70 protected:
71 // set(addr 0, 5) set(addr 1, 2) OP(addr 0, addr 1, addr 2) return(addr 2)
74 {
75 auto set_instruction_1 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
76 .result_address = AddressRef{ .address = 0 },
77 .value = 5 };
78 auto set_instruction_2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
79 .result_address = AddressRef{ .address = 1 },
80 .value = 2 };
81 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, instruction };
82 auto return_options =
83 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 2 };
84 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
85 auto control_flow = ControlFlow(instruction_blocks);
87 auto bytecode = control_flow.build_bytecode(return_options);
88
89 auto result = simulate_with_default_tx(bytecode, {});
90 return result.output.at(0);
91 }
92
93 // Helper function for 16-bit instructions
94 // set(addr 0, 5) set(addr 1, 2) OP_16(addr 0, addr 1, addr 2) return(addr 2)
97 {
98 auto set_instruction_1 =
100 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
101 .value = 5 };
102 auto set_instruction_2 =
104 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
105 .value = 2 };
106 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, instruction };
107
108 auto return_options =
109 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 2 };
110 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
111 auto control_flow = ControlFlow(instruction_blocks);
112 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
113 auto bytecode = control_flow.build_bytecode(return_options);
114
115 auto result = simulate_with_default_tx(bytecode, {});
116 return result.output.at(0);
117 }
118};
119
121{
122 auto add_instruction = ADD_8_Instruction{
123 .a_address =
126 .index = 0,
128 },
129 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
130 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
131 };
132 auto result = get_result_of_instruction(add_instruction);
133 EXPECT_EQ(result, 7);
134}
135
137{
138 auto sub_instruction = SUB_8_Instruction{
140 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
141 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
142 };
143 auto result = get_result_of_instruction(sub_instruction);
144 EXPECT_EQ(result, 3);
145}
146
148{
149 auto mul_instruction = MUL_8_Instruction{
151 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
152 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
153 };
154 auto result = get_result_of_instruction(mul_instruction);
155 EXPECT_EQ(result, 10);
156}
157
159{
160 auto div_instruction = DIV_8_Instruction{
162 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
163 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
164 };
165 auto result = get_result_of_instruction(div_instruction);
166 EXPECT_EQ(result, 2);
167}
168
170{
171 auto eq_instruction = EQ_8_Instruction{
173 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
174 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
175 };
176 auto result = get_result_of_instruction(eq_instruction, bb::avm2::MemoryTag::U1);
177 EXPECT_EQ(result, 0);
178}
179
181{
182 auto lt_instruction = LT_8_Instruction{
184 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
185 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
186 };
187 auto result = get_result_of_instruction(lt_instruction, bb::avm2::MemoryTag::U1);
188 EXPECT_EQ(result, 0);
189}
190
192{
193 auto lte_instruction = LTE_8_Instruction{
195 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
196 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
197 };
198 auto result = get_result_of_instruction(lte_instruction, bb::avm2::MemoryTag::U1);
199 EXPECT_EQ(result, 0);
200}
201
203{
204 auto and_instruction = AND_8_Instruction{
206 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
207 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
208 };
209 auto result = get_result_of_instruction(and_instruction);
210 EXPECT_EQ(result, 0);
211}
212
214{
215 auto or_instruction = OR_8_Instruction{
217 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
218 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
219 };
220 auto result = get_result_of_instruction(or_instruction);
221 EXPECT_EQ(result, 7);
222}
223
225{
226 auto xor_instruction = XOR_8_Instruction{
228 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
229 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
230 };
231 auto result = get_result_of_instruction(xor_instruction);
232 EXPECT_EQ(result, 7);
233}
234
236{
237 auto shl_instruction = SHL_8_Instruction{
239 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
240 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
241 };
242 auto result = get_result_of_instruction(shl_instruction);
243 EXPECT_EQ(result, 20);
244}
245
247{
248 auto shr_instruction = SHR_8_Instruction{
250 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
251 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
252 };
253 auto result = get_result_of_instruction(shr_instruction);
254 EXPECT_EQ(result, 1);
255}
256
257// set(0, 4, FF) set(1, 2, FF) fdiv(FF, 0, 1, 2) return(2)
259{
260 auto fdiv_instruction = FDIV_8_Instruction{
262 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
263 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
264 };
265 auto set_instruction_1 =
267 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
268 .value = 4 };
269 auto set_instruction_2 =
271 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
272 .value = 2 };
273 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, fdiv_instruction };
274
275 auto return_options =
276 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 };
277 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
278 auto control_flow = ControlFlow(instruction_blocks);
279 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
280 auto bytecode = control_flow.build_bytecode(return_options);
281
282 auto result = simulate_with_default_tx(bytecode, {});
283 EXPECT_EQ(result.output.at(0), 2);
284}
285
286// set(0, 0, U8) not(U8, 0, 1) return(1)
288{
289 auto set_instruction =
291 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
292 .value = 0 };
293 auto not_instruction = NOT_8_Instruction{
295 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
296 };
297 auto instructions = std::vector<FuzzInstruction>{ set_instruction, not_instruction };
298 auto return_options =
299 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
300 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
301 auto control_flow = ControlFlow(instruction_blocks);
302 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
303 auto bytecode = control_flow.build_bytecode(return_options);
304
305 auto result = simulate_with_default_tx(bytecode, {});
306 EXPECT_EQ(result.output.at(0), 255);
307}
308
310{
311 auto add_instruction = ADD_16_Instruction{
312 .a_address =
315 .index = 0,
317 },
318 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
319 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
320 };
321 auto result = get_result_of_instruction_16(add_instruction);
322 EXPECT_EQ(result, 7);
323}
324
326{
327 auto sub_instruction = SUB_16_Instruction{
329 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
330 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
331 };
332 auto result = get_result_of_instruction_16(sub_instruction);
333 EXPECT_EQ(result, 3);
334}
335
337{
338 auto mul_instruction = MUL_16_Instruction{
340 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
341 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
342 };
343 auto result = get_result_of_instruction_16(mul_instruction);
344 EXPECT_EQ(result, 10);
345}
346
348{
349 auto div_instruction = DIV_16_Instruction{
351 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
352 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
353 };
354 auto result = get_result_of_instruction_16(div_instruction);
355 EXPECT_EQ(result, 2);
356}
357
359{
360 auto eq_instruction = EQ_16_Instruction{
362 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
363 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
364 };
365 auto result = get_result_of_instruction_16(eq_instruction, bb::avm2::MemoryTag::U1);
366 EXPECT_EQ(result, 0);
367}
368
370{
371 auto lt_instruction = LT_16_Instruction{
373 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
374 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
375 };
376 auto result = get_result_of_instruction_16(lt_instruction, bb::avm2::MemoryTag::U1);
377 EXPECT_EQ(result, 0);
378}
379
381{
382 auto lte_instruction = LTE_16_Instruction{
384 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
385 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
386 };
387 auto result = get_result_of_instruction_16(lte_instruction, bb::avm2::MemoryTag::U1);
388 EXPECT_EQ(result, 0);
389}
390
392{
393 auto and_instruction = AND_16_Instruction{
395 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
396 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
397 };
398 auto result = get_result_of_instruction_16(and_instruction);
399 EXPECT_EQ(result, 0);
400}
401
403{
404 auto or_instruction = OR_16_Instruction{
406 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
407 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
408 };
409 auto result = get_result_of_instruction_16(or_instruction);
410 EXPECT_EQ(result, 7);
411}
412
414{
415 auto xor_instruction = XOR_16_Instruction{
417 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
418 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
419 };
420 auto result = get_result_of_instruction_16(xor_instruction);
421 EXPECT_EQ(result, 7);
422}
423
425{
426 auto shl_instruction = SHL_16_Instruction{
428 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
429 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
430 };
431 auto result = get_result_of_instruction_16(shl_instruction);
432 EXPECT_EQ(result, 20);
433}
434
436{
437 auto shr_instruction = SHR_16_Instruction{
439 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
440 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
441 };
442 auto result = get_result_of_instruction_16(shr_instruction);
443 EXPECT_EQ(result, 1);
444}
445
446// set(0, 4, FF) set(1, 2, FF) fdiv_16(FF, 0, 1, 2) return(2)
448{
449 auto fdiv_instruction = FDIV_16_Instruction{
451 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
452 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
453 };
454 auto set_instruction_1 =
456 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
457 .value = 4 };
458 auto set_instruction_2 =
460 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
461 .value = 2 };
462 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, fdiv_instruction };
463
464 auto return_options =
465 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 };
466 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
467 auto control_flow = ControlFlow(instruction_blocks);
468 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
469 auto bytecode = control_flow.build_bytecode(return_options);
470
471 auto result = simulate_with_default_tx(bytecode, {});
472 EXPECT_EQ(result.output.at(0), 2);
473}
474
475// set(0, 0, U8) not_16(U8, 0, 1) return(1)
477{
478 auto set_instruction =
480 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
481 .value = 0 };
482 auto not_instruction = NOT_16_Instruction{
484 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
485 };
486 auto instructions = std::vector<FuzzInstruction>{ set_instruction, not_instruction };
487 auto return_options =
488 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
489 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
490 auto control_flow = ControlFlow(instruction_blocks);
491 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
492 auto bytecode = control_flow.build_bytecode(return_options);
493
494 auto result = simulate_with_default_tx(bytecode, {});
495 EXPECT_EQ(result.output.at(0), 255);
496}
497
498} // namespace arithmetic
499
501// set(10, 1, U16) set(0, 2, U8) cast_8(U8, 0, 1, U16) return(1)
502// if cast worked, should return 2 (the U8 value cast to U16)
503// if cast failed, should return 1 (the original U16 value)
505{
507 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
508 .value = 1 };
510 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
511 .value = 2 };
512 auto cast_instruction = CAST_8_Instruction{
514 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
515 .target_tag = bb::avm2::MemoryTag::U16
516 };
517 auto instructions = std::vector<FuzzInstruction>{ set_u16, set_u8, cast_instruction };
518 auto return_options =
519 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
520 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
521 auto control_flow = ControlFlow(instruction_blocks);
522 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
523 auto bytecode = control_flow.build_bytecode(return_options);
524
525 auto result = simulate_with_default_tx(bytecode, {});
526 EXPECT_EQ(result.output.at(0), 2);
527}
528
529// set(10, 1, U16) set(0, 2, U8) cast_16(U8, 0, 1, U16) return(1)
530// if cast worked, should return 2 (the U8 value cast to U16)
531// if cast failed, should return 1 (the original U16 value)
533{
535 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
536 .value = 1 };
538 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
539 .value = 2 };
540 auto cast_instruction = CAST_16_Instruction{
542 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
543 .target_tag = bb::avm2::MemoryTag::U16
544 };
545 auto instructions = std::vector<FuzzInstruction>{ set_u16, set_u8, cast_instruction };
546 auto return_options =
547 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
548 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
549 auto control_flow = ControlFlow(instruction_blocks);
550 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
551 auto bytecode = control_flow.build_bytecode(return_options);
552
553 auto result = simulate_with_default_tx(bytecode, {});
554 EXPECT_EQ(result.output.at(0), 2);
555}
556} // namespace type_conversion
557
558namespace machine_memory {
559// set(0, 0xabcd, U16) return(0)
561{
562 const uint16_t test_value = 0xABCD;
563 auto set_instruction =
565 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
566 .value = test_value };
567 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
568 auto return_options =
569 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 0 };
570 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
571 auto control_flow = ControlFlow(instruction_blocks);
572 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
573 auto bytecode = control_flow.build_bytecode(return_options);
574
575 auto result = simulate_with_default_tx(bytecode, {});
576 EXPECT_EQ(result.output.at(0), test_value);
577}
578// set(0, 0x12345678, U32) return(0)
580{
581 const uint32_t test_value = 0x12345678UL;
582 auto set_instruction =
584 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
585 .value = test_value };
586 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
587 auto return_options =
588 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U32, .return_value_offset_index = 0 };
589 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
590 auto control_flow = ControlFlow(instruction_blocks);
591 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
592 auto bytecode = control_flow.build_bytecode(return_options);
593
594 auto result = simulate_with_default_tx(bytecode, {});
595 EXPECT_EQ(result.output.at(0), test_value);
596}
597
598// set(0, 0xabcdef0123456789, U64) return(0)
600{
601 const uint64_t test_value = 0xABCDEF0123456789ULL;
602 auto set_instruction =
604 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
605 .value = test_value };
606 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
607 auto return_options =
608 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U64, .return_value_offset_index = 0 };
609 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
610 auto control_flow = ControlFlow(instruction_blocks);
611 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
612 auto bytecode = control_flow.build_bytecode(return_options);
613
614 auto result = simulate_with_default_tx(bytecode, {});
615 EXPECT_EQ(result.output.at(0), test_value);
616}
617
618// set(0, something, U128) return(0)
620{
621 const uint64_t test_value_low = 0xFEDCBA9876543210ULL;
622 const uint64_t test_value_high = 0x123456789ABCDEF0ULL;
623 const uint128_t test_value =
624 (static_cast<uint128_t>(test_value_high) << 64) | static_cast<uint128_t>(test_value_low);
625 auto set_instruction =
627 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
628 .value_low = test_value_low,
629 .value_high = test_value_high };
630 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
631 auto return_options = ReturnOptions{ .return_size = 1,
632 .return_value_tag = bb::avm2::MemoryTag::U128,
633 .return_value_offset_index = 0 };
634 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
635 auto control_flow = ControlFlow(instruction_blocks);
636 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
637 auto bytecode = control_flow.build_bytecode(return_options);
638
639 auto result = simulate_with_default_tx(bytecode, {});
640 EXPECT_EQ(result.output.at(0), test_value);
641}
642
643// set(0, 123456789, FF) return(0)
645{
646 const bb::avm2::FF test_value = bb::avm2::FF(123456789);
647 auto set_instruction =
649 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
650 .value = test_value };
651 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
652 auto return_options =
653 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 };
654 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
655 auto control_flow = ControlFlow(instruction_blocks);
656 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
657 auto bytecode = control_flow.build_bytecode(return_options);
658
659 auto result = simulate_with_default_tx(bytecode, {});
660 EXPECT_EQ(result.output.at(0), test_value);
661}
662
663// set(0, 0x42, U8) set(1, 0x43, U8) mov_8(U8, 0, 1) return(1)
665{
666 const uint8_t test_value = 0x42;
667 const uint8_t test_value2 = 0x43;
668 auto set_instruction =
670 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
671 .value = test_value };
672 auto set_instruction2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
673 .result_address = AddressRef{ .address = 1 },
674 .value = test_value2 };
675 auto mov_instruction = MOV_8_Instruction{
677 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
678 };
679 auto instructions = std::vector<FuzzInstruction>{ set_instruction, set_instruction2, mov_instruction };
680 auto return_options =
681 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
682 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
683 auto control_flow = ControlFlow(instruction_blocks);
684 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
685 auto bytecode = control_flow.build_bytecode(return_options);
686
687 auto result = simulate_with_default_tx(bytecode, {});
688 EXPECT_EQ(result.output.at(0), test_value);
689}
690
691// set(0, 0xbabe, U16) set(1, 0xc0fe, U16) mov_16(U16, 0, 1) return(1)
693{
694 const uint16_t test_value = 0xbabe;
695 const uint16_t test_value2 = 0xc0fe;
696 auto set_instruction =
698 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
699 .value = test_value };
700 auto set_instruction2 =
702 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
703 .value = test_value2 };
704 auto mov_instruction = MOV_16_Instruction{
706 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
707 };
708 auto instructions = std::vector<FuzzInstruction>{ set_instruction, set_instruction2, mov_instruction };
709 auto return_options =
710 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
711 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
712 auto control_flow = ControlFlow(instruction_blocks);
713 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
714 auto bytecode = control_flow.build_bytecode(return_options);
715
716 auto result = simulate_with_default_tx(bytecode, {});
717 EXPECT_EQ(result.output.at(0), test_value);
718}
719
720} // namespace machine_memory
721
722namespace control_flow {
723
725 protected:
726 // set u1 condition value b1
727 // ↙ ↘
728 // set u1 b2 return 4
729 // ↙ ↘
730 // ret 2 ret 3
731 FF simulate_jump_if_depth_2_helper(uint8_t first_boolean_value, uint8_t second_boolean_value)
732 {
733 auto set_instruction_block_1 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
734 .result_address = AddressRef{ .address = 1 },
735 .value = first_boolean_value };
736 auto instruction_block_1 = std::vector<FuzzInstruction>{ set_instruction_block_1 };
737 auto set_instruction_block_2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
738 .result_address = AddressRef{ .address = 2 },
739 .value = second_boolean_value };
740 auto instruction_block_2 = std::vector<FuzzInstruction>{ set_instruction_block_2 };
741 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instruction_block_1, instruction_block_2 };
742 for (uint8_t i = 2; i < 5; i++) {
743 auto set_instruction =
745 .result_address = AddressRef{ .address = i, .mode = AddressingMode::Direct },
746 .value = i };
747 instruction_blocks.push_back({ set_instruction });
748 }
749 auto return_options = ReturnOptions{ .return_size = 1,
750 .return_value_tag = bb::avm2::MemoryTag::U8,
751 .return_value_offset_index = 1 };
752 auto control_flow = ControlFlow(instruction_blocks);
753 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
754 control_flow.process_cfg_instruction(
756 .else_program_block_instruction_block_idx = 4, // set 4
757 .condition_offset_index = 0 });
758 control_flow.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 2, // set 2
759 .else_program_block_instruction_block_idx = 3, // set 3
760 .condition_offset_index = 1 });
761 auto bytecode = control_flow.build_bytecode(return_options);
762
763 auto result = simulate_with_default_tx(bytecode, {});
764 return result.output.at(0);
765 }
766
767 // set u1 condition
768 // ↙ ↘
769 // nop ----→ return 2
770 FF simulate_jump_to_block_helper(uint8_t condition_value)
771 {
772 auto set_instruction_block_1 =
774 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
775 .value = condition_value };
776 auto set_return_value_block = std::vector<FuzzInstruction>{ SET_8_Instruction{
778 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
779 .value = 2 } };
780 auto instruction_block_1 = std::vector<FuzzInstruction>{ set_instruction_block_1 };
781 auto instruction_blocks =
782 std::vector<std::vector<FuzzInstruction>>{ instruction_block_1, {}, set_return_value_block };
783 auto return_options = ReturnOptions{ .return_size = 1,
784 .return_value_tag = bb::avm2::MemoryTag::U8,
785 .return_value_offset_index = 1 };
786 auto control_flow = ControlFlow(instruction_blocks);
787 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
788 control_flow.process_cfg_instruction(
790 .else_program_block_instruction_block_idx = 2, // set return value
791 .condition_offset_index = 0 });
792 control_flow.process_cfg_instruction(JumpToBlock{ .target_block_idx = 2 });
793 auto bytecode = control_flow.build_bytecode(return_options);
794
795 auto result = simulate_with_default_tx(bytecode, {});
796 return result.output.at(0);
797 }
798};
799
800// block1 set return value 10
801// ↓
802// block2 set return value 11 and return return value
803TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke)
804{
805 auto block1_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
807 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
808 .value = 10 } };
809 auto block2_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
811 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
812 .value = 11 } };
813 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ block1_instructions, block2_instructions };
814 auto return_options =
815 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
816 auto control_flow = ControlFlow(instruction_blocks);
817 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
819 auto bytecode = control_flow.build_bytecode(return_options);
820
821 auto result = simulate_with_default_tx(bytecode, {});
822 EXPECT_EQ(result.output.at(0), 11);
823}
824
825// block1 set return value 10
826// ↓
827// block2 set return value 11
828// ↓
829// block3 set return value 12 and return return value
830TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke2)
831{
832 auto block1_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
834 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
835 .value = 10 } };
836 auto block2_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
838 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
839 .value = 11 } };
840 auto block3_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
842 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
843 .value = 12 } };
844 auto instruction_blocks =
845 std::vector<std::vector<FuzzInstruction>>{ block1_instructions, block2_instructions, block3_instructions };
846 auto return_options =
847 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
848 auto control_flow = ControlFlow(instruction_blocks);
849 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
852 auto bytecode = control_flow.build_bytecode(return_options);
853
854 auto result = simulate_with_default_tx(bytecode, {});
855 EXPECT_EQ(result.output.at(0), 12);
856}
857
858// block1 set u8 value 10
859// ↓
860// block2 tries to return u8
861// if blocks does not share defined variables, block2 will return 0
862TEST_F(ControlFlowFuzzTest, JumpToNewBlockSharesVariables)
863{
864 auto block1_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
866 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
867 .value = 10 } };
868
869 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ block1_instructions };
870 auto return_options =
871 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
872 auto control_flow = ControlFlow(instruction_blocks);
873 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
875 auto bytecode = control_flow.build_bytecode(return_options);
876
877 auto result = simulate_with_default_tx(bytecode, {});
878 EXPECT_EQ(result.output.at(0), 10);
879}
880
881// block1 set u1 condition value
882// ↙ ↘
883// return 11 return 12
884TEST_F(ControlFlowFuzzTest, JumpIfToNewBlockSmoke)
885{
886 auto set_true_block = std::vector<FuzzInstruction>{ SET_8_Instruction{
888 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
889 .value = 1 } };
890 auto set_false_block = std::vector<FuzzInstruction>{ SET_8_Instruction{
892 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
893 .value = 0 } };
894 auto block2_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
896 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
897 .value = 11 } };
898 auto block3_instructions = std::vector<FuzzInstruction>{ SET_8_Instruction{
900 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
901 .value = 12 } };
902 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{
903 set_true_block, set_false_block, block2_instructions, block3_instructions
904 };
905 auto return_options =
906 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
907 auto control_flow = ControlFlow(instruction_blocks);
908 // set true, go to block2
909 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
911 .else_program_block_instruction_block_idx = 3,
912 .condition_offset_index = 1 });
913 auto bytecode_1 = control_flow.build_bytecode(return_options);
914 auto control_flow2 = ControlFlow(instruction_blocks);
915 // set false, go to block3
916 control_flow2.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
917 control_flow2.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 2,
918 .else_program_block_instruction_block_idx = 3,
919 .condition_offset_index = 1 });
920 auto bytecode_2 = control_flow2.build_bytecode(return_options);
921
922 auto result_1 = simulate_with_default_tx(bytecode_1, {});
923 auto result_2 = simulate_with_default_tx(bytecode_2, {});
924 EXPECT_EQ(result_1.output.at(0), 11);
925 EXPECT_EQ(result_2.output.at(0), 12);
926}
927
928TEST_F(ControlFlowFuzzTest, JumpIfDepth2Smoke)
929{
930 EXPECT_EQ(simulate_jump_if_depth_2_helper(1, 1), 2);
931 EXPECT_EQ(simulate_jump_if_depth_2_helper(1, 0), 3);
932 EXPECT_EQ(simulate_jump_if_depth_2_helper(0, 1), 4);
933 EXPECT_EQ(simulate_jump_if_depth_2_helper(0, 0), 4);
934}
935
936TEST_F(ControlFlowFuzzTest, JumpToBlockSmoke)
937{
938 EXPECT_EQ(simulate_jump_to_block_helper(1), 2);
939 EXPECT_EQ(simulate_jump_to_block_helper(0), 2);
940}
941
942// Nice catch! That's actually fully ai generated test.
943// test if terminate with return works
944// set u1 condition value
945// ↙ ↘
946// set FF, ret set U128, ret
947TEST_F(ControlFlowFuzzTest, JumpIfToNewBlockWithReturn)
948{
949 // Block 0: Set condition (U1)
950 auto set_condition_block = std::vector<FuzzInstruction>{ SET_8_Instruction{
952 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
953 .value = 1 } };
954
955 // Block 1: Set FF value
956 const bb::avm2::FF ff_value = bb::avm2::FF(123456789);
959 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
960 .value = ff_value } };
961
962 // Block 2: Set U128 value
963 const uint64_t u128_value_low = 0xFEDCBA9876543210ULL;
964 const uint64_t u128_value_high = 0x123456789ABCDEF0ULL;
967 .result_address = AddressRef{ .address = 20, .mode = AddressingMode::Direct },
968 .value_low = u128_value_low,
969 .value_high = u128_value_high } };
970
971 auto instruction_blocks =
972 std::vector<std::vector<FuzzInstruction>>{ set_condition_block, set_ff_block, set_u128_block };
973
974 auto control_flow = ControlFlow(instruction_blocks);
975
976 // Insert condition block
977 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
978
979 // JumpIf: if condition is true (1), go to block 1 (FF), else go to block 2 (U128)
981 .else_program_block_instruction_block_idx = 2,
982 .condition_offset_index = 0 });
983
984 // Finalize then block (FF) with Return
985 control_flow.process_cfg_instruction(FinalizeWithReturn{
987 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
988
989 // Finalize else block (U128) with Return
990 control_flow.process_cfg_instruction(FinalizeWithReturn{
992 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
993
994 // Test with condition = true (should return FF value)
995 auto control_flow_true = ControlFlow(instruction_blocks);
996 control_flow_true.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
997 control_flow_true.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 1,
998 .else_program_block_instruction_block_idx = 2,
999 .condition_offset_index = 0 });
1000 control_flow_true.process_cfg_instruction(FinalizeWithReturn{
1002 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1003 control_flow_true.process_cfg_instruction(FinalizeWithReturn{
1005 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1006
1007 auto bytecode_true = control_flow_true.build_bytecode(ReturnOptions{
1008 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 });
1009
1010 auto result_true = simulate_with_default_tx(bytecode_true, {});
1011 EXPECT_EQ(result_true.output.at(0), ff_value);
1012
1013 // Test with condition = false (should return U128 value)
1014 auto set_condition_false_block = std::vector<FuzzInstruction>{ SET_8_Instruction{
1016 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1017 .value = 0 } };
1018 auto instruction_blocks_false =
1019 std::vector<std::vector<FuzzInstruction>>{ set_condition_false_block, set_ff_block, set_u128_block };
1020
1021 auto control_flow_false = ControlFlow(instruction_blocks_false);
1022 control_flow_false.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1023 control_flow_false.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 1,
1024 .else_program_block_instruction_block_idx = 2,
1025 .condition_offset_index = 0 });
1026 control_flow_false.process_cfg_instruction(FinalizeWithReturn{
1028 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1029 control_flow_false.process_cfg_instruction(FinalizeWithReturn{
1031 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1032
1033 const uint128_t expected_u128_value =
1034 (static_cast<uint128_t>(u128_value_high) << 64) | static_cast<uint128_t>(u128_value_low);
1035 auto bytecode_false = control_flow_false.build_bytecode(ReturnOptions{
1036 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 });
1037
1038 auto result_false = simulate_with_default_tx(bytecode_false, {});
1039 EXPECT_EQ(result_false.output.at(0), expected_u128_value);
1040}
1041} // namespace control_flow
1042
1044TEST_F(FuzzTest, SstoreThenSload)
1045{
1046 // M[10] = 10
1047 auto set_value_instruction =
1049 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1050 .value = 10 };
1051 // S[10] = M[10]
1052 auto sstore_instruction = SSTORE_Instruction{
1054 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1055 .slot = 10
1056 };
1057 // M[2] = S[10], FF tag
1058 auto sload_instruction =
1060 .slot_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1061 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct } };
1062 // M[10] = 11
1063 auto set_value_instruction2 =
1065 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1066 .value = 11 };
1067
1068 auto set_sstore_sload_block = std::vector<FuzzInstruction>{
1069 set_value_instruction, sstore_instruction, sload_instruction, set_value_instruction2
1070 };
1071
1072 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ set_sstore_sload_block };
1073 // FF should be set via sload instruction
1074 auto return_options = ReturnOptions{ .return_size = 1,
1075 .return_value_tag = bb::avm2::MemoryTag::FF,
1076 .return_value_offset_index = 1 /* after sload instruction */ };
1077 auto control_flow = ControlFlow(instruction_blocks);
1078 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1079 auto bytecode = control_flow.build_bytecode(return_options);
1080
1081 auto result = simulate_with_default_tx(bytecode, {});
1082 EXPECT_EQ(result.output.at(0), 10);
1083}
1084} // namespace public_storage
1085
1087
1089 protected:
1091 {
1092 auto getenvvar_instruction =
1094 .type = type };
1095 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ { getenvvar_instruction } };
1096 auto control_flow = ControlFlow(instruction_blocks);
1097 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1098 auto return_options =
1099 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 0 };
1100 auto bytecode = control_flow.build_bytecode(return_options);
1101
1102 auto result = simulate_with_default_tx(bytecode, {});
1103 return result.output.at(0);
1104 }
1105};
1106
1108{
1109 EXPECT_EQ(getenvvar_helper(0),
1110 FF("0x02fea672ef18fe4b8d13dcfd8943797c99b9885da7b338d224dd5136a0cc8a6f")); // address with bytecode
1111 EXPECT_EQ(getenvvar_helper(1), MSG_SENDER); // sender, see simulator.cpp
1112 EXPECT_EQ(getenvvar_helper(2), TRANSACTION_FEE); // transaction fee, see simulator.cpp
1113 EXPECT_EQ(getenvvar_helper(3), CHAIN_ID); // chain id, see simulator.cpp globals
1114 EXPECT_EQ(getenvvar_helper(4), VERSION); // version, see simulator.cpp globals
1115 EXPECT_EQ(getenvvar_helper(5), BLOCK_NUMBER); // block number, see simulator.cpp globals
1116 EXPECT_EQ(getenvvar_helper(6, bb::avm2::MemoryTag::U64), 1000000); // timestamp, see simulator.cpp globals
1117 EXPECT_EQ(getenvvar_helper(7), FEE_PER_L2_GAS); // FEEPERL2GAS = 1, see simulator.cpp gas_fees
1118 EXPECT_EQ(getenvvar_helper(8), FEE_PER_DA_GAS); // FEEPERDAGAS = 1, see simulator.cpp gas_fees
1119 EXPECT_EQ(getenvvar_helper(9), 0); // is static call is always false
1120 EXPECT_EQ(getenvvar_helper(10), GAS_LIMIT.l2_gas - 2 * 6); // L2GASLEFT, gas spent on getenvvar + return
1121 EXPECT_EQ(getenvvar_helper(11), GAS_LIMIT.da_gas); // DAGASLEFT, see simulator.cpp
1122}
1123} // namespace execution_environment
1124
1126TEST_F(FuzzTest, EmitNullifierThenNullifierExists)
1127{
1128 auto set_field_instruction =
1130 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1131 .value = 1 };
1132 auto emit_nullifier_instruction = EMITNULLIFIER_Instruction{
1134 };
1135 auto nullifier_exists_instruction = NULLIFIEREXISTS_Instruction{
1137 .contract_address_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1138 .result_address = AddressRef{ .address = 20, .mode = AddressingMode::Direct }
1139 };
1140 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{
1141 { set_field_instruction, emit_nullifier_instruction, nullifier_exists_instruction }
1142 };
1143 auto control_flow = ControlFlow(instruction_blocks);
1144 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1145 auto bytecode = control_flow.build_bytecode(ReturnOptions{
1146 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 20 });
1147 auto result = simulate_with_default_tx(bytecode, {});
1148 EXPECT_EQ(result.output.at(0), 1);
1149}
1150
1151TEST_F(FuzzTest, EmitNullifierThenNullifierExistsOverwritingPreviousNullifier)
1152{
1153 auto set_field_instruction =
1155 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1156 .value = 1 };
1157 auto emit_nullifier_instruction = EMITNULLIFIER_Instruction{
1159 };
1160 auto nullifier_exists_instruction = NULLIFIEREXISTS_Instruction{
1162 .contract_address_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1163 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
1164 }; // GETENVVAR overwrites previous nullifier
1165 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{
1166 { set_field_instruction, emit_nullifier_instruction, nullifier_exists_instruction }
1167 };
1168 auto control_flow = ControlFlow(instruction_blocks);
1169 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1170 auto bytecode = control_flow.build_bytecode(
1171 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1172 auto result = simulate_with_default_tx(bytecode, {});
1173 EXPECT_EQ(result.output.at(0), 0);
1174}
1175
1176TEST_F(FuzzTest, EmitNoteHashThenNoteHashExists)
1177{
1178 auto emit_note_hash_instruction =
1180 .note_hash = 1 };
1181 auto note_hash_exists_instruction =
1183 .notehash_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1184 .leaf_index_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1185 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct } };
1186 auto instruction_blocks =
1187 std::vector<std::vector<FuzzInstruction>>{ { emit_note_hash_instruction, note_hash_exists_instruction } };
1188 auto control_flow = ControlFlow(instruction_blocks);
1189 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1190 auto bytecode = control_flow.build_bytecode(
1191 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1192 auto result = simulate_with_default_tx(bytecode, {});
1193 EXPECT_FALSE(result.reverted);
1194 // TODO(defkit): fix notehashexists
1195 // Right now we cannot know the contract address during bytecode construction
1196 // because contract address depends on bytecode commitment
1197 // So we cannot compute actual unique_note_hash for NOTEHASHEXISTS instruction
1198 //
1199 // EXPECT_EQ(result.output.at(0), 1);
1200}
1201} // namespace notes_and_nullifiers
1202
1204TEST_F(FuzzTest, CopyCalldataThenReturnData)
1205{
1206 auto calldatacopy_instruction = CALLDATACOPY_Instruction{ .dst_address = AddressRef{ .address = 0 },
1207 .copy_size = 1,
1208 .copy_size_address = AddressRef{ .address = 1 },
1209 .cd_start = 0,
1210 .cd_start_address = AddressRef{ .address = 2 } };
1211 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ { calldatacopy_instruction } };
1212 auto control_flow = ControlFlow(instruction_blocks);
1213 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1214 auto bytecode = control_flow.build_bytecode(
1215 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1216
1217 auto result = simulate_with_default_tx(bytecode, { FF(1337) });
1218 EXPECT_EQ(result.output.at(0), 1337);
1219}
1220
1221// call internal function overwrites memory address
1222TEST_F(FuzzTest, InternalCall)
1223{
1224 auto set_field_instruction =
1226 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1227 .value = 1337 };
1228 auto set_field_instruction2 =
1230 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1231 .value = 313373 };
1232 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1233 auto instruction_blocks =
1234 std::vector<std::vector<FuzzInstruction>>{ { set_field_instruction, set_field_instruction2 } };
1235 auto control_flow = ControlFlow(instruction_blocks);
1236 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1237 control_flow.process_cfg_instruction(internal_call_instruction);
1238 auto bytecode = control_flow.build_bytecode(
1239 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1240 auto result = simulate_with_default_tx(bytecode, {});
1241 EXPECT_EQ(result.output.at(0), 313373);
1242}
1243} // namespace calldata_returndata
1244
1246
1247// check if internal call does not halt execution on return
1248TEST_F(FuzzTest, InternalCalledBlockUsesInternalReturn)
1249{
1250 auto set_field_instruction =
1252 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1253 .value = 1337 };
1254 auto set_boolean_instruction =
1256 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1257 .value = 1 };
1258 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1259 auto instruction_blocks =
1260 std::vector<std::vector<FuzzInstruction>>{ { set_field_instruction, set_boolean_instruction } };
1261 auto control_flow = ControlFlow(instruction_blocks);
1262 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
1263 control_flow.process_cfg_instruction(internal_call_instruction);
1264 // this should do nothing, just insert INTERNALRETURN instruction
1265 // otherwise it will halt execution and return 1
1266 control_flow.process_cfg_instruction(FinalizeWithReturn{
1268 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 } });
1269 auto bytecode = control_flow.build_bytecode(
1270 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1271 auto result = simulate_with_default_tx(bytecode, {});
1272 EXPECT_EQ(result.output.at(0), 1337);
1273}
1274
1275// SSTORE(0, 1337); call f1; return SLOAD(0);
1276// f1: SSTORE(0, 31337); call f2; INTERNALRETURN
1277// f2: SSTORE(0, 313373); INTERNALRETURN
1278TEST_F(FuzzTest, SeveralInternalCalls)
1279{
1280 auto set_field_instruction =
1282 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1283 .value = 1337 };
1284 auto set_field_instruction2 =
1286 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1287 .value = 31337 };
1288 auto set_field_instruction3 =
1290 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1291 .value = 313373 };
1292 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1293 auto internal_call_instruction2 = InsertInternalCall{ .target_program_block_instruction_block_idx = 2 };
1294 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{
1295 { set_field_instruction, set_field_instruction2, set_field_instruction3 }
1296 };
1297 auto control_flow = ControlFlow(instruction_blocks);
1298 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1299 control_flow.process_cfg_instruction(internal_call_instruction);
1300 control_flow.process_cfg_instruction(internal_call_instruction2);
1301 auto bytecode = control_flow.build_bytecode(
1302 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1303 auto result = simulate_with_default_tx(bytecode, {});
1304 EXPECT_EQ(result.output.at(0), 313373);
1305}
1306
1324TEST_F(FuzzTest, Reentrancy)
1325{
1326 auto set_field_instruction0 =
1328 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1329 .value = 1 };
1330 auto set_field_instruction1 =
1332 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1333 .value = 1337 };
1334 auto set_field_instruction2 =
1336 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1337 .value = 31337 };
1338 auto set_field_instruction3 =
1340 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1341 .value = 313373 };
1342 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1343 auto internal_call_instruction2 = InsertInternalCall{ .target_program_block_instruction_block_idx = 2 };
1344 auto internal_call_instruction3 = InsertInternalCall{ .target_program_block_instruction_block_idx = 3 };
1345 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{
1346 { set_field_instruction0, set_field_instruction1, set_field_instruction2, set_field_instruction3 }
1347 };
1348 auto control_flow = ControlFlow(instruction_blocks);
1349 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1350 // call f1
1351 control_flow.process_cfg_instruction(internal_call_instruction);
1352 // call f2
1353 control_flow.process_cfg_instruction(internal_call_instruction2);
1354 // Should switch context to f1
1355 control_flow.process_cfg_instruction(FinalizeWithReturn{
1357 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1358 // SSTORE(0, 1337);
1359 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
1360 // Should switch context to f0 (START)
1361 control_flow.process_cfg_instruction(FinalizeWithReturn{
1363 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1364 // call f3
1365 control_flow.process_cfg_instruction(internal_call_instruction3);
1366 // Should switch context to f0 (START)
1367 control_flow.process_cfg_instruction(FinalizeWithReturn{
1369 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1370 auto bytecode = control_flow.build_bytecode(
1371 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1372 auto result = simulate_with_default_tx(bytecode, {});
1373 EXPECT_EQ(result.output.at(0), 313373);
1374}
1375} // namespace internal_calls
1376
1378TEST_F(FuzzTest, DirectWithIndirect)
1379{
1380 auto set_field_instruction =
1382 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1383 .value = 10 };
1384 auto set_field_instruction2 =
1386 .result_address = AddressRef{ .address = 3000, .mode = AddressingMode::Direct },
1387 .value = 20 };
1388 auto add_instruction = ADD_8_Instruction{
1390 .index = 1,
1391 .pointer_address_seed = 100,
1392 .mode = AddressingMode::Indirect },
1393 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1394 .result_address = AddressRef{ .address = 130, .mode = AddressingMode::Direct }
1395 };
1396 auto instruction_blocks =
1397 std::vector<std::vector<FuzzInstruction>>{ { set_field_instruction, set_field_instruction2, add_instruction } };
1398 auto control_flow = ControlFlow(instruction_blocks);
1399 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1400 auto bytecode = control_flow.build_bytecode(
1401 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1402 auto result = simulate_with_default_tx(bytecode, {});
1403 EXPECT_EQ(result.output.at(0), 30);
1404}
1405
1406TEST_F(FuzzTest, DirectWithIndirectRelative)
1407{
1408 auto set_field_instruction =
1410 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1411 .value = 10 };
1412 auto set_field_instruction2 =
1414 .result_address = AddressRef{ .address = 3000, .mode = AddressingMode::Direct },
1415 .value = 20 };
1416 auto add_instruction = ADD_8_Instruction{
1418 .index = 1,
1419 .pointer_address_seed = 100,
1420 .base_offset_seed = 100,
1422 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1423 .result_address = AddressRef{ .address = 130, .mode = AddressingMode::Direct }
1424 };
1425 auto instruction_blocks =
1426 std::vector<std::vector<FuzzInstruction>>{ { set_field_instruction, set_field_instruction2, add_instruction } };
1427 auto control_flow = ControlFlow(instruction_blocks);
1428 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1429 auto bytecode = control_flow.build_bytecode(
1430 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1431 auto result = simulate_with_default_tx(bytecode, {});
1432 EXPECT_EQ(result.output.at(0), 30);
1433}
1434
1435TEST_F(FuzzTest, IndirectResultCanBeUsedInNextInstruction)
1436{
1437 auto set_field_instruction =
1439 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1440 .value = 10 };
1441 auto add_instruction = ADD_8_Instruction{
1443 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
1444 .result_address = AddressRef{ .address = 130, .pointer_address_seed = 100, .mode = AddressingMode::Indirect }
1445 };
1446 auto mul_instruction = MUL_8_Instruction{
1448 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
1449 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct }
1450 };
1451 auto instruction_blocks =
1452 std::vector<std::vector<FuzzInstruction>>{ { set_field_instruction, add_instruction, mul_instruction } };
1453 auto control_flow = ControlFlow(instruction_blocks);
1454 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1455 auto bytecode = control_flow.build_bytecode(
1456 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1457 auto result = simulate_with_default_tx(bytecode, {});
1458 EXPECT_EQ(result.output.at(0), 400);
1459}
1460
1461TEST_F(FuzzTest, Memoryaddressing32BitWidth)
1462{
1463 auto set_field_instruction =
1465 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1466 .value = 10 };
1467 auto set_field_instruction2 = SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
1468 .result_address = AddressRef{ .address = 4294967295,
1469 .pointer_address_seed = 100,
1470 .mode = AddressingMode::Indirect },
1471 .value = 20 };
1472 auto add_instruction = MUL_8_Instruction{
1474 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF,
1475 .index = 1,
1476 .pointer_address_seed = 200,
1477 .mode = AddressingMode::Indirect },
1478 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct }
1479 };
1480 auto instruction_blocks =
1481 std::vector<std::vector<FuzzInstruction>>{ { set_field_instruction, set_field_instruction2, add_instruction } };
1482 auto control_flow = ControlFlow(instruction_blocks);
1483 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1484 auto bytecode = control_flow.build_bytecode(
1485 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1486 auto result = simulate_with_default_tx(bytecode, {});
1487 EXPECT_EQ(result.output.at(0), 200);
1488}
1489} // namespace avm_addressing
1490
1491namespace misc {
1492// TODO(defkit): get info from world state to be sure that the message will be sent / log emitted
1493TEST_F(FuzzTest, SendL2ToL1Msg)
1494{
1495 auto sendl2tol1msg_instruction =
1497 .recipient_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1498 .content = 200,
1499 .content_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct } };
1500 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ { sendl2tol1msg_instruction } };
1501 auto control_flow = ControlFlow(instruction_blocks);
1502 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1503 auto bytecode = control_flow.build_bytecode(
1504 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1505 auto result = simulate_with_default_tx(bytecode, {});
1506 EXPECT_EQ(result.reverted, false);
1507}
1508
1510{
1513 uint32_t log_size = 1;
1514 FF log_value = 42;
1515
1516 std::vector<FuzzInstruction> instructions;
1517
1518 instructions.push_back(SET_32_Instruction{
1519 .value_tag = bb::avm2::MemoryTag::U32, .result_address = log_size_address, .value = log_size });
1520
1521 instructions.push_back(SET_FF_Instruction{
1522 .value_tag = bb::avm2::MemoryTag::FF, .result_address = log_values_address, .value = log_value });
1523
1525 .log_values_address = log_values_address });
1526
1527 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
1528 auto control_flow = ControlFlow(instruction_blocks);
1529 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1530 auto bytecode = control_flow.build_bytecode(
1531 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1532 auto result = simulate_with_default_tx(bytecode, {});
1533 EXPECT_EQ(result.reverted, false);
1534}
1535} // namespace misc
1536
1538
1540 protected:
1542 {
1543 FF address = context.get_contract_address(0);
1544 std::vector<FuzzInstruction> instructions;
1545 instructions.push_back(
1547 .result_address = AddressRef{ .address = 123, .mode = AddressingMode::Direct },
1548 .value = address });
1549 instructions.push_back(GETCONTRACTINSTANCE_Instruction{
1551 .member_enum = member_enum,
1552 .dst_address = AddressRef{ .address = 124, .mode = AddressingMode::Direct } });
1553
1554 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
1555 auto control_flow = ControlFlow(instruction_blocks);
1556 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1557 auto bytecode = control_flow.build_bytecode(
1558 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 1 });
1559 auto result = simulate_with_default_tx(bytecode, {});
1560 return result.output.at(0);
1561 }
1562};
1563
1566TEST_F(ExternalCallsFuzzTest, ExternalCallToAdd8)
1567{
1568 std::vector<FuzzInstruction> instructions;
1569 auto contract_address = context.get_contract_address(0);
1571 instructions.push_back(SET_FF_Instruction{
1573
1574 uint32_t l2_gas = 10000;
1576 instructions.push_back(
1578
1579 uint32_t da_gas = 10000;
1581 instructions.push_back(
1583
1584 uint16_t arg_size = 0;
1585 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1586 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1587
1588 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1589 .da_gas_address = da_gas_address,
1590 .contract_address_address = contract_address_address,
1591 .calldata_address = args_address,
1592 .calldata_size_address = arg_size_address,
1593 .calldata_size = arg_size,
1594 .is_static_call = false });
1595
1597 .copy_size_offset = 6, .dst_address = 7, .rd_start = 0, .rd_start_offset = 8 });
1598
1599 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
1600 auto control_flow = ControlFlow(instruction_blocks);
1601 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1602 auto bytecode = control_flow.build_bytecode(
1603 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 1 });
1604 auto result = simulate_with_default_tx(bytecode, {});
1605 EXPECT_EQ(result.output.at(0), 2);
1606}
1607
1609{
1610
1611 EXPECT_EQ(get_contract_instance_helper(0),
1612 FF("0x0000000000000000000000000000000000000000000000000000000000000064")); // DEPLOYER
1613 EXPECT_EQ(get_contract_instance_helper(1),
1614 FF("0x0dc97dd1cc90c276ca76f34abb5085e1ae3addd8ace763a5da908bacf147d972")); // CLASS_ID
1615 EXPECT_EQ(get_contract_instance_helper(2),
1616 FF("0x0000000000000000000000000000000000000000000000000000000000000000")); // INIT HASH
1617 EXPECT_EQ(get_contract_instance_helper(0, bb::avm2::MemoryTag::U1), FF::one()); // EXISTS
1618}
1619
1620// Calls add8, sucesscopy, return
1622{
1623 std::vector<FuzzInstruction> instructions;
1624 auto contract_address = context.get_contract_address(0);
1626 instructions.push_back(SET_FF_Instruction{
1628
1629 uint32_t l2_gas = 10000;
1631 instructions.push_back(
1633
1634 uint32_t da_gas = 10000;
1636 instructions.push_back(
1638
1639 uint16_t arg_size = 0;
1640 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1641 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1642
1643 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1644 .da_gas_address = da_gas_address,
1645 .contract_address_address = contract_address_address,
1646 .calldata_address = args_address,
1647 .calldata_size_address = arg_size_address,
1648 .calldata_size = arg_size,
1649 .is_static_call = false });
1650
1651 instructions.push_back(
1653 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
1654 auto control_flow = ControlFlow(instruction_blocks);
1655 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1656 auto bytecode = control_flow.build_bytecode(
1657 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1658
1659 auto result = simulate_with_default_tx(bytecode, {});
1660 EXPECT_EQ(result.output.at(0), FF::one());
1661}
1662
1663// Performs static call to ZERO_DIVISION, SUCCESSCOPY, RETURN
1664// The result should be 0
1665TEST_F(ExternalCallsFuzzTest, CallToZeroDivisionSuccessCopy)
1666{
1667 std::vector<FuzzInstruction> instructions;
1668 auto contract_address = context.get_contract_address(1);
1670 instructions.push_back(SET_FF_Instruction{
1672
1673 uint32_t l2_gas = 10000;
1675 instructions.push_back(
1677
1678 uint32_t da_gas = 10000;
1680 instructions.push_back(
1682
1683 uint16_t arg_size = 0;
1684 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1685 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1686
1687 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1688 .da_gas_address = da_gas_address,
1689 .contract_address_address = contract_address_address,
1690 .calldata_address = args_address,
1691 .calldata_size_address = arg_size_address,
1692 .calldata_size = arg_size,
1693 .is_static_call = true });
1694 instructions.push_back(
1696 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
1697 auto control_flow = ControlFlow(instruction_blocks);
1698 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1699 auto bytecode = control_flow.build_bytecode(
1700 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 1 });
1701 auto result = simulate_with_default_tx(bytecode, {});
1702 EXPECT_EQ(result.output.at(0), FF::zero());
1703 EXPECT_EQ(result.reverted, false);
1704}
1705
1707TEST_F(ExternalCallsFuzzTest, StaticCallToNonStaticFunctionSuccessCopy)
1708{
1709 std::vector<FuzzInstruction> instructions;
1710 auto contract_address = context.get_contract_address(2);
1712 instructions.push_back(SET_FF_Instruction{
1714
1715 uint32_t l2_gas = 10000;
1717 instructions.push_back(
1719
1720 uint32_t da_gas = 10000;
1722 instructions.push_back(
1724
1725 uint16_t arg_size = 0;
1726 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1727 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1728
1729 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1730 .da_gas_address = da_gas_address,
1731 .contract_address_address = contract_address_address,
1732 .calldata_address = args_address,
1733 .calldata_size_address = arg_size_address,
1734 .calldata_size = arg_size,
1735 .is_static_call = true });
1736 instructions.push_back(
1738 auto instruction_blocks = std::vector<std::vector<FuzzInstruction>>{ instructions };
1739 auto control_flow = ControlFlow(instruction_blocks);
1740 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1741 auto bytecode = control_flow.build_bytecode(
1742 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 1 });
1743 auto result = simulate_with_default_tx(bytecode, {});
1744 EXPECT_EQ(result.output.at(0), FF::zero());
1745 EXPECT_EQ(result.reverted, false);
1746}
1747} // namespace external_calls
::FuzzInstruction FuzzInstruction
const uint32_t BLOCK_NUMBER
Definition constants.hpp:16
const Gas GAS_LIMIT
Definition constants.hpp:40
const std::vector< std::vector< uint8_t > > PREDEFINED_FUNCTIONS
Definition constants.hpp:67
const FF TRANSACTION_FEE
Definition constants.hpp:38
const FF MSG_SENDER
Definition constants.hpp:33
const FF CHAIN_ID
Definition constants.hpp:14
constexpr uint128_t FEE_PER_DA_GAS
Definition constants.hpp:21
const FF VERSION
Definition constants.hpp:15
const bool IS_STATIC_CALL
Definition constants.hpp:39
constexpr uint128_t FEE_PER_L2_GAS
Definition constants.hpp:22
std::shared_ptr< Napi::ThreadSafeFunction > bytecode
StrictMock< MockContractDB > contract_db
uses barretenberg/vm2 to simulate the bytecode
Definition simulator.hpp:54
void SetUp() override
Definition fuzz.test.cpp:32
void TearDown() override
Definition fuzz.test.cpp:43
FuzzerContext context
Definition fuzz.test.cpp:65
SimulatorResult simulate_with_default_tx(std::vector< uint8_t > &bytecode, std::vector< FF > calldata)
Definition fuzz.test.cpp:45
FF get_result_of_instruction_16(FuzzInstruction instruction, bb::avm2::MemoryTag return_value_tag=bb::avm2::MemoryTag::U8)
Definition fuzz.test.cpp:95
FF get_result_of_instruction(FuzzInstruction instruction, bb::avm2::MemoryTag return_value_tag=bb::avm2::MemoryTag::U8)
Definition fuzz.test.cpp:72
static FuzzerWorldStateManager * getInstance()
Definition dbs.hpp:80
world_state::WorldStateRevision fork()
Definition dbs.cpp:204
void write_fee_payer_balance(const AztecAddress &fee_payer, const FF &balance)
Definition dbs.cpp:227
FF simulate_jump_if_depth_2_helper(uint8_t first_boolean_value, uint8_t second_boolean_value)
FF simulate_jump_to_block_helper(uint8_t condition_value)
FF getenvvar_helper(uint8_t type, bb::avm2::MemoryTag return_value_tag=bb::avm2::MemoryTag::FF)
FF get_contract_instance_helper(uint8_t member_enum, bb::avm2::MemoryTag return_value_tag=bb::avm2::MemoryTag::FF)
FuzzerWorldStateManager * ws_mgr
Definition fuzz.test.cpp:16
void register_functions(FuzzerContext &context)
Definition fuzz.test.cpp:18
uint64_t da_gas
uint64_t l2_gas
Instruction instruction
TEST_F(ArithmeticFuzzTest, ADD8)
TEST_F(FuzzTest, DirectWithIndirect)
AvmFlavorSettings::FF FF
Definition field.hpp:10
TEST_F(FuzzTest, CopyCalldataThenReturnData)
TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke)
TEST_F(ExecutionEnvironmentFuzzTest, GetEnvVarSmoke)
TEST_F(ExternalCallsFuzzTest, ExternalCallToAdd8)
TEST_F(FuzzTest, InternalCalledBlockUsesInternalReturn)
TEST_F(FuzzTest, SET16)
TEST_F(FuzzTest, SendL2ToL1Msg)
TEST_F(FuzzTest, EmitNullifierThenNullifierExists)
TEST_F(FuzzTest, SstoreThenSload)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
TEST_F(FuzzTest, CAST8)
unsigned __int128 uint128_t
Definition serialize.hpp:44
Tx create_default_tx(const AztecAddress &contract_address, const AztecAddress &sender_address, const std::vector< FF > &calldata, const FF &transaction_fee, bool is_static_call, const Gas &gas_limit)
mem[result_offset] = mem[a_address] + mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] + mem[b_address]
mem[result_offset] = mem[a_address] & mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] & mem[b_address]
uint32_t address
ParamRef l2_gas_address
CALLDATACOPY: M[dstOffset:dstOffset+M[copySizeOffset]] = calldata[M[cdStartOffset]:M[cdStartOffset]+M...
CAST_16: cast mem[src_offset_index] to target_tag and store at dst_offset.
CAST_8: cast mem[src_offset_index] to target_tag and store at dst_offset.
mem[result_offset] = mem[a_address] / mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] / mem[b_address]
EMITNOTEHASH: M[note_hash_offset] = note_hash; emit note hash to the note hash tree.
EMITNULIFIER: inserts new nullifier to the nullifier tree.
mem[result_offset] = mem[a_address] == mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] == mem[b_address]
finalizes the current block with Return and switches to the first non-terminated block
ReturnOptions return_options
GETENVVAR: M[result_offset] = getenvvar(type)
inserts INTERNALCALL instruction to the current block creates a new block and sets it as the current ...
uint16_t target_program_block_instruction_block_idx
insert instruction block to the current block
finalizes the current block with jump if, creates two new blocks, sets the first as the then block an...
uint16_t then_program_block_instruction_block_idx
finalizes the current block with a jump to the block, which does not create a loop in the graph (defi...
uint16_t target_block_idx
finalizes the current block with jump, creates a new block and sets it as the current block
uint16_t target_program_block_instruction_block_idx
mem[result_offset] = mem[a_address] < mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] < mem[b_address]
mem[result_offset] = mem[a_address] <= mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] <= mem[b_address]
MOV_16 instruction: mem[dst_offset] = mem[src_offset].
MOV_8 instruction: mem[dst_offset] = mem[src_offset].
mem[result_offset] = mem[a_address] * mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] * mem[b_address]
NOTEHASHEXISTS: M[result_offset] = NOTEHASHEXISTS(M[notehash_offset], M[leaf_index_offset]) len = len...
NULLIFIEREXISTS: checks if nullifier exists in the nullifier tree Gets contract's address by GETENVVA...
mem[result_offset] = mem[a_address] | mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] | mem[b_address]
: RETURNDATASIZE + RETURNDATACOPY:
uint8_t return_size
SET_128 instruction.
MemoryTagWrapper value_tag
SET_16 instruction.
MemoryTagWrapper value_tag
SET_32 instruction.
MemoryTagWrapper value_tag
SET_64 instruction.
MemoryTagWrapper value_tag
SET_8 instruction.
MemoryTagWrapper value_tag
SET_FF instruction.
MemoryTagWrapper value_tag
mem[result_offset] = mem[a_address] << mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] << mem[b_address]
mem[result_offset] = mem[a_address] >> mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] >> mem[b_address]
SLOAD: M[slot_offset] = slot; M[result_offset] = S[M[slotOffset]].
SSTORE: M[slot_offset_index] = slot; S[M[slotOffset]] = M[srcOffset].
mem[result_offset] = mem[a_address] - mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] - mem[b_address]
std::vector< FF > output
Definition simulator.hpp:33
MemoryTagWrapper tag
mem[result_offset] = mem[a_address] ^ mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] ^ mem[b_address]