3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
26using simulation::Instruction;
27using simulation::InstructionFetchingEvent;
29TEST(BytecodeTraceGenTest, BasicShortLength)
31 TestTraceContainer
trace;
36 simulation::BytecodeDecompositionEvent{
46 ASSERT_EQ(rows.size(), 4 + 1);
49 EXPECT_THAT(rows.at(1),
59 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
61 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
66 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv, 0)));
68 EXPECT_THAT(rows.at(2),
77 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
79 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
83 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 1).invert()),
86 EXPECT_THAT(rows.at(3),
94 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
96 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
100 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 2).invert()),
103 EXPECT_THAT(rows.at(4),
110 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
112 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
116 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 3).invert()),
120TEST(BytecodeTraceGenTest, BasicLongerThanWindowSize)
122 TestTraceContainer
trace;
126 std::vector<uint8_t> bytecode(bytecode_size);
127 const uint8_t first_byte = 17;
130 for (uint8_t i = 0; i < bytecode_size; i++) {
131 bytecode[i] = i + first_byte;
136 simulation::BytecodeDecompositionEvent{
146 ASSERT_EQ(rows.size(), bytecode_size + 1);
149 EXPECT_THAT(rows.at(1),
154 ROW_FIELD_EQ(bc_decomposition_bytes_remaining, bytecode_size),
155 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 0),
156 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv,
FF(-8).invert()),
157 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
161 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv, 0),
166 EXPECT_THAT(rows.at(9),
172 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 0),
173 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv, 0),
174 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 1),
178 EXPECT_THAT(rows.at(10),
184 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
185 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv, 1),
186 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
190 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 9).invert()),
194 EXPECT_THAT(rows.at(bytecode_size),
197 ROW_FIELD_EQ(bc_decomposition_bytes, first_byte + bytecode_size - 1),
200 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
202 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
206 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(62 - (bytecode_size - 1)).invert()),
210TEST(BytecodeTraceGenTest, MultipleEvents)
212 TestTraceContainer
trace;
218 std::transform(bc_sizes.begin(), bc_sizes.end(), bytecodes.begin(), [](uint32_t bc_size) -> std::vector<uint8_t> {
219 std::vector<uint8_t> bytecode(bc_size);
220 for (uint8_t i = 0; i < bc_size; i++) {
229 simulation::BytecodeDecompositionEvent{
233 simulation::BytecodeDecompositionEvent{
237 simulation::BytecodeDecompositionEvent{
241 simulation::BytecodeDecompositionEvent{
253 for (uint32_t i = 0; i < 4; i++) {
254 uint32_t next_packed_pc = 0;
255 for (uint32_t j = 0; j < bc_sizes[i]; j++) {
256 const auto bytes_rem = bc_sizes[i] - j;
263 ROW_FIELD_EQ(bc_decomposition_bytes_remaining, bytes_rem),
266 bc_decomposition_windows_min_remaining_inv,
270 ROW_FIELD_EQ(bc_decomposition_sel_packed, j == next_packed_pc ? 1 : 0),
271 ROW_FIELD_EQ(bc_decomposition_next_packed_pc, next_packed_pc),
272 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
273 j == next_packed_pc ? 0 :
FF(next_packed_pc - j).invert()),
274 ROW_FIELD_EQ(bc_decomposition_last_of_contract, j == bc_sizes[i] - 1 ? 1 : 0)));
276 next_packed_pc += j % 31 == 0 ? 31 : 0;
281TEST(BytecodeTraceGenTest, BasicHashing)
283 TestTraceContainer
trace;
288 simulation::BytecodeHashingEvent{
290 .bytecode_length = 9,
291 .bytecode_fields = { 10, 20, 30 },
298 EXPECT_THAT(rows.at(1),
320 EXPECT_THAT(rows.at(2),
344 instructions.reserve(opcodes.size());
345 for (
const auto& opcode : opcodes) {
353 std::vector<uint8_t> bytecode;
355 auto serialized_instruction =
instruction.serialize();
356 bytecode.insert(bytecode.end(),
365 std::vector<size_t> pcs;
366 pcs.reserve(opcodes.size());
368 for (
const auto& opcode : opcodes) {
369 pcs.emplace_back(pc);
377 const std::vector<size_t>& pcs,
378 const std::shared_ptr<std::vector<uint8_t>>& bytecode_ptr,
382 events.reserve(instructions.size());
384 for (
size_t i = 0; i < instructions.size(); i++) {
385 events.emplace_back(InstructionFetchingEvent{
386 .bytecode_id = bytecode_id,
387 .pc =
static_cast<uint32_t
>(pcs.at(i)),
388 .instruction = instructions.at(i),
389 .bytecode = bytecode_ptr,
397TEST(BytecodeTraceGenTest, InstrDecompositionInBytesEachOpcode)
399 TestTraceContainer
trace;
403 C::instr_fetching_bd0, C::instr_fetching_bd1, C::instr_fetching_bd2, C::instr_fetching_bd3,
404 C::instr_fetching_bd4, C::instr_fetching_bd5, C::instr_fetching_bd6, C::instr_fetching_bd7,
405 C::instr_fetching_bd8, C::instr_fetching_bd9, C::instr_fetching_bd10, C::instr_fetching_bd11,
406 C::instr_fetching_bd12, C::instr_fetching_bd13, C::instr_fetching_bd14, C::instr_fetching_bd15,
407 C::instr_fetching_bd16, C::instr_fetching_bd17, C::instr_fetching_bd18, C::instr_fetching_bd19,
408 C::instr_fetching_bd20, C::instr_fetching_bd21, C::instr_fetching_bd22, C::instr_fetching_bd23,
409 C::instr_fetching_bd24, C::instr_fetching_bd25, C::instr_fetching_bd26, C::instr_fetching_bd27,
410 C::instr_fetching_bd28, C::instr_fetching_bd29, C::instr_fetching_bd30, C::instr_fetching_bd31,
411 C::instr_fetching_bd32, C::instr_fetching_bd33, C::instr_fetching_bd34, C::instr_fetching_bd35,
412 C::instr_fetching_bd36,
416 C::instr_fetching_op1, C::instr_fetching_op2, C::instr_fetching_op3, C::instr_fetching_op4,
417 C::instr_fetching_op5, C::instr_fetching_op6, C::instr_fetching_op7,
424 opcodes.reserve(num_opcodes);
425 for (
size_t i = 0; i < num_opcodes; i++) {
426 opcodes.emplace_back(
static_cast<WireOpCode>(i));
430 std::vector<size_t> pcs = gen_pcs(opcodes);
431 std::vector<uint8_t> bytecode = create_bytecode(instructions);
435 create_instruction_fetching_events(instructions, pcs, bytecode_ptr, bytecode_id);
439 for (uint32_t i = 0; i < num_opcodes; i++) {
440 const auto instr = instructions.at(i);
441 const auto instr_encoded = instr.serialize();
442 const auto w_opcode =
static_cast<WireOpCode>(i);
446 ASSERT_EQ(instr_encoded.size(), expected_size_in_bytes);
447 EXPECT_EQ(
FF(expected_size_in_bytes),
trace.
get(C::instr_fetching_instr_size, i + 1));
450 for (
size_t j = 0; j < static_cast<size_t>(expected_size_in_bytes); j++) {
451 EXPECT_EQ(
FF(instr_encoded.at(j)),
trace.
get(bd_columns.at(j), i + 1));
456 trace.
get(C::instr_fetching_exec_opcode, i + 1));
459 EXPECT_EQ(
FF(instr.indirect),
trace.
get(C::instr_fetching_indirect, i + 1));
462 EXPECT_EQ(
FF(pcs.at(i)),
trace.
get(C::instr_fetching_pc, i + 1));
465 size_t operand_idx = 0;
466 for (
const auto& operand : instr.operands) {
467 EXPECT_EQ(
FF(operand),
trace.
get(operand_columns.at(operand_idx++), i + 1));
472TEST(BytecodeTraceGenTest, InstrFetchingSingleBytecode)
474 TestTraceContainer
trace;
478 constexpr size_t num_of_opcodes = 10;
493 std::vector<size_t> pcs = gen_pcs(opcodes);
494 std::vector<uint8_t> bytecode = create_bytecode(instructions);
497 instructions, pcs,
std::make_shared<std::vector<uint8_t>>(bytecode), bytecode_id);
503 const auto bytecode_size = bytecode.size();
504 EXPECT_EQ(rows.size(), num_of_opcodes + 1);
506 for (
size_t i = 0; i < num_of_opcodes; i++) {
507 const auto pc = pcs.at(i);
510 const auto tag_is_op2 = has_tag ?
WIRE_INSTRUCTION_SPEC.at(opcodes.at(i)).tag_operand_idx.value() == 2 : 0;
511 const auto bytes_remaining = bytecode_size - pc;
514 EXPECT_LE(instr_size, bytes_to_read);
515 const auto instr_abs_diff = bytes_to_read - instr_size;
517 EXPECT_LT(pc, bytecode_size);
518 const auto pc_abs_diff = bytecode_size - pc - 1;
520 ASSERT_LE(bytecode_size, UINT16_MAX);
522 EXPECT_THAT(rows.at(i + 1),
525 ROW_FIELD_EQ(instr_fetching_bd0,
static_cast<uint8_t
>(opcodes.at(i))),
527 ROW_FIELD_EQ(instr_fetching_bytes_to_read, bytes_to_read),
528 ROW_FIELD_EQ(instr_fetching_bytecode_size, bytecode_size),
530 ROW_FIELD_EQ(instr_fetching_instr_abs_diff, instr_abs_diff),
539 ROW_FIELD_EQ(instr_fetching_sel_tag_is_op2, tag_is_op2),
545TEST(BytecodeTraceGenTest, InstrFetchingMultipleBytecodes)
547 TestTraceContainer
trace;
550 constexpr size_t num_of_opcodes = 2;
557 std::vector<size_t> pcs = gen_pcs(opcodes);
558 std::vector<uint8_t> bytecode = create_bytecode(instructions);
561 for (
size_t i = 0; i < 3; i++) {
564 create_instruction_fetching_events(instructions, pcs, bytecode_ptr,
static_cast<BytecodeId>(i + 1));
565 events.insert(events.end(), new_events.begin(), new_events.end());
572 EXPECT_EQ(rows.size(), 6 + 1);
574 for (
size_t i = 0; i < 3; i++) {
575 EXPECT_THAT(rows.at(2 * i + 1),
ROW_FIELD_EQ(instr_fetching_pc, 0));
589TEST(BytecodeTraceGenTest, InstrFetchingParsingErrors)
591 TestTraceContainer
trace;
595 constexpr size_t bytecode_size = 20;
596 std::vector<uint8_t> bytecode(bytecode_size);
597 for (
size_t i = 0; i < bytecode_size; i++) {
598 bytecode[i] =
static_cast<uint8_t
>(i);
604 events.emplace_back(InstructionFetchingEvent{
605 .bytecode_id = bytecode_id,
607 .bytecode = bytecode_ptr,
610 events.emplace_back(InstructionFetchingEvent{
611 .bytecode_id = bytecode_id,
613 .bytecode = bytecode_ptr,
616 events.emplace_back(InstructionFetchingEvent{
617 .bytecode_id = bytecode_id,
619 .bytecode = bytecode_ptr,
627 ASSERT_EQ(rows.size(), 3 + 1);
629 EXPECT_THAT(rows.at(1),
641 EXPECT_THAT(rows.at(2),
667TEST(BytecodeTraceGenTest, InstrFetchingErrorTagOutOfRange)
672 TestTraceContainer
trace;
677 constexpr uint32_t cast_size = 7;
678 constexpr uint32_t set_64_size = 13;
680 instr_cast.operands.at(2) = Operand::from<uint8_t>(0x09);
681 instr_set.operands.at(1) = Operand::from<uint8_t>(0x0A);
683 auto bytecode = instr_cast.serialize();
684 ASSERT_EQ(bytecode.size(), cast_size);
686 auto instr_set_bytecode = instr_set.serialize();
687 ASSERT_EQ(instr_set_bytecode.size(), set_64_size);
689 bytecode.insert(bytecode.end(), instr_set_bytecode.begin(), instr_set_bytecode.end());
694 events.emplace_back(InstructionFetchingEvent{
698 .bytecode = bytecode_ptr,
702 events.emplace_back(InstructionFetchingEvent{
707 .bytecode = bytecode_ptr,
715 ASSERT_EQ(rows.size(), 2 + 1);
717 EXPECT_THAT(rows.at(1),
724 ROW_FIELD_EQ(instr_fetching_bytes_to_read, cast_size + set_64_size),
730 cast_size + set_64_size - 1),
741 ROW_FIELD_EQ(instr_fetching_bytes_to_read, set_64_size),
745 ROW_FIELD_EQ(instr_fetching_pc_abs_diff, set_64_size - 1),
#define GENERATOR_INDEX__PUBLIC_BYTECODE
std::vector< AvmFullRowConstRef > as_rows() const
const FF & get(Column col, uint32_t row) const
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
#define ROW_FIELD_EQ(field_name, expression)
TEST(EmitUnencryptedLogTest, Basic)
@ INSTRUCTION_OUT_OF_RANGE
Instruction deserialize_instruction(std::span< const uint8_t > bytecode, size_t pos)
Parsing of an instruction in the supplied bytecode at byte position pos. This checks that the WireOpC...
Instruction random_instruction(WireOpCode w_opcode)
constexpr uint32_t DECOMPOSE_WINDOW_SIZE
const std::unordered_map< WireOpCode, WireInstructionSpec > WIRE_INSTRUCTION_SPEC
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept