1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
48using ::testing::StrictMock;
52using tracegen::BytecodeTraceBuilder;
53using tracegen::ClassIdDerivationTraceBuilder;
54using tracegen::ContractInstanceRetrievalTraceBuilder;
55using tracegen::FieldGreaterThanTraceBuilder;
56using tracegen::IndexedTreeCheckTraceBuilder;
57using tracegen::Poseidon2TraceBuilder;
58using tracegen::PrecomputedTraceBuilder;
59using tracegen::TestTraceContainer;
61using simulation::EventEmitter;
62using simulation::FieldGreaterThan;
63using simulation::IndexedTreeCheck;
65using simulation::IndexedTreeLeafData;
66using simulation::IndexedTreeReadWriteEvent;
67using simulation::MerkleCheck;
68using simulation::MockExecutionIdManager;
69using simulation::MockGreaterThan;
70using simulation::Poseidon2;
71using simulation::Poseidon2HashEvent;
72using simulation::Poseidon2PermutationEvent;
73using simulation::Poseidon2PermutationMemoryEvent;
74using simulation::RangeCheck;
75using simulation::RetrievedBytecodesTreeCheck;
82class BytecodeRetrievalConstrainingTest :
public ::testing::Test {
84 static TestTraceContainer init_trace()
87 TestTraceContainer
trace({
88 { { C::precomputed_first_row, 1 } },
94TEST_F(BytecodeRetrievalConstrainingTest, EmptyRow)
99TEST_F(BytecodeRetrievalConstrainingTest, SuccessfulRetrieval)
101 TestTraceContainer
trace = init_trace();
111 uint32_t bytecode_size = 20;
115 hash_input.reserve(1 + bytecode_fields.size());
116 hash_input.insert(hash_input.end(), bytecode_fields.begin(), bytecode_fields.end());
119 builder.process_hashing({ { .bytecode_id = bytecode_commitment,
120 .bytecode_length_in_bytes = bytecode_size,
121 .bytecode_fields = bytecode_fields } },
126 .nullifier_tree_root = nullifier_tree_root,
127 .public_data_tree_root = public_data_tree_root,
132 .artifact_hash = klass.artifact_hash,
133 .private_functions_root = klass.private_functions_root,
134 .public_bytecode_commitment = bytecode_commitment } },
137 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
142 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
149 IndexedTreeReadWriteEvent{
150 .value =
instance.current_contract_class_id,
151 .prev_snapshot = snapshot_before,
152 .next_snapshot = snapshot_before,
155 .low_leaf_data = IndexedTreeLeafData{ .value = 0, .next_value = 0, .next_index = 0 },
160 IndexedTreeReadWriteEvent{
161 .value =
instance.current_contract_class_id,
162 .prev_snapshot = snapshot_before,
163 .next_snapshot = snapshot_after,
166 .low_leaf_data = IndexedTreeLeafData{ .value = 0, .next_value = 0, .next_index = 0 },
175 .bytecode_id = bytecode_commitment,
177 .current_class_id =
instance.current_contract_class_id,
178 .contract_class = klass,
179 .nullifier_tree_root = nullifier_tree_root,
180 .public_data_tree_root = public_data_tree_root,
181 .retrieved_bytecodes_snapshot_before = snapshot_before,
182 .retrieved_bytecodes_snapshot_after = snapshot_after,
183 .is_new_class =
true,
187 check_relation<bc_retrieval>(trace);
195TEST_F(BytecodeRetrievalConstrainingTest, TooManyBytecodes)
197 TestTraceContainer
trace = init_trace();
204 uint32_t bytecode_size = 20;
207 AppendOnlyTreeSnapshot snapshot_before = AppendOnlyTreeSnapshot{
209 .next_available_leaf_index =
213 AppendOnlyTreeSnapshot snapshot_after = AppendOnlyTreeSnapshot{
215 .next_available_leaf_index =
223 .current_class_id =
instance.current_contract_class_id,
224 .nullifier_tree_root = nullifier_tree_root,
225 .public_data_tree_root = public_data_tree_root,
226 .retrieved_bytecodes_snapshot_before = snapshot_before,
227 .retrieved_bytecodes_snapshot_after = snapshot_after,
228 .is_new_class =
true,
233 check_relation<bc_retrieval>(trace);
236TEST_F(BytecodeRetrievalConstrainingTest, NonExistentInstance)
240 TestTraceContainer
trace = init_trace();
245 .address = contract_address,
255 { C::bc_retrieval_sel, 1 },
256 { C::bc_retrieval_instance_exists, 0 },
257 { C::bc_retrieval_current_class_id, 0 },
258 { C::bc_retrieval_artifact_hash, 0 },
259 { C::bc_retrieval_private_functions_root, 0 },
260 { C::bc_retrieval_bytecode_id, 0 },
261 { C::bc_retrieval_address, contract_address },
262 { C::bc_retrieval_prev_retrieved_bytecodes_tree_size, 1 },
263 { C::bc_retrieval_next_retrieved_bytecodes_tree_size, 1 },
267 { C::bc_retrieval_error, 1 },
270 check_relation<bc_retrieval>(trace);
273 trace.
set(C::bc_retrieval_current_class_id, 1, 99);
275 (check_interaction<BytecodeTraceBuilder, lookup_bc_retrieval_contract_instance_retrieval_settings>(trace)),
276 "Failed.*LOOKUP_BC_RETRIEVAL_CONTRACT_INSTANCE_RETRIEVAL.*Could not find tuple in destination.");
278 trace.
set(C::contract_instance_retrieval_current_class_id, 1, 99);
280 ,
"INSTANCE_MEMBER_CLASS_ID_IS_ZERO_IF_DNE");
283 trace.
set(C::bc_retrieval_current_class_id, 1, 0);
284 trace.
set(C::contract_instance_retrieval_current_class_id, 1, 0);
287 trace.
set(C::bc_retrieval_bytecode_id, 1, 99);
290 trace.
set(C::bc_retrieval_bytecode_id, 1, 0);
293class BytecodeRetrievalConstrainingTestFewerMocks :
public BytecodeRetrievalConstrainingTest {
309 Poseidon2(mock_execution_id_manager, mock_gt, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter);
312 FieldGreaterThan
field_gt = FieldGreaterThan(range_check, field_gt_emitter);
327TEST_F(BytecodeRetrievalConstrainingTestFewerMocks, SuccessfulRetrievalFewerMocks)
329 TestTraceContainer
trace = init_trace();
335 uint32_t bytecode_size = 20;
339 hash_input.reserve(1 + bytecode_fields.size());
340 hash_input.insert(hash_input.end(), bytecode_fields.begin(), bytecode_fields.end());
343 builder.process_decomposition({ { .bytecode_id = bytecode_commitment,
346 trace.
set(1, { { { C::bc_decomposition_sel_packed_read_0_, 1 } } });
347 builder.process_hashing({ { .bytecode_id = bytecode_commitment,
348 .bytecode_length_in_bytes = bytecode_size,
349 .bytecode_fields = bytecode_fields } },
354 instance.current_contract_class_id = class_id;
359 .nullifier_tree_root = nullifier_tree_root,
360 .public_data_tree_root = public_data_tree_root,
366 .artifact_hash = klass.artifact_hash,
367 .private_functions_root = klass.private_functions_root,
368 .public_bytecode_commitment = bytecode_commitment } },
385 .bytecode_id = bytecode_commitment,
387 .current_class_id =
instance.current_contract_class_id,
388 .contract_class = klass,
389 .nullifier_tree_root = nullifier_tree_root,
390 .public_data_tree_root = public_data_tree_root,
391 .retrieved_bytecodes_snapshot_before = snapshot_before,
392 .retrieved_bytecodes_snapshot_after = snapshot_after,
393 .is_new_class =
true,
401 check_relation<bc_retrieval>(trace);
402 check_relation<bb::avm2::bc_decomposition<FF>>(
trace);
403 check_relation<bb::avm2::bc_hashing<FF>>(
trace);
404 check_relation<bb::avm2::contract_instance_retrieval<FF>>(
trace);
405 check_relation<bb::avm2::class_id_derivation<FF>>(
trace);
406 check_relation<bb::avm2::indexed_tree_check<FF>>(
trace);
407 check_all_interactions<BytecodeTraceBuilder>(trace);
408 check_all_interactions<ClassIdDerivationTraceBuilder>(trace);
411TEST_F(BytecodeRetrievalConstrainingTestFewerMocks, SuccessfulRepeatedRetrievalFewerMocks)
413 TestTraceContainer
trace = init_trace();
419 uint32_t bytecode_size = 20;
423 hash_input.reserve(1 + bytecode_fields.size());
424 hash_input.insert(hash_input.end(), bytecode_fields.begin(), bytecode_fields.end());
427 builder.process_decomposition({ { .bytecode_id = bytecode_commitment,
430 trace.
set(1, { { { C::bc_decomposition_sel_packed_read_0_, 1 } } });
431 builder.process_hashing({ { .bytecode_id = bytecode_commitment,
432 .bytecode_length_in_bytes = bytecode_size,
433 .bytecode_fields = bytecode_fields } },
439 instance.current_contract_class_id = class_id;
444 .nullifier_tree_root = nullifier_tree_root,
445 .public_data_tree_root = public_data_tree_root,
450 .artifact_hash = klass.artifact_hash,
451 .private_functions_root = klass.private_functions_root,
452 .public_bytecode_commitment = bytecode_commitment } },
477 .bytecode_id = bytecode_commitment,
479 .current_class_id =
instance.current_contract_class_id,
480 .contract_class = klass,
481 .nullifier_tree_root = nullifier_tree_root,
482 .public_data_tree_root = public_data_tree_root,
483 .retrieved_bytecodes_snapshot_before = snapshot_before,
484 .retrieved_bytecodes_snapshot_after = snapshot_after,
485 .is_new_class =
true,
488 .bytecode_id = bytecode_commitment,
490 .current_class_id =
instance.current_contract_class_id,
491 .contract_class = klass,
492 .nullifier_tree_root = nullifier_tree_root,
493 .public_data_tree_root = public_data_tree_root,
494 .retrieved_bytecodes_snapshot_before = snapshot_after,
495 .retrieved_bytecodes_snapshot_after = snapshot_after,
496 .is_new_class =
false,
504 check_relation<bc_retrieval>(trace);
505 check_relation<bb::avm2::bc_decomposition<FF>>(
trace);
506 check_relation<bb::avm2::bc_hashing<FF>>(
trace);
507 check_relation<bb::avm2::contract_instance_retrieval<FF>>(
trace);
508 check_relation<bb::avm2::class_id_derivation<FF>>(
trace);
509 check_relation<bb::avm2::indexed_tree_check<FF>>(
trace);
510 check_all_interactions<BytecodeTraceBuilder>(trace);
511 check_all_interactions<ClassIdDerivationTraceBuilder>(trace);
516 trace.
set(C::bc_retrieval_is_new_class, 1, 1);
519 trace.
set(C::indexed_tree_check_not_exists, 2, 1);
520 trace.
set(C::indexed_tree_check_exists, 2, 0);
521 check_all_interactions<BytecodeTraceBuilder>(trace);
522 check_relation<bc_retrieval>(trace);
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
std::shared_ptr< Napi::ThreadSafeFunction > instance
#define AVM_RETRIEVED_BYTECODES_TREE_INITIAL_ROOT
#define AVM_RETRIEVED_BYTECODES_TREE_INITIAL_SIZE
#define MAX_PUBLIC_CALLS_TO_UNIQUE_CONTRACT_CLASS_IDS
#define AVM_RETRIEVED_BYTECODES_TREE_HEIGHT
#define DOM_SEP__RETRIEVED_BYTECODES_MERKLE
#define DOM_SEP__CONTRACT_CLASS_ID
StrictMock< MockGreaterThan > mock_gt
EventEmitter< Poseidon2PermutationMemoryEvent > perm_mem_event_emitter
EventEmitter< Poseidon2PermutationEvent > perm_event_emitter
EventEmitter< Poseidon2HashEvent > hash_event_emitter
Poseidon2TraceBuilder poseidon2_builder
StrictMock< MockExecutionIdManager > mock_execution_id_manager
FieldGreaterThan field_gt
IndexedTreeCheckTraceBuilder indexed_tree_check_builder
ClassIdDerivationTraceBuilder class_id_builder
EventEmitter< simulation::MerkleCheckEvent > merkle_check_emitter
ContractInstanceRetrievalTraceBuilder contract_instance_retrieval_builder
RetrievedBytecodesTreeCheck retrieved_bytecodes_tree_check
EventEmitter< simulation::FieldGreaterThanEvent > field_gt_emitter
IndexedTreeCheck indexed_tree_check
EventEmitter< simulation::RangeCheckEvent > range_check_emitter
EventEmitter< simulation::IndexedTreeCheckEvent > indexed_tree_check_event_emitter
bool contains(const FF &class_id) override
Checks whether a contract class ID exists in the retrieved bytecodes tree.
void insert(const FF &class_id) override
Inserts a contract class ID into the retrieved bytecodes tree.
AppendOnlyTreeSnapshot get_snapshot() const override
Returns the current tree snapshot.
void process(const simulation::EventEmitterInterface< simulation::ClassIdDerivationEvent >::Container &events, TraceContainer &trace)
Process class id derivation events and populate the relevant columns in the trace....
void process(const simulation::EventEmitterInterface< simulation::ContractInstanceRetrievalEvent >::Container &events, TraceContainer &trace)
Process the contract instance retrieval events and populate the relevant columns in the trace.
void process(const simulation::EventEmitterInterface< simulation::IndexedTreeCheckEvent >::Container &events, TraceContainer &trace)
Process generic indexed tree check events and populate the relevant columns in the trace.
void process_hash(const simulation::EventEmitterInterface< simulation::Poseidon2HashEvent >::Container &hash_events, TraceContainer &trace)
Processes the hash events for the Poseidon2 hash function. It populates the columns for the poseidon2...
void process_misc(TraceContainer &trace, const uint32_t num_rows=PRECOMPUTED_TRACE_SIZE)
Populate miscellaneous precomputed columns: first_row selector and idx (row index).
void process_sel_range_8(TraceContainer &trace)
Generate a selector column that activates the first 2^8 (256) rows.
void set(Column col, uint32_t row, const FF &value)
static FF hash(const std::vector< FF > &input)
Hashes a vector of field elements.
PrecomputedTraceBuilder precomputed_builder
FieldGreaterThanTraceBuilder field_gt_builder
void check_interaction(tracegen::TestTraceContainer &trace)
TEST_F(AvmRecursiveTests, TwoLayerAvmRecursionFailsWithWrongPIs)
void check_relation(const tracegen::TestTraceContainer &trace, Ts... subrelation)
RetrievedBytecodesTree build_retrieved_bytecodes_tree()
std::vector< FF > encode_bytecode(std::span< const uint8_t > bytecode)
Encodes the bytecode into a vector of field elements. Each field element represents 31 bytes of the b...
std::variant< IndexedTreeReadWriteEvent, CheckPointEventType > IndexedTreeCheckEvent
FF compute_public_bytecode_first_field(size_t bytecode_size)
ContractClass random_contract_class(size_t bytecode_size)
ContractInstance random_contract_instance()
TestTraceContainer empty_trace()
lookup_settings< lookup_bc_retrieval_retrieved_bytecodes_insertion_settings_ > lookup_bc_retrieval_retrieved_bytecodes_insertion_settings
lookup_settings< lookup_bc_retrieval_contract_instance_retrieval_settings_ > lookup_bc_retrieval_contract_instance_retrieval_settings
lookup_settings< lookup_bc_retrieval_class_id_derivation_settings_ > lookup_bc_retrieval_class_id_derivation_settings
lookup_settings< lookup_bc_retrieval_is_new_class_check_settings_ > lookup_bc_retrieval_is_new_class_check_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
constexpr field invert() const noexcept
static field random_element(numeric::RNG *engine=nullptr) noexcept