Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tx_execution.test.cpp
Go to the documentation of this file.
11
12#include <gmock/gmock.h>
13#include <gtest/gtest.h>
14
15namespace bb::avm2::simulation {
16namespace {
17
18using ::testing::_;
19using ::testing::NiceMock;
20using ::testing::Return;
21using ::testing::ReturnRef;
22
23class TxExecutionTest : public ::testing::Test {
24 protected:
25 TxExecutionTest() = default;
26
27 NiceMock<MockContextProvider> context_provider;
28 EventEmitter<TxEvent> tx_event_emitter;
29 NiceMock<MockHighLevelMerkleDB> merkle_db;
30 NiceMock<MockExecution> execution;
31 NiceMock<MockFieldGreaterThan> field_gt;
32 NiceMock<MockPoseidon2> poseidon2;
33 NiceMock<MockWrittenPublicDataSlotsTreeCheck> written_public_data_slots_tree_check;
34 TxExecution tx_execution = TxExecution(execution,
35 context_provider,
36 merkle_db,
37 written_public_data_slots_tree_check,
38 field_gt,
40 tx_event_emitter);
41};
42
43TEST_F(TxExecutionTest, simulateTx)
44{
45 // Create a mock transaction
46 Tx tx = {
47 .hash = "0x1234567890abcdef",
48 .nonRevertibleAccumulatedData =
49 AccumulatedData{
50 .noteHashes = testing::random_fields(5),
51 .nullifiers = testing::random_fields(6),
52 .l2ToL1Messages = testing::random_l2_to_l1_messages(2),
53 },
54 .revertibleAccumulatedData =
55 AccumulatedData{
56 .noteHashes = testing::random_fields(5),
57 .nullifiers = testing::random_fields(2),
58 .l2ToL1Messages = testing::random_l2_to_l1_messages(2),
59 },
60 .setupEnqueuedCalls = testing::random_enqueued_calls(1),
61 .appLogicEnqueuedCalls = testing::random_enqueued_calls(1),
62 .teardownEnqueuedCall = testing::random_enqueued_calls(1)[0],
63 };
64
65 AppendOnlyTreeSnapshot dummy_snapshot = {
66 .root = 0,
67 .nextAvailableLeafIndex = 0,
68 };
69 TreeStates tree_state = {
70 .noteHashTree = { .tree = dummy_snapshot, .counter = 0 },
71 .nullifierTree = { .tree = dummy_snapshot, .counter = 0 },
72 .l1ToL2MessageTree = { .tree = dummy_snapshot, .counter = 0 },
73 .publicDataTree = { .tree = dummy_snapshot, .counter = 0 },
74 };
75 ON_CALL(merkle_db, get_tree_state()).WillByDefault([&]() { return tree_state; });
76 ON_CALL(merkle_db, siloed_nullifier_write(_)).WillByDefault(Return(true));
77 // Number of Enqueued Calls in the transaction : 1 setup, 1 app logic, and 1 teardown
78
79 auto setup_context = std::make_unique<NiceMock<MockContext>>();
80 ON_CALL(*setup_context, halted()).WillByDefault(Return(true)); // dont do any actual
81
82 auto app_logic_context = std::make_unique<NiceMock<MockContext>>();
83 ON_CALL(*app_logic_context, halted()).WillByDefault(Return(true));
84
85 auto teardown_context = std::make_unique<NiceMock<MockContext>>();
86 ON_CALL(*teardown_context, halted()).WillByDefault(Return(true));
87
88 // Configure mock execution to return successful results
89 ExecutionResult successful_result = {
90 .rd_offset = 0,
91 .rd_size = 0,
92 .gas_used = Gas{ 100, 100 },
93 .side_effect_states = SideEffectStates{},
94 .success = true // This is the key - mark execution as successful
95 };
96 ON_CALL(execution, execute(_)).WillByDefault(Return(successful_result));
97
98 EXPECT_CALL(context_provider, make_enqueued_context)
99 .WillOnce(Return(std::move(setup_context)))
100 .WillOnce(Return(std::move(app_logic_context)))
101 .WillOnce(Return(std::move(teardown_context)));
102 EXPECT_CALL(merkle_db, create_checkpoint()).Times(1);
103
104 EXPECT_CALL(merkle_db, pad_trees()).Times(1);
105
107
108 // Check the event counts
109 bool has_startup_event = false;
110 auto expected_private_append_tree_events =
111 tx.nonRevertibleAccumulatedData.noteHashes.size() + tx.nonRevertibleAccumulatedData.nullifiers.size() +
112 tx.revertibleAccumulatedData.noteHashes.size() + tx.revertibleAccumulatedData.nullifiers.size();
113 auto actual_private_append_tree_events = 0;
114
115 auto expected_l2_l1_msg_events =
116 tx.nonRevertibleAccumulatedData.l2ToL1Messages.size() + tx.revertibleAccumulatedData.l2ToL1Messages.size();
117 auto actual_l2_l1_msg_events = 0;
118
119 auto expected_public_call_events = 3; // setup, app logic, teardown
120 auto actual_public_call_events = 0;
121
122 bool has_collect_fee_event = false;
123
124 // Get PrivateAppendTreeEvent from tx event dump events
125 auto events = tx_event_emitter.get_events();
126 for (const auto& tx_event : events) {
128 has_startup_event = true;
129 continue;
130 }
131 auto event = std::get<TxPhaseEvent>(tx_event).event;
133 actual_private_append_tree_events++;
134 }
136 actual_l2_l1_msg_events++;
137 }
139 actual_public_call_events++;
140 }
142 has_collect_fee_event = true;
143 }
144 }
145
146 EXPECT_TRUE(has_startup_event);
147 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
148 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
149 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
150 EXPECT_TRUE(has_collect_fee_event);
151}
152
153TEST_F(TxExecutionTest, NoteHashLimitReached)
154{
155 // Create a mock transaction
156 Tx tx = {
157 .hash = "0x1234567890abcdef",
158 .nonRevertibleAccumulatedData =
159 AccumulatedData{
161 .nullifiers = testing::random_fields(1),
162 },
163 .revertibleAccumulatedData =
164 AccumulatedData{
165 .noteHashes = testing::random_fields(1),
166 },
167 .appLogicEnqueuedCalls = testing::random_enqueued_calls(1),
168 };
169
170 AppendOnlyTreeSnapshot dummy_snapshot = {
171 .root = 0,
172 .nextAvailableLeafIndex = 0,
173 };
174 TreeStates tree_state = {
175 .noteHashTree = { .tree = dummy_snapshot, .counter = 0 },
176 .nullifierTree = { .tree = dummy_snapshot, .counter = 0 },
177 .l1ToL2MessageTree = { .tree = dummy_snapshot, .counter = 0 },
178 .publicDataTree = { .tree = dummy_snapshot, .counter = 0 },
179 };
180 ON_CALL(merkle_db, get_tree_state()).WillByDefault([&]() { return tree_state; });
181 ON_CALL(merkle_db, siloed_nullifier_write(_)).WillByDefault([&](const auto& /*nullifier*/) {
182 tree_state.nullifierTree.counter++;
183 return true;
184 });
185 ON_CALL(merkle_db, siloed_note_hash_write(_)).WillByDefault([&](const auto& /*note_hash*/) {
186 tree_state.noteHashTree.counter++;
187 return true;
188 });
189 ON_CALL(merkle_db, unique_note_hash_write(_)).WillByDefault([&](const auto& /*note_hash*/) {
190 tree_state.noteHashTree.counter++;
191 return true;
192 });
193
194 EXPECT_CALL(merkle_db, create_checkpoint()).Times(2); // once at start, once after app-logic revert
195
197
198 // Check the event counts
199 bool has_startup_event = false;
200 auto expected_private_append_tree_events =
201 tx.nonRevertibleAccumulatedData.noteHashes.size() + tx.nonRevertibleAccumulatedData.nullifiers.size() +
202 tx.revertibleAccumulatedData.noteHashes.size() + tx.revertibleAccumulatedData.nullifiers.size();
203 auto actual_private_append_tree_events = 0;
204
205 auto expected_l2_l1_msg_events =
206 tx.nonRevertibleAccumulatedData.l2ToL1Messages.size() + tx.revertibleAccumulatedData.l2ToL1Messages.size();
207 auto actual_l2_l1_msg_events = 0;
208
209 auto expected_public_call_events = 0; // None, since we revert before the public call
210 auto actual_public_call_events = 0;
211 auto reverts = 0;
212
213 bool has_collect_fee_event = false;
214
215 // Get PrivateAppendTreeEvent from tx event dump events
216 auto events = tx_event_emitter.get_events();
217 for (const auto& tx_event : events) {
219 has_startup_event = true;
220 continue;
221 }
222 TxPhaseEvent phase_event = std::get<TxPhaseEvent>(tx_event);
223 if (phase_event.reverted) {
224 reverts++;
225 }
226 auto event = phase_event.event;
228 actual_private_append_tree_events++;
229 }
231 actual_l2_l1_msg_events++;
232 }
234 actual_public_call_events++;
235 }
237 has_collect_fee_event = true;
238 }
239 }
240
241 EXPECT_TRUE(has_startup_event);
242 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
243 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
244 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
245 EXPECT_TRUE(has_collect_fee_event);
246 EXPECT_EQ(reverts, 1);
247}
248
249TEST_F(TxExecutionTest, NullifierLimitReached)
250{
251 // Create a mock transaction
252 Tx tx = {
253 .hash = "0x1234567890abcdef",
254 .nonRevertibleAccumulatedData =
255 AccumulatedData{
257 },
258 .revertibleAccumulatedData =
259 AccumulatedData{
260 .nullifiers = testing::random_fields(1),
261 },
262 .appLogicEnqueuedCalls = testing::random_enqueued_calls(1),
263 };
264
265 AppendOnlyTreeSnapshot dummy_snapshot = {
266 .root = 0,
267 .nextAvailableLeafIndex = 0,
268 };
269 TreeStates tree_state = {
270 .noteHashTree = { .tree = dummy_snapshot, .counter = 0 },
271 .nullifierTree = { .tree = dummy_snapshot, .counter = 0 },
272 .l1ToL2MessageTree = { .tree = dummy_snapshot, .counter = 0 },
273 .publicDataTree = { .tree = dummy_snapshot, .counter = 0 },
274 };
275 ON_CALL(merkle_db, get_tree_state()).WillByDefault([&]() { return tree_state; });
276 ON_CALL(merkle_db, siloed_nullifier_write(_)).WillByDefault([&](const auto& /*nullifier*/) {
277 tree_state.nullifierTree.counter++;
278 return true;
279 });
280 ON_CALL(merkle_db, siloed_note_hash_write(_)).WillByDefault([&](const auto& /*note_hash*/) {
281 tree_state.noteHashTree.counter++;
282 return true;
283 });
284 ON_CALL(merkle_db, unique_note_hash_write(_)).WillByDefault([&](const auto& /*note_hash*/) {
285 tree_state.noteHashTree.counter++;
286 return true;
287 });
288
289 EXPECT_CALL(merkle_db, create_checkpoint()).Times(2); // once at start, once after app-logic revert
290
292
293 // Check the event counts
294 bool has_startup_event = false;
295 auto expected_private_append_tree_events =
296 tx.nonRevertibleAccumulatedData.noteHashes.size() + tx.nonRevertibleAccumulatedData.nullifiers.size() +
297 tx.revertibleAccumulatedData.noteHashes.size() + tx.revertibleAccumulatedData.nullifiers.size();
298 auto actual_private_append_tree_events = 0;
299
300 auto expected_l2_l1_msg_events =
301 tx.nonRevertibleAccumulatedData.l2ToL1Messages.size() + tx.revertibleAccumulatedData.l2ToL1Messages.size();
302 auto actual_l2_l1_msg_events = 0;
303
304 auto expected_public_call_events = 0; // None, since we revert before the public call
305 auto actual_public_call_events = 0;
306 auto reverts = 0;
307
308 bool has_collect_fee_event = false;
309
310 // Get PrivateAppendTreeEvent from tx event dump events
311 auto events = tx_event_emitter.get_events();
312 for (const auto& tx_event : events) {
314 has_startup_event = true;
315 continue;
316 }
317 TxPhaseEvent phase_event = std::get<TxPhaseEvent>(tx_event);
318 if (phase_event.reverted) {
319 reverts++;
320 }
321 auto event = phase_event.event;
323 actual_private_append_tree_events++;
324 }
326 actual_l2_l1_msg_events++;
327 }
329 actual_public_call_events++;
330 }
332 has_collect_fee_event = true;
333 }
334 }
335
336 EXPECT_TRUE(has_startup_event);
337 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
338 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
339 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
340 EXPECT_TRUE(has_collect_fee_event);
341 EXPECT_EQ(reverts, 1);
342}
343
344TEST_F(TxExecutionTest, L2ToL1MessageLimitReached)
345{
346 // Create a mock transaction
347 Tx tx = {
348 .hash = "0x1234567890abcdef",
349 .nonRevertibleAccumulatedData =
350 AccumulatedData{
351 .nullifiers = testing::random_fields(1),
353 },
354 .revertibleAccumulatedData =
355 AccumulatedData{
356 .l2ToL1Messages = testing::random_l2_to_l1_messages(1),
357 },
358 .appLogicEnqueuedCalls = testing::random_enqueued_calls(1),
359 };
360
361 AppendOnlyTreeSnapshot dummy_snapshot = {
362 .root = 0,
363 .nextAvailableLeafIndex = 0,
364 };
365 TreeStates tree_state = {
366 .noteHashTree = { .tree = dummy_snapshot, .counter = 0 },
367 .nullifierTree = { .tree = dummy_snapshot, .counter = 0 },
368 .l1ToL2MessageTree = { .tree = dummy_snapshot, .counter = 0 },
369 .publicDataTree = { .tree = dummy_snapshot, .counter = 0 },
370 };
371 ON_CALL(merkle_db, get_tree_state()).WillByDefault([&]() { return tree_state; });
372 ON_CALL(merkle_db, siloed_nullifier_write(_)).WillByDefault([&](const auto& /*nullifier*/) {
373 tree_state.nullifierTree.counter++;
374 return true;
375 });
376 ON_CALL(merkle_db, siloed_note_hash_write(_)).WillByDefault([&](const auto& /*note_hash*/) {
377 tree_state.noteHashTree.counter++;
378 return true;
379 });
380 ON_CALL(merkle_db, unique_note_hash_write(_)).WillByDefault([&](const auto& /*note_hash*/) {
381 tree_state.noteHashTree.counter++;
382 return true;
383 });
384
385 EXPECT_CALL(merkle_db, create_checkpoint()).Times(2); // once at start, once after app-logic revert
386
388
389 // Check the event counts
390 bool has_startup_event = false;
391 auto expected_private_append_tree_events =
392 tx.nonRevertibleAccumulatedData.noteHashes.size() + tx.nonRevertibleAccumulatedData.nullifiers.size() +
393 tx.revertibleAccumulatedData.noteHashes.size() + tx.revertibleAccumulatedData.nullifiers.size();
394 auto actual_private_append_tree_events = 0;
395
396 auto expected_l2_l1_msg_events =
397 tx.nonRevertibleAccumulatedData.l2ToL1Messages.size() + tx.revertibleAccumulatedData.l2ToL1Messages.size();
398 auto actual_l2_l1_msg_events = 0;
399
400 auto expected_public_call_events = 0; // None, since we revert before the public call
401 auto actual_public_call_events = 0;
402 auto reverts = 0;
403
404 bool has_collect_fee_event = false;
405
406 // Get PrivateAppendTreeEvent from tx event dump events
407 auto events = tx_event_emitter.get_events();
408 for (const auto& tx_event : events) {
410 has_startup_event = true;
411 continue;
412 }
413 TxPhaseEvent phase_event = std::get<TxPhaseEvent>(tx_event);
414 if (phase_event.reverted) {
415 reverts++;
416 }
417 auto event = phase_event.event;
419 actual_private_append_tree_events++;
420 }
422 actual_l2_l1_msg_events++;
423 }
425 actual_public_call_events++;
426 }
428 has_collect_fee_event = true;
429 }
430 }
431
432 EXPECT_TRUE(has_startup_event);
433 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
434 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
435 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
436 EXPECT_TRUE(has_collect_fee_event);
437 EXPECT_EQ(reverts, 1);
438}
439
440} // namespace
441} // namespace bb::avm2::simulation
#define MAX_L2_TO_L1_MSGS_PER_TX
#define MAX_NOTE_HASHES_PER_TX
StrictMock< MockHighLevelMerkleDB > merkle_db
std::vector< PublicCallRequestWithCalldata > random_enqueued_calls(size_t n)
Definition fixtures.cpp:60
std::vector< ScopedL2ToL1Message > random_l2_to_l1_messages(size_t n)
Definition fixtures.cpp:43
std::vector< FF > random_fields(size_t n)
Definition fixtures.cpp:23
CommandResponse execute(BBApiRequest &request, Command &&command)
Executes a command by visiting a variant of all possible commands.
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:123
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13
simulation::PublicDataTreeReadWriteEvent event
TxExecution tx_execution
NiceMock< MockFieldGreaterThan > field_gt
NiceMock< MockContextProvider > context_provider
NiceMock< MockExecution > execution
EventEmitter< TxEvent > tx_event_emitter
NiceMock< MockWrittenPublicDataSlotsTreeCheck > written_public_data_slots_tree_check