4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
21using simulation::ExecutionEvent;
23using ::bb::avm2::testing::InstructionBuilder;
27using ::testing::AllOf;
28using ::testing::ElementsAre;
33ExecutionEvent create_base_event(
const simulation::Instruction&
instruction,
38 ExecutionEvent ex_event;
41 ex_event.after_context_event.parent_id = parent_id;
42 ex_event.after_context_event.phase = phase;
43 ex_event.before_context_event = ex_event.after_context_event;
49 const auto add_instr =
50 InstructionBuilder(
WireOpCode::ADD_8).operand<uint8_t>(0).operand<uint8_t>(0).operand<uint8_t>(0).build();
51 auto ex_event = create_base_event(add_instr,
context_id, parent_id, phase);
57ExecutionEvent create_call_event(uint32_t
context_id,
60 uint32_t next_context_id)
70 ex_event.next_context_id = next_context_id;
71 ex_event.inputs = { MemoryValue::from<uint32_t>(10),
72 MemoryValue ::from<uint32_t>(11),
74 MemoryValue::from<uint32_t>(0xdeadbeef),
75 MemoryValue::from<uint32_t>(0) };
81 const auto return_instr = InstructionBuilder(
WireOpCode::RETURN).operand<uint8_t>(0).operand<uint8_t>(0).build();
82 auto ex_event = create_base_event(return_instr,
context_id, parent_id, phase);
83 ex_event.inputs = { MemoryValue::from<uint32_t>(2) };
87ExecutionEvent create_error_event(uint32_t
context_id,
90 uint32_t next_context_id)
93 const auto add_instr =
94 InstructionBuilder(
WireOpCode::ADD_8).operand<uint8_t>(0).operand<uint8_t>(0).operand<uint8_t>(0).build();
95 auto ex_event = create_base_event(add_instr,
context_id, parent_id, phase);
98 ex_event.next_context_id = next_context_id;
105TEST(ExecutionTraceGenTest, RegisterAllocation)
107 TestTraceContainer
trace;
119 ExecutionEvent ex_event = {
120 .wire_instruction = instr,
123 .addressing_event = {},
150TEST(ExecutionTraceGenTest, Call)
152 TestTraceContainer
trace;
160 .operand<uint8_t>(10)
161 .operand<uint8_t>(20)
164 Gas allocated_gas = { .l2_gas = 100, .da_gas = 200 };
165 Gas gas_limit = { .l2_gas = 1000, .da_gas = 2000 };
166 Gas gas_used = { .l2_gas = 500, .da_gas = 1900 };
167 Gas gas_left = gas_limit - gas_used;
169 ExecutionEvent ex_event = {
171 .inputs = { MemoryValue::from<uint32_t>(allocated_gas.l2_gas),
172 MemoryValue ::from<uint32_t>(allocated_gas.da_gas),
173 MemoryValue::from<FF>(0xdeadbeef),
174 MemoryValue::from<uint32_t>(0) },
175 .next_context_id = 2,
176 .addressing_event = {
178 { .after_relative = MemoryValue::from<uint32_t>(0),
179 .resolved_operand = MemoryValue::from<uint32_t>(0),
181 { .after_relative = MemoryValue::from<uint32_t>(0),
182 .resolved_operand = MemoryValue::from<uint32_t>(0),
184 { .after_relative = MemoryValue::from<uint32_t>(0),
185 .resolved_operand = MemoryValue::from<uint32_t>(0) },
186 { .after_relative = MemoryValue::from<uint32_t>(0),
187 .resolved_operand = MemoryValue::from<uint32_t>(10) },
188 { .after_relative = MemoryValue::from<uint32_t>(0),
189 .resolved_operand = MemoryValue::from<uint32_t>(20) },
191 .after_context_event = {
193 .contract_addr = 0xdeadbeef,
194 .gas_used = gas_used,
195 .gas_limit = gas_limit,
210 ROW_FIELD_EQ(execution_register_0_, allocated_gas.l2_gas),
211 ROW_FIELD_EQ(execution_register_1_, allocated_gas.da_gas),
227 ROW_FIELD_EQ(execution_is_l2_gas_left_gt_allocated,
true),
228 ROW_FIELD_EQ(execution_is_da_gas_left_gt_allocated,
false))));
231TEST(ExecutionTraceGenTest, Return)
233 TestTraceContainer
trace;
237 const auto return_instr = InstructionBuilder(
WireOpCode::RETURN).operand<uint8_t>(4).operand<uint8_t>(20).build();
239 ExecutionEvent ex_event = {
240 .wire_instruction = return_instr,
241 .inputs = { MemoryValue::from<uint32_t>(2) },
242 .next_context_id = 2,
243 .addressing_event = {
245 { .after_relative = MemoryValue::from<uint32_t>(0),
246 .resolved_operand = MemoryValue::from<uint32_t>(4),
248 { .after_relative = MemoryValue::from<uint32_t>(0),
249 .resolved_operand = MemoryValue::from<uint32_t>(5),
252 .after_context_event = {
254 .contract_addr = 0xdeadbeef,
278TEST(ExecutionTraceGenTest, Gas)
280 TestTraceContainer
trace;
291 ExecutionEvent ex_event = {
292 .wire_instruction = instr,
295 .addressing_event = {},
300 const uint32_t addressing_gas = 50;
301 const uint32_t opcode_gas = exec_instruction_spec.gas_cost.opcode_gas;
302 const uint32_t dynamic_l2_gas = exec_instruction_spec.gas_cost.dyn_l2;
303 const uint32_t dynamic_da_gas = exec_instruction_spec.gas_cost.dyn_da;
304 const uint32_t base_da_gas = exec_instruction_spec.gas_cost.base_da;
306 Gas gas_limit = { .l2_gas = 110149, .da_gas = 100000 };
307 Gas prev_gas_used = { .l2_gas = 100000, .da_gas = 70000 };
309 ex_event.after_context_event.gas_limit = gas_limit;
310 ex_event.before_context_event.gas_used = prev_gas_used;
311 ex_event.gas_event.addressing_gas = addressing_gas;
312 ex_event.gas_event.dynamic_gas_factor = { .l2_gas = 2, .da_gas = 1 };
313 ex_event.gas_event.oog_l2 =
true;
314 ex_event.gas_event.oog_da =
false;
316 uint64_t total_gas_used_l2 = prev_gas_used.l2_gas + opcode_gas + addressing_gas + (dynamic_l2_gas * 2);
317 uint64_t total_gas_used_da = prev_gas_used.da_gas + base_da_gas + (dynamic_da_gas * 1);
319 ex_event.gas_event.total_gas_used_l2 = total_gas_used_l2;
320 ex_event.gas_event.total_gas_used_da = total_gas_used_da;
342 ROW_FIELD_EQ(execution_total_gas_l2, total_gas_used_l2),
343 ROW_FIELD_EQ(execution_total_gas_da, total_gas_used_da))));
346TEST(ExecutionTraceGenTest, DiscardNestedFailContext)
348 TestTraceContainer
trace;
408TEST(ExecutionTraceGenTest, DiscardAppLogicDueToTeardownError)
410 TestTraceContainer
trace;
454TEST(ExecutionTraceGenTest, DiscardAppLogicDueToSecondEnqueuedCallError)
456 TestTraceContainer
trace;
501TEST(ExecutionTraceGenTest, InternalCall)
503 TestTraceContainer
trace;
508 .operand<uint32_t>(10)
511 ExecutionEvent ex_event = {
512 .wire_instruction = instr,
513 .addressing_event = {
516 .resolved_operand = MemoryValue::from<uint32_t>(10) },
519 .before_context_event {
520 .internal_call_id = 1,
521 .internal_call_return_id = 0,
522 .next_internal_call_id = 2,
541TEST(ExecutionTraceGenTest, InternalRetError)
543 TestTraceContainer
trace;
549 .wire_instruction = instr,
550 .addressing_event = {},
551 .before_context_event{
552 .internal_call_id = 1,
553 .internal_call_return_id = 0,
554 .next_internal_call_id = 2,
571 ROW_FIELD_EQ(execution_internal_call_return_id_inv, 0))));
574TEST(ExecutionTraceGenTest, Jump)
576 TestTraceContainer
trace;
580 .operand<uint32_t>(120)
583 ExecutionEvent ex_event_jump = {
584 .wire_instruction = instr,
585 .addressing_event = { .resolution_info = { {
586 .resolved_operand = MemoryValue::from<uint32_t>(120),
603TEST(ExecutionTraceGenTest, JumpI)
605 TestTraceContainer
trace;
609 .operand<uint16_t>(654)
610 .operand<uint32_t>(9876)
613 ExecutionEvent ex_event_jumpi = {
614 .wire_instruction = instr,
615 .inputs = { MemoryValue::from<uint1_t>(1) },
616 .addressing_event = { .resolution_info = { {
617 .resolved_operand = MemoryValue::from<uint32_t>(654),
620 .resolved_operand = MemoryValue::from<uint32_t>(9876),
644TEST(ExecutionTraceGenTest, JumpiWrongTag)
646 TestTraceContainer
trace;
650 .operand<uint16_t>(654)
651 .operand<uint32_t>(9876)
654 ExecutionEvent ex_event_jumpi = {
656 .wire_instruction = instr,
657 .inputs = { MemoryValue::from<uint8_t>(1) },
658 .addressing_event = { .resolution_info = { {
659 .resolved_operand = MemoryValue::from<uint32_t>(654),
662 .resolved_operand = MemoryValue::from<uint32_t>(9876),
688TEST(ExecutionTraceGenTest, Mov16)
690 TestTraceContainer
trace;
694 .operand<uint32_t>(1000)
695 .operand<uint32_t>(1001)
698 ExecutionEvent ex_event_mov = {
699 .wire_instruction = instr,
700 .inputs = { MemoryValue::from<uint128_t>(100) },
701 .output = MemoryValue::from<uint128_t>(100),
702 .addressing_event = { .resolution_info = { {
703 .resolved_operand = MemoryValue::from<uint32_t>(1000),
706 .resolved_operand = MemoryValue::from<uint32_t>(1001),
732TEST(ExecutionTraceGenTest, Mov8)
734 TestTraceContainer
trace;
738 .operand<uint32_t>(10)
739 .operand<uint32_t>(11)
742 ExecutionEvent ex_event_mov = {
743 .wire_instruction = instr,
744 .inputs = { MemoryValue::from<uint64_t>(100) },
745 .output = MemoryValue::from<uint64_t>(100),
746 .addressing_event = { .resolution_info = { {
747 .resolved_operand = MemoryValue::from<uint32_t>(10),
750 .resolved_operand = MemoryValue::from<uint32_t>(11),
776TEST(ExecutionTraceGenTest, SuccessCopy)
778 TestTraceContainer
trace;
781 .operand<uint8_t>(45)
784 ExecutionEvent ex_event = {
785 .wire_instruction = instr,
787 .addressing_event = {
788 .resolution_info = { { .resolved_operand = MemoryValue::from<uint8_t>(45) } }
790 .after_context_event = { .last_child_success =
true }
809TEST(ExecutionTraceGenTest, RdSize)
811 TestTraceContainer
trace;
814 .operand<uint16_t>(1234)
817 ExecutionEvent ex_event = {
818 .wire_instruction = instr,
820 .addressing_event = {
821 .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(1234) } }
824 .after_context_event = { .last_child_rd_size = 100 }
839 ROW_FIELD_EQ(execution_last_child_returndata_size, 100),
843TEST(ExecutionTraceGenTest, SLoad)
845 TestTraceContainer
trace;
848 uint16_t slot_offset = 1234;
849 uint16_t contract_address_offset = 2345;
850 uint16_t dst_offset = 4567;
853 FF contract_address = 0xdeadbeef;
857 .operand<uint16_t>(slot_offset)
858 .operand<uint16_t>(contract_address_offset)
859 .operand<uint16_t>(dst_offset)
862 ExecutionEvent ex_event = {
863 .wire_instruction = instr,
864 .inputs = { MemoryValue::from<FF>(
slot), MemoryValue::from<FF>(contract_address) },
865 .output = MemoryValue::from<FF>(dst_value),
866 .addressing_event = { .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(slot_offset) },
867 { .resolved_operand =
868 MemoryValue::from<uint16_t>(contract_address_offset) },
869 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
881 ROW_FIELD_EQ(execution_rop_1_, contract_address_offset),
892TEST(ExecutionTraceGenTest, SStore)
894 TestTraceContainer
trace;
897 uint16_t slot_offset = 1234;
898 uint16_t value_offset = 4567;
904 InstructionBuilder(
WireOpCode::SSTORE).operand<uint16_t>(value_offset).operand<uint16_t>(slot_offset).build();
906 ExecutionEvent ex_event = {
907 .wire_instruction = instr,
908 .inputs = { MemoryValue::from<FF>(
value), MemoryValue::from<FF>(
slot) },
909 .addressing_event = {
911 { .resolved_operand = MemoryValue::from<uint16_t>(value_offset) },
912 { .resolved_operand = MemoryValue::from<uint16_t>(slot_offset) },
914 .before_context_event = {
916 .public_data_tree = {
922 .dynamic_gas_factor = { .da_gas = 1 },
948TEST(ExecutionTraceGenTest, NoteHashExists)
950 TestTraceContainer
trace;
953 uint16_t unique_note_hash_offset = 1234;
954 uint16_t leaf_index_offset = 4567;
955 uint16_t dst_offset = 8901;
957 FF unique_note_hash = 42;
958 uint64_t leaf_index = 27;
959 uint1_t dst_value = 1;
962 .operand<uint16_t>(unique_note_hash_offset)
963 .operand<uint16_t>(leaf_index_offset)
964 .operand<uint16_t>(dst_offset)
967 ExecutionEvent ex_event = {
968 .wire_instruction = instr,
969 .inputs = { MemoryValue::from<FF>(unique_note_hash), MemoryValue::from<uint64_t>(leaf_index) },
970 .output = MemoryValue::from<uint1_t>(dst_value),
971 .addressing_event = { .resolution_info = { { .resolved_operand =
972 MemoryValue::from<uint16_t>(unique_note_hash_offset) },
973 { .resolved_operand =
974 MemoryValue::from<uint16_t>(leaf_index_offset) },
975 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
987 ROW_FIELD_EQ(execution_rop_0_, unique_note_hash_offset),
1001TEST(ExecutionTraceGenTest, EmitNoteHash)
1003 TestTraceContainer
trace;
1004 ExecutionTraceBuilder
builder;
1006 uint16_t note_hash_offset = 1234;
1013 ExecutionEvent ex_event = {
1014 .wire_instruction = instr,
1015 .inputs = { MemoryValue::from<FF>(
note_hash) },
1016 .addressing_event = {
1017 .resolution_info = { { .resolved_operand =
1018 MemoryValue::from<uint16_t>(note_hash_offset) } } },
1019 .before_context_event = {
1022 .counter = prev_num_note_hashes_emitted,
1045TEST(ExecutionTraceGenTest, L1ToL2MessageExists)
1047 TestTraceContainer
trace;
1048 ExecutionTraceBuilder
builder;
1050 uint16_t msg_hash_offset = 1234;
1051 uint16_t leaf_index_offset = 4567;
1052 uint16_t dst_offset = 8901;
1055 uint64_t leaf_index = 27;
1056 uint1_t dst_value = 1;
1059 .operand<uint16_t>(msg_hash_offset)
1060 .operand<uint16_t>(leaf_index_offset)
1061 .operand<uint16_t>(dst_offset)
1064 ExecutionEvent ex_event = {
1065 .wire_instruction = instr,
1066 .inputs = { MemoryValue::from<FF>(msg_hash), MemoryValue::from<uint64_t>(leaf_index) },
1067 .output = MemoryValue::from<uint1_t>(dst_value),
1068 .addressing_event = { .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(msg_hash_offset) },
1069 { .resolved_operand =
1070 MemoryValue::from<uint16_t>(leaf_index_offset) },
1071 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
1081 ROW_FIELD_EQ(execution_sel_execute_l1_to_l2_message_exists, 1),
1097TEST(ExecutionTraceGenTest, NullifierExists)
1099 TestTraceContainer
trace;
1100 ExecutionTraceBuilder
builder;
1102 uint16_t nullifier_offset = 100;
1103 uint16_t exists_offset = 300;
1104 FF siloed_nullifier = 0x123456;
1108 .operand<uint16_t>(nullifier_offset)
1109 .operand<uint16_t>(exists_offset)
1111 ExecutionEvent ex_event = { .wire_instruction = instr,
1114 .addressing_event = {
1115 .resolution_info = {
1116 { .resolved_operand = MemoryValue::from<FF>(siloed_nullifier) },
1117 { .resolved_operand = MemoryValue::from<uint16_t>(exists_offset) } } } };
1120 EXPECT_THAT(
trace.as_rows(),
1126 ROW_FIELD_EQ(execution_sel_execute_nullifier_exists, 1),
1136TEST(ExecutionTraceGenTest, EmitNullifier)
1138 TestTraceContainer
trace;
1139 ExecutionTraceBuilder
builder;
1141 uint16_t nullifier_offset = 100;
1142 FF nullifier = 0x123456;
1145 const auto instr = InstructionBuilder(WireOpCode::EMITNULLIFIER).operand<uint16_t>(nullifier_offset).build();
1147 ExecutionEvent ex_event = {
1148 .wire_instruction = instr,
1149 .inputs = { MemoryValue::from_tag(ValueTag::FF, nullifier) },
1150 .addressing_event = {
1151 .resolution_info = { { .resolved_operand = MemoryValue::from<FF>(nullifier) } } },
1152 .before_context_event = {
1155 .counter = prev_num_nullifiers_emitted,
1162 EXPECT_THAT(
trace.as_rows(),
1178TEST(ExecutionTraceGenTest, SendL2ToL1Msg)
1180 TestTraceContainer
trace;
1181 ExecutionTraceBuilder
builder;
1183 uint16_t recipient_offset = 100;
1184 uint16_t content_offset = 101;
1185 FF recipient = 0x123456;
1186 FF content = 0xdeadbeef;
1189 const auto instr = InstructionBuilder(WireOpCode::SENDL2TOL1MSG)
1190 .operand<uint16_t>(recipient_offset)
1191 .operand<uint16_t>(content_offset)
1194 ExecutionEvent ex_event = { .wire_instruction = instr,
1195 .inputs = { MemoryValue::from_tag(ValueTag::FF, recipient),
1196 MemoryValue::from_tag(ValueTag::FF, content) },
1197 .addressing_event = { .resolution_info = { { .resolved_operand =
1198 MemoryValue::from<FF>(recipient) },
1199 { .resolved_operand =
1200 MemoryValue::from<FF>(content) } } },
1201 .before_context_event = {
1202 .numL2ToL1Messages = prev_num_l2_to_l1_msgs,
1213 ROW_FIELD_EQ(execution_sel_execute_send_l2_to_l1_msg, 1),
TEST(acir_formal_proofs, uint_terms_add)
Tests 128-bit unsigned addition Verifies that the ACIR implementation of addition is correct Executio...
bb::field< bb::Bn254FrParams > FF
#define AVM_EXEC_OP_ID_SUCCESSCOPY
#define AVM_EXEC_OP_ID_NULLIFIER_EXISTS
#define AVM_EXEC_OP_ID_SSTORE
#define AVM_PUBLIC_INPUTS_AVM_ACCUMULATED_DATA_L2_TO_L1_MSGS_ROW_IDX
#define AVM_EXEC_OP_ID_EMIT_NULLIFIER
#define AVM_EXEC_OP_ID_NOTEHASH_EXISTS
#define AVM_EXEC_OP_ID_SLOAD
#define NOTE_HASH_TREE_LEAF_COUNT
#define AVM_EXEC_OP_ID_JUMP
#define L1_TO_L2_MSG_TREE_LEAF_COUNT
#define AVM_EXEC_OP_ID_EMIT_NOTEHASH
#define MAX_L2_TO_L1_MSGS_PER_TX
#define MAX_NOTE_HASHES_PER_TX
#define AVM_EXEC_OP_ID_MOV
#define MAX_NULLIFIERS_PER_TX
#define AVM_EXEC_OP_ID_SENDL2TOL1MSG
#define AVM_EXEC_OP_ID_RETURNDATASIZE
#define AVM_EXEC_OP_ID_JUMPI
#define AVM_EXEC_OP_ID_L1_TO_L2_MESSAGE_EXISTS
#define MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
static TaggedValue from_tag(ValueTag tag, FF value)
void process(const simulation::EventEmitterInterface< simulation::AluEvent >::Container &events, TraceContainer &trace)
Process the ALU events and populate the ALU relevant columns in the trace.
std::vector< AvmFullRowConstRef > as_rows() const
#define ROW_FIELD_EQ(field_name, expression)
const std::unordered_map< ExecutionOpCode, ExecInstructionSpec > & get_exec_instruction_spec()
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept