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
12
13using namespace bb::avm2::fuzzer;
14
16
18{
19 for (auto& function : PREDEFINED_FUNCTIONS) {
20 try {
21 context.register_contract_from_bytecode(function);
22 } catch (...) {
23 std::cout << "Failed to register predefined function: " << function.size() << std::endl;
24 continue;
25 }
26 }
27}
28
29class FuzzTest : public ::testing::Test {
30 protected:
31 void SetUp() override
32 {
34 if (ws_mgr == nullptr) {
36 }
37 ws_mgr->fork();
40 }
41
42 void TearDown() override { ws_mgr->reset_world_state(); }
43
44 SimulatorResult simulate_with_default_tx(std::vector<uint8_t>& bytecode, std::vector<FF> calldata)
45 {
47 }
48
50 std::vector<FF> calldata,
51 const std::vector<FF>& note_hashes)
52 {
54
55 ws_mgr->append_note_hashes(note_hashes);
56
57 auto contract_address = context.register_contract_from_bytecode(bytecode);
58 FuzzerContractDB contract_db = context.get_contract_db();
59
61 FF fee_required_da = FF(tx.effective_gas_fees.fee_per_da_gas) * FF(tx.gas_settings.gas_limits.da_gas);
62 FF fee_required_l2 = FF(tx.effective_gas_fees.fee_per_l2_gas) * FF(tx.gas_settings.gas_limits.l2_gas);
63 ws_mgr->write_fee_payer_balance(tx.fee_payer, fee_required_da + fee_required_l2);
64 auto cpp_simulator = CppSimulator();
65 auto globals = create_default_globals();
66
67 auto result = cpp_simulator.simulate(*ws_mgr,
69 tx,
70 globals,
71 /*public_data_writes=*/{},
72 /*note_hashes=*/{},
73 /*protocol_contracts=*/{});
74
75 ws_mgr->revert();
76
77 return result;
78 }
79
81};
82
83namespace arithmetic {
85 protected:
86 // set(addr 0, 5) set(addr 1, 2) OP(addr 0, addr 1, addr 2) return(addr 2)
89 {
90 auto set_instruction_1 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
91 .result_address = AddressRef{ .address = 0 },
92 .value = 5 };
93 auto set_instruction_2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
94 .result_address = AddressRef{ .address = 1 },
95 .value = 2 };
96 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, instruction };
97 auto return_options =
98 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 2 };
99 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
100 auto control_flow = ControlFlow(instruction_blocks);
101 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
102 auto bytecode = control_flow.build_bytecode(return_options);
103
104 auto result = simulate_with_default_tx(bytecode, {});
105 return result.output.at(0);
106 }
107
108 // Helper function for 16-bit instructions
109 // set(addr 0, 5) set(addr 1, 2) OP_16(addr 0, addr 1, addr 2) return(addr 2)
112 {
113 auto set_instruction_1 =
115 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
116 .value = 5 };
117 auto set_instruction_2 =
119 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
120 .value = 2 };
121 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, instruction };
122
123 auto return_options =
124 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 2 };
125 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
126 auto control_flow = ControlFlow(instruction_blocks);
127 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
128 auto bytecode = control_flow.build_bytecode(return_options);
129
130 auto result = simulate_with_default_tx(bytecode, {});
131 return result.output.at(0);
132 }
133};
134
136{
137 auto add_instruction = ADD_8_Instruction{
138 .a_address =
141 .index = 0,
143 },
144 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
145 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
146 };
147 auto result = get_result_of_instruction(add_instruction);
148 EXPECT_EQ(result, 7);
149}
150
152{
153 auto sub_instruction = SUB_8_Instruction{
155 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
156 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
157 };
158 auto result = get_result_of_instruction(sub_instruction);
159 EXPECT_EQ(result, 3);
160}
161
163{
164 auto mul_instruction = MUL_8_Instruction{
166 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
167 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
168 };
169 auto result = get_result_of_instruction(mul_instruction);
170 EXPECT_EQ(result, 10);
171}
172
174{
175 auto div_instruction = DIV_8_Instruction{
177 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
178 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
179 };
180 auto result = get_result_of_instruction(div_instruction);
181 EXPECT_EQ(result, 2);
182}
183
185{
186 auto eq_instruction = EQ_8_Instruction{
188 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
189 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
190 };
191 auto result = get_result_of_instruction(eq_instruction, bb::avm2::MemoryTag::U1);
192 EXPECT_EQ(result, 0);
193}
194
196{
197 auto lt_instruction = LT_8_Instruction{
199 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
200 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
201 };
202 auto result = get_result_of_instruction(lt_instruction, bb::avm2::MemoryTag::U1);
203 EXPECT_EQ(result, 0);
204}
205
207{
208 auto lte_instruction = LTE_8_Instruction{
210 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
211 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
212 };
213 auto result = get_result_of_instruction(lte_instruction, bb::avm2::MemoryTag::U1);
214 EXPECT_EQ(result, 0);
215}
216
218{
219 auto and_instruction = AND_8_Instruction{
221 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
222 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
223 };
224 auto result = get_result_of_instruction(and_instruction);
225 EXPECT_EQ(result, 0);
226}
227
229{
230 auto or_instruction = OR_8_Instruction{
232 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
233 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
234 };
235 auto result = get_result_of_instruction(or_instruction);
236 EXPECT_EQ(result, 7);
237}
238
240{
241 auto xor_instruction = XOR_8_Instruction{
243 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
244 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
245 };
246 auto result = get_result_of_instruction(xor_instruction);
247 EXPECT_EQ(result, 7);
248}
249
251{
252 auto shl_instruction = SHL_8_Instruction{
254 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
255 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
256 };
257 auto result = get_result_of_instruction(shl_instruction);
258 EXPECT_EQ(result, 20);
259}
260
262{
263 auto shr_instruction = SHR_8_Instruction{
265 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
266 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
267 };
268 auto result = get_result_of_instruction(shr_instruction);
269 EXPECT_EQ(result, 1);
270}
271
272// set(0, 4, FF) set(1, 2, FF) fdiv(FF, 0, 1, 2) return(2)
274{
275 auto fdiv_instruction = FDIV_8_Instruction{
277 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
278 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
279 };
280 auto set_instruction_1 =
282 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
283 .value = 4 };
284 auto set_instruction_2 =
286 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
287 .value = 2 };
288 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, fdiv_instruction };
289
290 auto return_options =
291 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 };
292 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
293 auto control_flow = ControlFlow(instruction_blocks);
294 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
295 auto bytecode = control_flow.build_bytecode(return_options);
296
297 auto result = simulate_with_default_tx(bytecode, {});
298 EXPECT_EQ(result.output.at(0), 2);
299}
300
301// set(0, 0, U8) not(U8, 0, 1) return(1)
303{
304 auto set_instruction =
306 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
307 .value = 0 };
308 auto not_instruction = NOT_8_Instruction{
310 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
311 };
312 auto instructions = std::vector<FuzzInstruction>{ set_instruction, not_instruction };
313 auto return_options =
314 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
315 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
316 auto control_flow = ControlFlow(instruction_blocks);
317 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
318 auto bytecode = control_flow.build_bytecode(return_options);
319
320 auto result = simulate_with_default_tx(bytecode, {});
321 EXPECT_EQ(result.output.at(0), 255);
322}
323
325{
326 auto add_instruction = ADD_16_Instruction{
327 .a_address =
330 .index = 0,
332 },
333 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
334 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
335 };
336 auto result = get_result_of_instruction_16(add_instruction);
337 EXPECT_EQ(result, 7);
338}
339
341{
342 auto sub_instruction = SUB_16_Instruction{
344 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
345 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
346 };
347 auto result = get_result_of_instruction_16(sub_instruction);
348 EXPECT_EQ(result, 3);
349}
350
352{
353 auto mul_instruction = MUL_16_Instruction{
355 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
356 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
357 };
358 auto result = get_result_of_instruction_16(mul_instruction);
359 EXPECT_EQ(result, 10);
360}
361
363{
364 auto div_instruction = DIV_16_Instruction{
366 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
367 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
368 };
369 auto result = get_result_of_instruction_16(div_instruction);
370 EXPECT_EQ(result, 2);
371}
372
374{
375 auto eq_instruction = EQ_16_Instruction{
377 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
378 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
379 };
380 auto result = get_result_of_instruction_16(eq_instruction, bb::avm2::MemoryTag::U1);
381 EXPECT_EQ(result, 0);
382}
383
385{
386 auto lt_instruction = LT_16_Instruction{
388 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
389 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
390 };
391 auto result = get_result_of_instruction_16(lt_instruction, bb::avm2::MemoryTag::U1);
392 EXPECT_EQ(result, 0);
393}
394
396{
397 auto lte_instruction = LTE_16_Instruction{
399 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
400 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
401 };
402 auto result = get_result_of_instruction_16(lte_instruction, bb::avm2::MemoryTag::U1);
403 EXPECT_EQ(result, 0);
404}
405
407{
408 auto and_instruction = AND_16_Instruction{
410 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
411 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
412 };
413 auto result = get_result_of_instruction_16(and_instruction);
414 EXPECT_EQ(result, 0);
415}
416
418{
419 auto or_instruction = OR_16_Instruction{
421 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
422 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
423 };
424 auto result = get_result_of_instruction_16(or_instruction);
425 EXPECT_EQ(result, 7);
426}
427
429{
430 auto xor_instruction = XOR_16_Instruction{
432 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
433 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
434 };
435 auto result = get_result_of_instruction_16(xor_instruction);
436 EXPECT_EQ(result, 7);
437}
438
440{
441 auto shl_instruction = SHL_16_Instruction{
443 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
444 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
445 };
446 auto result = get_result_of_instruction_16(shl_instruction);
447 EXPECT_EQ(result, 20);
448}
449
451{
452 auto shr_instruction = SHR_16_Instruction{
454 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::U8, .index = 1, .mode = AddressingMode::Direct },
455 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
456 };
457 auto result = get_result_of_instruction_16(shr_instruction);
458 EXPECT_EQ(result, 1);
459}
460
461// set(0, 4, FF) set(1, 2, FF) fdiv_16(FF, 0, 1, 2) return(2)
463{
464 auto fdiv_instruction = FDIV_16_Instruction{
466 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
467 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct }
468 };
469 auto set_instruction_1 =
471 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
472 .value = 4 };
473 auto set_instruction_2 =
475 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
476 .value = 2 };
477 auto instructions = std::vector<FuzzInstruction>{ set_instruction_1, set_instruction_2, fdiv_instruction };
478
479 auto return_options =
480 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 };
481 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
482 auto control_flow = ControlFlow(instruction_blocks);
483 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
484 auto bytecode = control_flow.build_bytecode(return_options);
485
486 auto result = simulate_with_default_tx(bytecode, {});
487 EXPECT_EQ(result.output.at(0), 2);
488}
489
490// set(0, 0, U8) not_16(U8, 0, 1) return(1)
492{
493 auto set_instruction =
495 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
496 .value = 0 };
497 auto not_instruction = NOT_16_Instruction{
499 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
500 };
501 auto instructions = std::vector<FuzzInstruction>{ set_instruction, not_instruction };
502 auto return_options =
503 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
504 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
505 auto control_flow = ControlFlow(instruction_blocks);
506 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
507 auto bytecode = control_flow.build_bytecode(return_options);
508
509 auto result = simulate_with_default_tx(bytecode, {});
510 EXPECT_EQ(result.output.at(0), 255);
511}
512
513} // namespace arithmetic
514
516// set(10, 1, U16) set(0, 2, U8) cast_8(U8, 0, 1, U16) return(1)
517// if cast worked, should return 2 (the U8 value cast to U16)
518// if cast failed, should return 1 (the original U16 value)
520{
522 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
523 .value = 1 };
525 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
526 .value = 2 };
527 auto cast_instruction = CAST_8_Instruction{
529 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
530 .target_tag = bb::avm2::MemoryTag::U16
531 };
532 auto instructions = std::vector<FuzzInstruction>{ set_u16, set_u8, cast_instruction };
533 auto return_options =
534 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
535 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
536 auto control_flow = ControlFlow(instruction_blocks);
537 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
538 auto bytecode = control_flow.build_bytecode(return_options);
539
540 auto result = simulate_with_default_tx(bytecode, {});
541 EXPECT_EQ(result.output.at(0), 2);
542}
543
544// set(10, 1, U16) set(0, 2, U8) cast_16(U8, 0, 1, U16) return(1)
545// if cast worked, should return 2 (the U8 value cast to U16)
546// if cast failed, should return 1 (the original U16 value)
548{
550 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
551 .value = 1 };
553 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
554 .value = 2 };
555 auto cast_instruction = CAST_16_Instruction{
557 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
558 .target_tag = bb::avm2::MemoryTag::U16
559 };
560 auto instructions = std::vector<FuzzInstruction>{ set_u16, set_u8, cast_instruction };
561 auto return_options =
562 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
563 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
564 auto control_flow = ControlFlow(instruction_blocks);
565 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
566 auto bytecode = control_flow.build_bytecode(return_options);
567
568 auto result = simulate_with_default_tx(bytecode, {});
569 EXPECT_EQ(result.output.at(0), 2);
570}
571} // namespace type_conversion
572
573namespace machine_memory {
574// set(0, 0xabcd, U16) return(0)
576{
577 const uint16_t test_value = 0xABCD;
578 auto set_instruction =
580 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
581 .value = test_value };
582 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
583 auto return_options =
584 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 0 };
585 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
586 auto control_flow = ControlFlow(instruction_blocks);
587 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
588 auto bytecode = control_flow.build_bytecode(return_options);
589
590 auto result = simulate_with_default_tx(bytecode, {});
591 EXPECT_EQ(result.output.at(0), test_value);
592}
593// set(0, 0x12345678, U32) return(0)
595{
596 const uint32_t test_value = 0x12345678UL;
597 auto set_instruction =
599 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
600 .value = test_value };
601 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
602 auto return_options =
603 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U32, .return_value_offset_index = 0 };
604 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
605 auto control_flow = ControlFlow(instruction_blocks);
606 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
607 auto bytecode = control_flow.build_bytecode(return_options);
608
609 auto result = simulate_with_default_tx(bytecode, {});
610 EXPECT_EQ(result.output.at(0), test_value);
611}
612
613// set(0, 0xabcdef0123456789, U64) return(0)
615{
616 const uint64_t test_value = 0xABCDEF0123456789ULL;
617 auto set_instruction =
619 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
620 .value = test_value };
621 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
622 auto return_options =
623 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U64, .return_value_offset_index = 0 };
624 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
625 auto control_flow = ControlFlow(instruction_blocks);
626 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
627 auto bytecode = control_flow.build_bytecode(return_options);
628
629 auto result = simulate_with_default_tx(bytecode, {});
630 EXPECT_EQ(result.output.at(0), test_value);
631}
632
633// set(0, something, U128) return(0)
635{
636 const uint64_t test_value_low = 0xFEDCBA9876543210ULL;
637 const uint64_t test_value_high = 0x123456789ABCDEF0ULL;
638 const uint128_t test_value =
639 (static_cast<uint128_t>(test_value_high) << 64) | static_cast<uint128_t>(test_value_low);
640 auto set_instruction =
642 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
643 .value_low = test_value_low,
644 .value_high = test_value_high };
645 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
646 auto return_options = ReturnOptions{ .return_size = 1,
647 .return_value_tag = bb::avm2::MemoryTag::U128,
648 .return_value_offset_index = 0 };
649 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
650 auto control_flow = ControlFlow(instruction_blocks);
651 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
652 auto bytecode = control_flow.build_bytecode(return_options);
653
654 auto result = simulate_with_default_tx(bytecode, {});
655 EXPECT_EQ(result.output.at(0), test_value);
656}
657
658// set(0, 123456789, FF) return(0)
660{
661 const bb::avm2::FF test_value = bb::avm2::FF(123456789);
662 auto set_instruction =
664 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
665 .value = test_value };
666 auto instructions = std::vector<FuzzInstruction>{ set_instruction };
667 auto return_options =
668 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 };
669 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
670 auto control_flow = ControlFlow(instruction_blocks);
671 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
672 auto bytecode = control_flow.build_bytecode(return_options);
673
674 auto result = simulate_with_default_tx(bytecode, {});
675 EXPECT_EQ(result.output.at(0), test_value);
676}
677
678// set(0, 0x42, U8) set(1, 0x43, U8) mov_8(U8, 0, 1) return(1)
680{
681 const uint8_t test_value = 0x42;
682 const uint8_t test_value2 = 0x43;
683 auto set_instruction =
685 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
686 .value = test_value };
687 auto set_instruction2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U8,
688 .result_address = AddressRef{ .address = 1 },
689 .value = test_value2 };
690 auto mov_instruction = MOV_8_Instruction{
692 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
693 };
694 auto instructions = std::vector<FuzzInstruction>{ set_instruction, set_instruction2, mov_instruction };
695 auto return_options =
696 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
697 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
698 auto control_flow = ControlFlow(instruction_blocks);
699 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
700 auto bytecode = control_flow.build_bytecode(return_options);
701
702 auto result = simulate_with_default_tx(bytecode, {});
703 EXPECT_EQ(result.output.at(0), test_value);
704}
705
706// set(0, 0xbabe, U16) set(1, 0xc0fe, U16) mov_16(U16, 0, 1) return(1)
708{
709 const uint16_t test_value = 0xbabe;
710 const uint16_t test_value2 = 0xc0fe;
711 auto set_instruction =
713 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
714 .value = test_value };
715 auto set_instruction2 =
717 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
718 .value = test_value2 };
719 auto mov_instruction = MOV_16_Instruction{
721 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
722 };
723 auto instructions = std::vector<FuzzInstruction>{ set_instruction, set_instruction2, mov_instruction };
724 auto return_options =
725 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U16, .return_value_offset_index = 1 };
726 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
727 auto control_flow = ControlFlow(instruction_blocks);
728 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
729 auto bytecode = control_flow.build_bytecode(return_options);
730
731 auto result = simulate_with_default_tx(bytecode, {});
732 EXPECT_EQ(result.output.at(0), test_value);
733}
734
735} // namespace machine_memory
736
737namespace control_flow {
738
740 protected:
741 // set u1 condition value b1
742 // ↙ ↘
743 // set u1 b2 return 4
744 // ↙ ↘
745 // ret 2 ret 3
746 FF simulate_jump_if_depth_2_helper(uint8_t first_boolean_value, uint8_t second_boolean_value)
747 {
748 auto set_instruction_block_1 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
749 .result_address = AddressRef{ .address = 1 },
750 .value = first_boolean_value };
751 auto instruction_block_1 = InstructionBlock{ .instructions = { set_instruction_block_1 } };
752 auto set_instruction_block_2 = SET_8_Instruction{ .value_tag = bb::avm2::MemoryTag::U1,
753 .result_address = AddressRef{ .address = 2 },
754 .value = second_boolean_value };
755 auto instruction_block_2 = InstructionBlock{ .instructions = { set_instruction_block_2 } };
756 auto instruction_blocks = std::vector<InstructionBlock>{ instruction_block_1, instruction_block_2 };
757 for (uint8_t i = 2; i < 5; i++) {
758 auto set_instruction =
760 .result_address = AddressRef{ .address = i, .mode = AddressingMode::Direct },
761 .value = i };
762 instruction_blocks.push_back(InstructionBlock{ .instructions = { set_instruction } });
763 }
764 auto return_options = ReturnOptions{ .return_size = 1,
765 .return_value_tag = bb::avm2::MemoryTag::U8,
766 .return_value_offset_index = 1 };
767 auto control_flow = ControlFlow(instruction_blocks);
768 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
769 control_flow.process_cfg_instruction(
771 .else_program_block_instruction_block_idx = 4, // set 4
772 .condition_offset_index = 0 });
773 control_flow.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 2, // set 2
774 .else_program_block_instruction_block_idx = 3, // set 3
775 .condition_offset_index = 1 });
776 auto bytecode = control_flow.build_bytecode(return_options);
777
778 auto result = simulate_with_default_tx(bytecode, {});
779 return result.output.at(0);
780 }
781
782 // set u1 condition
783 // ↙ ↘
784 // nop ----→ return 2
785 FF simulate_jump_to_block_helper(uint8_t condition_value)
786 {
787 auto set_return_value_block =
790 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
791 .value = 2 } } };
792 auto instruction_block_1 =
795 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
796 .value = condition_value } } };
797 auto instruction_blocks =
798 std::vector<InstructionBlock>{ instruction_block_1, InstructionBlock(), set_return_value_block };
799 auto return_options = ReturnOptions{ .return_size = 1,
800 .return_value_tag = bb::avm2::MemoryTag::U8,
801 .return_value_offset_index = 1 };
802 auto control_flow = ControlFlow(instruction_blocks);
803 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
804 control_flow.process_cfg_instruction(
806 .else_program_block_instruction_block_idx = 2, // set return value
807 .condition_offset_index = 0 });
808 control_flow.process_cfg_instruction(JumpToBlock{ .target_block_idx = 2 });
809 auto bytecode = control_flow.build_bytecode(return_options);
810
811 auto result = simulate_with_default_tx(bytecode, {});
812 return result.output.at(0);
813 }
814};
815
816// block1 set return value 10
817// ↓
818// block2 set return value 11 and return return value
819TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke)
820{
821 auto block1_instructions =
824 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
825 .value = 10 } } };
826 auto block2_instructions =
829 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
830 .value = 11 } } };
831 auto instruction_blocks = std::vector<InstructionBlock>{ block1_instructions, block2_instructions };
832 auto return_options =
833 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
834 auto control_flow = ControlFlow(instruction_blocks);
835 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
837 auto bytecode = control_flow.build_bytecode(return_options);
838
839 auto result = simulate_with_default_tx(bytecode, {});
840 EXPECT_EQ(result.output.at(0), 11);
841}
842
843// block1 set return value 10
844// ↓
845// block2 set return value 11
846// ↓
847// block3 set return value 12 and return return value
848TEST_F(ControlFlowFuzzTest, JumpToNewBlockSmoke2)
849{
850 auto block1_instructions =
853 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
854 .value = 10 } } };
855 auto block2_instructions =
858 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
859 .value = 11 } } };
860 auto block3_instructions =
863 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
864 .value = 12 } } };
865 auto instruction_blocks =
866 std::vector<InstructionBlock>{ block1_instructions, block2_instructions, block3_instructions };
867 auto return_options =
868 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
869 auto control_flow = ControlFlow(instruction_blocks);
870 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
873 auto bytecode = control_flow.build_bytecode(return_options);
874
875 auto result = simulate_with_default_tx(bytecode, {});
876 EXPECT_EQ(result.output.at(0), 12);
877}
878
879// block1 set u8 value 10
880// ↓
881// block2 tries to return u8
882// if blocks does not share defined variables, block2 will return 0
883TEST_F(ControlFlowFuzzTest, JumpToNewBlockSharesVariables)
884{
887 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
888 .value = 10 } } };
889
890 auto instruction_blocks = std::vector<InstructionBlock>{ block1 };
891 auto return_options =
892 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
893 auto control_flow = ControlFlow(instruction_blocks);
894 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
896 auto bytecode = control_flow.build_bytecode(return_options);
897
898 auto result = simulate_with_default_tx(bytecode, {});
899 EXPECT_EQ(result.output.at(0), 10);
900}
901
902// block1 set u1 condition value
903// ↙ ↘
904// return 11 return 12
905TEST_F(ControlFlowFuzzTest, JumpIfToNewBlockSmoke)
906{
907 auto set_true_block =
910 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
911 .value = 1 } } };
912 auto set_false_block =
915 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
916 .value = 0 } } };
917 auto block2_instructions =
920 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
921 .value = 11 } } };
922 auto block3_instructions =
925 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
926 .value = 12 } } };
927 auto instruction_blocks =
928 std::vector<InstructionBlock>{ set_true_block, set_false_block, block2_instructions, block3_instructions };
929 auto return_options =
930 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U8, .return_value_offset_index = 1 };
931 auto control_flow = ControlFlow(instruction_blocks);
932 // set true, go to block2
933 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
935 .else_program_block_instruction_block_idx = 3,
936 .condition_offset_index = 1 });
937 auto bytecode_1 = control_flow.build_bytecode(return_options);
938 auto control_flow2 = ControlFlow(instruction_blocks);
939 // set false, go to block3
940 control_flow2.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
941 control_flow2.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 2,
942 .else_program_block_instruction_block_idx = 3,
943 .condition_offset_index = 1 });
944 auto bytecode_2 = control_flow2.build_bytecode(return_options);
945
946 auto result_1 = simulate_with_default_tx(bytecode_1, {});
947 auto result_2 = simulate_with_default_tx(bytecode_2, {});
948 EXPECT_EQ(result_1.output.at(0), 11);
949 EXPECT_EQ(result_2.output.at(0), 12);
950}
951
952TEST_F(ControlFlowFuzzTest, JumpIfDepth2Smoke)
953{
954 EXPECT_EQ(simulate_jump_if_depth_2_helper(1, 1), 2);
955 EXPECT_EQ(simulate_jump_if_depth_2_helper(1, 0), 3);
956 EXPECT_EQ(simulate_jump_if_depth_2_helper(0, 1), 4);
957 EXPECT_EQ(simulate_jump_if_depth_2_helper(0, 0), 4);
958}
959
960TEST_F(ControlFlowFuzzTest, JumpToBlockSmoke)
961{
962 EXPECT_EQ(simulate_jump_to_block_helper(1), 2);
963 EXPECT_EQ(simulate_jump_to_block_helper(0), 2);
964}
965
966// Nice catch! That's actually fully ai generated test.
967// test if terminate with return works
968// set u1 condition value
969// ↙ ↘
970// set FF, ret set U128, ret
971TEST_F(ControlFlowFuzzTest, JumpIfToNewBlockWithReturn)
972{
973 // Block 0: Set condition (U1)
974 auto set_condition_block =
977 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
978 .value = 1 } } };
979
980 // Block 1: Set FF value
981 const bb::avm2::FF ff_value = bb::avm2::FF(123456789);
982 auto set_ff_block =
985 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
986 .value = ff_value } } };
987
988 // Block 2: Set U128 value
989 const uint64_t u128_value_low = 0xFEDCBA9876543210ULL;
990 const uint64_t u128_value_high = 0x123456789ABCDEF0ULL;
991 auto set_u128_block =
994 .result_address = AddressRef{ .address = 20, .mode = AddressingMode::Direct },
995 .value_low = u128_value_low,
996 .value_high = u128_value_high } } };
997
998 auto instruction_blocks = std::vector<InstructionBlock>{ set_condition_block, set_ff_block, set_u128_block };
999
1000 auto control_flow = ControlFlow(instruction_blocks);
1001
1002 // Insert condition block
1003 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1004
1005 // JumpIf: if condition is true (1), go to block 1 (FF), else go to block 2 (U128)
1007 .else_program_block_instruction_block_idx = 2,
1008 .condition_offset_index = 0 });
1009
1010 // Finalize then block (FF) with Return
1011 control_flow.process_cfg_instruction(FinalizeWithReturn{
1013 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1014
1015 // Finalize else block (U128) with Return
1016 control_flow.process_cfg_instruction(FinalizeWithReturn{
1018 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1019
1020 // Test with condition = true (should return FF value)
1021 auto control_flow_true = ControlFlow(instruction_blocks);
1022 control_flow_true.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1023 control_flow_true.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_true.process_cfg_instruction(FinalizeWithReturn{
1028 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1029 control_flow_true.process_cfg_instruction(FinalizeWithReturn{
1031 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1032
1033 auto bytecode_true = control_flow_true.build_bytecode(ReturnOptions{
1034 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 });
1035
1036 auto result_true = simulate_with_default_tx(bytecode_true, {});
1037 EXPECT_EQ(result_true.output.at(0), ff_value);
1038
1039 // Test with condition = false (should return U128 value)
1040 auto set_condition_false_block =
1043 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1044 .value = 0 } } };
1045 auto instruction_blocks_false =
1046 std::vector<InstructionBlock>{ set_condition_false_block, set_ff_block, set_u128_block };
1047
1048 auto control_flow_false = ControlFlow(instruction_blocks_false);
1049 control_flow_false.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1050 control_flow_false.process_cfg_instruction(JumpIfToNewBlock{ .then_program_block_instruction_block_idx = 1,
1051 .else_program_block_instruction_block_idx = 2,
1052 .condition_offset_index = 0 });
1053 control_flow_false.process_cfg_instruction(FinalizeWithReturn{
1055 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 10 } });
1056 control_flow_false.process_cfg_instruction(FinalizeWithReturn{
1058 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 } });
1059
1060 const uint128_t expected_u128_value =
1061 (static_cast<uint128_t>(u128_value_high) << 64) | static_cast<uint128_t>(u128_value_low);
1062 auto bytecode_false = control_flow_false.build_bytecode(ReturnOptions{
1063 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U128, .return_value_offset_index = 20 });
1064
1065 auto result_false = simulate_with_default_tx(bytecode_false, {});
1066 EXPECT_EQ(result_false.output.at(0), expected_u128_value);
1067}
1068} // namespace control_flow
1069
1071TEST_F(FuzzTest, SstoreThenSload)
1072{
1073 // M[10] = 10
1074 auto set_value_instruction =
1076 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1077 .value = 10 };
1078 // S[10] = M[10]
1079 auto sstore_instruction = SSTORE_Instruction{
1081 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1082 .slot = 10
1083 };
1084 // M[2] = S[10], FF tag
1085 auto sload_instruction =
1087 .slot_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1088 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct } };
1089 // M[10] = 11
1090 auto set_value_instruction2 =
1092 .result_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1093 .value = 11 };
1094
1095 auto set_sstore_sload_block = InstructionBlock{
1096 .instructions = { set_value_instruction, sstore_instruction, sload_instruction, set_value_instruction2 }
1097 };
1098
1099 auto instruction_blocks = std::vector<InstructionBlock>{ set_sstore_sload_block };
1100 // FF should be set via sload instruction
1101 auto return_options = ReturnOptions{ .return_size = 1,
1102 .return_value_tag = bb::avm2::MemoryTag::FF,
1103 .return_value_offset_index = 1 /* after sload instruction */ };
1104 auto control_flow = ControlFlow(instruction_blocks);
1105 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1106 auto bytecode = control_flow.build_bytecode(return_options);
1107
1108 auto result = simulate_with_default_tx(bytecode, {});
1109 EXPECT_EQ(result.output.at(0), 10);
1110}
1111} // namespace public_storage
1112
1114
1116 protected:
1118 {
1119 auto getenvvar_instruction =
1121 .type = type };
1122 auto instruction_blocks =
1123 std::vector<InstructionBlock>{ InstructionBlock{ .instructions = { getenvvar_instruction } } };
1124 auto control_flow = ControlFlow(instruction_blocks);
1125 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1126 auto return_options =
1127 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 0 };
1128 auto bytecode = control_flow.build_bytecode(return_options);
1129
1130 auto result = simulate_with_default_tx(bytecode, {});
1131 return result.output.at(0);
1132 }
1133};
1134
1136{
1137 EXPECT_EQ(getenvvar_helper(0),
1138 FF("0x0dcd235d388105fa4154fc2d1c0143686d5da4d4aa9826d8f6609a02dc2d7c56")); // address with bytecode
1139 EXPECT_EQ(getenvvar_helper(1), MSG_SENDER); // sender, see simulator.cpp
1140 EXPECT_EQ(getenvvar_helper(2), TRANSACTION_FEE); // transaction fee, see simulator.cpp
1141 EXPECT_EQ(getenvvar_helper(3), CHAIN_ID); // chain id, see simulator.cpp globals
1142 EXPECT_EQ(getenvvar_helper(4), VERSION); // version, see simulator.cpp globals
1143 EXPECT_EQ(getenvvar_helper(5), BLOCK_NUMBER); // block number, see simulator.cpp globals
1144 EXPECT_EQ(getenvvar_helper(6, bb::avm2::MemoryTag::U64), 1000000); // timestamp, see simulator.cpp globals
1145 EXPECT_EQ(getenvvar_helper(7), FEE_PER_L2_GAS); // FEEPERL2GAS = 1, see simulator.cpp gas_fees
1146 EXPECT_EQ(getenvvar_helper(8), FEE_PER_DA_GAS); // FEEPERDAGAS = 1, see simulator.cpp gas_fees
1147 EXPECT_EQ(getenvvar_helper(9), 0); // is static call is always false
1148 EXPECT_EQ(getenvvar_helper(10),
1149 GAS_LIMIT.l2_gas - AVM_SET_BASE_L2_GAS - 2 * 6); // L2GASLEFT, gas spent on set + getenvvar + return
1150 EXPECT_EQ(getenvvar_helper(11), GAS_LIMIT.da_gas); // DAGASLEFT, see simulator.cpp
1151}
1152} // namespace execution_environment
1153
1155TEST_F(FuzzTest, EmitNullifierThenNullifierExists)
1156{
1157 auto set_field_instruction =
1159 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1160 .value = 1 };
1161 auto emit_nullifier_instruction = EMITNULLIFIER_Instruction{
1163 };
1164 auto nullifier_exists_instruction = NULLIFIEREXISTS_Instruction{
1165 .nullifier_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1166 .contract_address_address = AddressRef{ .address = 10, .mode = AddressingMode::Direct },
1167 .result_address = AddressRef{ .address = 20, .mode = AddressingMode::Direct }
1168 };
1169 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1170 .instructions = { set_field_instruction, emit_nullifier_instruction, nullifier_exists_instruction } } };
1171 auto control_flow = ControlFlow(instruction_blocks);
1172 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1173 auto bytecode = control_flow.build_bytecode(ReturnOptions{
1174 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 20 });
1175 auto result = simulate_with_default_tx(bytecode, {});
1176 EXPECT_EQ(result.output.at(0), 1);
1177}
1178
1179TEST_F(FuzzTest, EmitNullifierThenNullifierExistsOverwritingPreviousNullifier)
1180{
1181 auto set_field_instruction =
1183 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1184 .value = 1 };
1185 auto emit_nullifier_instruction = EMITNULLIFIER_Instruction{
1187 };
1188 auto nullifier_exists_instruction = NULLIFIEREXISTS_Instruction{
1189 .nullifier_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1190 .contract_address_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1191 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct }
1192 }; // GETENVVAR overwrites previous nullifier
1193 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1194 .instructions = { set_field_instruction, emit_nullifier_instruction, nullifier_exists_instruction } } };
1195 auto control_flow = ControlFlow(instruction_blocks);
1196 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1197 auto bytecode = control_flow.build_bytecode(
1198 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1199 auto result = simulate_with_default_tx(bytecode, {});
1200 EXPECT_EQ(result.output.at(0), 0);
1201}
1202
1203TEST_F(FuzzTest, EmitNoteHashThenNoteHashExists)
1204{
1205 FF note_hash = 42;
1206 uint64_t leaf_index = 0;
1207 auto set_note_hash_instruction =
1209 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1210 .value = note_hash };
1211 auto set_leaf_index_instruction =
1213 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1214 .value = leaf_index };
1215 auto note_hash_exists_instruction =
1217 .leaf_index_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1218 .result_address = AddressRef{ .address = 2, .mode = AddressingMode::Direct } };
1219 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1220 .instructions = { set_note_hash_instruction, set_leaf_index_instruction, note_hash_exists_instruction } } };
1221 auto control_flow = ControlFlow(instruction_blocks);
1222 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1223 auto bytecode = control_flow.build_bytecode(
1224 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1225 auto result = simulate_with_default_tx(bytecode, {}, { note_hash });
1226 EXPECT_FALSE(result.reverted);
1227 EXPECT_EQ(result.output.at(0), 1);
1228}
1229} // namespace notes_and_nullifiers
1230
1232TEST_F(FuzzTest, CopyCalldataThenReturnData)
1233{
1234 auto calldatacopy_instruction = CALLDATACOPY_Instruction{ .dst_address = AddressRef{ .address = 0 },
1235 .copy_size = 1,
1236 .copy_size_address = AddressRef{ .address = 1 },
1237 .cd_start = 0,
1238 .cd_start_address = AddressRef{ .address = 2 } };
1239 auto instruction_blocks =
1240 std::vector<InstructionBlock>{ InstructionBlock{ .instructions = { calldatacopy_instruction } } };
1241 auto control_flow = ControlFlow(instruction_blocks);
1242 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1243 auto bytecode = control_flow.build_bytecode(
1244 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1245
1246 auto result = simulate_with_default_tx(bytecode, { FF(1337) });
1247 EXPECT_EQ(result.output.at(0), 1337);
1248}
1249
1250// call internal function overwrites memory address
1251TEST_F(FuzzTest, InternalCall)
1252{
1253 auto set_field_instruction =
1255 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1256 .value = 1337 };
1257 auto set_field_instruction2 =
1259 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1260 .value = 313373 };
1261 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1262 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1263 .instructions = { set_field_instruction, set_field_instruction2 } } };
1264 auto control_flow = ControlFlow(instruction_blocks);
1265 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1266 control_flow.process_cfg_instruction(internal_call_instruction);
1267 auto bytecode = control_flow.build_bytecode(
1268 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1269 auto result = simulate_with_default_tx(bytecode, {});
1270 EXPECT_EQ(result.output.at(0), 313373);
1271}
1272} // namespace calldata_returndata
1273
1275
1276// check if internal call does not halt execution on return
1277TEST_F(FuzzTest, InternalCalledBlockUsesInternalReturn)
1278{
1279 auto set_field_instruction =
1281 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1282 .value = 1337 };
1283 auto set_boolean_instruction =
1285 .result_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct },
1286 .value = 1 };
1287 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1288 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1289 .instructions = { set_field_instruction, set_boolean_instruction } } };
1290 auto control_flow = ControlFlow(instruction_blocks);
1291 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
1292 control_flow.process_cfg_instruction(internal_call_instruction);
1293 // this should do nothing, just insert INTERNALRETURN instruction
1294 // otherwise it will halt execution and return 1
1295 control_flow.process_cfg_instruction(FinalizeWithReturn{
1297 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 } });
1298 auto bytecode = control_flow.build_bytecode(
1299 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1300 auto result = simulate_with_default_tx(bytecode, {});
1301 EXPECT_EQ(result.output.at(0), 1337);
1302}
1303
1304// SSTORE(0, 1337); call f1; return SLOAD(0);
1305// f1: SSTORE(0, 31337); call f2; INTERNALRETURN
1306// f2: SSTORE(0, 313373); INTERNALRETURN
1307TEST_F(FuzzTest, SeveralInternalCalls)
1308{
1309 auto set_field_instruction =
1311 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1312 .value = 1337 };
1313 auto set_field_instruction2 =
1315 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1316 .value = 31337 };
1317 auto set_field_instruction3 =
1319 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1320 .value = 313373 };
1321 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1322 auto internal_call_instruction2 = InsertInternalCall{ .target_program_block_instruction_block_idx = 2 };
1323 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1324 .instructions = { set_field_instruction, set_field_instruction2, set_field_instruction3 } } };
1325 auto control_flow = ControlFlow(instruction_blocks);
1326 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1327 control_flow.process_cfg_instruction(internal_call_instruction);
1328 control_flow.process_cfg_instruction(internal_call_instruction2);
1329 auto bytecode = control_flow.build_bytecode(
1330 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1331 auto result = simulate_with_default_tx(bytecode, {});
1332 EXPECT_EQ(result.output.at(0), 313373);
1333}
1334
1352TEST_F(FuzzTest, Reentrancy)
1353{
1354 auto set_field_instruction0 =
1356 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1357 .value = 1 };
1358 auto set_field_instruction1 =
1360 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1361 .value = 1337 };
1362 auto set_field_instruction2 =
1364 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1365 .value = 31337 };
1366 auto set_field_instruction3 =
1368 .result_address = AddressRef{ .address = 0, .mode = AddressingMode::Direct },
1369 .value = 313373 };
1370 auto internal_call_instruction = InsertInternalCall{ .target_program_block_instruction_block_idx = 1 };
1371 auto internal_call_instruction2 = InsertInternalCall{ .target_program_block_instruction_block_idx = 2 };
1372 auto internal_call_instruction3 = InsertInternalCall{ .target_program_block_instruction_block_idx = 3 };
1373 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1374 { set_field_instruction0, set_field_instruction1, set_field_instruction2, set_field_instruction3 } } };
1375 auto control_flow = ControlFlow(instruction_blocks);
1376 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1377 // call f1
1378 control_flow.process_cfg_instruction(internal_call_instruction);
1379 // call f2
1380 control_flow.process_cfg_instruction(internal_call_instruction2);
1381 // Should switch context to f1
1382 control_flow.process_cfg_instruction(FinalizeWithReturn{
1384 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1385 // SSTORE(0, 1337);
1386 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 1 });
1387 // Should switch context to f0 (START)
1388 control_flow.process_cfg_instruction(FinalizeWithReturn{
1390 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1391 // call f3
1392 control_flow.process_cfg_instruction(internal_call_instruction3);
1393 // Should switch context to f0 (START)
1394 control_flow.process_cfg_instruction(FinalizeWithReturn{
1396 .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 } });
1397 auto bytecode = control_flow.build_bytecode(
1398 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1399 auto result = simulate_with_default_tx(bytecode, {});
1400 EXPECT_EQ(result.output.at(0), 313373);
1401}
1402} // namespace internal_calls
1403
1405TEST_F(FuzzTest, DirectWithIndirect)
1406{
1407 auto set_field_instruction =
1409 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1410 .value = 10 };
1411 auto set_field_instruction2 =
1413 .result_address = AddressRef{ .address = 3000, .mode = AddressingMode::Direct },
1414 .value = 20 };
1415 auto add_instruction = ADD_8_Instruction{
1417 .index = 1,
1418 .pointer_address_seed = 100,
1419 .mode = AddressingMode::Indirect },
1420 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1421 .result_address = AddressRef{ .address = 130, .mode = AddressingMode::Direct }
1422 };
1423 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1424 .instructions = { set_field_instruction, set_field_instruction2, add_instruction } } };
1425 auto control_flow = ControlFlow(instruction_blocks);
1426 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1427 auto bytecode = control_flow.build_bytecode(
1428 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1429 auto result = simulate_with_default_tx(bytecode, {});
1430 EXPECT_EQ(result.output.at(0), 30);
1431}
1432
1433TEST_F(FuzzTest, DirectWithIndirectRelative)
1434{
1435 auto set_field_instruction =
1437 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1438 .value = 10 };
1439 auto set_field_instruction2 =
1441 .result_address = AddressRef{ .address = 3000, .mode = AddressingMode::Direct },
1442 .value = 20 };
1443 auto add_instruction = ADD_8_Instruction{
1445 .index = 1,
1446 .pointer_address_seed = 100,
1448 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 0, .mode = AddressingMode::Direct },
1449 .result_address = AddressRef{ .address = 130, .mode = AddressingMode::Direct }
1450 };
1451 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1452 .instructions = { set_field_instruction, set_field_instruction2, add_instruction }, .base_offset = 100 } };
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), 30);
1459}
1460
1461TEST_F(FuzzTest, IndirectResultCanBeUsedInNextInstruction)
1462{
1463 auto set_field_instruction =
1465 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1466 .value = 10 };
1467 auto add_instruction = ADD_8_Instruction{
1469 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
1470 .result_address = AddressRef{ .address = 130, .pointer_address_seed = 100, .mode = AddressingMode::Indirect }
1471 };
1472 auto mul_instruction = MUL_8_Instruction{
1474 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF, .index = 1, .mode = AddressingMode::Direct },
1475 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct }
1476 };
1477 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1478 .instructions = { set_field_instruction, add_instruction, mul_instruction } } };
1479 auto control_flow = ControlFlow(instruction_blocks);
1480 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1481 auto bytecode = control_flow.build_bytecode(
1482 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1483 auto result = simulate_with_default_tx(bytecode, {});
1484 EXPECT_EQ(result.output.at(0), 400);
1485}
1486
1487TEST_F(FuzzTest, Memoryaddressing32BitWidth)
1488{
1489 auto set_field_instruction =
1491 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct },
1492 .value = 10 };
1493 auto set_field_instruction2 = SET_FF_Instruction{ .value_tag = bb::avm2::MemoryTag::FF,
1494 .result_address = AddressRef{ .address = 4294967295,
1495 .pointer_address_seed = 100,
1496 .mode = AddressingMode::Indirect },
1497 .value = 20 };
1498 auto add_instruction = MUL_8_Instruction{
1500 .b_address = VariableRef{ .tag = bb::avm2::MemoryTag::FF,
1501 .index = 1,
1502 .pointer_address_seed = 200,
1503 .mode = AddressingMode::Indirect },
1504 .result_address = AddressRef{ .address = 150, .mode = AddressingMode::Direct }
1505 };
1506 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{
1507 .instructions = { set_field_instruction, set_field_instruction2, add_instruction } } };
1508 auto control_flow = ControlFlow(instruction_blocks);
1509 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1510 auto bytecode = control_flow.build_bytecode(
1511 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 2 });
1512 auto result = simulate_with_default_tx(bytecode, {});
1513 EXPECT_EQ(result.output.at(0), 200);
1514}
1515} // namespace avm_addressing
1516
1517namespace misc {
1518// TODO(defkit): get info from world state to be sure that the message will be sent / log emitted
1519TEST_F(FuzzTest, SendL2ToL1Msg)
1520{
1521 auto sendl2tol1msg_instruction =
1522 SENDL2TOL1MSG_Instruction{ .recipient = 100,
1524 .content = 200,
1525 .content_address = AddressRef{ .address = 1, .mode = AddressingMode::Direct } };
1526 auto instruction_blocks =
1527 std::vector<InstructionBlock>{ InstructionBlock{ .instructions = { sendl2tol1msg_instruction } } };
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
1537{
1540 uint32_t log_size = 1;
1541 FF log_value = 42;
1542
1543 std::vector<FuzzInstruction> instructions;
1544
1545 instructions.push_back(SET_32_Instruction{
1546 .value_tag = bb::avm2::MemoryTag::U32, .result_address = log_size_address, .value = log_size });
1547
1548 instructions.push_back(SET_FF_Instruction{
1549 .value_tag = bb::avm2::MemoryTag::FF, .result_address = log_values_address, .value = log_value });
1550
1551 instructions.push_back(
1553
1554 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ 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 = bb::avm2::MemoryTag::FF, .return_value_offset_index = 0 });
1559 auto result = simulate_with_default_tx(bytecode, {});
1560 EXPECT_EQ(result.reverted, false);
1561}
1562} // namespace misc
1563
1565
1567 protected:
1569 {
1570 FF address = context.get_contract_address(0);
1571 std::vector<FuzzInstruction> instructions;
1572 instructions.push_back(
1574 .result_address = AddressRef{ .address = 123, .mode = AddressingMode::Direct },
1575 .value = address });
1576 instructions.push_back(GETCONTRACTINSTANCE_Instruction{
1578 .member_enum = member_enum,
1579 .dst_address = AddressRef{ .address = 124, .mode = AddressingMode::Direct } });
1580
1581 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1582 auto control_flow = ControlFlow(instruction_blocks);
1583 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1584 auto bytecode = control_flow.build_bytecode(
1585 ReturnOptions{ .return_size = 1, .return_value_tag = return_value_tag, .return_value_offset_index = 1 });
1586 auto result = simulate_with_default_tx(bytecode, {});
1587 return result.output.at(0);
1588 }
1589};
1590
1593TEST_F(ExternalCallsFuzzTest, ExternalCallToAdd8)
1594{
1595 std::vector<FuzzInstruction> instructions;
1596 auto contract_address = context.get_contract_address(0);
1598 instructions.push_back(SET_FF_Instruction{
1599 .value_tag = bb::avm2::MemoryTag::FF, .result_address = contract_address_address, .value = contract_address });
1600
1601 uint32_t l2_gas = 10000;
1603 instructions.push_back(
1605
1606 uint32_t da_gas = 10000;
1608 instructions.push_back(
1610
1611 uint16_t arg_size = 0;
1612 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1613 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1614
1615 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1616 .da_gas_address = da_gas_address,
1617 .contract_address_address = contract_address_address,
1618 .calldata_address = args_address,
1619 .calldata_size_address = arg_size_address,
1620 .calldata_size = arg_size,
1621 .is_static_call = false });
1622
1623 instructions.push_back(RETURNDATASIZE_WITH_RETURNDATACOPY_Instruction{
1624 .copy_size_offset = 6, .dst_address = 7, .rd_start = 0, .rd_start_offset = 8 });
1625
1626 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1627 auto control_flow = ControlFlow(instruction_blocks);
1628 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1629 auto bytecode = control_flow.build_bytecode(
1630 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::FF, .return_value_offset_index = 1 });
1631 auto result = simulate_with_default_tx(bytecode, {});
1632 EXPECT_EQ(result.output.at(0), 2);
1633}
1634
1636{
1637
1638 EXPECT_EQ(get_contract_instance_helper(0),
1639 FF("0x0000000000000000000000000000000000000000000000000000000000000064")); // DEPLOYER
1640 EXPECT_EQ(get_contract_instance_helper(1),
1641 FF("0x0dc97dd1cc90c276ca76f34abb5085e1ae3addd8ace763a5da908bacf147d972")); // CLASS_ID
1642 EXPECT_EQ(get_contract_instance_helper(2),
1643 FF("0x0000000000000000000000000000000000000000000000000000000000000000")); // INIT HASH
1644 EXPECT_EQ(get_contract_instance_helper(0, bb::avm2::MemoryTag::U1), FF::one()); // EXISTS
1645}
1646
1647// Calls add8, sucesscopy, return
1649{
1650 std::vector<FuzzInstruction> instructions;
1651 auto contract_address = context.get_contract_address(0);
1653 instructions.push_back(SET_FF_Instruction{
1654 .value_tag = bb::avm2::MemoryTag::FF, .result_address = contract_address_address, .value = contract_address });
1655
1656 uint32_t l2_gas = 10000;
1658 instructions.push_back(
1660
1661 uint32_t da_gas = 10000;
1663 instructions.push_back(
1665
1666 uint16_t arg_size = 0;
1667 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1668 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1669
1670 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1671 .da_gas_address = da_gas_address,
1672 .contract_address_address = contract_address_address,
1673 .calldata_address = args_address,
1674 .calldata_size_address = arg_size_address,
1675 .calldata_size = arg_size,
1676 .is_static_call = false });
1677
1678 instructions.push_back(
1680 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1681 auto control_flow = ControlFlow(instruction_blocks);
1682 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1683 auto bytecode = control_flow.build_bytecode(
1684 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 0 });
1685
1686 auto result = simulate_with_default_tx(bytecode, {});
1687 EXPECT_EQ(result.output.at(0), FF::one());
1688}
1689
1690// Performs static call to ZERO_DIVISION, SUCCESSCOPY, RETURN
1691// The result should be 0
1692TEST_F(ExternalCallsFuzzTest, CallToZeroDivisionSuccessCopy)
1693{
1694 std::vector<FuzzInstruction> instructions;
1695 auto contract_address = context.get_contract_address(1);
1697 instructions.push_back(SET_FF_Instruction{
1698 .value_tag = bb::avm2::MemoryTag::FF, .result_address = contract_address_address, .value = contract_address });
1699
1700 uint32_t l2_gas = 10000;
1702 instructions.push_back(
1704
1705 uint32_t da_gas = 10000;
1707 instructions.push_back(
1709
1710 uint16_t arg_size = 0;
1711 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1712 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1713
1714 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1715 .da_gas_address = da_gas_address,
1716 .contract_address_address = contract_address_address,
1717 .calldata_address = args_address,
1718 .calldata_size_address = arg_size_address,
1719 .calldata_size = arg_size,
1720 .is_static_call = true });
1721 instructions.push_back(
1723 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1724 auto control_flow = ControlFlow(instruction_blocks);
1725 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1726 auto bytecode = control_flow.build_bytecode(
1727 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 1 });
1728 auto result = simulate_with_default_tx(bytecode, {});
1729 EXPECT_EQ(result.output.at(0), FF::zero());
1730 EXPECT_EQ(result.reverted, false);
1731}
1732
1734TEST_F(ExternalCallsFuzzTest, StaticCallToNonStaticFunctionSuccessCopy)
1735{
1736 std::vector<FuzzInstruction> instructions;
1737 auto contract_address = context.get_contract_address(2);
1739 instructions.push_back(SET_FF_Instruction{
1740 .value_tag = bb::avm2::MemoryTag::FF, .result_address = contract_address_address, .value = contract_address });
1741
1742 uint32_t l2_gas = 10000;
1744 instructions.push_back(
1746
1747 uint32_t da_gas = 10000;
1749 instructions.push_back(
1751
1752 uint16_t arg_size = 0;
1753 AddressRef arg_size_address = AddressRef{ .address = 4, .mode = AddressingMode::Direct };
1754 AddressRef args_address = AddressRef{ .address = 5, .mode = AddressingMode::Direct };
1755
1756 instructions.push_back(CALL_Instruction{ .l2_gas_address = l2_gas_address,
1757 .da_gas_address = da_gas_address,
1758 .contract_address_address = contract_address_address,
1759 .calldata_address = args_address,
1760 .calldata_size_address = arg_size_address,
1761 .calldata_size = arg_size,
1762 .is_static_call = true });
1763 instructions.push_back(
1765 auto instruction_blocks = std::vector<InstructionBlock>{ InstructionBlock{ instructions } };
1766 auto control_flow = ControlFlow(instruction_blocks);
1767 control_flow.process_cfg_instruction(InsertSimpleInstructionBlock{ .instruction_block_idx = 0 });
1768 auto bytecode = control_flow.build_bytecode(
1769 ReturnOptions{ .return_size = 1, .return_value_tag = bb::avm2::MemoryTag::U1, .return_value_offset_index = 1 });
1770 auto result = simulate_with_default_tx(bytecode, {});
1771 EXPECT_EQ(result.output.at(0), FF::zero());
1772 EXPECT_EQ(result.reverted, false);
1773}
1774} // namespace external_calls
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:44
void SetUp() override
Definition fuzz.test.cpp:31
void TearDown() override
Definition fuzz.test.cpp:42
FuzzerContext context
Definition fuzz.test.cpp:80
SimulatorResult simulate_with_default_tx(std::vector< uint8_t > &bytecode, std::vector< FF > calldata, const std::vector< FF > &note_hashes)
Definition fuzz.test.cpp:49
SimulatorResult simulate_with_default_tx(std::vector< uint8_t > &bytecode, std::vector< FF > calldata)
Definition fuzz.test.cpp:44
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:87
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:254
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:15
void register_functions(FuzzerContext &context)
Definition fuzz.test.cpp:17
std::variant< ADD_8_Instruction, FDIV_8_Instruction, SET_8_Instruction, SET_16_Instruction, SET_32_Instruction, SET_64_Instruction, SET_128_Instruction, SET_FF_Instruction, MOV_8_Instruction, MOV_16_Instruction, SUB_8_Instruction, MUL_8_Instruction, DIV_8_Instruction, EQ_8_Instruction, LT_8_Instruction, LTE_8_Instruction, AND_8_Instruction, OR_8_Instruction, XOR_8_Instruction, SHL_8_Instruction, SHR_8_Instruction, NOT_8_Instruction, ADD_16_Instruction, SUB_16_Instruction, MUL_16_Instruction, DIV_16_Instruction, FDIV_16_Instruction, EQ_16_Instruction, LT_16_Instruction, LTE_16_Instruction, AND_16_Instruction, OR_16_Instruction, XOR_16_Instruction, NOT_16_Instruction, SHL_16_Instruction, SHR_16_Instruction, CAST_8_Instruction, CAST_16_Instruction, SSTORE_Instruction, SLOAD_Instruction, GETENVVAR_Instruction, EMITNULLIFIER_Instruction, NULLIFIEREXISTS_Instruction, L1TOL2MSGEXISTS_Instruction, EMITNOTEHASH_Instruction, NOTEHASHEXISTS_Instruction, CALLDATACOPY_Instruction, SENDL2TOL1MSG_Instruction, EMITPUBLICLOG_Instruction, CALL_Instruction, RETURNDATASIZE_Instruction, RETURNDATACOPY_Instruction, GETCONTRACTINSTANCE_Instruction, SUCCESSCOPY_Instruction, ECADD_Instruction, POSEIDON2PERM_Instruction, KECCAKF1600_Instruction, SHA256COMPRESSION_Instruction, TORADIXBE_Instruction, DEBUGLOG_Instruction > FuzzInstruction
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:45
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)
Definition simulator.cpp:96
GlobalVariables create_default_globals()
Definition simulator.cpp:31
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 a siloed nullifier exists in the nullifier tree M[result_address] = NULLIF...
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:17
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