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
51 std::vector<FF> calldata,
52 const std::vector<FF>& note_hashes)
53 {
55
56 ws_mgr->append_note_hashes(note_hashes);
57
58 auto contract_address = context.register_contract_from_bytecode(bytecode);
59 FuzzerContractDB contract_db = context.get_contract_db();
60
62 FF fee_required_da = FF(tx.effective_gas_fees.fee_per_da_gas) * FF(tx.gas_settings.gas_limits.da_gas);
63 FF fee_required_l2 = FF(tx.effective_gas_fees.fee_per_l2_gas) * FF(tx.gas_settings.gas_limits.l2_gas);
64 ws_mgr->write_fee_payer_balance(tx.fee_payer, fee_required_da + fee_required_l2);
65 auto cpp_simulator = CppSimulator();
66 auto globals = create_default_globals();
67
68 auto result = cpp_simulator.simulate(*ws_mgr,
70 tx,
71 globals,
72 /*public_data_writes=*/{},
73 /*note_hashes=*/{},
74 /*protocol_contracts=*/{});
75
76 ws_mgr->revert();
77
78 return result;
79 }
80
82};
83
84namespace arithmetic {
86 protected:
87 // set(addr 0, 5) set(addr 1, 2) OP(addr 0, addr 1, addr 2) return(addr 2)
90 {
91 auto set_instruction_1 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
92 .result_address = AddressRef{ .address = 0 },
93 .value = 5 };
94 auto set_instruction_2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
95 .result_address = AddressRef{ .address = 1 },
96 .value = 2 };
97 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, instruction };
98 auto return_options =
99 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 2 };
100 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
101 auto control_flow = ControlFlow(instruction_blocks);
102 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
103 auto bytecode = control_flow.build_bytecode(return_options);
104
105 auto result = simulate_with_default_tx(bytecode, {});
106 return result.output.at(0);
107 }
108
109 // Helper function for 16-bit instructions
110 // set(addr 0, 5) set(addr 1, 2) OP_16(addr 0, addr 1, addr 2) return(addr 2)
113 {
114 auto set_instruction_1 =
116 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
117 .value = 5 };
118 auto set_instruction_2 =
120 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
121 .value = 2 };
122 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, instruction };
123
124 auto return_options =
125 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 2 };
126 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
127 auto control_flow = ControlFlow(instruction_blocks);
128 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
129 auto bytecode = control_flow.build_bytecode(return_options);
130
131 auto result = simulate_with_default_tx(bytecode, {});
132 return result.output.at(0);
133 }
134};
135
137{
138 auto add_instruction = ADD_8_Instruction{
139 .a_address =
142 .index = 0,
144 },
145 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
146 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
147 };
148 auto result = get_result_of_instruction(add_instruction);
149 EXPECT_EQ(result, 7);
150}
151
153{
154 auto sub_instruction = SUB_8_Instruction{
156 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
157 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
158 };
159 auto result = get_result_of_instruction(sub_instruction);
160 EXPECT_EQ(result, 3);
161}
162
164{
165 auto mul_instruction = MUL_8_Instruction{
167 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
168 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
169 };
170 auto result = get_result_of_instruction(mul_instruction);
171 EXPECT_EQ(result, 10);
172}
173
175{
176 auto div_instruction = DIV_8_Instruction{
178 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
179 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
180 };
181 auto result = get_result_of_instruction(div_instruction);
182 EXPECT_EQ(result, 2);
183}
184
186{
187 auto eq_instruction = EQ_8_Instruction{
189 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
190 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
191 };
192 auto result = get_result_of_instruction(eq_instruction, bb::avm2::MemoryTag::U1);
193 EXPECT_EQ(result, 0);
194}
195
197{
198 auto lt_instruction = LT_8_Instruction{
200 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
201 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
202 };
203 auto result = get_result_of_instruction(lt_instruction, bb::avm2::MemoryTag::U1);
204 EXPECT_EQ(result, 0);
205}
206
208{
209 auto lte_instruction = LTE_8_Instruction{
211 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
212 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
213 };
214 auto result = get_result_of_instruction(lte_instruction, bb::avm2::MemoryTag::U1);
215 EXPECT_EQ(result, 0);
216}
217
219{
220 auto and_instruction = AND_8_Instruction{
222 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
223 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
224 };
225 auto result = get_result_of_instruction(and_instruction);
226 EXPECT_EQ(result, 0);
227}
228
230{
231 auto or_instruction = OR_8_Instruction{
233 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
234 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
235 };
236 auto result = get_result_of_instruction(or_instruction);
237 EXPECT_EQ(result, 7);
238}
239
241{
242 auto xor_instruction = XOR_8_Instruction{
244 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
245 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
246 };
247 auto result = get_result_of_instruction(xor_instruction);
248 EXPECT_EQ(result, 7);
249}
250
252{
253 auto shl_instruction = SHL_8_Instruction{
255 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
256 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
257 };
258 auto result = get_result_of_instruction(shl_instruction);
259 EXPECT_EQ(result, 20);
260}
261
263{
264 auto shr_instruction = SHR_8_Instruction{
266 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
267 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
268 };
269 auto result = get_result_of_instruction(shr_instruction);
270 EXPECT_EQ(result, 1);
271}
272
273// set(0, 4, FF) set(1, 2, FF) fdiv(FF, 0, 1, 2) return(2)
275{
276 auto fdiv_instruction = FDIV_8_Instruction{
278 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
279 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
280 };
281 auto set_instruction_1 =
283 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
284 .value = 4 };
285 auto set_instruction_2 =
287 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
288 .value = 2 };
289 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, fdiv_instruction };
290
291 auto return_options =
292 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 };
293 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
294 auto control_flow = ControlFlow(instruction_blocks);
295 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
296 auto bytecode = control_flow.build_bytecode(return_options);
297
298 auto result = simulate_with_default_tx(bytecode, {});
299 EXPECT_EQ(result.output.at(0), 2);
300}
301
302// set(0, 0, U8) not(U8, 0, 1) return(1)
304{
305 auto set_instruction =
307 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
308 .value = 0 };
309 auto not_instruction = NOT_8_Instruction{
311 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
312 };
313 auto instructions = std::vector<FuzzInstruction>{ set_instruction, not_instruction };
314 auto return_options =
315 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
316 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
317 auto control_flow = ControlFlow(instruction_blocks);
318 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
319 auto bytecode = control_flow.build_bytecode(return_options);
320
321 auto result = simulate_with_default_tx(bytecode, {});
322 EXPECT_EQ(result.output.at(0), 255);
323}
324
326{
327 auto add_instruction = ADD_16_Instruction{
328 .a_address =
331 .index = 0,
333 },
334 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
335 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
336 };
337 auto result = get_result_of_instruction_16(add_instruction);
338 EXPECT_EQ(result, 7);
339}
340
342{
343 auto sub_instruction = SUB_16_Instruction{
345 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
346 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
347 };
348 auto result = get_result_of_instruction_16(sub_instruction);
349 EXPECT_EQ(result, 3);
350}
351
353{
354 auto mul_instruction = MUL_16_Instruction{
356 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
357 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
358 };
359 auto result = get_result_of_instruction_16(mul_instruction);
360 EXPECT_EQ(result, 10);
361}
362
364{
365 auto div_instruction = DIV_16_Instruction{
367 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
368 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
369 };
370 auto result = get_result_of_instruction_16(div_instruction);
371 EXPECT_EQ(result, 2);
372}
373
375{
376 auto eq_instruction = EQ_16_Instruction{
378 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
379 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
380 };
381 auto result = get_result_of_instruction_16(eq_instruction, bb::avm2::MemoryTag::U1);
382 EXPECT_EQ(result, 0);
383}
384
386{
387 auto lt_instruction = LT_16_Instruction{
389 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
390 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
391 };
392 auto result = get_result_of_instruction_16(lt_instruction, bb::avm2::MemoryTag::U1);
393 EXPECT_EQ(result, 0);
394}
395
397{
398 auto lte_instruction = LTE_16_Instruction{
400 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
401 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
402 };
403 auto result = get_result_of_instruction_16(lte_instruction, bb::avm2::MemoryTag::U1);
404 EXPECT_EQ(result, 0);
405}
406
408{
409 auto and_instruction = AND_16_Instruction{
411 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
412 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
413 };
414 auto result = get_result_of_instruction_16(and_instruction);
415 EXPECT_EQ(result, 0);
416}
417
419{
420 auto or_instruction = OR_16_Instruction{
422 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
423 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
424 };
425 auto result = get_result_of_instruction_16(or_instruction);
426 EXPECT_EQ(result, 7);
427}
428
430{
431 auto xor_instruction = XOR_16_Instruction{
433 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
434 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
435 };
436 auto result = get_result_of_instruction_16(xor_instruction);
437 EXPECT_EQ(result, 7);
438}
439
441{
442 auto shl_instruction = SHL_16_Instruction{
444 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
445 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
446 };
447 auto result = get_result_of_instruction_16(shl_instruction);
448 EXPECT_EQ(result, 20);
449}
450
452{
453 auto shr_instruction = SHR_16_Instruction{
455 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
456 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
457 };
458 auto result = get_result_of_instruction_16(shr_instruction);
459 EXPECT_EQ(result, 1);
460}
461
462// set(0, 4, FF) set(1, 2, FF) fdiv_16(FF, 0, 1, 2) return(2)
464{
465 auto fdiv_instruction = FDIV_16_Instruction{
467 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
468 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
469 };
470 auto set_instruction_1 =
472 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
473 .value = 4 };
474 auto set_instruction_2 =
476 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
477 .value = 2 };
478 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, fdiv_instruction };
479
480 auto return_options =
481 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 };
482 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
483 auto control_flow = ControlFlow(instruction_blocks);
484 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
485 auto bytecode = control_flow.build_bytecode(return_options);
486
487 auto result = simulate_with_default_tx(bytecode, {});
488 EXPECT_EQ(result.output.at(0), 2);
489}
490
491// set(0, 0, U8) not_16(U8, 0, 1) return(1)
493{
494 auto set_instruction =
496 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
497 .value = 0 };
498 auto not_instruction = NOT_16_Instruction{
500 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
501 };
502 auto instructions = std::vector<FuzzInstruction>{ set_instruction, not_instruction };
503 auto return_options =
504 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
505 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
506 auto control_flow = ControlFlow(instruction_blocks);
507 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
508 auto bytecode = control_flow.build_bytecode(return_options);
509
510 auto result = simulate_with_default_tx(bytecode, {});
511 EXPECT_EQ(result.output.at(0), 255);
512}
513
514} // namespace arithmetic
515
517// set(10, 1, U16) set(0, 2, U8) cast_8(U8, 0, 1, U16) return(1)
518// if cast worked, should return 2 (the U8 value cast to U16)
519// if cast failed, should return 1 (the original U16 value)
521{
523 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
524 .value = 1 };
526 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
527 .value = 2 };
528 auto cast_instruction = CAST_8_Instruction{
530 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
531 .target_tag = bb::avm2::MemoryTag::U16
532 };
533 auto instructions = std::vector<FuzzInstruction>{ set_u16, set_u8, cast_instruction };
534 auto return_options =
535 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
536 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
537 auto control_flow = ControlFlow(instruction_blocks);
538 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
539 auto bytecode = control_flow.build_bytecode(return_options);
540
541 auto result = simulate_with_default_tx(bytecode, {});
542 EXPECT_EQ(result.output.at(0), 2);
543}
544
545// set(10, 1, U16) set(0, 2, U8) cast_16(U8, 0, 1, U16) return(1)
546// if cast worked, should return 2 (the U8 value cast to U16)
547// if cast failed, should return 1 (the original U16 value)
549{
551 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
552 .value = 1 };
554 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
555 .value = 2 };
556 auto cast_instruction = CAST_16_Instruction{
558 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
559 .target_tag = bb::avm2::MemoryTag::U16
560 };
561 auto instructions = std::vector<FuzzInstruction>{ set_u16, set_u8, cast_instruction };
562 auto return_options =
563 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
564 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
565 auto control_flow = ControlFlow(instruction_blocks);
566 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
567 auto bytecode = control_flow.build_bytecode(return_options);
568
569 auto result = simulate_with_default_tx(bytecode, {});
570 EXPECT_EQ(result.output.at(0), 2);
571}
572} // namespace type_conversion
573
574namespace machine_memory {
575// set(0, 0xabcd, U16) return(0)
577{
578 const uint16_t test_value = 0xABCD;
579 auto set_instruction =
581 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
582 .value = test_value };
583 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
584 auto return_options =
585 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 0 };
586 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
587 auto control_flow = ControlFlow(instruction_blocks);
588 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
589 auto bytecode = control_flow.build_bytecode(return_options);
590
591 auto result = simulate_with_default_tx(bytecode, {});
592 EXPECT_EQ(result.output.at(0), test_value);
593}
594// set(0, 0x12345678, U32) return(0)
596{
597 const uint32_t test_value = 0x12345678UL;
598 auto set_instruction =
600 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
601 .value = test_value };
602 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
603 auto return_options =
604 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U32, .return_value_offset_index = 0 };
605 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
606 auto control_flow = ControlFlow(instruction_blocks);
607 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
608 auto bytecode = control_flow.build_bytecode(return_options);
609
610 auto result = simulate_with_default_tx(bytecode, {});
611 EXPECT_EQ(result.output.at(0), test_value);
612}
613
614// set(0, 0xabcdef0123456789, U64) return(0)
616{
617 const uint64_t test_value = 0xABCDEF0123456789ULL;
618 auto set_instruction =
620 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
621 .value = test_value };
622 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
623 auto return_options =
624 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U64, .return_value_offset_index = 0 };
625 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
626 auto control_flow = ControlFlow(instruction_blocks);
627 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
628 auto bytecode = control_flow.build_bytecode(return_options);
629
630 auto result = simulate_with_default_tx(bytecode, {});
631 EXPECT_EQ(result.output.at(0), test_value);
632}
633
634// set(0, something, U128) return(0)
636{
637 const uint64_t test_value_low = 0xFEDCBA9876543210ULL;
638 const uint64_t test_value_high = 0x123456789ABCDEF0ULL;
639 const uint128_t test_value =
640 (static_cast<uint128_t>(test_value_high) << 64) | static_cast<uint128_t>(test_value_low);
641 auto set_instruction =
643 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
644 .value_low = test_value_low,
645 .value_high = test_value_high };
646 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
647 auto return_options = ReturnOptions{ .return_size = 1,
648 .return_value_tag = bb::avm2::MemoryTag::U128,
649 .return_value_offset_index = 0 };
650 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
651 auto control_flow = ControlFlow(instruction_blocks);
652 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
653 auto bytecode = control_flow.build_bytecode(return_options);
654
655 auto result = simulate_with_default_tx(bytecode, {});
656 EXPECT_EQ(result.output.at(0), test_value);
657}
658
659// set(0, 123456789, FF) return(0)
661{
662 const bb::avm2::FF test_value = bb::avm2::FF(123456789);
663 auto set_instruction =
665 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
666 .value = test_value };
667 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
668 auto return_options =
669 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 };
670 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
671 auto control_flow = ControlFlow(instruction_blocks);
672 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
673 auto bytecode = control_flow.build_bytecode(return_options);
674
675 auto result = simulate_with_default_tx(bytecode, {});
676 EXPECT_EQ(result.output.at(0), test_value);
677}
678
679// set(0, 0x42, U8) set(1, 0x43, U8) mov_8(U8, 0, 1) return(1)
681{
682 const uint8_t test_value = 0x42;
683 const uint8_t test_value2 = 0x43;
684 auto set_instruction =
686 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
687 .value = test_value };
688 auto set_instruction2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
689 .result_address = AddressRef{ .address = 1 },
690 .value = test_value2 };
691 auto mov_instruction = MOV_8_Instruction{
693 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
694 };
695 auto instructions = std::vector<FuzzInstruction>{ set_instruction, set_instruction2, mov_instruction };
696 auto return_options =
697 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
698 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
699 auto control_flow = ControlFlow(instruction_blocks);
700 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
701 auto bytecode = control_flow.build_bytecode(return_options);
702
703 auto result = simulate_with_default_tx(bytecode, {});
704 EXPECT_EQ(result.output.at(0), test_value);
705}
706
707// set(0, 0xbabe, U16) set(1, 0xc0fe, U16) mov_16(U16, 0, 1) return(1)
709{
710 const uint16_t test_value = 0xbabe;
711 const uint16_t test_value2 = 0xc0fe;
712 auto set_instruction =
714 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
715 .value = test_value };
716 auto set_instruction2 =
718 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
719 .value = test_value2 };
720 auto mov_instruction = MOV_16_Instruction{
722 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
723 };
724 auto instructions = std::vector<FuzzInstruction>{ set_instruction, set_instruction2, mov_instruction };
725 auto return_options =
726 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
727 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
728 auto control_flow = ControlFlow(instruction_blocks);
729 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
730 auto bytecode = control_flow.build_bytecode(return_options);
731
732 auto result = simulate_with_default_tx(bytecode, {});
733 EXPECT_EQ(result.output.at(0), test_value);
734}
735
736} // namespace machine_memory
737
738namespace control_flow {
739
741 protected:
742 // set u1 condition value b1
743 // ↙ ↘
744 // set u1 b2 return 4
745 // ↙ ↘
746 // ret 2 ret 3
747 FF simulate_jump_if_depth_2_helper(uint8_t first_boolean_value, uint8_t second_boolean_value)
748 {
749 auto set_instruction_block_1 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
750 .result_address = AddressRef{ .address = 1 },
751 .value = first_boolean_value };
752 auto instruction_block_1 = InstructionBlock{ .instructions = { set_instruction_block_1 } };
753 auto set_instruction_block_2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
754 .result_address = AddressRef{ .address = 2 },
755 .value = second_boolean_value };
756 auto instruction_block_2 = InstructionBlock{ .instructions = { set_instruction_block_2 } };
757 auto instruction_blocks = std::vector<InstructionBlock>{ instruction_block_1, instruction_block_2 };
758 for (uint8_t i = 2; i < 5; i++) {
759 auto set_instruction =
761 .result_address = AddressRef{ .address = i, .mode = AddressingMode::Direct },
762 .value = i };
763 instruction_blocks.push_back(InstructionBlock{ .instructions = { set_instruction } });
764 }
765 auto return_options = ReturnOptions{ .return_size = 1,
766 .return_value_tag = bb::avm2::MemoryTag::U8,
767 .return_value_offset_index = 1 };
768 auto control_flow = ControlFlow(instruction_blocks);
769 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
770 control_flow.process_cfg_instruction(
772 .else_program_block_instruction_block_idx = 4, // set 4
773 .condition_offset_index = 0 });
774 control_flow.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 2, // set 2
775 .else_program_block_instruction_block_idx = 3, // set 3
776 .condition_offset_index = 1 });
777 auto bytecode = control_flow.build_bytecode(return_options);
778
779 auto result = simulate_with_default_tx(bytecode, {});
780 return result.output.at(0);
781 }
782
783 // set u1 condition
784 // ↙ ↘
785 // nop ----→ return 2
786 FF simulate_jump_to_block_helper(uint8_t condition_value)
787 {
788 auto set_return_value_block =
791 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
792 .value = 2 } } };
793 auto instruction_block_1 =
796 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
797 .value = condition_value } } };
798 auto instruction_blocks =
799 std::vector<InstructionBlock>{ instruction_block_1, InstructionBlock(), set_return_value_block };
800 auto return_options = ReturnOptions{ .return_size = 1,
801 .return_value_tag = bb::avm2::MemoryTag::U8,
802 .return_value_offset_index = 1 };
803 auto control_flow = ControlFlow(instruction_blocks);
804 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
805 control_flow.process_cfg_instruction(
807 .else_program_block_instruction_block_idx = 2, // set return value
808 .condition_offset_index = 0 });
809 control_flow.process_cfg_instruction(JumpToBlock{ .target_block_idx = 2 });
810 auto bytecode = control_flow.build_bytecode(return_options);
811
812 auto result = simulate_with_default_tx(bytecode, {});
813 return result.output.at(0);
814 }
815};
816
817// block1 set return value 10
818// ↓
819// block2 set return value 11 and return return value
820TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke)
821{
822 auto block1_instructions =
825 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
826 .value = 10 } } };
827 auto block2_instructions =
830 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
831 .value = 11 } } };
832 auto instruction_blocks = std::vector<InstructionBlock>{ block1_instructions, block2_instructions };
833 auto return_options =
834 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
835 auto control_flow = ControlFlow(instruction_blocks);
836 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
838 auto bytecode = control_flow.build_bytecode(return_options);
839
840 auto result = simulate_with_default_tx(bytecode, {});
841 EXPECT_EQ(result.output.at(0), 11);
842}
843
844// block1 set return value 10
845// ↓
846// block2 set return value 11
847// ↓
848// block3 set return value 12 and return return value
849TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke2)
850{
851 auto block1_instructions =
854 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
855 .value = 10 } } };
856 auto block2_instructions =
859 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
860 .value = 11 } } };
861 auto block3_instructions =
864 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
865 .value = 12 } } };
866 auto instruction_blocks =
867 std::vector<InstructionBlock>{ block1_instructions, block2_instructions, block3_instructions };
868 auto return_options =
869 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
870 auto control_flow = ControlFlow(instruction_blocks);
871 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
874 auto bytecode = control_flow.build_bytecode(return_options);
875
876 auto result = simulate_with_default_tx(bytecode, {});
877 EXPECT_EQ(result.output.at(0), 12);
878}
879
880// block1 set u8 value 10
881// ↓
882// block2 tries to return u8
883// if blocks does not share defined variables, block2 will return 0
884TEST_F(ControlFlowFuzzTest, JumpToNewBlockSharesVariables)
885{
888 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
889 .value = 10 } } };
890
891 auto instruction_blocks = std::vector<InstructionBlock>{ block1 };
892 auto return_options =
893 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
894 auto control_flow = ControlFlow(instruction_blocks);
895 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
897 auto bytecode = control_flow.build_bytecode(return_options);
898
899 auto result = simulate_with_default_tx(bytecode, {});
900 EXPECT_EQ(result.output.at(0), 10);
901}
902
903// block1 set u1 condition value
904// ↙ ↘
905// return 11 return 12
906TEST_F(ControlFlowFuzzTest, JumpIfToNewBlockSmoke)
907{
908 auto set_true_block =
911 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
912 .value = 1 } } };
913 auto set_false_block =
916 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
917 .value = 0 } } };
918 auto block2_instructions =
921 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
922 .value = 11 } } };
923 auto block3_instructions =
926 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
927 .value = 12 } } };
928 auto instruction_blocks =
929 std::vector<InstructionBlock>{ set_true_block, set_false_block, block2_instructions, block3_instructions };
930 auto return_options =
931 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
932 auto control_flow = ControlFlow(instruction_blocks);
933 // set true, go to block2
934 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
936 .else_program_block_instruction_block_idx = 3,
937 .condition_offset_index = 1 });
938 auto bytecode_1 = control_flow.build_bytecode(return_options);
939 auto control_flow2 = ControlFlow(instruction_blocks);
940 // set false, go to block3
941 control_flow2.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
942 control_flow2.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 2,
943 .else_program_block_instruction_block_idx = 3,
944 .condition_offset_index = 1 });
945 auto bytecode_2 = control_flow2.build_bytecode(return_options);
946
947 auto result_1 = simulate_with_default_tx(bytecode_1, {});
948 auto result_2 = simulate_with_default_tx(bytecode_2, {});
949 EXPECT_EQ(result_1.output.at(0), 11);
950 EXPECT_EQ(result_2.output.at(0), 12);
951}
952
953TEST_F(ControlFlowFuzzTest, JumpIfDepth2Smoke)
954{
955 EXPECT_EQ(simulate_jump_if_depth_2_helper(1, 1), 2);
956 EXPECT_EQ(simulate_jump_if_depth_2_helper(1, 0), 3);
957 EXPECT_EQ(simulate_jump_if_depth_2_helper(0, 1), 4);
958 EXPECT_EQ(simulate_jump_if_depth_2_helper(0, 0), 4);
959}
960
961TEST_F(ControlFlowFuzzTest, JumpToBlockSmoke)
962{
963 EXPECT_EQ(simulate_jump_to_block_helper(1), 2);
964 EXPECT_EQ(simulate_jump_to_block_helper(0), 2);
965}
966
967// Nice catch! That's actually fully ai generated test.
968// test if terminate with return works
969// set u1 condition value
970// ↙ ↘
971// set FF, ret set U128, ret
972TEST_F(ControlFlowFuzzTest, JumpIfToNewBlockWithReturn)
973{
974 // Block 0: Set condition (U1)
975 auto set_condition_block =
978 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
979 .value = 1 } } };
980
981 // Block 1: Set FF value
982 const bb::avm2::FF ff_value = bb::avm2::FF(123456789);
983 auto set_ff_block =
986 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
987 .value = ff_value } } };
988
989 // Block 2: Set U128 value
990 const uint64_t u128_value_low = 0xFEDCBA9876543210ULL;
991 const uint64_t u128_value_high = 0x123456789ABCDEF0ULL;
992 auto set_u128_block =
995 .result_address = AddressRef{ .address = 20, .mode = AddressingMode::Direct },
996 .value_low = u128_value_low,
997 .value_high = u128_value_high } } };
998
999 auto instruction_blocks = std::vector<InstructionBlock>{ set_condition_block, set_ff_block, set_u128_block };
1000
1001 auto control_flow = ControlFlow(instruction_blocks);
1002
1003 // Insert condition block
1004 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1005
1006 // JumpIf: if condition is true (1), go to block 1 (FF), else go to block 2 (U128)
1008 .else_program_block_instruction_block_idx = 2,
1009 .condition_offset_index = 0 });
1010
1011 // Finalize then block (FF) with Return
1012 control_flow.process_cfg_instruction(FinalizeWithReturn{
1014 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1015
1016 // Finalize else block (U128) with Return
1017 control_flow.process_cfg_instruction(FinalizeWithReturn{
1019 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1020
1021 // Test with condition = true (should return FF value)
1022 auto control_flow_true = ControlFlow(instruction_blocks);
1023 control_flow_true.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1024 control_flow_true.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 1,
1025 .else_program_block_instruction_block_idx = 2,
1026 .condition_offset_index = 0 });
1027 control_flow_true.process_cfg_instruction(FinalizeWithReturn{
1029 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1030 control_flow_true.process_cfg_instruction(FinalizeWithReturn{
1032 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1033
1034 auto bytecode_true = control_flow_true.build_bytecode(ReturnOptions{
1035 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 });
1036
1037 auto result_true = simulate_with_default_tx(bytecode_true, {});
1038 EXPECT_EQ(result_true.output.at(0), ff_value);
1039
1040 // Test with condition = false (should return U128 value)
1041 auto set_condition_false_block =
1044 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1045 .value = 0 } } };
1046 auto instruction_blocks_false =
1047 std::vector<InstructionBlock>{ set_condition_false_block, set_ff_block, set_u128_block };
1048
1049 auto control_flow_false = ControlFlow(instruction_blocks_false);
1050 control_flow_false.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1051 control_flow_false.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 1,
1052 .else_program_block_instruction_block_idx = 2,
1053 .condition_offset_index = 0 });
1054 control_flow_false.process_cfg_instruction(FinalizeWithReturn{
1056 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1057 control_flow_false.process_cfg_instruction(FinalizeWithReturn{
1059 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1060
1061 const uint128_t expected_u128_value =
1062 (static_cast<uint128_t>(u128_value_high) << 64) | static_cast<uint128_t>(u128_value_low);
1063 auto bytecode_false = control_flow_false.build_bytecode(ReturnOptions{
1064 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 });
1065
1066 auto result_false = simulate_with_default_tx(bytecode_false, {});
1067 EXPECT_EQ(result_false.output.at(0), expected_u128_value);
1068}
1069} // namespace control_flow
1070
1072TEST_F(FuzzTest, SstoreThenSload)
1073{
1074 // M[10] = 10
1075 auto set_value_instruction =
1077 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1078 .value = 10 };
1079 // S[10] = M[10]
1080 auto sstore_instruction = SSTORE_Instruction{
1082 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1083 .slot = 10
1084 };
1085 // M[2] = S[10], FF tag
1086 auto sload_instruction =
1088 .slot_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1089 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct } };
1090 // M[10] = 11
1091 auto set_value_instruction2 =
1093 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1094 .value = 11 };
1095
1096 auto set_sstore_sload_block = InstructionBlock{
1097 .instructions = { set_value_instruction, sstore_instruction, sload_instruction, set_value_instruction2 }
1098 };
1099
1100 auto instruction_blocks = std::vector<InstructionBlock>{ set_sstore_sload_block };
1101 // FF should be set via sload instruction
1102 auto return_options = ReturnOptions{ .return_size = 1,
1103 .return_value_tag = bb::avm2::MemoryTag::FF,
1104 .return_value_offset_index = 1 /* after sload instruction */ };
1105 auto control_flow = ControlFlow(instruction_blocks);
1106 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1107 auto bytecode = control_flow.build_bytecode(return_options);
1108
1109 auto result = simulate_with_default_tx(bytecode, {});
1110 EXPECT_EQ(result.output.at(0), 10);
1111}
1112} // namespace public_storage
1113
1115
1117 protected:
1119 {
1120 auto getenvvar_instruction =
1122 .type = type };
1123 auto instruction_blocks =
1124 std::vector<InstructionBlock>{ InstructionBlock{ .instructions = { getenvvar_instruction } } };
1125 auto control_flow = ControlFlow(instruction_blocks);
1126 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1127 auto return_options =
1128 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 0 };
1129 auto bytecode = control_flow.build_bytecode(return_options);
1130
1131 auto result = simulate_with_default_tx(bytecode, {});
1132 return result.output.at(0);
1133 }
1134};
1135
1137{
1138 EXPECT_EQ(getenvvar_helper(0),
1139 FF("0x0dcd235d388105fa4154fc2d1c0143686d5da4d4aa9826d8f6609a02dc2d7c56")); // address with bytecode
1140 EXPECT_EQ(getenvvar_helper(1), MSG_SENDER); // sender, see simulator.cpp
1141 EXPECT_EQ(getenvvar_helper(2), TRANSACTION_FEE); // transaction fee, see simulator.cpp
1142 EXPECT_EQ(getenvvar_helper(3), CHAIN_ID); // chain id, see simulator.cpp globals
1143 EXPECT_EQ(getenvvar_helper(4), VERSION); // version, see simulator.cpp globals
1144 EXPECT_EQ(getenvvar_helper(5), BLOCK_NUMBER); // block number, see simulator.cpp globals
1145 EXPECT_EQ(getenvvar_helper(6, bb::avm2::MemoryTag::U64), 1000000); // timestamp, see simulator.cpp globals
1146 EXPECT_EQ(getenvvar_helper(7), FEE_PER_L2_GAS); // FEEPERL2GAS = 1, see simulator.cpp gas_fees
1147 EXPECT_EQ(getenvvar_helper(8), FEE_PER_DA_GAS); // FEEPERDAGAS = 1, see simulator.cpp gas_fees
1148 EXPECT_EQ(getenvvar_helper(9), 0); // is static call is always false
1149 EXPECT_EQ(getenvvar_helper(10),
1150 GAS_LIMIT.l2_gas - AVM_SET_BASE_L2_GAS - 2 * 6); // L2GASLEFT, gas spent on set + getenvvar + return
1151 EXPECT_EQ(getenvvar_helper(11), GAS_LIMIT.da_gas); // DAGASLEFT, see simulator.cpp
1152}
1153} // namespace execution_environment
1154
1156TEST_F(FuzzTest, EmitNullifierThenNullifierExists)
1157{
1158 auto set_field_instruction =
1160 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1161 .value = 1 };
1162 auto emit_nullifier_instruction = EMITNULLIFIER_Instruction{
1164 };
1165 auto nullifier_exists_instruction = NULLIFIEREXISTS_Instruction{
1167 .contract_address_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1168 .result_address = AddressRef{ .address = 20, .mode = AddressingMode::Direct }
1169 };
1170 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1171 .instructions = { set_field_instruction, emit_nullifier_instruction, nullifier_exists_instruction } } };
1172 auto control_flow = ControlFlow(instruction_blocks);
1173 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1174 auto bytecode = control_flow.build_bytecode(ReturnOptions{
1175 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 20 });
1176 auto result = simulate_with_default_tx(bytecode, {});
1177 EXPECT_EQ(result.output.at(0), 1);
1178}
1179
1180TEST_F(FuzzTest, EmitNullifierThenNullifierExistsOverwritingPreviousNullifier)
1181{
1182 auto set_field_instruction =
1184 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1185 .value = 1 };
1186 auto emit_nullifier_instruction = EMITNULLIFIER_Instruction{
1188 };
1189 auto nullifier_exists_instruction = NULLIFIEREXISTS_Instruction{
1191 .contract_address_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1192 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
1193 }; // GETENVVAR overwrites previous nullifier
1194 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1195 .instructions = { set_field_instruction, emit_nullifier_instruction, nullifier_exists_instruction } } };
1196 auto control_flow = ControlFlow(instruction_blocks);
1197 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1198 auto bytecode = control_flow.build_bytecode(
1199 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1200 auto result = simulate_with_default_tx(bytecode, {});
1201 EXPECT_EQ(result.output.at(0), 0);
1202}
1203
1204TEST_F(FuzzTest, EmitNoteHashThenNoteHashExists)
1205{
1206 FF note_hash = 42;
1207 uint64_t leaf_index = 0;
1208 auto set_note_hash_instruction =
1210 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1211 .value = note_hash };
1212 auto set_leaf_index_instruction =
1214 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1215 .value = leaf_index };
1216 auto note_hash_exists_instruction =
1218 .leaf_index_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1219 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct } };
1220 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1221 .instructions = { set_note_hash_instruction, set_leaf_index_instruction, note_hash_exists_instruction } } };
1222 auto control_flow = ControlFlow(instruction_blocks);
1223 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1224 auto bytecode = control_flow.build_bytecode(
1225 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1226 auto result = simulate_with_default_tx(bytecode, {}, { note_hash });
1227 EXPECT_FALSE(result.reverted);
1228 EXPECT_EQ(result.output.at(0), 1);
1229}
1230} // namespace notes_and_nullifiers
1231
1233TEST_F(FuzzTest, CopyCalldataThenReturnData)
1234{
1235 auto calldatacopy_instruction = CALLDATACOPY_Instruction{ .dst_address = AddressRef{ .address = 0 },
1236 .copy_size = 1,
1237 .copy_size_address = AddressRef{ .address = 1 },
1238 .cd_start = 0,
1239 .cd_start_address = AddressRef{ .address = 2 } };
1240 auto instruction_blocks =
1241 std::vector<InstructionBlock>{ InstructionBlock{ .instructions = { calldatacopy_instruction } } };
1242 auto control_flow = ControlFlow(instruction_blocks);
1243 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1244 auto bytecode = control_flow.build_bytecode(
1245 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1246
1247 auto result = simulate_with_default_tx(bytecode, { FF(1337) });
1248 EXPECT_EQ(result.output.at(0), 1337);
1249}
1250
1251// call internal function overwrites memory address
1252TEST_F(FuzzTest, InternalCall)
1253{
1254 auto set_field_instruction =
1256 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1257 .value = 1337 };
1258 auto set_field_instruction2 =
1260 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1261 .value = 313373 };
1262 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1263 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1264 .instructions = { set_field_instruction, set_field_instruction2 } } };
1265 auto control_flow = ControlFlow(instruction_blocks);
1266 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1267 control_flow.process_cfg_instruction(internal_call_instruction);
1268 auto bytecode = control_flow.build_bytecode(
1269 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1270 auto result = simulate_with_default_tx(bytecode, {});
1271 EXPECT_EQ(result.output.at(0), 313373);
1272}
1273} // namespace calldata_returndata
1274
1276
1277// check if internal call does not halt execution on return
1278TEST_F(FuzzTest, InternalCalledBlockUsesInternalReturn)
1279{
1280 auto set_field_instruction =
1282 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1283 .value = 1337 };
1284 auto set_boolean_instruction =
1286 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1287 .value = 1 };
1288 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1289 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1290 .instructions = { set_field_instruction, set_boolean_instruction } } };
1291 auto control_flow = ControlFlow(instruction_blocks);
1292 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
1293 control_flow.process_cfg_instruction(internal_call_instruction);
1294 // this should do nothing, just insert INTERNALRETURN instruction
1295 // otherwise it will halt execution and return 1
1296 control_flow.process_cfg_instruction(FinalizeWithReturn{
1298 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 } });
1299 auto bytecode = control_flow.build_bytecode(
1300 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1301 auto result = simulate_with_default_tx(bytecode, {});
1302 EXPECT_EQ(result.output.at(0), 1337);
1303}
1304
1305// SSTORE(0, 1337); call f1; return SLOAD(0);
1306// f1: SSTORE(0, 31337); call f2; INTERNALRETURN
1307// f2: SSTORE(0, 313373); INTERNALRETURN
1308TEST_F(FuzzTest, SeveralInternalCalls)
1309{
1310 auto set_field_instruction =
1312 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1313 .value = 1337 };
1314 auto set_field_instruction2 =
1316 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1317 .value = 31337 };
1318 auto set_field_instruction3 =
1320 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1321 .value = 313373 };
1322 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1323 auto internal_call_instruction2 = InsertInternalCall{ .target_program_block_instruction_block_idx = 2 };
1324 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1325 .instructions = { set_field_instruction, set_field_instruction2, set_field_instruction3 } } };
1326 auto control_flow = ControlFlow(instruction_blocks);
1327 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1328 control_flow.process_cfg_instruction(internal_call_instruction);
1329 control_flow.process_cfg_instruction(internal_call_instruction2);
1330 auto bytecode = control_flow.build_bytecode(
1331 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1332 auto result = simulate_with_default_tx(bytecode, {});
1333 EXPECT_EQ(result.output.at(0), 313373);
1334}
1335
1353TEST_F(FuzzTest, Reentrancy)
1354{
1355 auto set_field_instruction0 =
1357 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1358 .value = 1 };
1359 auto set_field_instruction1 =
1361 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1362 .value = 1337 };
1363 auto set_field_instruction2 =
1365 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1366 .value = 31337 };
1367 auto set_field_instruction3 =
1369 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1370 .value = 313373 };
1371 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1372 auto internal_call_instruction2 = InsertInternalCall{ .target_program_block_instruction_block_idx = 2 };
1373 auto internal_call_instruction3 = InsertInternalCall{ .target_program_block_instruction_block_idx = 3 };
1374 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1375 { set_field_instruction0, set_field_instruction1, set_field_instruction2, set_field_instruction3 } } };
1376 auto control_flow = ControlFlow(instruction_blocks);
1377 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1378 // call f1
1379 control_flow.process_cfg_instruction(internal_call_instruction);
1380 // call f2
1381 control_flow.process_cfg_instruction(internal_call_instruction2);
1382 // Should switch context to f1
1383 control_flow.process_cfg_instruction(FinalizeWithReturn{
1385 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1386 // SSTORE(0, 1337);
1387 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
1388 // Should switch context to f0 (START)
1389 control_flow.process_cfg_instruction(FinalizeWithReturn{
1391 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1392 // call f3
1393 control_flow.process_cfg_instruction(internal_call_instruction3);
1394 // Should switch context to f0 (START)
1395 control_flow.process_cfg_instruction(FinalizeWithReturn{
1397 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1398 auto bytecode = control_flow.build_bytecode(
1399 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1400 auto result = simulate_with_default_tx(bytecode, {});
1401 EXPECT_EQ(result.output.at(0), 313373);
1402}
1403} // namespace internal_calls
1404
1406TEST_F(FuzzTest, DirectWithIndirect)
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 .mode = AddressingMode::Indirect },
1421 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1422 .result_address = AddressRef{ .address = 130, .mode = AddressingMode::Direct }
1423 };
1424 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1425 .instructions = { set_field_instruction, set_field_instruction2, add_instruction } } };
1426 auto control_flow = ControlFlow(instruction_blocks);
1427 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1428 auto bytecode = control_flow.build_bytecode(
1429 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1430 auto result = simulate_with_default_tx(bytecode, {});
1431 EXPECT_EQ(result.output.at(0), 30);
1432}
1433
1434TEST_F(FuzzTest, DirectWithIndirectRelative)
1435{
1436 auto set_field_instruction =
1438 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1439 .value = 10 };
1440 auto set_field_instruction2 =
1442 .result_address = AddressRef{ .address = 3000, .mode = AddressingMode::Direct },
1443 .value = 20 };
1444 auto add_instruction = ADD_8_Instruction{
1446 .index = 1,
1447 .pointer_address_seed = 100,
1449 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1450 .result_address = AddressRef{ .address = 130, .mode = AddressingMode::Direct }
1451 };
1452 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1453 .instructions = { set_field_instruction, set_field_instruction2, add_instruction }, .base_offset = 100 } };
1454 auto control_flow = ControlFlow(instruction_blocks);
1455 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1456 auto bytecode = control_flow.build_bytecode(
1457 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1458 auto result = simulate_with_default_tx(bytecode, {});
1459 EXPECT_EQ(result.output.at(0), 30);
1460}
1461
1462TEST_F(FuzzTest, IndirectResultCanBeUsedInNextInstruction)
1463{
1464 auto set_field_instruction =
1466 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1467 .value = 10 };
1468 auto add_instruction = ADD_8_Instruction{
1470 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
1471 .result_address = AddressRef{ .address = 130, .pointer_address_seed = 100, .mode = AddressingMode::Indirect }
1472 };
1473 auto mul_instruction = MUL_8_Instruction{
1475 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
1476 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct }
1477 };
1478 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1479 .instructions = { set_field_instruction, add_instruction, mul_instruction } } };
1480 auto control_flow = ControlFlow(instruction_blocks);
1481 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1482 auto bytecode = control_flow.build_bytecode(
1483 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1484 auto result = simulate_with_default_tx(bytecode, {});
1485 EXPECT_EQ(result.output.at(0), 400);
1486}
1487
1488TEST_F(FuzzTest, Memoryaddressing32BitWidth)
1489{
1490 auto set_field_instruction =
1492 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1493 .value = 10 };
1494 auto set_field_instruction2 = SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
1495 .result_address = AddressRef{ .address = 4294967295,
1496 .pointer_address_seed = 100,
1497 .mode = AddressingMode::Indirect },
1498 .value = 20 };
1499 auto add_instruction = MUL_8_Instruction{
1501 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF,
1502 .index = 1,
1503 .pointer_address_seed = 200,
1504 .mode = AddressingMode::Indirect },
1505 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct }
1506 };
1507 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1508 .instructions = { set_field_instruction, set_field_instruction2, add_instruction } } };
1509 auto control_flow = ControlFlow(instruction_blocks);
1510 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1511 auto bytecode = control_flow.build_bytecode(
1512 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1513 auto result = simulate_with_default_tx(bytecode, {});
1514 EXPECT_EQ(result.output.at(0), 200);
1515}
1516} // namespace avm_addressing
1517
1518namespace misc {
1519// TODO(defkit): get info from world state to be sure that the message will be sent / log emitted
1520TEST_F(FuzzTest, SendL2ToL1Msg)
1521{
1522 auto sendl2tol1msg_instruction =
1524 .recipient_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1525 .content = 200,
1526 .content_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct } };
1527 auto instruction_blocks =
1528 std::vector<InstructionBlock>{ InstructionBlock{ .instructions = { sendl2tol1msg_instruction } } };
1529 auto control_flow = ControlFlow(instruction_blocks);
1530 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1531 auto bytecode = control_flow.build_bytecode(
1532 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1533 auto result = simulate_with_default_tx(bytecode, {});
1534 EXPECT_EQ(result.reverted, false);
1535}
1536
1538{
1541 uint32_t log_size = 1;
1542 FF log_value = 42;
1543
1544 std::vector<FuzzInstruction> instructions;
1545
1546 instructions.push_back(SET_32_Instruction{
1547 .value_tag = bb::avm2::MemoryTag::U32, .result_address = log_size_address, .value = log_size });
1548
1549 instructions.push_back(SET_FF_Instruction{
1550 .value_tag = bb::avm2::MemoryTag::FF, .result_address = log_values_address, .value = log_value });
1551
1553 .log_values_address = log_values_address });
1554
1555 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1556 auto control_flow = ControlFlow(instruction_blocks);
1557 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1558 auto bytecode = control_flow.build_bytecode(
1559 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1560 auto result = simulate_with_default_tx(bytecode, {});
1561 EXPECT_EQ(result.reverted, false);
1562}
1563} // namespace misc
1564
1566
1568 protected:
1570 {
1571 FF address = context.get_contract_address(0);
1572 std::vector<FuzzInstruction> instructions;
1573 instructions.push_back(
1575 .result_address = AddressRef{ .address = 123, .mode = AddressingMode::Direct },
1576 .value = address });
1577 instructions.push_back(GETCONTRACTINSTANCE_Instruction{
1579 .member_enum = member_enum,
1580 .dst_address = AddressRef{ .address = 124, .mode = AddressingMode::Direct } });
1581
1582 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1583 auto control_flow = ControlFlow(instruction_blocks);
1584 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1585 auto bytecode = control_flow.build_bytecode(
1586 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 1 });
1587 auto result = simulate_with_default_tx(bytecode, {});
1588 return result.output.at(0);
1589 }
1590};
1591
1594TEST_F(ExternalCallsFuzzTest, ExternalCallToAdd8)
1595{
1596 std::vector<FuzzInstruction> instructions;
1597 auto contract_address = context.get_contract_address(0);
1599 instructions.push_back(SET_FF_Instruction{
1601
1602 uint32_t l2_gas = 10000;
1604 instructions.push_back(
1606
1607 uint32_t da_gas = 10000;
1609 instructions.push_back(
1611
1612 uint16_t arg_size = 0;
1613 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1614 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1615
1616 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1617 .da_gas_address = da_gas_address,
1618 .contract_address_address = contract_address_address,
1619 .calldata_address = args_address,
1620 .calldata_size_address = arg_size_address,
1621 .calldata_size = arg_size,
1622 .is_static_call = false });
1623
1624 instructions.push_back(RETURNDATASIZE_WITH_RETURNDATACOPY_Instruction{
1625 .copy_size_offset = 6, .dst_address = 7, .rd_start = 0, .rd_start_offset = 8 });
1626
1627 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1628 auto control_flow = ControlFlow(instruction_blocks);
1629 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1630 auto bytecode = control_flow.build_bytecode(
1631 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 1 });
1632 auto result = simulate_with_default_tx(bytecode, {});
1633 EXPECT_EQ(result.output.at(0), 2);
1634}
1635
1637{
1638
1639 EXPECT_EQ(get_contract_instance_helper(0),
1640 FF("0x0000000000000000000000000000000000000000000000000000000000000064")); // DEPLOYER
1641 EXPECT_EQ(get_contract_instance_helper(1),
1642 FF("0x0dc97dd1cc90c276ca76f34abb5085e1ae3addd8ace763a5da908bacf147d972")); // CLASS_ID
1643 EXPECT_EQ(get_contract_instance_helper(2),
1644 FF("0x0000000000000000000000000000000000000000000000000000000000000000")); // INIT HASH
1645 EXPECT_EQ(get_contract_instance_helper(0, bb::avm2::MemoryTag::U1), FF::one()); // EXISTS
1646}
1647
1648// Calls add8, sucesscopy, return
1650{
1651 std::vector<FuzzInstruction> instructions;
1652 auto contract_address = context.get_contract_address(0);
1654 instructions.push_back(SET_FF_Instruction{
1656
1657 uint32_t l2_gas = 10000;
1659 instructions.push_back(
1661
1662 uint32_t da_gas = 10000;
1664 instructions.push_back(
1666
1667 uint16_t arg_size = 0;
1668 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1669 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1670
1671 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1672 .da_gas_address = da_gas_address,
1673 .contract_address_address = contract_address_address,
1674 .calldata_address = args_address,
1675 .calldata_size_address = arg_size_address,
1676 .calldata_size = arg_size,
1677 .is_static_call = false });
1678
1679 instructions.push_back(
1681 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1682 auto control_flow = ControlFlow(instruction_blocks);
1683 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1684 auto bytecode = control_flow.build_bytecode(
1685 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1686
1687 auto result = simulate_with_default_tx(bytecode, {});
1688 EXPECT_EQ(result.output.at(0), FF::one());
1689}
1690
1691// Performs static call to ZERO_DIVISION, SUCCESSCOPY, RETURN
1692// The result should be 0
1693TEST_F(ExternalCallsFuzzTest, CallToZeroDivisionSuccessCopy)
1694{
1695 std::vector<FuzzInstruction> instructions;
1696 auto contract_address = context.get_contract_address(1);
1698 instructions.push_back(SET_FF_Instruction{
1700
1701 uint32_t l2_gas = 10000;
1703 instructions.push_back(
1705
1706 uint32_t da_gas = 10000;
1708 instructions.push_back(
1710
1711 uint16_t arg_size = 0;
1712 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1713 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1714
1715 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1716 .da_gas_address = da_gas_address,
1717 .contract_address_address = contract_address_address,
1718 .calldata_address = args_address,
1719 .calldata_size_address = arg_size_address,
1720 .calldata_size = arg_size,
1721 .is_static_call = true });
1722 instructions.push_back(
1724 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1725 auto control_flow = ControlFlow(instruction_blocks);
1726 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1727 auto bytecode = control_flow.build_bytecode(
1728 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 1 });
1729 auto result = simulate_with_default_tx(bytecode, {});
1730 EXPECT_EQ(result.output.at(0), FF::zero());
1731 EXPECT_EQ(result.reverted, false);
1732}
1733
1735TEST_F(ExternalCallsFuzzTest, StaticCallToNonStaticFunctionSuccessCopy)
1736{
1737 std::vector<FuzzInstruction> instructions;
1738 auto contract_address = context.get_contract_address(2);
1740 instructions.push_back(SET_FF_Instruction{
1742
1743 uint32_t l2_gas = 10000;
1745 instructions.push_back(
1747
1748 uint32_t da_gas = 10000;
1750 instructions.push_back(
1752
1753 uint16_t arg_size = 0;
1754 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1755 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1756
1757 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1758 .da_gas_address = da_gas_address,
1759 .contract_address_address = contract_address_address,
1760 .calldata_address = args_address,
1761 .calldata_size_address = arg_size_address,
1762 .calldata_size = arg_size,
1763 .is_static_call = true });
1764 instructions.push_back(
1766 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1767 auto control_flow = ControlFlow(instruction_blocks);
1768 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1769 auto bytecode = control_flow.build_bytecode(
1770 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 1 });
1771 auto result = simulate_with_default_tx(bytecode, {});
1772 EXPECT_EQ(result.output.at(0), FF::zero());
1773 EXPECT_EQ(result.reverted, false);
1774}
1775} // 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
#define AVM_SET_BASE_L2_GAS
StrictMock< MockContractDB > contract_db
uses barretenberg/vm2 to simulate the bytecode
Definition simulator.hpp:75
void SetUp() override
Definition fuzz.test.cpp:32
void TearDown() override
Definition fuzz.test.cpp:43
FuzzerContext context
Definition fuzz.test.cpp:81
SimulatorResult simulate_with_default_tx(std::vector< uint8_t > &bytecode, std::vector< FF > calldata, const std::vector< FF > &note_hashes)
Definition fuzz.test.cpp:50
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)
FF get_result_of_instruction(FuzzInstruction instruction, bb::avm2::MemoryTag return_value_tag=bb::avm2::MemoryTag::U8)
Definition fuzz.test.cpp:88
static FuzzerWorldStateManager * getInstance()
Definition dbs.hpp:80
world_state::WorldStateRevision fork()
Definition dbs.cpp:211
void append_note_hashes(const std::vector< FF > &note_hashes)
Definition dbs.cpp:253
void write_fee_payer_balance(const AztecAddress &fee_payer, const FF &balance)
Definition dbs.cpp:234
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)
GlobalVariables create_default_globals()
Definition simulator.cpp:68
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
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]
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]
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]
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:48
MemoryTagWrapper tag
mem[result_offset] = mem[a_address] ^ mem[b_address] (16-bit)
mem[result_offset] = mem[a_address] ^ mem[b_address]
std::vector< FuzzInstruction > instructions