3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
27using simulation::Instruction;
28using simulation::InstructionFetchingEvent;
30TEST(BytecodeTraceGenTest, BasicShortLength)
32 TestTraceContainer
trace;
37 simulation::BytecodeDecompositionEvent{
47 ASSERT_EQ(rows.size(), 4 + 1);
50 EXPECT_THAT(rows.at(1),
60 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
62 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
68 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv, 0)));
70 EXPECT_THAT(rows.at(2),
79 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
81 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
85 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 1).invert()),
88 EXPECT_THAT(rows.at(3),
96 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
98 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
102 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 2).invert()),
105 EXPECT_THAT(rows.at(4),
112 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
114 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
118 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 3).invert()),
122TEST(BytecodeTraceGenTest, BasicSingleByte)
124 TestTraceContainer
trace;
129 simulation::BytecodeDecompositionEvent{
139 ASSERT_EQ(rows.size(), 1 + 1);
142 EXPECT_THAT(rows.at(1),
152 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
154 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
160 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv, 0)));
163TEST(BytecodeTraceGenTest, BasicLongerThanWindowSize)
165 TestTraceContainer
trace;
169 std::vector<uint8_t>
bytecode(bytecode_size);
170 const uint8_t first_byte = 17;
173 for (uint8_t i = 0; i < bytecode_size; i++) {
179 simulation::BytecodeDecompositionEvent{
189 ASSERT_EQ(rows.size(), bytecode_size + 1);
192 EXPECT_THAT(rows.at(1),
197 ROW_FIELD_EQ(bc_decomposition_bytes_remaining, bytecode_size),
198 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 0),
199 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv,
FF(-8).invert()),
200 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
205 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv, 0),
210 EXPECT_THAT(rows.at(9),
216 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 0),
217 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv, 0),
218 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 1),
222 EXPECT_THAT(rows.at(10),
228 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
229 ROW_FIELD_EQ(bc_decomposition_windows_min_remaining_inv, 1),
230 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
234 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(31 - 9).invert()),
238 EXPECT_THAT(rows.at(bytecode_size),
241 ROW_FIELD_EQ(bc_decomposition_bytes, first_byte + bytecode_size - 1),
244 ROW_FIELD_EQ(bc_decomposition_sel_windows_gt_remaining, 1),
246 ROW_FIELD_EQ(bc_decomposition_sel_windows_eq_remaining, 0),
250 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
FF(62 - (bytecode_size - 1)).invert()),
254TEST(BytecodeTraceGenTest, MultipleEvents)
256 TestTraceContainer
trace;
262 std::transform(bc_sizes.begin(), bc_sizes.end(), bytecodes.begin(), [](uint32_t bc_size) -> std::vector<uint8_t> {
263 std::vector<uint8_t> bytecode(bc_size);
264 for (uint8_t i = 0; i < bc_size; i++) {
273 simulation::BytecodeDecompositionEvent{
277 simulation::BytecodeDecompositionEvent{
281 simulation::BytecodeDecompositionEvent{
285 simulation::BytecodeDecompositionEvent{
297 for (uint32_t i = 0; i < 4; i++) {
298 uint32_t next_packed_pc = 0;
299 for (uint32_t j = 0; j < bc_sizes[i]; j++) {
300 const auto bytes_rem = bc_sizes[i] - j;
307 ROW_FIELD_EQ(bc_decomposition_bytes_remaining, bytes_rem),
310 bc_decomposition_windows_min_remaining_inv,
314 ROW_FIELD_EQ(bc_decomposition_sel_packed, j == next_packed_pc ? 1 : 0),
315 ROW_FIELD_EQ(bc_decomposition_next_packed_pc, next_packed_pc),
316 ROW_FIELD_EQ(bc_decomposition_next_packed_pc_min_pc_inv,
317 j == next_packed_pc ? 0 :
FF(next_packed_pc - j).invert()),
319 ROW_FIELD_EQ(bc_decomposition_last_of_contract, j == bc_sizes[i] - 1 ? 1 : 0)));
321 next_packed_pc += j % 31 == 0 ? 31 : 0;
326TEST(BytecodeTraceGenTest, BasicHashing)
328 TestTraceContainer
trace;
333 simulation::BytecodeHashingEvent{
335 .bytecode_length = 93,
336 .bytecode_fields = { 10, 20, 30 },
392 instructions.reserve(opcodes.size());
393 for (
const auto& opcode : opcodes) {
403 auto serialized_instruction =
instruction.serialize();
413 std::vector<size_t> pcs;
414 pcs.reserve(opcodes.size());
416 for (
const auto& opcode : opcodes) {
417 pcs.emplace_back(pc);
425 const std::vector<size_t>& pcs,
426 const std::shared_ptr<std::vector<uint8_t>>& bytecode_ptr,
430 events.reserve(instructions.size());
432 for (
size_t i = 0; i < instructions.size(); i++) {
433 events.emplace_back(InstructionFetchingEvent{
434 .bytecode_id = bytecode_id,
435 .pc =
static_cast<uint32_t
>(pcs.at(i)),
436 .instruction = instructions.at(i),
437 .bytecode = bytecode_ptr,
445TEST(BytecodeTraceGenTest, InstrDecompositionInBytesEachOpcode)
447 TestTraceContainer
trace;
451 C::instr_fetching_bd0, C::instr_fetching_bd1, C::instr_fetching_bd2, C::instr_fetching_bd3,
452 C::instr_fetching_bd4, C::instr_fetching_bd5, C::instr_fetching_bd6, C::instr_fetching_bd7,
453 C::instr_fetching_bd8, C::instr_fetching_bd9, C::instr_fetching_bd10, C::instr_fetching_bd11,
454 C::instr_fetching_bd12, C::instr_fetching_bd13, C::instr_fetching_bd14, C::instr_fetching_bd15,
455 C::instr_fetching_bd16, C::instr_fetching_bd17, C::instr_fetching_bd18, C::instr_fetching_bd19,
456 C::instr_fetching_bd20, C::instr_fetching_bd21, C::instr_fetching_bd22, C::instr_fetching_bd23,
457 C::instr_fetching_bd24, C::instr_fetching_bd25, C::instr_fetching_bd26, C::instr_fetching_bd27,
458 C::instr_fetching_bd28, C::instr_fetching_bd29, C::instr_fetching_bd30, C::instr_fetching_bd31,
459 C::instr_fetching_bd32, C::instr_fetching_bd33, C::instr_fetching_bd34, C::instr_fetching_bd35,
460 C::instr_fetching_bd36,
464 C::instr_fetching_op1, C::instr_fetching_op2, C::instr_fetching_op3, C::instr_fetching_op4,
465 C::instr_fetching_op5, C::instr_fetching_op6, C::instr_fetching_op7,
472 opcodes.reserve(num_opcodes);
473 for (
size_t i = 0; i < num_opcodes; i++) {
474 opcodes.emplace_back(
static_cast<WireOpCode>(i));
478 std::vector<size_t> pcs = gen_pcs(opcodes);
483 create_instruction_fetching_events(instructions, pcs, bytecode_ptr, bytecode_id);
485 builder.process_instruction_fetching(events, trace);
487 for (uint32_t i = 0; i < num_opcodes; i++) {
488 const auto instr = instructions.at(i);
489 const auto instr_encoded = instr.serialize();
490 const auto w_opcode =
static_cast<WireOpCode>(i);
494 ASSERT_EQ(instr_encoded.size(), expected_size_in_bytes);
495 EXPECT_EQ(
FF(expected_size_in_bytes),
trace.
get(C::instr_fetching_instr_size, i + 1));
498 for (
size_t j = 0; j < static_cast<size_t>(expected_size_in_bytes); j++) {
499 EXPECT_EQ(
FF(instr_encoded.at(j)),
trace.
get(bd_columns.at(j), i + 1));
504 trace.
get(C::instr_fetching_exec_opcode, i + 1));
507 EXPECT_EQ(
FF(instr.addressing_mode),
trace.
get(C::instr_fetching_addressing_mode, i + 1));
510 EXPECT_EQ(
FF(pcs.at(i)),
trace.
get(C::instr_fetching_pc, i + 1));
513 size_t operand_idx = 0;
514 for (
const auto& operand : instr.operands) {
515 EXPECT_EQ(
FF(operand),
trace.
get(operand_columns.at(operand_idx++), i + 1));
520TEST(BytecodeTraceGenTest, InstrFetchingSingleBytecode)
522 TestTraceContainer
trace;
526 constexpr size_t num_of_opcodes = 10;
535 std::vector<size_t> pcs = gen_pcs(opcodes);
541 builder.process_instruction_fetching(events, trace);
545 const auto bytecode_size =
bytecode.size();
546 EXPECT_EQ(rows.size(), num_of_opcodes + 1);
548 for (
size_t i = 0; i < num_of_opcodes; i++) {
549 const auto pc = pcs.at(i);
552 const auto tag_is_op2 =
554 const auto bytes_remaining = bytecode_size - pc;
557 EXPECT_LE(instr_size, bytes_to_read);
558 const auto instr_abs_diff = bytes_to_read - instr_size;
560 EXPECT_LT(pc, bytecode_size);
561 const auto pc_abs_diff = bytecode_size - pc - 1;
563 ASSERT_LE(bytecode_size, UINT16_MAX);
565 EXPECT_THAT(rows.at(i + 1),
568 ROW_FIELD_EQ(instr_fetching_bd0,
static_cast<uint8_t
>(opcodes.at(i))),
570 ROW_FIELD_EQ(instr_fetching_bytes_to_read, bytes_to_read),
571 ROW_FIELD_EQ(instr_fetching_bytecode_size, bytecode_size),
573 ROW_FIELD_EQ(instr_fetching_instr_abs_diff, instr_abs_diff),
582 ROW_FIELD_EQ(instr_fetching_sel_tag_is_op2, tag_is_op2),
588TEST(BytecodeTraceGenTest, InstrFetchingMultipleBytecodes)
590 TestTraceContainer
trace;
593 constexpr size_t num_of_opcodes = 2;
600 std::vector<size_t> pcs = gen_pcs(opcodes);
604 for (
size_t i = 0; i < 3; i++) {
607 create_instruction_fetching_events(instructions, pcs, bytecode_ptr,
static_cast<BytecodeId>(i + 1));
608 events.insert(events.end(), new_events.begin(), new_events.end());
611 builder.process_instruction_fetching(events, trace);
615 EXPECT_EQ(rows.size(), 6 + 1);
617 for (
size_t i = 0; i < 3; i++) {
618 EXPECT_THAT(rows.at(2 * i + 1),
ROW_FIELD_EQ(instr_fetching_pc, 0));
632TEST(BytecodeTraceGenTest, InstrFetchingParsingErrors)
634 TestTraceContainer
trace;
638 constexpr size_t bytecode_size = 20;
639 std::vector<uint8_t>
bytecode(bytecode_size);
640 for (
size_t i = 0; i < bytecode_size; i++) {
641 bytecode[i] =
static_cast<uint8_t
>(i);
647 events.emplace_back(InstructionFetchingEvent{
648 .bytecode_id = bytecode_id,
650 .bytecode = bytecode_ptr,
653 events.emplace_back(InstructionFetchingEvent{
654 .bytecode_id = bytecode_id,
656 .bytecode = bytecode_ptr,
659 events.emplace_back(InstructionFetchingEvent{
660 .bytecode_id = bytecode_id,
662 .bytecode = bytecode_ptr,
666 builder.process_instruction_fetching(events, trace);
670 ASSERT_EQ(rows.size(), 3 + 1);
672 EXPECT_THAT(rows.at(1),
684 EXPECT_THAT(rows.at(2),
710TEST(BytecodeTraceGenTest, InstrFetchingErrorTagOutOfRange)
715 TestTraceContainer
trace;
720 constexpr uint32_t cast_size = 7;
721 constexpr uint32_t set_64_size = 13;
723 instr_cast.operands.at(2) = Operand::from<uint8_t>(0x09);
724 instr_set.operands.at(1) = Operand::from<uint8_t>(0x0A);
726 auto bytecode = instr_cast.serialize();
727 ASSERT_EQ(
bytecode.size(), cast_size);
729 auto instr_set_bytecode = instr_set.serialize();
730 ASSERT_EQ(instr_set_bytecode.size(), set_64_size);
732 bytecode.insert(
bytecode.end(), instr_set_bytecode.begin(), instr_set_bytecode.end());
737 events.emplace_back(InstructionFetchingEvent{
741 .bytecode = bytecode_ptr,
745 events.emplace_back(InstructionFetchingEvent{
750 .bytecode = bytecode_ptr,
754 builder.process_instruction_fetching(events, trace);
758 ASSERT_EQ(rows.size(), 2 + 1);
760 EXPECT_THAT(rows.at(1),
767 ROW_FIELD_EQ(instr_fetching_bytes_to_read, cast_size + set_64_size),
773 cast_size + set_64_size - 1),
784 ROW_FIELD_EQ(instr_fetching_bytes_to_read, set_64_size),
788 ROW_FIELD_EQ(instr_fetching_pc_abs_diff, set_64_size - 1),
std::shared_ptr< Napi::ThreadSafeFunction > 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.
std::vector< uint8_t > create_bytecode(const std::vector< bb::avm2::simulation::Instruction > &instructions)
#define ROW_FIELD_EQ(field_name, expression)
@ INSTRUCTION_OUT_OF_RANGE
FF compute_public_bytecode_first_field(size_t bytecode_size)
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)
const std::unordered_map< WireOpCode, WireInstructionSpec > & get_wire_instruction_spec()
constexpr uint32_t DECOMPOSE_WINDOW_SIZE
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept