Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
get_contract_instance.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
20
21namespace bb::avm2::constraining {
22namespace {
23
24using simulation::EventEmitter;
25using simulation::GetContractInstanceEvent;
26using tracegen::GetContractInstanceTraceBuilder;
27using tracegen::PrecomputedTraceBuilder;
28using tracegen::TestTraceContainer;
30using C = Column;
31using get_contract_instance = bb::avm2::get_contract_instance<FF>;
32
33TEST(GetContractInstanceConstrainingTest, EmptyRow)
34{
35 check_relation<get_contract_instance>(testing::empty_trace());
36}
37
38TEST(GetContractInstanceConstrainingTest, WriteInBoundsCheck)
39{
40 // Test constants
41 const FF dst_offset = FF(100); // Use a smaller offset for clear testing
42 const FF dst_offset_diff_max = FF(AVM_HIGHEST_MEM_ADDRESS) - dst_offset; // AVM_HIGHEST_MEM_ADDRESS - 100
43 const FF dst_offset_diff_max_inv = dst_offset_diff_max.invert(); // 1/DST_OFFSET_DIFF_MAX
44 const FF wrong_inv_value = FF(42);
45
46 TestTraceContainer trace({
47 { { C::precomputed_first_row, 1 } },
48 { { C::get_contract_instance_sel, 1 },
49 { C::get_contract_instance_dst_offset, dst_offset },
50 { C::get_contract_instance_is_valid_writes_in_bounds, 1 },
51 { C::get_contract_instance_dst_offset_diff_max_inv, dst_offset_diff_max_inv } },
52 });
53
54 check_relation<get_contract_instance>(trace, get_contract_instance::SR_WRITE_OUT_OF_BOUNDS_CHECK);
55
56 // Negative test: mutate to incorrect dst_offset_diff_max_inv
57 trace.set(C::get_contract_instance_dst_offset_diff_max_inv, 1, wrong_inv_value); // Wrong inv value
59 check_relation<get_contract_instance>(trace, get_contract_instance::SR_WRITE_OUT_OF_BOUNDS_CHECK),
60 "WRITE_OUT_OF_BOUNDS_CHECK");
61 // Reset
62 trace.set(C::get_contract_instance_dst_offset_diff_max_inv, 1, dst_offset_diff_max_inv);
63
64 // Negative test: mutate to incorrect sel_write_in_bounds
65 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 0); // Out of bounds
67 check_relation<get_contract_instance>(trace, get_contract_instance::SR_WRITE_OUT_OF_BOUNDS_CHECK),
68 "WRITE_OUT_OF_BOUNDS_CHECK");
69 // Reset
70 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 1);
71}
72
73TEST(GetContractInstanceConstrainingTest, WriteOutOfBoundsCheck)
74{
75 // Test constants
76 const FF dst_offset = FF(AVM_HIGHEST_MEM_ADDRESS); // Boundary case: dst_offset + 1 is out of bounds
77 const FF dst_offset_diff_max_inv = FF(0);
78
79 TestTraceContainer trace({
80 { { C::precomputed_first_row, 1 } },
81 { { C::get_contract_instance_sel, 1 },
82 { C::get_contract_instance_dst_offset, dst_offset },
83 { C::get_contract_instance_is_valid_writes_in_bounds, 0 },
84 { C::get_contract_instance_dst_offset_diff_max_inv, dst_offset_diff_max_inv } },
85 });
86
87 check_relation<get_contract_instance>(trace, get_contract_instance::SR_WRITE_OUT_OF_BOUNDS_CHECK);
88
89 // Negative test: mutate to incorrect sel_write_in_bounds
90 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 1);
92 check_relation<get_contract_instance>(trace, get_contract_instance::SR_WRITE_OUT_OF_BOUNDS_CHECK),
93 "WRITE_OUT_OF_BOUNDS_CHECK");
94 // Reset
95 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 0);
96}
97
98TEST(GetContractInstanceConstrainingTest, ErrorAggregationConstraint)
99{
100 // Test error aggregation subrelation
101 TestTraceContainer trace({
102 { { C::precomputed_first_row, 1 } },
103 // No error case
104 { { C::get_contract_instance_sel, 1 },
105 { C::get_contract_instance_sel_error, 0 },
106 { C::get_contract_instance_is_valid_writes_in_bounds, 1 },
107 { C::get_contract_instance_is_valid_member_enum, 1 } },
108 });
109
110 check_relation<get_contract_instance>(trace, get_contract_instance::SR_ERROR_AGGREGATION);
111
112 // Test bounds error
113 trace.set(C::get_contract_instance_sel_error, 1, 1);
114 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 0); // Out of bounds
115 check_relation<get_contract_instance>(trace, get_contract_instance::SR_ERROR_AGGREGATION);
116
117 // Test enum error
118 trace.set(C::get_contract_instance_sel_error, 1, 1);
119 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 1); // In bounds
120 trace.set(C::get_contract_instance_is_valid_member_enum, 1, 0); // Invalid enum
121 check_relation<get_contract_instance>(trace, get_contract_instance::SR_ERROR_AGGREGATION);
122
123 // Test both errors
124 trace.set(C::get_contract_instance_sel_error, 1, 1);
125 trace.set(C::get_contract_instance_is_valid_writes_in_bounds, 1, 0); // Out of bounds
126 trace.set(C::get_contract_instance_is_valid_member_enum, 1, 0); // Invalid enum
127 check_relation<get_contract_instance>(trace, get_contract_instance::SR_ERROR_AGGREGATION);
128
129 // Negative test: wrong error value
130 trace.set(C::get_contract_instance_sel_error, 1, 0);
132 "ERROR_AGGREGATION");
133}
134
135TEST(GetContractInstanceConstrainingTest, SelectedMemberConstraint)
136{
137 // Test constants
138 const FF deployer_addr = 0x1234;
139 const FF class_id = 0x5678;
140 const FF init_hash = 0x9ABC;
141 const FF wrong_value = 0x1111;
142
143 // Test selected member subrelation
144 TestTraceContainer trace({
145 { { C::precomputed_first_row, 1 } },
146 // DEPLOYER selection
147 { { C::get_contract_instance_sel, 1 },
148 { C::get_contract_instance_selected_member, deployer_addr },
149 { C::get_contract_instance_is_deployer, 1 },
150 { C::get_contract_instance_is_class_id, 0 },
151 { C::get_contract_instance_is_init_hash, 0 },
152 { C::get_contract_instance_retrieved_deployer_addr, deployer_addr },
153 { C::get_contract_instance_retrieved_class_id, class_id },
154 { C::get_contract_instance_retrieved_init_hash, init_hash } },
155 });
156
157 check_relation<get_contract_instance>(trace, get_contract_instance::SR_SELECTED_MEMBER);
158
159 // Test CLASS_ID selection
160 trace.set(C::get_contract_instance_selected_member, 1, class_id);
161 trace.set(C::get_contract_instance_is_deployer, 1, 0);
162 trace.set(C::get_contract_instance_is_class_id, 1, 1);
163 check_relation<get_contract_instance>(trace, get_contract_instance::SR_SELECTED_MEMBER);
164
165 // Test INIT_HASH selection
166 trace.set(C::get_contract_instance_selected_member, 1, init_hash);
167 trace.set(C::get_contract_instance_is_class_id, 1, 0);
168 trace.set(C::get_contract_instance_is_init_hash, 1, 1);
169 check_relation<get_contract_instance>(trace, get_contract_instance::SR_SELECTED_MEMBER);
170
171 // Negative test: wrong selected member
172 trace.set(C::get_contract_instance_selected_member, 1, wrong_value); // Wrong value
173 EXPECT_THROW_WITH_MESSAGE(check_relation<get_contract_instance>(trace, get_contract_instance::SR_SELECTED_MEMBER),
174 "SELECTED_MEMBER");
175}
176
177TEST(GetContractInstanceConstrainingTest, ComplexMultiRowSequence)
178{
179 // Test constants
180 const uint32_t dst_offset_1 = 100;
181 const uint32_t dst_offset_2 = 200;
182 const uint32_t dst_offset_3 = 300;
183 const uint8_t deployer_enum = 0;
184 const uint8_t class_id_enum = 1;
185 const uint8_t invalid_enum = 5;
186 const FF deployer_addr_1 = 0x1234;
187 const FF class_id_1 = 0x5678;
188 const FF init_hash_1 = 0x9ABC;
189 const FF deployer_addr_2 = 0x1111;
190 const FF class_id_2 = 0x2222;
191 const FF init_hash_2 = 0x3333;
192 const FF deployer_addr_3 = 0x4444;
193 const FF class_id_3 = 0x5555;
194 const FF init_hash_3 = 0x6666;
195 const uint32_t member_write_offset_1 = 101;
196 const uint32_t member_write_offset_2 = 201;
197 const uint32_t member_write_offset_3 = 301;
198 const uint8_t u1_tag = static_cast<uint8_t>(ValueTag::U1);
199 const uint8_t ff_tag = static_cast<uint8_t>(ValueTag::FF);
200
201 // Test multiple GetContractInstance operations in sequence
202 TestTraceContainer trace({
203 { { C::precomputed_first_row, 1 } },
204 // Row 1: skippable gadget selector
205 { { C::get_contract_instance_sel, 0 } }, // Must satisfy error constraint
206 // Row 2: Valid DEPLOYER retrieval
207 { { C::get_contract_instance_sel, 1 },
208 { C::get_contract_instance_dst_offset, dst_offset_1 },
209 { C::get_contract_instance_member_enum, deployer_enum }, // DEPLOYER
210 { C::get_contract_instance_is_valid_writes_in_bounds, 1 },
211 { C::get_contract_instance_dst_offset_diff_max_inv, FF(AVM_HIGHEST_MEM_ADDRESS - dst_offset_1).invert() },
212 { C::get_contract_instance_sel_error, 0 },
213 { C::get_contract_instance_is_valid_member_enum, 1 },
214 { C::get_contract_instance_is_deployer, 1 },
215 { C::get_contract_instance_is_class_id, 0 },
216 { C::get_contract_instance_is_init_hash, 0 },
217 { C::get_contract_instance_retrieved_deployer_addr, deployer_addr_1 },
218 { C::get_contract_instance_retrieved_class_id, class_id_1 },
219 { C::get_contract_instance_retrieved_init_hash, init_hash_1 },
220 { C::get_contract_instance_selected_member, deployer_addr_1 },
221 { C::get_contract_instance_member_write_offset, member_write_offset_1 },
222 { C::get_contract_instance_exists_tag, u1_tag },
223 { C::get_contract_instance_member_tag, ff_tag } },
224 // Row 3: Valid CLASS_ID retrieval
225 { { C::get_contract_instance_sel, 1 },
226 { C::get_contract_instance_dst_offset, dst_offset_2 },
227 { C::get_contract_instance_member_enum, class_id_enum }, // CLASS_ID
228 { C::get_contract_instance_is_valid_writes_in_bounds, 1 },
229 { C::get_contract_instance_dst_offset_diff_max_inv, FF(AVM_HIGHEST_MEM_ADDRESS - dst_offset_2).invert() },
230 { C::get_contract_instance_sel_error, 0 },
231 { C::get_contract_instance_is_valid_member_enum, 1 },
232 { C::get_contract_instance_is_deployer, 0 },
233 { C::get_contract_instance_is_class_id, 1 },
234 { C::get_contract_instance_is_init_hash, 0 },
235 { C::get_contract_instance_retrieved_deployer_addr, deployer_addr_2 },
236 { C::get_contract_instance_retrieved_class_id, class_id_2 },
237 { C::get_contract_instance_retrieved_init_hash, init_hash_2 },
238 { C::get_contract_instance_selected_member, class_id_2 },
239 { C::get_contract_instance_member_write_offset, member_write_offset_2 },
240 { C::get_contract_instance_exists_tag, u1_tag },
241 { C::get_contract_instance_member_tag, ff_tag } },
242 // Row 4: Invalid member enum with error
243 { { C::get_contract_instance_sel, 1 },
244 { C::get_contract_instance_dst_offset, dst_offset_3 },
245 { C::get_contract_instance_member_enum, invalid_enum }, // Invalid
246 { C::get_contract_instance_is_valid_writes_in_bounds, 1 },
247 { C::get_contract_instance_dst_offset_diff_max_inv, FF(AVM_HIGHEST_MEM_ADDRESS - dst_offset_3).invert() },
248 { C::get_contract_instance_sel_error, 1 }, // Error due to invalid enum
249 { C::get_contract_instance_is_valid_member_enum, 0 },
250 { C::get_contract_instance_is_deployer, 0 },
251 { C::get_contract_instance_is_class_id, 0 },
252 { C::get_contract_instance_is_init_hash, 0 },
253 { C::get_contract_instance_retrieved_deployer_addr, deployer_addr_3 },
254 { C::get_contract_instance_retrieved_class_id, class_id_3 },
255 { C::get_contract_instance_retrieved_init_hash, init_hash_3 },
256 { C::get_contract_instance_selected_member, 0 }, // No selection due to invalid enum
257 { C::get_contract_instance_member_write_offset, member_write_offset_3 },
258 { C::get_contract_instance_exists_tag, u1_tag },
259 { C::get_contract_instance_member_tag, ff_tag } },
260 });
261
262 check_relation<get_contract_instance>(trace);
263}
264
265// Integration-style tests using tracegen components
266TEST(GetContractInstanceConstrainingTest, IntegrationTracegenValid)
267{
268 // Test constants
269 const uint32_t execution_clk = 42;
270 const FF contract_address = 0x1234;
271 const uint32_t dst_offset = 100;
272 const uint8_t deployer_enum = static_cast<uint8_t>(ContractInstanceMember::DEPLOYER);
273 const uint32_t space_id = 1;
274 const FF nullifier_tree_root = 0x1234;
275 const FF public_data_tree_root = 0x5678;
276 const FF deployer_addr = 0x5678;
277 const FF class_id = 0x9ABC;
278 const FF init_hash = 0xDEF0;
279
280 // Use real tracegen to generate a valid trace
281 EventEmitter<GetContractInstanceEvent> emitter;
282
283 GetContractInstanceEvent event{
284 .execution_clk = execution_clk,
285 .contract_address = contract_address,
286 .dst_offset = dst_offset,
287 .member_enum = deployer_enum,
288 .space_id = space_id,
289 .nullifier_tree_root = nullifier_tree_root,
290 .public_data_tree_root = public_data_tree_root,
291 .instance_exists = true,
292 .retrieved_deployer_addr = deployer_addr,
293 .retrieved_class_id = class_id,
294 .retrieved_init_hash = init_hash,
295 };
296
297 emitter.emit(std::move(event));
298 auto events = emitter.dump_events();
299
300 TestTraceContainer trace;
301 GetContractInstanceTraceBuilder builder;
302 builder.process(events, trace);
303
304 // Add precomputed table entries
305 PrecomputedTraceBuilder precomputed_builder;
306 precomputed_builder.process_get_contract_instance_table(trace);
307
308 check_relation<get_contract_instance>(trace);
309}
310
311TEST(GetContractInstanceConstrainingTest, IntegrationTracegenInvalidEnum)
312{
313 // Test constants
314 const uint32_t execution_clk = 42;
315 const FF contract_address = 0x1234;
316 const uint32_t dst_offset = 100;
317 const uint8_t invalid_enum = 200;
318 const uint32_t space_id = 1;
319 const FF nullifier_tree_root = 0x1234;
320 const FF public_data_tree_root = 0x5678;
321 const FF deployer_addr = 0x5678;
322 const FF class_id = 0x9ABC;
323 const FF init_hash = 0xDEF0;
324
325 // Test with invalid member enum
326 EventEmitter<GetContractInstanceEvent> emitter;
327
328 GetContractInstanceEvent event{
329 .execution_clk = execution_clk,
330 .contract_address = contract_address,
331 .dst_offset = dst_offset,
332 .member_enum = invalid_enum,
333 .space_id = space_id,
334 .nullifier_tree_root = nullifier_tree_root,
335 .public_data_tree_root = public_data_tree_root,
336 .instance_exists = true,
337 .retrieved_deployer_addr = deployer_addr,
338 .retrieved_class_id = class_id,
339 .retrieved_init_hash = init_hash,
340 };
341
342 emitter.emit(std::move(event));
343 auto events = emitter.dump_events();
344
345 TestTraceContainer trace;
346 GetContractInstanceTraceBuilder builder;
347 builder.process(events, trace);
348
349 // Add precomputed table entries
350 PrecomputedTraceBuilder precomputed_builder;
351 precomputed_builder.process_get_contract_instance_table(trace);
352
353 check_relation<get_contract_instance>(trace);
354}
355
356TEST(GetContractInstanceConstrainingTest, IntegrationTracegenOutOfBounds)
357{
358 // Test constants
359 const uint32_t execution_clk = 42;
360 const FF contract_address = 0x1234;
361 const uint32_t dst_offset = AVM_HIGHEST_MEM_ADDRESS;
362 const uint8_t class_id_enum = static_cast<uint8_t>(ContractInstanceMember::CLASS_ID);
363 const uint32_t space_id = 1;
364 const FF nullifier_tree_root = 0x1234;
365 const FF public_data_tree_root = 0x5678;
366 const FF deployer_addr = 0x5678;
367 const FF class_id = 0x9ABC;
368 const FF init_hash = 0xDEF0;
369
370 // Test with out-of-bounds destination
371 EventEmitter<GetContractInstanceEvent> emitter;
372
373 GetContractInstanceEvent event{
374 .execution_clk = execution_clk,
375 .contract_address = contract_address,
376 .dst_offset = dst_offset,
377 .member_enum = class_id_enum,
378 .space_id = space_id,
379 .nullifier_tree_root = nullifier_tree_root,
380 .public_data_tree_root = public_data_tree_root,
381 .instance_exists = true,
382 .retrieved_deployer_addr = deployer_addr,
383 .retrieved_class_id = class_id,
384 .retrieved_init_hash = init_hash,
385 };
386
387 emitter.emit(std::move(event));
388 auto events = emitter.dump_events();
389
390 TestTraceContainer trace;
391 GetContractInstanceTraceBuilder builder;
392 builder.process(events, trace);
393
394 // Add precomputed table entries
395 PrecomputedTraceBuilder precomputed_builder;
396 precomputed_builder.process_get_contract_instance_table(trace);
397
398 check_relation<get_contract_instance>(trace);
399}
400
401} // namespace
402} // namespace bb::avm2::constraining
#define AVM_HIGHEST_MEM_ADDRESS
static constexpr size_t SR_ERROR_AGGREGATION
static constexpr size_t SR_SELECTED_MEMBER
static constexpr size_t SR_WRITE_OUT_OF_BOUNDS_CHECK
void set(Column col, uint32_t row, const FF &value)
PrecomputedTraceBuilder precomputed_builder
Definition alu.test.cpp:119
AluTraceBuilder builder
Definition alu.test.cpp:123
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
AvmFlavorSettings::FF FF
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:508
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
typename Flavor::FF FF
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event