Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
data_copy.test.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
6
31
32namespace bb::avm2::constraining {
33namespace {
34
35using namespace simulation;
36using ::testing::Return;
37using ::testing::ReturnRef;
38using ::testing::StrictMock;
39using tracegen::DataCopyTraceBuilder;
40using tracegen::ExecutionTraceBuilder;
41using tracegen::TestTraceContainer;
42
44using C = Column;
46
47class DataCopyConstrainingBuilderTest : public ::testing::Test {
48 protected:
49 DataCopyConstrainingBuilderTest() { EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem)); }
50
51 ExecutionIdManager execution_id_manager = ExecutionIdManager(0);
52 EventEmitter<RangeCheckEvent> range_check_event_emitter;
53 RangeCheck range_check = RangeCheck(range_check_event_emitter);
54 EventEmitter<GreaterThanEvent> gt_event_emitter;
55 StrictMock<MockFieldGreaterThan> mock_field_gt;
56 GreaterThan gt = GreaterThan(mock_field_gt, range_check, gt_event_emitter);
57 EventEmitter<DataCopyEvent> event_emitter;
58 DataCopy copy_data = DataCopy(execution_id_manager, gt, event_emitter);
59 StrictMock<MockContext> context;
60
62
63 TestTraceContainer trace = TestTraceContainer({
64 {
65 { C::precomputed_first_row, 1 },
66 },
67 });
68
69 uint32_t dst_addr = 0; // Destination address in memory for the data.
71 MemoryValue::from<FF>(1), MemoryValue::from<FF>(2), MemoryValue::from<FF>(3), MemoryValue::from<FF>(4),
72 MemoryValue::from<FF>(5), MemoryValue::from<FF>(6), MemoryValue::from<FF>(7), MemoryValue::from<FF>(8),
73 };
74};
75
76class NestedCdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
77 protected:
78 NestedCdConstrainingBuilderTest()
79 {
80 // Set up parent context
81 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
82 EXPECT_CALL(context, get_parent_id).WillRepeatedly(Return(1));
83 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(2));
84 EXPECT_CALL(context, get_parent_cd_size).WillRepeatedly(Return(data.size()));
85 EXPECT_CALL(context, get_parent_cd_addr).WillRepeatedly(Return(0));
86 }
87};
88
89TEST_F(NestedCdConstrainingBuilderTest, CdZeroCopy)
90{
91 uint32_t copy_size = 0;
92 uint32_t cd_offset = 0; // Offset into calldata
93
95
96 tracegen::DataCopyTraceBuilder builder;
97 builder.process(event_emitter.dump_events(), trace);
98
99 tracegen::GreaterThanTraceBuilder gt_builder;
100 gt_builder.process(gt_event_emitter.dump_events(), trace);
101
102 check_relation<data_copy>(trace);
103 check_interaction<DataCopyTraceBuilder,
108}
109
110TEST_F(NestedCdConstrainingBuilderTest, SimpleNestedCdCopy)
111{
112 uint32_t copy_size = static_cast<uint32_t>(data.size());
113 uint32_t cd_offset = 0; // Offset into calldata
114
115 EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(Return(data));
116
118
119 DataCopyTraceBuilder builder;
120 builder.process(event_emitter.dump_events(), trace);
121
122 tracegen::GreaterThanTraceBuilder gt_builder;
123 gt_builder.process(gt_event_emitter.dump_events(), trace);
124
125 check_relation<data_copy>(trace);
126 check_interaction<DataCopyTraceBuilder,
131}
132
133// Copying one element tests the case where the trace populates a single row
134// where both sel_start and sel_end are toggled on but is a different code path
135// in tracegen than with copy_size == 0.
136TEST_F(NestedCdConstrainingBuilderTest, SimpleNestedCdCopySizeOneNoPadding)
137{
138 uint32_t copy_size = 1;
139 uint32_t cd_offset = static_cast<uint32_t>(data.size() - 1);
140
141 std::vector<MemoryValue> result_cd = { data.begin() + cd_offset, data.begin() + cd_offset + copy_size };
142
143 EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(Return(result_cd));
144
146
147 DataCopyTraceBuilder builder;
148 builder.process(event_emitter.dump_events(), trace);
149
150 tracegen::GreaterThanTraceBuilder gt_builder;
151 gt_builder.process(gt_event_emitter.dump_events(), trace);
152
153 check_relation<data_copy>(trace);
154 check_interaction<DataCopyTraceBuilder,
159}
160
161TEST_F(NestedCdConstrainingBuilderTest, SimpleNestedCdCopySizeOneWithPadding)
162{
163 uint32_t copy_size = 1;
164 uint32_t cd_offset = static_cast<uint32_t>(data.size());
165
167
168 DataCopyTraceBuilder builder;
169 builder.process(event_emitter.dump_events(), trace);
170
171 tracegen::GreaterThanTraceBuilder gt_builder;
173
174 check_relation<data_copy>(trace);
175 check_interaction<DataCopyTraceBuilder,
180}
181
182TEST_F(NestedCdConstrainingBuilderTest, NestedCdCopyPadded)
183{
184 uint32_t cd_offset = 0;
185
186 std::vector<MemoryValue> result_cd = data;
187 ASSERT_LT(result_cd.size(), 10); // Ensure we have less than 10 elements so we can pad
188 result_cd.resize(10, MemoryValue::from<FF>(0)); // Pad with zeros to 10 elements
189 uint32_t copy_size = static_cast<uint32_t>(result_cd.size()); // Request more than available
190
191 EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(Return(result_cd));
192
194
195 DataCopyTraceBuilder builder;
196 builder.process(event_emitter.dump_events(), trace);
197
198 tracegen::GreaterThanTraceBuilder gt_builder;
199 gt_builder.process(gt_event_emitter.dump_events(), trace);
200
201 check_relation<data_copy>(trace);
202 check_interaction<DataCopyTraceBuilder,
207}
208
209TEST_F(NestedCdConstrainingBuilderTest, NestedCdCopyPartial)
210{
211 uint32_t offset = 3;
212 uint32_t size = 4;
213
214 // Starting at offset = 3
215 std::vector<MemoryValue> result_cd = { data.begin() + offset, data.begin() + offset + size };
216
217 EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
218
219 copy_data.cd_copy(context, size, offset, dst_addr);
220
221 DataCopyTraceBuilder builder;
222 builder.process(event_emitter.dump_events(), trace);
223
224 tracegen::GreaterThanTraceBuilder gt_builder;
225 gt_builder.process(gt_event_emitter.dump_events(), trace);
226
227 check_relation<data_copy>(trace);
228 check_interaction<DataCopyTraceBuilder,
233}
234
235TEST_F(NestedCdConstrainingBuilderTest, ZeroCopySizeOffsetOOB)
236{
237 uint32_t offset = static_cast<uint32_t>(data.size()) + 1;
238 uint32_t size = 0;
239
240 // No call to get_calldata since offset is out of bounds
241 // Therefore, no need for an EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
242
243 copy_data.cd_copy(context, size, offset, dst_addr);
244
245 DataCopyTraceBuilder builder;
246 builder.process(event_emitter.dump_events(), trace);
247
248 tracegen::GreaterThanTraceBuilder gt_builder;
250
251 check_relation<data_copy>(trace);
252 check_interaction<DataCopyTraceBuilder,
257}
258
259TEST_F(NestedCdConstrainingBuilderTest, NonZeroCopySizeOffsetOOB)
260{
261 uint32_t offset = static_cast<uint32_t>(data.size()) + 1;
262 uint32_t size = 4;
263
264 // No call to get_calldata since offset is out of bounds
265 // Therefore, no need for an EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
266
267 copy_data.cd_copy(context, size, offset, dst_addr);
268
269 DataCopyTraceBuilder builder;
270 builder.process(event_emitter.dump_events(), trace);
271
272 tracegen::GreaterThanTraceBuilder gt_builder;
274
275 check_relation<data_copy>(trace);
276 check_interaction<DataCopyTraceBuilder,
281}
282
283TEST_F(NestedCdConstrainingBuilderTest, OutofRangeError)
284{
285 uint32_t offset = 10; // Offset beyond the size of calldata
286 uint32_t size = 4;
287
288 uint32_t big_dst_addr = AVM_HIGHEST_MEM_ADDRESS - 1;
289 EXPECT_THROW_WITH_MESSAGE(copy_data.cd_copy(context, size, offset, big_dst_addr),
290 "Attempting to access out of bounds memory");
291
292 DataCopyTraceBuilder builder;
293 builder.process(event_emitter.dump_events(), trace);
294
295 tracegen::GreaterThanTraceBuilder gt_builder;
296 gt_builder.process(gt_event_emitter.dump_events(), trace);
297
298 check_relation<data_copy>(trace);
299 check_interaction<DataCopyTraceBuilder,
304}
305
306TEST_F(NestedCdConstrainingBuilderTest, HighestMemoryAddressesWithPadding)
307{
308 uint32_t offset = static_cast<uint32_t>(data.size() - 1); // Last offset in calldata valid range
309 uint32_t size = 5; // Some padding will be needed
310
311 uint32_t high_dst_addr = AVM_HIGHEST_MEM_ADDRESS - size + 1;
312
313 std::vector<MemoryValue> result_cd(size, MemoryValue::from<FF>(0));
314 result_cd.at(0) = data.at(offset);
315
316 EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
317
318 copy_data.cd_copy(context, size, offset, high_dst_addr);
319
320 DataCopyTraceBuilder builder;
321 builder.process(event_emitter.dump_events(), trace);
322
323 tracegen::GreaterThanTraceBuilder gt_builder;
324 gt_builder.process(gt_event_emitter.dump_events(), trace);
325
326 check_relation<data_copy>(trace);
327 check_interaction<DataCopyTraceBuilder,
332}
333
334TEST_F(NestedCdConstrainingBuilderTest, HighestMemoryAddressesNoPadding)
335{
336 uint32_t offset = 0;
337 uint32_t size = static_cast<uint32_t>(data.size()) - 2;
338
339 uint32_t high_dst_addr = AVM_HIGHEST_MEM_ADDRESS - size + 1;
340 std::vector<MemoryValue> result_cd(data.begin(), data.begin() + size);
341
342 EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
343
344 copy_data.cd_copy(context, size, offset, high_dst_addr);
345
346 DataCopyTraceBuilder builder;
347 builder.process(event_emitter.dump_events(), trace);
348
349 tracegen::GreaterThanTraceBuilder gt_builder;
350 gt_builder.process(gt_event_emitter.dump_events(), trace);
351
352 check_relation<data_copy>(trace);
353 check_interaction<DataCopyTraceBuilder,
358}
359
360class HighCdAddressConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
361 protected:
362 HighCdAddressConstrainingBuilderTest()
363 {
364 // Set up parent context
365 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
366 EXPECT_CALL(context, get_parent_id).WillRepeatedly(Return(1));
367 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(2));
368 EXPECT_CALL(context, get_parent_cd_size).WillRepeatedly(Return(data.size()));
369 EXPECT_CALL(context, get_parent_cd_addr).WillRepeatedly(Return(AVM_HIGHEST_MEM_ADDRESS - data.size()));
370 }
371};
372
373TEST_F(HighCdAddressConstrainingBuilderTest, HighestMemoryAddressesWithPadding)
374{
375 uint32_t offset = static_cast<uint32_t>(data.size() - 1); // Last offset in calldata valid range
376 uint32_t size = 5; // Some padding will be needed
377
378 uint32_t high_dst_addr = AVM_HIGHEST_MEM_ADDRESS - size + 1;
379
380 std::vector<MemoryValue> result_cd(size, MemoryValue::from<FF>(0));
381 result_cd.at(0) = data.at(offset);
382
383 EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
384
385 copy_data.cd_copy(context, size, offset, high_dst_addr);
386
387 DataCopyTraceBuilder builder;
388 builder.process(event_emitter.dump_events(), trace);
389
390 tracegen::GreaterThanTraceBuilder gt_builder;
391 gt_builder.process(gt_event_emitter.dump_events(), trace);
392
393 check_relation<data_copy>(trace);
394 check_interaction<DataCopyTraceBuilder,
399}
400
401TEST_F(HighCdAddressConstrainingBuilderTest, HighestMemoryAddressesNoPadding)
402{
403 uint32_t offset = 0;
404 uint32_t size = static_cast<uint32_t>(data.size()) - 2;
405
406 uint32_t high_dst_addr = AVM_HIGHEST_MEM_ADDRESS - size + 1;
407 std::vector<MemoryValue> result_cd(data.begin(), data.begin() + size);
408
409 EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
410
411 copy_data.cd_copy(context, size, offset, high_dst_addr);
412
413 DataCopyTraceBuilder builder;
414 builder.process(event_emitter.dump_events(), trace);
415
416 tracegen::GreaterThanTraceBuilder gt_builder;
417 gt_builder.process(gt_event_emitter.dump_events(), trace);
418
419 check_relation<data_copy>(trace);
420 check_interaction<DataCopyTraceBuilder,
425}
426
427class EnqueuedCdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
428 protected:
429 EnqueuedCdConstrainingBuilderTest()
430 {
431 // Set up for enqueued call
432 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(false));
433 EXPECT_CALL(context, get_parent_id).WillRepeatedly(Return(0));
434 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(1));
435 EXPECT_CALL(context, get_parent_cd_size).WillRepeatedly(Return(data.size()));
436 EXPECT_CALL(context, get_parent_cd_addr).WillRepeatedly(Return(0));
437
438 // Build Calldata Column
439 tracegen::CalldataTraceBuilder calldata_builder;
440 std::vector<FF> calldata_ff(data.size());
441 std::ranges::transform(
442 data.begin(), data.end(), calldata_ff.begin(), [](const MemoryValue& value) { return value.as_ff(); });
443
444 CalldataEvent cd_event = {
445 .context_id = 1,
446 .calldata = calldata_ff,
447 };
448 calldata_builder.process_retrieval({ cd_event }, trace);
449 }
450};
451
452TEST_F(EnqueuedCdConstrainingBuilderTest, CdZeroCopy)
453{
454 uint32_t copy_size = 0;
455 uint32_t cd_offset = 0; // Offset into calldata
456
458
459 tracegen::DataCopyTraceBuilder builder;
460 builder.process(event_emitter.dump_events(), trace);
461
462 tracegen::GreaterThanTraceBuilder gt_builder;
463 gt_builder.process(gt_event_emitter.dump_events(), trace);
464
465 check_relation<data_copy>(trace);
466 check_all_interactions<DataCopyTraceBuilder>(trace);
467}
468
469TEST_F(EnqueuedCdConstrainingBuilderTest, SimpleEnqueuedCdCopy)
470{
471 auto copy_size = static_cast<uint32_t>(data.size());
472 uint32_t cd_offset = 0;
473
474 EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(Return(data));
475
477
478 DataCopyTraceBuilder builder;
479 builder.process(event_emitter.dump_events(), trace);
480
481 tracegen::GreaterThanTraceBuilder gt_builder;
482 gt_builder.process(gt_event_emitter.dump_events(), trace);
483
484 check_relation<data_copy>(trace);
485 check_all_interactions<DataCopyTraceBuilder>(trace);
486}
487
488TEST_F(EnqueuedCdConstrainingBuilderTest, EnqueuedCallCdCopyPadding)
489{
490 uint32_t cd_offset = 0;
491 std::vector<MemoryValue> result_cd = data;
492 ASSERT_LT(result_cd.size(), 10); // Ensure we have less than 10 elements so we can pad
493 result_cd.resize(10, MemoryValue::from<FF>(0)); // Pad with zeros to 10 elements
494 auto copy_size = static_cast<uint32_t>(result_cd.size()); // Request more than available
495
496 EXPECT_CALL(context, get_calldata(cd_offset, copy_size)).WillOnce(Return(result_cd));
497
499
500 DataCopyTraceBuilder builder;
501 builder.process(event_emitter.dump_events(), trace);
502
503 tracegen::GreaterThanTraceBuilder gt_builder;
504 gt_builder.process(gt_event_emitter.dump_events(), trace);
505
506 check_relation<data_copy>(trace);
507 check_all_interactions<DataCopyTraceBuilder>(trace);
508}
509
510TEST_F(EnqueuedCdConstrainingBuilderTest, EnqueuedCallCdCopyPartial)
511{
512 uint32_t offset = 3;
513 uint32_t size = 4;
514
515 // Starting at offset = 3
516 std::vector<MemoryValue> result_cd = { data.begin() + offset, data.begin() + offset + size };
517
518 EXPECT_CALL(context, get_calldata(offset, size)).WillOnce(Return(result_cd));
519
520 copy_data.cd_copy(context, size, offset, dst_addr);
521
522 DataCopyTraceBuilder builder;
523 builder.process(event_emitter.dump_events(), trace);
524
525 tracegen::GreaterThanTraceBuilder gt_builder;
526 gt_builder.process(gt_event_emitter.dump_events(), trace);
527
528 check_relation<data_copy>(trace);
529 check_all_interactions<DataCopyTraceBuilder>(trace);
530}
531
532class EnqueuedEmptyCdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
533 protected:
534 EnqueuedEmptyCdConstrainingBuilderTest()
535 {
536 // Set up for enqueued call
537 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(false));
538 EXPECT_CALL(context, get_parent_id).WillRepeatedly(Return(0));
539 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(1));
540 EXPECT_CALL(context, get_parent_cd_size).WillRepeatedly(Return(0));
541 EXPECT_CALL(context, get_parent_cd_addr).WillRepeatedly(Return(0));
542
543 // Build Calldata Column
544 tracegen::CalldataTraceBuilder calldata_builder;
545 CalldataEvent cd_event = {
546 .context_id = 1,
547 .calldata = {},
548 };
549 calldata_builder.process_retrieval({ cd_event }, trace);
550 }
551};
552
553TEST_F(EnqueuedEmptyCdConstrainingBuilderTest, CdZeroCopy)
554{
555 uint32_t copy_size = 0;
556 uint32_t cd_offset = 0; // Offset into calldata
557
559
560 tracegen::DataCopyTraceBuilder builder;
561 builder.process(event_emitter.dump_events(), trace);
562
563 tracegen::GreaterThanTraceBuilder gt_builder;
564 gt_builder.process(gt_event_emitter.dump_events(), trace);
565
566 check_relation<data_copy>(trace);
567 check_all_interactions<DataCopyTraceBuilder>(trace);
568}
569
570TEST_F(EnqueuedEmptyCdConstrainingBuilderTest, SimpleEnqueuedCdCopy)
571{
572 uint32_t copy_size = 4;
573 uint32_t cd_offset = 0;
574
576
577 DataCopyTraceBuilder builder;
578 builder.process(event_emitter.dump_events(), trace);
579
580 tracegen::GreaterThanTraceBuilder gt_builder;
581 gt_builder.process(gt_event_emitter.dump_events(), trace);
582
583 check_relation<data_copy>(trace);
584 check_all_interactions<DataCopyTraceBuilder>(trace);
585}
586
587TEST_F(EnqueuedEmptyCdConstrainingBuilderTest, EnqueuedCallCdCopyPadding)
588{
589 uint32_t cd_offset = 0;
590 std::vector<FF> result_cd = {};
591 result_cd.resize(10, 0); // Pad with zeros to 10 elements
592 auto copy_size = static_cast<uint32_t>(result_cd.size()); // Request more than available
593
595
596 DataCopyTraceBuilder builder;
597 builder.process(event_emitter.dump_events(), trace);
598
599 tracegen::GreaterThanTraceBuilder gt_builder;
601
602 check_relation<data_copy>(trace);
603 check_all_interactions<DataCopyTraceBuilder>(trace);
604}
605
607// DataCopy Tests with Execution Permutation
609
610TEST(DataCopyWithExecutionPerm, CdCopy)
611{
612 // Current Context
613 uint32_t context_id = 2;
614 uint32_t cd_offset = 3;
615 uint32_t copy_size = 4;
616 MemoryAddress dst_addr = 0xdeadbeef; // Destination address in memory for the data.
617 // Parent Context
618 uint32_t parent_context_id = 99; // Parent context ID
619 uint32_t parent_cd_addr = 0xc0ffee; // Parent calldata address in memory.
621 MemoryValue::from<FF>(8), MemoryValue::from<FF>(7), MemoryValue::from<FF>(6), MemoryValue::from<FF>(5),
622 MemoryValue::from<FF>(4), MemoryValue::from<FF>(3), MemoryValue::from<FF>(2), MemoryValue::from<FF>(1),
623 };
624
625 // Set up Memory
626 MemoryStore mem(static_cast<uint16_t>(context_id));
627
628 // Execution clk is 0 for this test
629 StrictMock<MockExecutionIdManager> execution_id_manager;
630 EXPECT_CALL(execution_id_manager, get_execution_id()).WillOnce(Return(0));
631
632 // Mock current context
633 StrictMock<MockContext> context;
634 EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem));
635 EXPECT_CALL(context, get_parent_cd_size).WillRepeatedly(Return(data.size()));
636 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
637 EXPECT_CALL(context, get_parent_cd_addr).WillRepeatedly(Return(parent_cd_addr));
638 EXPECT_CALL(context, get_calldata(cd_offset, copy_size))
639 .WillRepeatedly(::testing::Invoke([&data, cd_offset, copy_size]() {
640 // Return a slice of data from the calldata
641 return std::vector<MemoryValue>(data.begin() + cd_offset, data.begin() + cd_offset + copy_size);
642 }));
643 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(context_id));
644 EXPECT_CALL(context, get_parent_id).WillRepeatedly(Return(parent_context_id));
645
646 PureGreaterThan gt;
647
648 EventEmitter<DataCopyEvent> event_emitter;
649 DataCopy copy_data = DataCopy(execution_id_manager, gt, event_emitter);
650 // Set up execution trace
651 TestTraceContainer trace({
652 {
653 { C::precomputed_first_row, 1 },
654 { C::execution_sel, 1 },
655 { C::execution_context_id, context_id },
656 { C::execution_parent_id, parent_context_id },
657 { C::execution_sel_exec_dispatch_calldata_copy, 1 },
658 { C::execution_register_0_, copy_size },
659 { C::execution_register_1_, cd_offset },
660 { C::execution_rop_2_, dst_addr },
661 { C::execution_sel_opcode_error, 0 },
662 { C::execution_parent_calldata_addr, parent_cd_addr },
663 { C::execution_parent_calldata_size, static_cast<uint32_t>(data.size()) },
664 },
665 });
666
668
669 DataCopyTraceBuilder builder;
670 builder.process(event_emitter.dump_events(), trace);
671
672 check_relation<data_copy>(trace);
673 check_interaction<ExecutionTraceBuilder,
676}
677
678class NestedRdConstrainingBuilderTest : public DataCopyConstrainingBuilderTest {
679 protected:
680 NestedRdConstrainingBuilderTest()
681 {
682 // Set up parent context
683 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
684 EXPECT_CALL(context, get_last_child_id).WillRepeatedly(Return(2));
685 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(2));
686 EXPECT_CALL(context, get_last_rd_size).WillRepeatedly(Return(data.size()));
687 EXPECT_CALL(context, get_last_rd_addr).WillRepeatedly(Return(0));
688 }
689};
690
691TEST_F(NestedRdConstrainingBuilderTest, RdZeroCopy)
692{
693 uint32_t copy_size = 0;
694 uint32_t rd_offset = 0; // Offset into calldata
695
696 copy_data.rd_copy(context, copy_size, rd_offset, dst_addr);
697
698 tracegen::DataCopyTraceBuilder builder;
699 builder.process(event_emitter.dump_events(), trace);
700
701 tracegen::GreaterThanTraceBuilder gt_builder;
702 gt_builder.process(gt_event_emitter.dump_events(), trace);
703
704 check_relation<data_copy>(trace);
705 check_all_interactions<DataCopyTraceBuilder>(trace);
706}
707
708TEST(DataCopyWithExecutionPerm, RdCopy)
709{
710 // Current Context
711 uint32_t context_id = 2;
712 uint32_t rd_offset = 3;
713 uint32_t copy_size = 4;
714 MemoryAddress dst_addr = 0xdeadbeef; // Destination address in memory for the data.
715 // Child Context
716 uint32_t child_context_id = 1; // Child context ID
717 MemoryAddress child_rd_addr = 0xc0ffee; // Child returndata address in memory.
719 MemoryValue::from<FF>(1), MemoryValue::from<FF>(2), MemoryValue::from<FF>(3), MemoryValue::from<FF>(4),
720 MemoryValue::from<FF>(5), MemoryValue::from<FF>(6), MemoryValue::from<FF>(7), MemoryValue::from<FF>(8),
721 };
722
723 // Set up Memory
725
726 StrictMock<MockExecutionIdManager> execution_id_manager;
727 EXPECT_CALL(execution_id_manager, get_execution_id()).WillOnce(Return(0));
728 StrictMock<MockContext> context;
729 EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem));
730 EXPECT_CALL(context, get_last_rd_size).WillRepeatedly(Return(data.size()));
731 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
732 EXPECT_CALL(context, get_last_rd_addr).WillRepeatedly(Return(child_rd_addr));
733 EXPECT_CALL(context, get_returndata(rd_offset, copy_size))
734 .WillRepeatedly(::testing::Invoke([&data, rd_offset, copy_size]() {
735 // Return a slice of data from the calldata
736 return std::vector<MemoryValue>(data.begin() + rd_offset, data.begin() + rd_offset + copy_size);
737 }));
738 EXPECT_CALL(context, get_last_child_id).WillRepeatedly(Return(child_context_id));
739 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(context_id));
740
741 PureGreaterThan gt;
742
743 EventEmitter<DataCopyEvent> event_emitter;
744 DataCopy copy_data = DataCopy(execution_id_manager, gt, event_emitter);
745 // Set up execution trace
746 TestTraceContainer trace({
747 {
748 { C::precomputed_first_row, 1 },
749 { C::execution_sel, 1 },
750 { C::execution_context_id, context_id },
751 { C::execution_last_child_id, child_context_id },
752 { C::execution_sel_exec_dispatch_returndata_copy, 1 },
753 { C::execution_register_0_, copy_size },
754 { C::execution_register_1_, rd_offset },
755 { C::execution_rop_2_, dst_addr },
756 { C::execution_sel_opcode_error, 0 },
757 { C::execution_last_child_returndata_addr, child_rd_addr },
758 { C::execution_last_child_returndata_size, static_cast<uint32_t>(data.size()) },
759 },
760 });
761
762 copy_data.rd_copy(context, copy_size, rd_offset, dst_addr);
763
764 DataCopyTraceBuilder builder;
765 builder.process(event_emitter.dump_events(), trace);
766
767 check_relation<data_copy>(trace);
768 check_interaction<ExecutionTraceBuilder,
771}
772
773TEST(DataCopyWithExecutionPerm, ErrorPropagation)
774{
775 // Current Context
776 uint32_t context_id = 2;
777 uint32_t rd_offset = 10;
778 uint32_t copy_size = 4;
779 MemoryAddress big_dst_addr = AVM_HIGHEST_MEM_ADDRESS - 1;
780
781 // Child context
782 uint32_t child_context_id = 3; // Child context ID
783 uint32_t child_rd_addr = 0xc0ffee; // Last child returndata address in memory.
784 uint32_t child_data_size = 10; // Size of the last child returndata.
785
787 StrictMock<MockContext> context;
788 EXPECT_CALL(context, get_memory()).WillRepeatedly(ReturnRef(mem));
789 EXPECT_CALL(context, get_last_rd_size).WillRepeatedly(Return(child_data_size));
790 EXPECT_CALL(context, has_parent).WillRepeatedly(Return(true));
791 EXPECT_CALL(context, get_last_rd_addr).WillRepeatedly(Return(child_rd_addr));
792 EXPECT_CALL(context, get_context_id).WillRepeatedly(Return(context_id));
793 EXPECT_CALL(context, get_last_child_id).WillRepeatedly(Return(child_context_id));
794
795 StrictMock<MockExecutionIdManager> execution_id_manager;
796 EXPECT_CALL(execution_id_manager, get_execution_id()).WillOnce(Return(0));
797
798 PureGreaterThan gt;
799
800 EventEmitter<DataCopyEvent> event_emitter;
801 DataCopy copy_data = DataCopy(execution_id_manager, gt, event_emitter);
802
803 TestTraceContainer trace({
804 {
805 { C::precomputed_first_row, 1 },
806 { C::execution_sel, 1 },
807 { C::execution_context_id, context_id },
808 { C::execution_last_child_id, child_context_id },
809 { C::execution_sel_exec_dispatch_returndata_copy, 1 },
810 { C::execution_register_0_, copy_size },
811 { C::execution_register_1_, rd_offset },
812 { C::execution_rop_2_, big_dst_addr },
813 { C::execution_sel_opcode_error, 1 }, // Error flag is on
814 { C::execution_last_child_returndata_addr, child_rd_addr },
815 { C::execution_last_child_returndata_size, child_data_size },
816 },
817 });
818
819 EXPECT_THROW_WITH_MESSAGE(copy_data.rd_copy(context, copy_size, rd_offset, big_dst_addr),
820 "Attempting to access out of bounds memory");
821
822 DataCopyTraceBuilder builder;
823 builder.process(event_emitter.dump_events(), trace);
824
825 check_relation<data_copy>(trace);
826 check_interaction<ExecutionTraceBuilder,
829}
830
831} // namespace
832} // namespace bb::avm2::constraining
#define AVM_HIGHEST_MEM_ADDRESS
void rd_copy(ContextInterface &context, uint32_t copy_size, uint32_t offset, MemoryAddress dst_addr) override
Copies returndata from the last executed context to the dst_addr.
void cd_copy(ContextInterface &context, uint32_t copy_size, uint32_t offset, MemoryAddress dst_addr) override
Writes calldata into dst_addr. There is slight difference in how enqueued and nested contexts are han...
Definition data_copy.cpp:98
void process(const simulation::EventEmitterInterface< simulation::AluEvent >::Container &events, TraceContainer &trace)
Process the ALU events and populate the ALU relevant columns in the trace.
void process(const simulation::EventEmitterInterface< simulation::GreaterThanEvent >::Container &events, TraceContainer &trace)
Definition gt_trace.cpp:11
AluTraceBuilder builder
Definition alu.test.cpp:124
GreaterThanTraceBuilder gt_builder
Definition alu.test.cpp:123
DataCopy copy_data
EventEmitter< GreaterThanEvent > gt_event_emitter
ExecutionIdManager execution_id_manager
MemoryStore mem
EventEmitter< RangeCheckEvent > range_check_event_emitter
StrictMock< MockFieldGreaterThan > mock_field_gt
EventEmitter< DataCopyEvent > event_emitter
uint32_t dst_addr
const std::vector< MemoryValue > data
RangeCheck range_check
GreaterThan gt
TestTraceContainer trace
StrictMock< MockContext > context
ssize_t offset
Definition engine.cpp:36
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST_F(AvmRecursiveTests, GoblinRecursion)
A test of the Goblinized AVM recursive verifier.
void check_interaction(tracegen::TestTraceContainer &trace)
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:441
TaggedValue MemoryValue
lookup_settings< lookup_data_copy_check_dst_addr_in_range_settings_ > lookup_data_copy_check_dst_addr_in_range_settings
permutation_settings< perm_execution_dispatch_to_cd_copy_settings_ > perm_execution_dispatch_to_cd_copy_settings
lookup_settings< lookup_data_copy_data_index_upper_bound_gt_offset_settings_ > lookup_data_copy_data_index_upper_bound_gt_offset_settings
lookup_settings< lookup_data_copy_offset_plus_size_is_gt_data_size_settings_ > lookup_data_copy_offset_plus_size_is_gt_data_size_settings
lookup_settings< lookup_data_copy_check_src_addr_in_range_settings_ > lookup_data_copy_check_src_addr_in_range_settings
uint32_t MemoryAddress
permutation_settings< perm_execution_dispatch_to_rd_copy_settings_ > perm_execution_dispatch_to_rd_copy_settings
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
uint32_t context_id
uint32_t child_rd_addr
uint32_t parent_cd_addr
uint32_t child_context_id
DataCopy data_copy
uint32_t cd_offset