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;
39 ex_event.addressing_event.instruction =
instruction;
41 ex_event.after_context_event.id = context_id;
42 ex_event.after_context_event.parent_id = parent_id;
43 ex_event.after_context_event.phase = phase;
44 ex_event.before_context_event = ex_event.after_context_event;
48ExecutionEvent create_add_event(uint32_t context_id, uint32_t parent_id,
TransactionPhase phase)
50 const auto add_instr =
51 InstructionBuilder(
WireOpCode::ADD_8).operand<uint8_t>(0).operand<uint8_t>(0).operand<uint8_t>(0).build();
52 auto ex_event = create_base_event(add_instr, context_id, parent_id, phase);
58ExecutionEvent create_call_event(uint32_t context_id,
61 uint32_t next_context_id)
70 auto ex_event = create_base_event(call_instr, context_id, parent_id, phase);
71 ex_event.next_context_id = next_context_id;
72 ex_event.inputs = { MemoryValue::from<uint32_t>(10),
73 MemoryValue ::from<uint32_t>(11),
74 MemoryValue::from<uint32_t>(0xdeadbeef) };
78ExecutionEvent create_return_event(uint32_t context_id, uint32_t parent_id,
TransactionPhase phase)
80 const auto return_instr = InstructionBuilder(
WireOpCode::RETURN).operand<uint8_t>(0).operand<uint8_t>(0).build();
81 auto ex_event = create_base_event(return_instr, context_id, parent_id, phase);
82 ex_event.inputs = { MemoryValue::from<uint32_t>(2) };
86ExecutionEvent create_error_event(uint32_t context_id,
89 uint32_t next_context_id)
92 const auto add_instr =
93 InstructionBuilder(
WireOpCode::ADD_8).operand<uint8_t>(0).operand<uint8_t>(0).operand<uint8_t>(0).build();
94 auto ex_event = create_base_event(add_instr, context_id, parent_id, phase);
97 ex_event.next_context_id = next_context_id;
104TEST(ExecutionTraceGenTest, RegisterAllocation)
106 TestTraceContainer
trace;
118 ExecutionEvent ex_event = {
119 .wire_instruction = instr,
122 .addressing_event = { .instruction = instr },
149TEST(ExecutionTraceGenTest, Call)
151 TestTraceContainer
trace;
159 .operand<uint8_t>(10)
160 .operand<uint8_t>(20)
163 Gas allocated_gas = { .l2Gas = 100, .daGas = 200 };
164 Gas gas_limit = { .l2Gas = 1000, .daGas = 2000 };
165 Gas gas_used = { .l2Gas = 500, .daGas = 1900 };
166 Gas gas_left = gas_limit - gas_used;
168 ExecutionEvent ex_event = {
169 .wire_instruction = call_instr,
170 .inputs = { MemoryValue::from<uint32_t>(allocated_gas.l2Gas),
171 MemoryValue ::from<uint32_t>(allocated_gas.daGas),
172 MemoryValue::from<FF>(0xdeadbeef) },
173 .next_context_id = 2,
174 .addressing_event = { .instruction = call_instr,
176 { .after_relative = MemoryValue::from<uint32_t>(0),
177 .resolved_operand = MemoryValue::from<uint32_t>(0),
179 { .after_relative = MemoryValue::from<uint32_t>(0),
180 .resolved_operand = MemoryValue::from<uint32_t>(0),
182 { .after_relative = MemoryValue::from<uint32_t>(0),
183 .resolved_operand = MemoryValue::from<uint32_t>(0) },
184 { .after_relative = MemoryValue::from<uint32_t>(0),
185 .resolved_operand = MemoryValue::from<uint32_t>(10) },
186 { .after_relative = MemoryValue::from<uint32_t>(0),
187 .resolved_operand = MemoryValue::from<uint32_t>(20) },
189 .after_context_event = {
191 .contract_addr = 0xdeadbeef,
192 .gas_used = gas_used,
193 .gas_limit = gas_limit,
209 ROW_FIELD_EQ(execution_register_0_, allocated_gas.l2Gas),
210 ROW_FIELD_EQ(execution_register_1_, allocated_gas.daGas),
225 ROW_FIELD_EQ(execution_call_is_l2_gas_allocated_lt_left,
true),
226 ROW_FIELD_EQ(execution_call_allocated_left_l2_cmp_diff, gas_left.l2Gas - allocated_gas.l2Gas - 1),
227 ROW_FIELD_EQ(execution_call_is_da_gas_allocated_lt_left,
false),
228 ROW_FIELD_EQ(execution_call_allocated_left_da_cmp_diff, allocated_gas.daGas - gas_left.daGas))));
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 = { .instruction = return_instr,
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 = { .instruction = instr },
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 = { .l2Gas = 110149, .daGas = 100000 };
307 Gas prev_gas_used = { .l2Gas = 100000, .daGas = 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 = { .l2Gas = 2, .daGas = 1 };
313 ex_event.gas_event.oog_l2 =
true;
314 ex_event.gas_event.oog_da =
false;
315 ex_event.gas_event.limit_used_l2_comparison_witness = 0;
316 ex_event.gas_event.limit_used_da_comparison_witness =
317 gas_limit.daGas - prev_gas_used.daGas - base_da_gas - dynamic_da_gas * 1;
341 ex_event.gas_event.limit_used_da_comparison_witness))));
344TEST(ExecutionTraceGenTest, DiscardNestedFailContext)
346 TestTraceContainer
trace;
406TEST(ExecutionTraceGenTest, DiscardAppLogicDueToTeardownError)
408 TestTraceContainer
trace;
452TEST(ExecutionTraceGenTest, DiscardAppLogicDueToSecondEnqueuedCallError)
454 TestTraceContainer
trace;
499TEST(ExecutionTraceGenTest, InternalCall)
501 TestTraceContainer
trace;
506 .operand<uint32_t>(10)
509 ExecutionEvent ex_event = {
510 .wire_instruction = instr,
511 .addressing_event = {
512 .instruction = instr,
515 .resolved_operand = MemoryValue::from<uint32_t>(10) },
518 .before_context_event {
519 .internal_call_id = 1,
520 .internal_call_return_id = 0,
521 .next_internal_call_id = 2,
540TEST(ExecutionTraceGenTest, InternalRetError)
542 TestTraceContainer
trace;
547 simulation::ExecutionEvent ex_event = {
549 .wire_instruction = instr,
550 .addressing_event = {
551 .instruction = instr,
553 .before_context_event {
554 .internal_call_id = 1,
555 .internal_call_return_id = 0,
556 .next_internal_call_id = 2,
573 ROW_FIELD_EQ(execution_internal_call_return_id_inv, 0))));
576TEST(ExecutionTraceGenTest, Jump)
578 TestTraceContainer
trace;
582 .operand<uint32_t>(120)
585 ExecutionEvent ex_event_jump = {
586 .wire_instruction = instr,
587 .addressing_event = { .instruction = instr,
588 .resolution_info = { {
589 .resolved_operand = MemoryValue::from<uint32_t>(120),
606TEST(ExecutionTraceGenTest, JumpI)
608 TestTraceContainer
trace;
612 .operand<uint16_t>(654)
613 .operand<uint32_t>(9876)
616 ExecutionEvent ex_event_jumpi = {
617 .wire_instruction = instr,
618 .inputs = { MemoryValue::from<uint1_t>(1) },
619 .addressing_event = { .instruction = instr,
620 .resolution_info = { {
621 .resolved_operand = MemoryValue::from<uint32_t>(654),
624 .resolved_operand = MemoryValue::from<uint32_t>(9876),
648TEST(ExecutionTraceGenTest, JumpiWrongTag)
650 TestTraceContainer
trace;
654 .operand<uint16_t>(654)
655 .operand<uint32_t>(9876)
658 ExecutionEvent ex_event_jumpi = {
659 .wire_instruction = instr,
660 .inputs = { MemoryValue::from<uint8_t>(1) },
661 .addressing_event = { .instruction = instr,
662 .resolution_info = { {
663 .resolved_operand = MemoryValue::from<uint32_t>(654),
666 .resolved_operand = MemoryValue::from<uint32_t>(9876),
692TEST(ExecutionTraceGenTest, Mov16)
694 TestTraceContainer
trace;
698 .operand<uint32_t>(1000)
699 .operand<uint32_t>(1001)
702 ExecutionEvent ex_event_mov = {
703 .wire_instruction = instr,
704 .inputs = { MemoryValue::from<uint128_t>(100) },
705 .output = MemoryValue::from<uint128_t>(100),
706 .addressing_event = { .instruction = instr,
707 .resolution_info = { {
708 .resolved_operand = MemoryValue::from<uint32_t>(1000),
711 .resolved_operand = MemoryValue::from<uint32_t>(1001),
737TEST(ExecutionTraceGenTest, Mov8)
739 TestTraceContainer
trace;
743 .operand<uint32_t>(10)
744 .operand<uint32_t>(11)
747 ExecutionEvent ex_event_mov = {
748 .wire_instruction = instr,
749 .inputs = { MemoryValue::from<uint64_t>(100) },
750 .output = MemoryValue::from<uint64_t>(100),
751 .addressing_event = { .instruction = instr,
752 .resolution_info = { {
753 .resolved_operand = MemoryValue::from<uint32_t>(10),
756 .resolved_operand = MemoryValue::from<uint32_t>(11),
782TEST(ExecutionTraceGenTest, SuccessCopy)
784 TestTraceContainer
trace;
787 .operand<uint8_t>(45)
790 ExecutionEvent ex_event = {
791 .wire_instruction = instr,
793 .addressing_event = {
794 .instruction = instr,
795 .resolution_info = { { .resolved_operand = MemoryValue::from<uint8_t>(45) } }
797 .after_context_event = { .last_child_success =
true }
816TEST(ExecutionTraceGenTest, RdSize)
818 TestTraceContainer
trace;
821 .operand<uint16_t>(1234)
824 ExecutionEvent ex_event = {
825 .wire_instruction = instr,
827 .addressing_event = {
828 .instruction = instr,
829 .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(1234) } }
832 .after_context_event = { .last_child_rd_size = 100 }
847 ROW_FIELD_EQ(execution_last_child_returndata_size, 100),
851TEST(ExecutionTraceGenTest, SLoad)
853 TestTraceContainer
trace;
856 uint16_t slot_offset = 1234;
857 uint16_t dst_offset = 4567;
863 InstructionBuilder(
WireOpCode::SLOAD).operand<uint16_t>(slot_offset).operand<uint16_t>(dst_offset).build();
865 ExecutionEvent ex_event = {
866 .wire_instruction = instr,
867 .inputs = { MemoryValue::from<FF>(
slot) },
868 .output = MemoryValue::from<FF>(dst_value),
869 .addressing_event = { .instruction = instr,
870 .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(slot_offset) },
871 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
891TEST(ExecutionTraceGenTest, SStore)
893 TestTraceContainer
trace;
896 uint16_t slot_offset = 1234;
897 uint16_t value_offset = 4567;
903 InstructionBuilder(
WireOpCode::SSTORE).operand<uint16_t>(value_offset).operand<uint16_t>(slot_offset).build();
905 ExecutionEvent ex_event = {
906 .wire_instruction = instr,
907 .inputs = { MemoryValue::from<FF>(
value), MemoryValue::from<FF>(
slot) },
908 .addressing_event = { .instruction = instr,
910 { .resolved_operand = MemoryValue::from<uint16_t>(value_offset) },
911 { .resolved_operand = MemoryValue::from<uint16_t>(slot_offset) },
913 .before_context_event = {
921 .dynamic_gas_factor = { .daGas = 1 },
947TEST(ExecutionTraceGenTest, NoteHashExists)
949 TestTraceContainer
trace;
952 uint16_t unique_note_hash_offset = 1234;
953 uint16_t leaf_index_offset = 4567;
954 uint16_t dst_offset = 8901;
956 FF unique_note_hash = 42;
957 uint64_t leaf_index = 27;
958 uint1_t dst_value = 1;
961 .operand<uint16_t>(unique_note_hash_offset)
962 .operand<uint16_t>(leaf_index_offset)
963 .operand<uint16_t>(dst_offset)
966 ExecutionEvent ex_event = {
967 .wire_instruction = instr,
968 .inputs = { MemoryValue::from<FF>(unique_note_hash), MemoryValue::from<uint64_t>(leaf_index) },
969 .output = MemoryValue::from<uint1_t>(dst_value),
970 .addressing_event = { .instruction = instr,
971 .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 = { .instruction = instr,
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 = { .instruction = instr,
1069 .resolution_info = { { .resolved_operand = MemoryValue::from<uint16_t>(msg_hash_offset) },
1070 { .resolved_operand =
1071 MemoryValue::from<uint16_t>(leaf_index_offset) },
1072 { .resolved_operand = MemoryValue::from<uint16_t>(dst_offset) } } },
1082 ROW_FIELD_EQ(execution_sel_execute_l1_to_l2_message_exists, 1),
1098TEST(ExecutionTraceGenTest, NullifierExists)
1100 TestTraceContainer
trace;
1101 ExecutionTraceBuilder
builder;
1103 uint16_t nullifier_offset = 100;
1104 uint16_t address_offset = 200;
1105 uint16_t exists_offset = 300;
1107 FF address = 0xdeadbeef;
1111 .operand<uint16_t>(nullifier_offset)
1112 .operand<uint16_t>(address_offset)
1113 .operand<uint16_t>(exists_offset)
1115 ExecutionEvent ex_event = {
1116 .wire_instruction = instr,
1119 .addressing_event = { .instruction = instr,
1120 .resolution_info = { { .resolved_operand = MemoryValue::from<FF>(
nullifier) },
1121 { .resolved_operand = MemoryValue::from<FF>(address) },
1122 { .resolved_operand =
1123 MemoryValue::from<uint16_t>(exists_offset) } } }
1127 EXPECT_THAT(
trace.as_rows(),
1133 ROW_FIELD_EQ(execution_sel_execute_nullifier_exists, 1),
1146TEST(ExecutionTraceGenTest, EmitNullifier)
1148 TestTraceContainer
trace;
1149 ExecutionTraceBuilder
builder;
1151 uint16_t nullifier_offset = 100;
1155 const auto instr = InstructionBuilder(WireOpCode::EMITNULLIFIER).operand<uint16_t>(nullifier_offset).build();
1157 ExecutionEvent ex_event = {
1158 .wire_instruction = instr,
1159 .inputs = { TaggedValue::from_tag(ValueTag::FF,
nullifier) },
1160 .addressing_event = { .instruction = instr,
1161 .resolution_info = { { .resolved_operand = MemoryValue::from<FF>(
nullifier) } } },
1162 .before_context_event = {
1165 .counter = prev_num_nullifiers_emitted,
1172 EXPECT_THAT(
trace.as_rows(),
1188TEST(ExecutionTraceGenTest, SendL2ToL1Msg)
1190 TestTraceContainer
trace;
1191 ExecutionTraceBuilder
builder;
1193 uint16_t recipient_offset = 100;
1194 uint16_t content_offset = 101;
1195 FF recipient = 0x123456;
1196 FF content = 0xdeadbeef;
1199 const auto instr = InstructionBuilder(WireOpCode::SENDL2TOL1MSG)
1200 .operand<uint16_t>(recipient_offset)
1201 .operand<uint16_t>(content_offset)
1204 ExecutionEvent ex_event = { .wire_instruction = instr,
1205 .inputs = { TaggedValue::from_tag(ValueTag::FF, recipient),
1206 TaggedValue::from_tag(ValueTag::FF, content) },
1207 .addressing_event = { .instruction = instr,
1208 .resolution_info = { { .resolved_operand =
1209 MemoryValue::from<FF>(recipient) },
1210 { .resolved_operand =
1211 MemoryValue::from<FF>(content) } } },
1212 .before_context_event = { .side_effect_states = {
1213 .numL2ToL1Messages = prev_num_l2_to_l1_msgs,
1224 ROW_FIELD_EQ(execution_sel_execute_send_l2_to_l1_msg, 1),
TEST(acir_formal_proofs, uint_terms_add)
Tests 127-bit unsigned addition Verifies that the ACIR implementation of addition is correct Executio...
#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)
std::vector< AvmFullRowConstRef > as_rows() const
#define ROW_FIELD_EQ(field_name, expression)
TEST(EmitUnencryptedLogTest, Basic)
const std::unordered_map< ExecutionOpCode, ExecInstructionSpec > EXEC_INSTRUCTION_SPEC
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept