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 = {},
165TEST(ExecutionTraceGenTest, Call)
167 TestTraceContainer
trace;
175 .operand<uint8_t>(10)
176 .operand<uint8_t>(20)
179 Gas allocated_gas = { .l2_gas = 100, .da_gas = 200 };
180 Gas gas_limit = { .l2_gas = 1000, .da_gas = 2000 };
181 Gas gas_used = { .l2_gas = 500, .da_gas = 1900 };
182 Gas gas_left = gas_limit - gas_used;
184 ExecutionEvent ex_event = {
186 .inputs = { MemoryValue::from<uint32_t>(allocated_gas.l2_gas),
187 MemoryValue ::from<uint32_t>(allocated_gas.da_gas),
188 MemoryValue::from<FF>(0xdeadbeef),
189 MemoryValue::from<uint32_t>(0) },
190 .next_context_id = 2,
191 .addressing_event = {
193 { .after_relative = MemoryValue::from<uint32_t>(0),
194 .resolved_operand = MemoryValue::from<uint32_t>(0),
196 { .after_relative = MemoryValue::from<uint32_t>(0),
197 .resolved_operand = MemoryValue::from<uint32_t>(0),
199 { .after_relative = MemoryValue::from<uint32_t>(0),
200 .resolved_operand = MemoryValue::from<uint32_t>(0) },
201 { .after_relative = MemoryValue::from<uint32_t>(0),
202 .resolved_operand = MemoryValue::from<uint32_t>(10) },
203 { .after_relative = MemoryValue::from<uint32_t>(0),
204 .resolved_operand = MemoryValue::from<uint32_t>(20) },
206 .after_context_event = {
208 .contract_addr = 0xdeadbeef,
209 .gas_used = gas_used,
210 .gas_limit = gas_limit,
225 ROW_FIELD_EQ(execution_register_0_, allocated_gas.l2_gas),
226 ROW_FIELD_EQ(execution_register_1_, allocated_gas.da_gas),
242 ROW_FIELD_EQ(execution_is_l2_gas_left_gt_allocated,
true),
243 ROW_FIELD_EQ(execution_is_da_gas_left_gt_allocated,
false))));
246TEST(ExecutionTraceGenTest, Return)
248 TestTraceContainer
trace;
252 const auto return_instr = InstructionBuilder(
WireOpCode::RETURN).operand<uint8_t>(4).operand<uint8_t>(20).build();
254 ExecutionEvent ex_event = {
255 .wire_instruction = return_instr,
256 .inputs = { MemoryValue::from<uint32_t>(2) },
257 .next_context_id = 2,
258 .addressing_event = {
260 { .after_relative = MemoryValue::from<uint32_t>(0),
261 .resolved_operand = MemoryValue::from<uint32_t>(4),
263 { .after_relative = MemoryValue::from<uint32_t>(0),
264 .resolved_operand = MemoryValue::from<uint32_t>(5),
267 .after_context_event = {
269 .contract_addr = 0xdeadbeef,
293TEST(ExecutionTraceGenTest, Gas)
295 TestTraceContainer
trace;
306 ExecutionEvent ex_event = {
307 .wire_instruction = instr,
310 .addressing_event = {},
315 const uint32_t addressing_gas = 50;
316 const uint32_t opcode_gas = exec_instruction_spec.gas_cost.opcode_gas;
317 const uint32_t dynamic_l2_gas = exec_instruction_spec.gas_cost.dyn_l2;
318 const uint32_t dynamic_da_gas = exec_instruction_spec.gas_cost.dyn_da;
319 const uint32_t base_da_gas = exec_instruction_spec.gas_cost.base_da;
321 Gas gas_limit = { .l2_gas = 110149, .da_gas = 100000 };
322 Gas prev_gas_used = { .l2_gas = 100000, .da_gas = 70000 };
324 ex_event.after_context_event.gas_limit = gas_limit;
325 ex_event.before_context_event.gas_used = prev_gas_used;
326 ex_event.gas_event.addressing_gas = addressing_gas;
327 ex_event.gas_event.dynamic_gas_factor = { .l2_gas = 2, .da_gas = 1 };
328 ex_event.gas_event.oog_l2 =
true;
329 ex_event.gas_event.oog_da =
false;
331 uint64_t total_gas_used_l2 = prev_gas_used.l2_gas + opcode_gas + addressing_gas + (dynamic_l2_gas * 2);
332 uint64_t total_gas_used_da = prev_gas_used.da_gas + base_da_gas + (dynamic_da_gas * 1);
334 ex_event.gas_event.total_gas_used_l2 = total_gas_used_l2;
335 ex_event.gas_event.total_gas_used_da = total_gas_used_da;
357 ROW_FIELD_EQ(execution_total_gas_l2, total_gas_used_l2),
358 ROW_FIELD_EQ(execution_total_gas_da, total_gas_used_da))));
361TEST(ExecutionTraceGenTest, DiscardNestedFailContext)
363 TestTraceContainer
trace;
423TEST(ExecutionTraceGenTest, DiscardAppLogicDueToTeardownError)
425 TestTraceContainer
trace;
469TEST(ExecutionTraceGenTest, DiscardAppLogicDueToSecondEnqueuedCallError)
471 TestTraceContainer
trace;
516TEST(ExecutionTraceGenTest, InternalCall)
518 TestTraceContainer
trace;
523 .operand<uint32_t>(10)
526 ExecutionEvent ex_event = {
527 .wire_instruction = instr,
528 .addressing_event = {
531 .resolved_operand = MemoryValue::from<uint32_t>(10) },
534 .before_context_event {
535 .internal_call_id = 1,
536 .internal_call_return_id = 0,
537 .next_internal_call_id = 2,
556TEST(ExecutionTraceGenTest, InternalRetError)
558 TestTraceContainer
trace;
564 .wire_instruction = instr,
565 .addressing_event = {},
566 .before_context_event{
567 .internal_call_id = 1,
568 .internal_call_return_id = 0,
569 .next_internal_call_id = 2,
586 ROW_FIELD_EQ(execution_internal_call_return_id_inv, 0))));
589TEST(ExecutionTraceGenTest, Jump)
591 TestTraceContainer
trace;
595 .operand<uint32_t>(120)
598 ExecutionEvent ex_event_jump = {
599 .wire_instruction = instr,
600 .addressing_event = { .resolution_info = { {
601 .resolved_operand = MemoryValue::from<uint32_t>(120),
618TEST(ExecutionTraceGenTest, JumpI)
620 TestTraceContainer
trace;
624 .operand<uint16_t>(654)
625 .operand<uint32_t>(9876)
628 ExecutionEvent ex_event_jumpi = {
629 .wire_instruction = instr,
630 .inputs = { MemoryValue::from<uint1_t>(1) },
631 .addressing_event = { .resolution_info = { {
632 .resolved_operand = MemoryValue::from<uint32_t>(654),
635 .resolved_operand = MemoryValue::from<uint32_t>(9876),
659TEST(ExecutionTraceGenTest, JumpiWrongTag)
661 TestTraceContainer
trace;
665 .operand<uint16_t>(654)
666 .operand<uint32_t>(9876)
669 ExecutionEvent ex_event_jumpi = {
671 .wire_instruction = instr,
672 .inputs = { MemoryValue::from<uint8_t>(1) },
673 .addressing_event = { .resolution_info = { {
674 .resolved_operand = MemoryValue::from<uint32_t>(654),
677 .resolved_operand = MemoryValue::from<uint32_t>(9876),
703TEST(ExecutionTraceGenTest, Mov16)
705 TestTraceContainer
trace;
709 .operand<uint32_t>(1000)
710 .operand<uint32_t>(1001)
713 ExecutionEvent ex_event_mov = {
714 .wire_instruction = instr,
715 .inputs = { MemoryValue::from<uint128_t>(100) },
716 .output = MemoryValue::from<uint128_t>(100),
717 .addressing_event = { .resolution_info = { {
718 .resolved_operand = MemoryValue::from<uint32_t>(1000),
721 .resolved_operand = MemoryValue::from<uint32_t>(1001),
747TEST(ExecutionTraceGenTest, Mov8)
749 TestTraceContainer
trace;
753 .operand<uint32_t>(10)
754 .operand<uint32_t>(11)
757 ExecutionEvent ex_event_mov = {
758 .wire_instruction = instr,
759 .inputs = { MemoryValue::from<uint64_t>(100) },
760 .output = MemoryValue::from<uint64_t>(100),
761 .addressing_event = { .resolution_info = { {
762 .resolved_operand = MemoryValue::from<uint32_t>(10),
765 .resolved_operand = MemoryValue::from<uint32_t>(11),
791TEST(ExecutionTraceGenTest, SuccessCopy)
793 TestTraceContainer
trace;
796 .operand<uint8_t>(45)
799 ExecutionEvent ex_event = {
800 .wire_instruction = instr,
802 .addressing_event = {
803 .resolution_info = { { .resolved_operand = MemoryValue::from<uint8_t>(45) } }
805 .after_context_event = { .last_child_success =
true }
824TEST(ExecutionTraceGenTest, RdSize)
826 TestTraceContainer
trace;
829 .operand<uint16_t>(1234)
832 ExecutionEvent ex_event = {
833 .wire_instruction = instr,
835 .addressing_event = {
836 .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(1234) } }
839 .after_context_event = { .last_child_rd_size = 100 }
854 ROW_FIELD_EQ(execution_last_child_returndata_size, 100),
858TEST(ExecutionTraceGenTest, SLoad)
860 TestTraceContainer
trace;
863 uint16_t slot_offset = 1234;
864 uint16_t contract_address_offset = 2345;
865 uint16_t dst_offset = 4567;
868 FF contract_address = 0xdeadbeef;
872 .operand<uint16_t>(slot_offset)
873 .operand<uint16_t>(contract_address_offset)
874 .operand<uint16_t>(dst_offset)
877 ExecutionEvent ex_event = {
878 .wire_instruction = instr,
879 .inputs = { MemoryValue::from<FF>(
slot), MemoryValue::from<FF>(contract_address) },
880 .output = MemoryValue::from<FF>(dst_value),
881 .addressing_event = { .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(slot_offset) },
882 { .resolved_operand =
883 MemoryValue::from<uint16_t>(contract_address_offset) },
884 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
896 ROW_FIELD_EQ(execution_rop_1_, contract_address_offset),
907TEST(ExecutionTraceGenTest, SStore)
909 TestTraceContainer
trace;
912 uint16_t slot_offset = 1234;
913 uint16_t value_offset = 4567;
919 InstructionBuilder(
WireOpCode::SSTORE).operand<uint16_t>(value_offset).operand<uint16_t>(slot_offset).build();
921 ExecutionEvent ex_event = {
922 .wire_instruction = instr,
923 .inputs = { MemoryValue::from<FF>(
value), MemoryValue::from<FF>(
slot) },
924 .addressing_event = {
926 { .resolved_operand = MemoryValue::from<uint16_t>(value_offset) },
927 { .resolved_operand = MemoryValue::from<uint16_t>(slot_offset) },
929 .before_context_event = {
931 .public_data_tree = {
937 .dynamic_gas_factor = { .da_gas = 1 },
963TEST(ExecutionTraceGenTest, NoteHashExists)
965 TestTraceContainer
trace;
968 uint16_t unique_note_hash_offset = 1234;
969 uint16_t leaf_index_offset = 4567;
970 uint16_t dst_offset = 8901;
972 FF unique_note_hash = 42;
973 uint64_t leaf_index = 27;
974 uint1_t dst_value = 1;
977 .operand<uint16_t>(unique_note_hash_offset)
978 .operand<uint16_t>(leaf_index_offset)
979 .operand<uint16_t>(dst_offset)
982 ExecutionEvent ex_event = {
983 .wire_instruction = instr,
984 .inputs = { MemoryValue::from<FF>(unique_note_hash), MemoryValue::from<uint64_t>(leaf_index) },
985 .output = MemoryValue::from<uint1_t>(dst_value),
986 .addressing_event = { .resolution_info = { { .resolved_operand =
987 MemoryValue::from<uint16_t>(unique_note_hash_offset) },
988 { .resolved_operand =
989 MemoryValue::from<uint16_t>(leaf_index_offset) },
990 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
1001 ROW_FIELD_EQ(execution_sel_execute_notehash_exists, 1),
1002 ROW_FIELD_EQ(execution_rop_0_, unique_note_hash_offset),
1016TEST(ExecutionTraceGenTest, EmitNoteHash)
1018 TestTraceContainer
trace;
1019 ExecutionTraceBuilder
builder;
1021 uint16_t note_hash_offset = 1234;
1028 ExecutionEvent ex_event = {
1029 .wire_instruction = instr,
1030 .inputs = { MemoryValue::from<FF>(
note_hash) },
1031 .addressing_event = {
1032 .resolution_info = { { .resolved_operand =
1033 MemoryValue::from<uint16_t>(note_hash_offset) } } },
1034 .before_context_event = {
1037 .counter = prev_num_note_hashes_emitted,
1060TEST(ExecutionTraceGenTest, L1ToL2MessageExists)
1062 TestTraceContainer
trace;
1063 ExecutionTraceBuilder
builder;
1065 uint16_t msg_hash_offset = 1234;
1066 uint16_t leaf_index_offset = 4567;
1067 uint16_t dst_offset = 8901;
1070 uint64_t leaf_index = 27;
1071 uint1_t dst_value = 1;
1074 .operand<uint16_t>(msg_hash_offset)
1075 .operand<uint16_t>(leaf_index_offset)
1076 .operand<uint16_t>(dst_offset)
1079 ExecutionEvent ex_event = {
1080 .wire_instruction = instr,
1081 .inputs = { MemoryValue::from<FF>(msg_hash), MemoryValue::from<uint64_t>(leaf_index) },
1082 .output = MemoryValue::from<uint1_t>(dst_value),
1083 .addressing_event = { .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(msg_hash_offset) },
1084 { .resolved_operand =
1085 MemoryValue::from<uint16_t>(leaf_index_offset) },
1086 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
1096 ROW_FIELD_EQ(execution_sel_execute_l1_to_l2_message_exists, 1),
1112TEST(ExecutionTraceGenTest, NullifierExists)
1114 TestTraceContainer
trace;
1115 ExecutionTraceBuilder
builder;
1117 uint16_t nullifier_offset = 100;
1118 uint16_t exists_offset = 300;
1119 FF siloed_nullifier = 0x123456;
1123 .operand<uint16_t>(nullifier_offset)
1124 .operand<uint16_t>(exists_offset)
1126 ExecutionEvent ex_event = { .wire_instruction = instr,
1129 .addressing_event = {
1130 .resolution_info = {
1131 { .resolved_operand = MemoryValue::from<FF>(siloed_nullifier) },
1132 { .resolved_operand = MemoryValue::from<uint16_t>(exists_offset) } } } };
1135 EXPECT_THAT(
trace.as_rows(),
1141 ROW_FIELD_EQ(execution_sel_execute_nullifier_exists, 1),
1151TEST(ExecutionTraceGenTest, EmitNullifier)
1153 TestTraceContainer
trace;
1154 ExecutionTraceBuilder
builder;
1156 uint16_t nullifier_offset = 100;
1157 FF nullifier = 0x123456;
1160 const auto instr = InstructionBuilder(WireOpCode::EMITNULLIFIER).operand<uint16_t>(nullifier_offset).build();
1162 ExecutionEvent ex_event = {
1163 .wire_instruction = instr,
1164 .inputs = { MemoryValue::from_tag(ValueTag::FF, nullifier) },
1165 .addressing_event = {
1166 .resolution_info = { { .resolved_operand = MemoryValue::from<FF>(nullifier) } } },
1167 .before_context_event = {
1170 .counter = prev_num_nullifiers_emitted,
1177 EXPECT_THAT(
trace.as_rows(),
1193TEST(ExecutionTraceGenTest, SendL2ToL1Msg)
1195 TestTraceContainer
trace;
1196 ExecutionTraceBuilder
builder;
1198 uint16_t recipient_offset = 100;
1199 uint16_t content_offset = 101;
1200 FF recipient = 0x123456;
1201 FF content = 0xdeadbeef;
1204 const auto instr = InstructionBuilder(WireOpCode::SENDL2TOL1MSG)
1205 .operand<uint16_t>(recipient_offset)
1206 .operand<uint16_t>(content_offset)
1209 ExecutionEvent ex_event = { .wire_instruction = instr,
1210 .inputs = { MemoryValue::from_tag(ValueTag::FF, recipient),
1211 MemoryValue::from_tag(ValueTag::FF, content) },
1212 .addressing_event = { .resolution_info = { { .resolved_operand =
1213 MemoryValue::from<FF>(recipient) },
1214 { .resolved_operand =
1215 MemoryValue::from<FF>(content) } } },
1216 .before_context_event = {
1217 .numL2ToL1Messages = prev_num_l2_to_l1_msgs,
1228 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