3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
25using simulation::Instruction;
26using simulation::InstructionFetchingEvent;
28TEST(BytecodeTraceGenTest, BasicShortLength)
30 TestTraceContainer
trace;
35 simulation::BytecodeDecompositionEvent{
45 ASSERT_EQ(rows.size(), 4 + 1);
48 EXPECT_THAT(rows.at(1),
58 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
60 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
64 EXPECT_THAT(rows.at(2),
73 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
75 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
79 EXPECT_THAT(rows.at(3),
87 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
89 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
93 EXPECT_THAT(rows.at(4),
100 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
102 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
107TEST(BytecodeTraceGenTest, BasicLongerThanWindowSize)
109 TestTraceContainer
trace;
113 std::vector<uint8_t> bytecode(bytecode_size);
114 const uint8_t first_byte = 17;
117 for (uint8_t i = 0; i < bytecode_size; i++) {
118 bytecode[i] = i + first_byte;
123 simulation::BytecodeDecompositionEvent{
133 ASSERT_EQ(rows.size(), bytecode_size + 1);
136 EXPECT_THAT(rows.at(1),
141 ROW_FIELD_EQ(bc_decomposition_bytes_remaining, bytecode_size),
142 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 0),
143 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv,
FF(-8).invert()),
144 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
150 EXPECT_THAT(rows.at(9),
156 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 0),
157 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv, 0),
158 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 1),
162 EXPECT_THAT(rows.at(10),
168 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
169 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv, 1),
170 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
175 EXPECT_THAT(rows.at(bytecode_size),
178 ROW_FIELD_EQ(bc_decomposition_bytes, first_byte + bytecode_size - 1),
181 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
183 ROW_FIELD_EQ(bc_decomposition_is_windows_eq_remaining, 0),
188TEST(BytecodeTraceGenTest, MultipleEvents)
190 TestTraceContainer
trace;
196 std::transform(bc_sizes.begin(), bc_sizes.end(), bytecodes.begin(), [](uint32_t bc_size) -> std::vector<uint8_t> {
197 std::vector<uint8_t> bytecode(bc_size);
198 for (uint8_t i = 0; i < bc_size; i++) {
207 simulation::BytecodeDecompositionEvent{
211 simulation::BytecodeDecompositionEvent{
215 simulation::BytecodeDecompositionEvent{
219 simulation::BytecodeDecompositionEvent{
231 for (uint32_t i = 0; i < 4; i++) {
232 for (uint32_t j = 0; j < bc_sizes[i]; j++) {
233 const auto bytes_rem = bc_sizes[i] - j;
240 ROW_FIELD_EQ(bc_decomposition_bytes_remaining, bytes_rem),
243 bc_decomposition_windows_min_remaining_inv,
247 ROW_FIELD_EQ(bc_decomposition_last_of_contract, j == bc_sizes[i] - 1 ? 1 : 0)));
253TEST(BytecodeTraceGenTest, BasicHashing)
255 TestTraceContainer
trace;
260 simulation::BytecodeHashingEvent{
262 .bytecode_length = 6,
263 .bytecode_fields = { 10, 20 },
270 EXPECT_THAT(rows.at(1),
280 EXPECT_THAT(rows.at(2),
292 instructions.reserve(opcodes.size());
293 for (
const auto& opcode : opcodes) {
301 std::vector<uint8_t> bytecode;
303 auto serialized_instruction =
instruction.serialize();
304 bytecode.insert(bytecode.end(),
313 std::vector<size_t> pcs;
314 pcs.reserve(opcodes.size());
316 for (
const auto& opcode : opcodes) {
317 pcs.emplace_back(pc);
325 const std::vector<size_t>& pcs,
326 const std::shared_ptr<std::vector<uint8_t>>& bytecode_ptr,
330 events.reserve(instructions.size());
332 for (
size_t i = 0; i < instructions.size(); i++) {
333 events.emplace_back(InstructionFetchingEvent{
334 .bytecode_id = bytecode_id,
335 .pc =
static_cast<uint32_t
>(pcs.at(i)),
336 .instruction = instructions.at(i),
337 .bytecode = bytecode_ptr,
345TEST(BytecodeTraceGenTest, InstrDecompositionInBytesEachOpcode)
347 TestTraceContainer
trace;
351 C::instr_fetching_bd0, C::instr_fetching_bd1, C::instr_fetching_bd2, C::instr_fetching_bd3,
352 C::instr_fetching_bd4, C::instr_fetching_bd5, C::instr_fetching_bd6, C::instr_fetching_bd7,
353 C::instr_fetching_bd8, C::instr_fetching_bd9, C::instr_fetching_bd10, C::instr_fetching_bd11,
354 C::instr_fetching_bd12, C::instr_fetching_bd13, C::instr_fetching_bd14, C::instr_fetching_bd15,
355 C::instr_fetching_bd16, C::instr_fetching_bd17, C::instr_fetching_bd18, C::instr_fetching_bd19,
356 C::instr_fetching_bd20, C::instr_fetching_bd21, C::instr_fetching_bd22, C::instr_fetching_bd23,
357 C::instr_fetching_bd24, C::instr_fetching_bd25, C::instr_fetching_bd26, C::instr_fetching_bd27,
358 C::instr_fetching_bd28, C::instr_fetching_bd29, C::instr_fetching_bd30, C::instr_fetching_bd31,
359 C::instr_fetching_bd32, C::instr_fetching_bd33, C::instr_fetching_bd34, C::instr_fetching_bd35,
360 C::instr_fetching_bd36,
364 C::instr_fetching_op1, C::instr_fetching_op2, C::instr_fetching_op3, C::instr_fetching_op4,
365 C::instr_fetching_op5, C::instr_fetching_op6, C::instr_fetching_op7,
372 opcodes.reserve(num_opcodes);
373 for (
size_t i = 0; i < num_opcodes; i++) {
374 opcodes.emplace_back(
static_cast<WireOpCode>(i));
378 std::vector<size_t> pcs = gen_pcs(opcodes);
379 std::vector<uint8_t> bytecode = create_bytecode(instructions);
383 create_instruction_fetching_events(instructions, pcs, bytecode_ptr, bytecode_id);
387 for (uint32_t i = 0; i < num_opcodes; i++) {
388 const auto instr = instructions.at(i);
389 const auto instr_encoded = instr.serialize();
390 const auto w_opcode =
static_cast<WireOpCode>(i);
394 ASSERT_EQ(instr_encoded.size(), expected_size_in_bytes);
395 EXPECT_EQ(
FF(expected_size_in_bytes),
trace.
get(C::instr_fetching_instr_size, i + 1));
398 for (
size_t j = 0; j < static_cast<size_t>(expected_size_in_bytes); j++) {
399 EXPECT_EQ(
FF(instr_encoded.at(j)),
trace.
get(bd_columns.at(j), i + 1));
404 trace.
get(C::instr_fetching_exec_opcode, i + 1));
407 EXPECT_EQ(
FF(instr.indirect),
trace.
get(C::instr_fetching_indirect, i + 1));
410 EXPECT_EQ(
FF(pcs.at(i)),
trace.
get(C::instr_fetching_pc, i + 1));
413 size_t operand_idx = 0;
414 for (
const auto& operand : instr.operands) {
415 EXPECT_EQ(
FF(operand),
trace.
get(operand_columns.at(operand_idx++), i + 1));
420TEST(BytecodeTraceGenTest, InstrFetchingSingleBytecode)
422 TestTraceContainer
trace;
426 constexpr size_t num_of_opcodes = 10;
441 std::vector<size_t> pcs = gen_pcs(opcodes);
442 std::vector<uint8_t> bytecode = create_bytecode(instructions);
445 instructions, pcs,
std::make_shared<std::vector<uint8_t>>(bytecode), bytecode_id);
451 const auto bytecode_size = bytecode.size();
452 EXPECT_EQ(rows.size(), num_of_opcodes + 1);
454 for (
size_t i = 0; i < num_of_opcodes; i++) {
455 const auto pc = pcs.at(i);
458 const auto tag_is_op2 = has_tag ?
WIRE_INSTRUCTION_SPEC.at(opcodes.at(i)).tag_operand_idx.value() == 2 : 0;
459 const auto bytes_remaining = bytecode_size - pc;
462 EXPECT_LE(instr_size, bytes_to_read);
463 const auto instr_abs_diff = bytes_to_read - instr_size;
465 EXPECT_LT(pc, bytecode_size);
466 const auto pc_abs_diff = bytecode_size - pc - 1;
468 ASSERT_LE(bytecode_size, UINT16_MAX);
470 EXPECT_THAT(rows.at(i + 1),
473 ROW_FIELD_EQ(instr_fetching_bd0,
static_cast<uint8_t
>(opcodes.at(i))),
475 ROW_FIELD_EQ(instr_fetching_bytes_to_read, bytes_to_read),
476 ROW_FIELD_EQ(instr_fetching_bytecode_size, bytecode_size),
478 ROW_FIELD_EQ(instr_fetching_instr_abs_diff, instr_abs_diff),
487 ROW_FIELD_EQ(instr_fetching_sel_tag_is_op2, tag_is_op2),
493TEST(BytecodeTraceGenTest, InstrFetchingMultipleBytecodes)
495 TestTraceContainer
trace;
498 constexpr size_t num_of_opcodes = 2;
505 std::vector<size_t> pcs = gen_pcs(opcodes);
506 std::vector<uint8_t> bytecode = create_bytecode(instructions);
509 for (
size_t i = 0; i < 3; i++) {
512 create_instruction_fetching_events(instructions, pcs, bytecode_ptr,
static_cast<BytecodeId>(i + 1));
513 events.insert(events.end(), new_events.begin(), new_events.end());
520 EXPECT_EQ(rows.size(), 6 + 1);
522 for (
size_t i = 0; i < 3; i++) {
523 EXPECT_THAT(rows.at(2 * i + 1),
ROW_FIELD_EQ(instr_fetching_pc, 0));
537TEST(BytecodeTraceGenTest, InstrFetchingParsingErrors)
539 TestTraceContainer
trace;
543 constexpr size_t bytecode_size = 20;
544 std::vector<uint8_t> bytecode(bytecode_size);
545 for (
size_t i = 0; i < bytecode_size; i++) {
546 bytecode[i] =
static_cast<uint8_t
>(i);
552 events.emplace_back(InstructionFetchingEvent{
553 .bytecode_id = bytecode_id,
555 .bytecode = bytecode_ptr,
558 events.emplace_back(InstructionFetchingEvent{
559 .bytecode_id = bytecode_id,
561 .bytecode = bytecode_ptr,
564 events.emplace_back(InstructionFetchingEvent{
565 .bytecode_id = bytecode_id,
567 .bytecode = bytecode_ptr,
575 ASSERT_EQ(rows.size(), 3 + 1);
577 EXPECT_THAT(rows.at(1),
589 EXPECT_THAT(rows.at(2),
615TEST(BytecodeTraceGenTest, InstrFetchingErrorTagOutOfRange)
620 TestTraceContainer
trace;
625 constexpr uint32_t cast_size = 7;
626 constexpr uint32_t set_64_size = 13;
628 instr_cast.operands.at(2) = Operand::from<uint8_t>(0x09);
629 instr_set.operands.at(1) = Operand::from<uint8_t>(0x0A);
631 auto bytecode = instr_cast.serialize();
632 ASSERT_EQ(bytecode.size(), cast_size);
634 auto instr_set_bytecode = instr_set.serialize();
635 ASSERT_EQ(instr_set_bytecode.size(), set_64_size);
637 bytecode.insert(bytecode.end(), instr_set_bytecode.begin(), instr_set_bytecode.end());
642 events.emplace_back(InstructionFetchingEvent{
646 .bytecode = bytecode_ptr,
650 events.emplace_back(InstructionFetchingEvent{
655 .bytecode = bytecode_ptr,
663 ASSERT_EQ(rows.size(), 2 + 1);
665 EXPECT_THAT(rows.at(1),
672 ROW_FIELD_EQ(instr_fetching_bytes_to_read, cast_size + set_64_size),
678 cast_size + set_64_size - 1),
689 ROW_FIELD_EQ(instr_fetching_bytes_to_read, set_64_size),
693 ROW_FIELD_EQ(instr_fetching_pc_abs_diff, set_64_size - 1),
std::vector< AvmFullRowConstRef > as_rows() const
const FF & get(Column col, uint32_t row) const
#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