15#include <gmock/gmock.h>
16#include <gtest/gtest.h>
22using ::testing::NiceMock;
23using ::testing::Return;
24using ::testing::ReturnRef;
26class TxExecutionTest :
public ::testing::Test {
28 TxExecutionTest() =
default;
45 written_public_data_slots_tree_check,
46 retrieved_bytecodes_tree_check,
50 call_stack_metadata_collector,
54TEST_F(TxExecutionTest, simulateTx)
58 .hash =
"0x1234567890abcdef",
59 .non_revertible_accumulated_data =
65 .revertible_accumulated_data =
77 AppendOnlyTreeSnapshot dummy_snapshot = {
79 .next_available_leaf_index = 0,
81 TreeStates tree_state = {
82 .note_hash_tree = { .tree = dummy_snapshot, .counter = 0 },
83 .nullifier_tree = { .tree = dummy_snapshot, .counter = 0 },
84 .l1_to_l2_message_tree = { .tree = dummy_snapshot, .counter = 0 },
85 .public_data_tree = { .tree = dummy_snapshot, .counter = 0 },
87 ON_CALL(
merkle_db, get_tree_state()).WillByDefault([&]() {
return tree_state; });
88 ON_CALL(
merkle_db, siloed_nullifier_write(_)).WillByDefault(Return());
92 ON_CALL(*setup_context, halted()).WillByDefault(Return(
true));
95 ON_CALL(*app_logic_context, halted()).WillByDefault(Return(
true));
98 ON_CALL(*teardown_context, halted()).WillByDefault(Return(
true));
101 EnqueuedCallResult successful_result = {
103 .gas_used = Gas{ 100, 100 },
107 ON_CALL(execution,
execute(_)).WillByDefault(Return(successful_result));
110 .WillOnce(Return(
std::move(setup_context)))
111 .WillOnce(Return(
std::move(app_logic_context)))
112 .WillOnce(Return(
std::move(teardown_context)));
115 EXPECT_CALL(
merkle_db, pad_trees()).Times(1);
120 bool has_startup_event =
false;
121 auto expected_private_append_tree_events =
122 tx.non_revertible_accumulated_data.note_hashes.size() + tx.non_revertible_accumulated_data.nullifiers.size() +
123 tx.revertible_accumulated_data.note_hashes.size() + tx.revertible_accumulated_data.nullifiers.size();
124 auto actual_private_append_tree_events = 0;
126 auto expected_l2_l1_msg_events = tx.non_revertible_accumulated_data.l2_to_l1_messages.size() +
127 tx.revertible_accumulated_data.l2_to_l1_messages.size();
128 auto actual_l2_l1_msg_events = 0;
130 auto expected_public_call_events = 3;
131 auto actual_public_call_events = 0;
133 bool has_collect_fee_event =
false;
137 for (
const auto& tx_event : events) {
139 has_startup_event =
true;
144 actual_private_append_tree_events++;
147 actual_l2_l1_msg_events++;
150 actual_public_call_events++;
153 has_collect_fee_event =
true;
157 EXPECT_TRUE(has_startup_event);
158 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
159 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
160 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
161 EXPECT_TRUE(has_collect_fee_event);
164TEST_F(TxExecutionTest, NoteHashLimitReached)
168 .hash =
"0x1234567890abcdef",
169 .non_revertible_accumulated_data =
174 .revertible_accumulated_data =
182 AppendOnlyTreeSnapshot dummy_snapshot = {
184 .next_available_leaf_index = 0,
186 TreeStates tree_state = {
187 .note_hash_tree = { .tree = dummy_snapshot, .counter = 0 },
188 .nullifier_tree = { .tree = dummy_snapshot, .counter = 0 },
189 .l1_to_l2_message_tree = { .tree = dummy_snapshot, .counter = 0 },
190 .public_data_tree = { .tree = dummy_snapshot, .counter = 0 },
192 ON_CALL(
merkle_db, get_tree_state()).WillByDefault([&]() {
return tree_state; });
193 ON_CALL(
merkle_db, siloed_nullifier_write(_)).WillByDefault([&](
const auto& ) {
194 tree_state.nullifier_tree.counter++;
196 ON_CALL(
merkle_db, siloed_note_hash_write(_)).WillByDefault([&](
const auto& ) {
197 tree_state.note_hash_tree.counter++;
200 ON_CALL(
merkle_db, unique_note_hash_write(_)).WillByDefault([&](
const auto& ) {
201 tree_state.note_hash_tree.counter++;
210 bool has_startup_event =
false;
211 auto expected_private_append_tree_events =
212 tx.non_revertible_accumulated_data.note_hashes.size() + tx.non_revertible_accumulated_data.nullifiers.size() +
213 tx.revertible_accumulated_data.note_hashes.size() + tx.revertible_accumulated_data.nullifiers.size();
214 auto actual_private_append_tree_events = 0;
216 auto expected_l2_l1_msg_events = tx.non_revertible_accumulated_data.l2_to_l1_messages.size() +
217 tx.revertible_accumulated_data.l2_to_l1_messages.size();
218 auto actual_l2_l1_msg_events = 0;
220 auto expected_public_call_events = 0;
221 auto actual_public_call_events = 0;
224 bool has_collect_fee_event =
false;
228 for (
const auto& tx_event : events) {
230 has_startup_event =
true;
234 if (phase_event.reverted) {
237 auto event = phase_event.event;
239 actual_private_append_tree_events++;
242 actual_l2_l1_msg_events++;
245 actual_public_call_events++;
248 has_collect_fee_event =
true;
252 EXPECT_TRUE(has_startup_event);
253 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
254 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
255 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
256 EXPECT_TRUE(has_collect_fee_event);
257 EXPECT_EQ(reverts, 1);
260TEST_F(TxExecutionTest, NullifierLimitReached)
264 .hash =
"0x1234567890abcdef",
265 .non_revertible_accumulated_data =
269 .revertible_accumulated_data =
277 AppendOnlyTreeSnapshot dummy_snapshot = {
279 .next_available_leaf_index = 0,
281 TreeStates tree_state = {
282 .note_hash_tree = { .tree = dummy_snapshot, .counter = 0 },
283 .nullifier_tree = { .tree = dummy_snapshot, .counter = 0 },
284 .l1_to_l2_message_tree = { .tree = dummy_snapshot, .counter = 0 },
285 .public_data_tree = { .tree = dummy_snapshot, .counter = 0 },
287 ON_CALL(
merkle_db, get_tree_state()).WillByDefault([&]() {
return tree_state; });
288 ON_CALL(
merkle_db, siloed_nullifier_write(_)).WillByDefault([&](
const auto& ) {
289 tree_state.nullifier_tree.counter++;
292 ON_CALL(
merkle_db, siloed_note_hash_write(_)).WillByDefault([&](
const auto& ) {
293 tree_state.note_hash_tree.counter++;
296 ON_CALL(
merkle_db, unique_note_hash_write(_)).WillByDefault([&](
const auto& ) {
297 tree_state.note_hash_tree.counter++;
306 bool has_startup_event =
false;
307 auto expected_private_append_tree_events =
308 tx.non_revertible_accumulated_data.note_hashes.size() + tx.non_revertible_accumulated_data.nullifiers.size() +
309 tx.revertible_accumulated_data.note_hashes.size() + tx.revertible_accumulated_data.nullifiers.size();
310 auto actual_private_append_tree_events = 0;
312 auto expected_l2_l1_msg_events = tx.non_revertible_accumulated_data.l2_to_l1_messages.size() +
313 tx.revertible_accumulated_data.l2_to_l1_messages.size();
314 auto actual_l2_l1_msg_events = 0;
316 auto expected_public_call_events = 0;
317 auto actual_public_call_events = 0;
320 bool has_collect_fee_event =
false;
324 for (
const auto& tx_event : events) {
326 has_startup_event =
true;
330 if (phase_event.reverted) {
333 auto event = phase_event.event;
335 actual_private_append_tree_events++;
338 actual_l2_l1_msg_events++;
341 actual_public_call_events++;
344 has_collect_fee_event =
true;
348 EXPECT_TRUE(has_startup_event);
349 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
350 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
351 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
352 EXPECT_TRUE(has_collect_fee_event);
353 EXPECT_EQ(reverts, 1);
356TEST_F(TxExecutionTest, L2ToL1MessageLimitReached)
360 .hash =
"0x1234567890abcdef",
361 .non_revertible_accumulated_data =
366 .revertible_accumulated_data =
374 AppendOnlyTreeSnapshot dummy_snapshot = {
376 .next_available_leaf_index = 0,
378 TreeStates tree_state = {
379 .note_hash_tree = { .tree = dummy_snapshot, .counter = 0 },
380 .nullifier_tree = { .tree = dummy_snapshot, .counter = 0 },
381 .l1_to_l2_message_tree = { .tree = dummy_snapshot, .counter = 0 },
382 .public_data_tree = { .tree = dummy_snapshot, .counter = 0 },
384 ON_CALL(
merkle_db, get_tree_state()).WillByDefault([&]() {
return tree_state; });
385 ON_CALL(
merkle_db, siloed_nullifier_write(_)).WillByDefault([&](
const auto& ) {
386 tree_state.nullifier_tree.counter++;
389 ON_CALL(
merkle_db, siloed_note_hash_write(_)).WillByDefault([&](
const auto& ) {
390 tree_state.note_hash_tree.counter++;
393 ON_CALL(
merkle_db, unique_note_hash_write(_)).WillByDefault([&](
const auto& ) {
394 tree_state.note_hash_tree.counter++;
403 bool has_startup_event =
false;
404 auto expected_private_append_tree_events =
405 tx.non_revertible_accumulated_data.note_hashes.size() + tx.non_revertible_accumulated_data.nullifiers.size() +
406 tx.revertible_accumulated_data.note_hashes.size() + tx.revertible_accumulated_data.nullifiers.size();
407 auto actual_private_append_tree_events = 0;
409 auto expected_l2_l1_msg_events = tx.non_revertible_accumulated_data.l2_to_l1_messages.size() +
410 tx.revertible_accumulated_data.l2_to_l1_messages.size();
411 auto actual_l2_l1_msg_events = 0;
413 auto expected_public_call_events = 0;
414 auto actual_public_call_events = 0;
417 bool has_collect_fee_event =
false;
421 for (
const auto& tx_event : events) {
423 has_startup_event =
true;
427 if (phase_event.reverted) {
430 auto event = phase_event.event;
432 actual_private_append_tree_events++;
435 actual_l2_l1_msg_events++;
438 actual_public_call_events++;
441 has_collect_fee_event =
true;
445 EXPECT_TRUE(has_startup_event);
446 EXPECT_EQ(actual_private_append_tree_events, expected_private_append_tree_events);
447 EXPECT_EQ(expected_l2_l1_msg_events, actual_l2_l1_msg_events);
448 EXPECT_EQ(expected_public_call_events, actual_public_call_events);
449 EXPECT_TRUE(has_collect_fee_event);
450 EXPECT_EQ(reverts, 1);
FieldGreaterThan field_gt
std::shared_ptr< Napi::ThreadSafeFunction > create_checkpoint
#define MAX_L2_TO_L1_MSGS_PER_TX
#define MAX_NOTE_HASHES_PER_TX
StrictMock< MockHighLevelMerkleDB > merkle_db
StrictMock< MockRetrievedBytecodesTreeCheck > retrieved_bytecodes_tree_check
StrictMock< MockContractDB > contract_db
TxExecutionResult simulate(const Tx &tx)
Simulates the entire transaction execution phases.
std::vector< PublicCallRequestWithCalldata > random_enqueued_calls(size_t n)
std::vector< ScopedL2ToL1Message > random_l2_to_l1_messages(size_t n)
std::vector< FF > random_fields(size_t n)
CommandResponse execute(BBApiRequest &request, Command &&command)
Executes a command by visiting a variant of all possible commands.
TEST_F(IPATest, ChallengesAreZero)
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
simulation::PublicDataTreeReadWriteEvent event
static field random_element(numeric::RNG *engine=nullptr) noexcept
SideEffectTracker side_effect_tracker
NiceMock< MockContextProvider > context_provider
NiceMock< MockExecution > execution
NoopCallStackMetadataCollector call_stack_metadata_collector
EventEmitter< TxEvent > tx_event_emitter
NiceMock< MockWrittenPublicDataSlotsTreeCheck > written_public_data_slots_tree_check