Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tx_trace.test.cpp
Go to the documentation of this file.
2
3#include <cstdint>
4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
6
16
17namespace bb::avm2::tracegen {
18namespace {
19
20using enum ::bb::avm2::WireOpCode;
21
22using ::testing::AllOf;
23
24TEST(TxTraceGenTest, EnqueuedCallEvent)
25{
26 TestTraceContainer trace;
27 TxTraceBuilder builder;
28
29 auto msg_sender = FF::random_element();
31 auto calldata_hash = FF::random_element();
32
33 simulation::TxStartupEvent startup_event = {
34 .gas_used = { 500, 1000 },
35 .gas_limit = { 1000, 2000 },
36 .teardown_gas_limit = { 0, 0 },
37 .phase_lengths = { .setup = 1 },
38 };
39
40 simulation::TxPhaseEvent tx_event = {
42 .state_before = {},
43 .state_after = {},
44 .reverted = false,
45 .event =
46 simulation::EnqueuedCallEvent{
47 .msg_sender = msg_sender,
48 .contract_address = contract_address,
49 .is_static = false,
50 .calldata_size = 2,
51 .calldata_hash = calldata_hash,
52 .success = true,
53 },
54 };
55
56 builder.process({ startup_event, tx_event }, trace);
57 auto rows = trace.as_rows();
58 ASSERT_EQ(rows.size(), 2); // 0th precomputed, setup
59
60 // Setup
61 EXPECT_THAT(rows[1],
62 AllOf(ROW_FIELD_EQ(tx_sel, 1),
63 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::SETUP)),
64 ROW_FIELD_EQ(tx_start_phase, 1),
65 ROW_FIELD_EQ(tx_is_public_call_request, 1),
66 ROW_FIELD_EQ(tx_read_pi_length_offset,
69 ROW_FIELD_EQ(tx_remaining_phase_counter, 1),
70 ROW_FIELD_EQ(tx_remaining_phase_inv, 1),
71 ROW_FIELD_EQ(tx_msg_sender, msg_sender),
72 ROW_FIELD_EQ(tx_contract_addr, contract_address),
73 ROW_FIELD_EQ(tx_calldata_size, 2),
74 ROW_FIELD_EQ(tx_calldata_hash, calldata_hash),
75 ROW_FIELD_EQ(tx_end_phase, 1),
76 ROW_FIELD_EQ(tx_is_static, false)));
77};
78
79TEST(TxTraceGenTest, CollectFeeEvent)
80{
81 TestTraceContainer trace;
82 TxTraceBuilder builder;
83
84 auto fee_payer = FF::random_element();
85 auto fee_payer_balance = FF::neg_one();
86 auto effective_fee_per_da_gas = 100;
87 auto effective_fee_per_l2_gas = 200;
88 auto prev_da_gas_used = 1000;
89 auto prev_l2_gas_used = 500;
90 auto fee = effective_fee_per_da_gas * prev_da_gas_used + effective_fee_per_l2_gas * prev_l2_gas_used;
91
92 simulation::TxStartupEvent startup_event = {
93 .gas_used = { 500, 1000 },
94 .gas_limit = { 1000, 2000 },
95 .teardown_gas_limit = { 0, 0 },
96 };
97
98 simulation::TxPhaseEvent tx_event = { .phase = TransactionPhase::COLLECT_GAS_FEES,
99 .state_before = {},
100 .state_after = {},
101 .reverted = false,
102 .event = simulation::CollectGasFeeEvent{
103 .effective_fee_per_da_gas =
104 static_cast<uint128_t>(effective_fee_per_da_gas),
105 .effective_fee_per_l2_gas =
106 static_cast<uint128_t>(effective_fee_per_l2_gas),
107 .fee_payer = fee_payer,
108 .fee_payer_balance = fee_payer_balance,
109 .fee = fee,
110 } };
111
112 builder.process({ startup_event, tx_event }, trace);
113 auto rows = trace.as_rows();
114 ASSERT_EQ(rows.size(), 2); // 0th precomputed, collect-gas-fees
115
116 EXPECT_THAT(rows[1],
117 AllOf(ROW_FIELD_EQ(tx_sel, 1),
118 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::COLLECT_GAS_FEES)),
119 ROW_FIELD_EQ(tx_is_padded, 0),
120 ROW_FIELD_EQ(tx_start_phase, 1),
121 ROW_FIELD_EQ(tx_sel_read_phase_length, 0),
122 ROW_FIELD_EQ(tx_end_phase, 1),
123 ROW_FIELD_EQ(tx_prev_da_gas_used, prev_da_gas_used),
124 ROW_FIELD_EQ(tx_prev_l2_gas_used, prev_l2_gas_used),
126 ROW_FIELD_EQ(tx_read_pi_length_offset, 0),
128 ROW_FIELD_EQ(tx_remaining_phase_counter, 1),
129 ROW_FIELD_EQ(tx_remaining_phase_inv, FF(1).invert()),
130 ROW_FIELD_EQ(tx_remaining_phase_minus_one_inv, 0),
131 ROW_FIELD_EQ(tx_is_collect_fee, 1),
132 ROW_FIELD_EQ(tx_effective_fee_per_da_gas, FF(effective_fee_per_da_gas)),
133 ROW_FIELD_EQ(tx_effective_fee_per_l2_gas, FF(effective_fee_per_l2_gas)),
134 ROW_FIELD_EQ(tx_fee_payer, fee_payer),
135 ROW_FIELD_EQ(tx_fee_payer_pi_offset, AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX),
136 ROW_FIELD_EQ(tx_fee, fee),
137 ROW_FIELD_EQ(tx_fee_payer_balance, fee_payer_balance),
138 ROW_FIELD_EQ(tx_next_da_gas_used, prev_da_gas_used),
139 ROW_FIELD_EQ(tx_next_l2_gas_used, prev_l2_gas_used),
140 ROW_FIELD_EQ(tx_uint32_max, 0xffffffff)));
141};
142
143TEST(TxTraceGenTest, BasicFirstPaddedRow)
144{
145 TestTraceContainer trace;
146 TxTraceBuilder builder;
147
148 simulation::TxStartupEvent startup_event = {
149 .gas_used = { 500, 1000 },
150 .gas_limit = { 1000, 2000 },
151 .teardown_gas_limit = { 0, 0 },
152 };
153
154 simulation::TxPhaseEvent empty_nr_nullifier_insertion_event = { .phase = TransactionPhase::NR_NULLIFIER_INSERTION,
155 .state_before = {},
156 .state_after = {},
157 .reverted = false,
158 .event = simulation::EmptyPhaseEvent{} };
159
160 builder.process({ startup_event, empty_nr_nullifier_insertion_event }, trace);
161
162 auto rows = trace.as_rows();
163 ASSERT_EQ(rows.size(), 2);
164
165 EXPECT_THAT(
166 rows[1],
167 AllOf(
168 ROW_FIELD_EQ(tx_sel, 1),
169 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::NR_NULLIFIER_INSERTION)),
170 ROW_FIELD_EQ(tx_is_padded, 1),
171 ROW_FIELD_EQ(tx_is_tree_insert_phase, 1),
172 ROW_FIELD_EQ(tx_sel_non_revertible_append_nullifier, 1),
173 ROW_FIELD_EQ(tx_start_tx, 1),
174 ROW_FIELD_EQ(tx_should_read_gas_limit, 1),
176 ROW_FIELD_EQ(tx_read_pi_start_offset,
178 ROW_FIELD_EQ(tx_read_pi_offset,
180 ROW_FIELD_EQ(tx_sel_read_phase_length, 1),
181 ROW_FIELD_EQ(tx_read_pi_length_offset,
183}
184
185TEST(TxTraceGenTest, PadTreesEvent)
186{
187 TestTraceContainer trace;
188 TxTraceBuilder builder;
189
190 simulation::TxStartupEvent startup_event = {
191 .gas_used = { 500, 1000 },
192 .gas_limit = { 1000, 2000 },
193 .teardown_gas_limit = { 0, 0 },
194 };
195
196 simulation::TxPhaseEvent tx_event = { .phase = TransactionPhase::TREE_PADDING,
197 .state_before = {
198 .tree_states = {
199 .note_hash_tree = {
200 .tree = {
201 .root = 27,
202 .next_available_leaf_index = 65,
203 },
204 .counter = 1
205 },
206 .nullifier_tree = {
207 .tree = {
208 .root = 28,
209 .next_available_leaf_index = 127,
210 },
211 .counter = 63
212 },
213 },
214 },
215 .state_after = {
216 .tree_states = {
217 .note_hash_tree = {
218 .tree = {
219 .root = 27,
220 .next_available_leaf_index = 128,
221 },
222 .counter = 1
223 },
224 .nullifier_tree = {
225 .tree = {
226 .root = 28,
227 .next_available_leaf_index = 128,
228 },
229 .counter = 63
230 },
231 },
232 },
233 .reverted = false,
234 .event = simulation::PadTreesEvent{} };
235
236 builder.process({ startup_event, tx_event }, trace);
237 auto rows = trace.as_rows();
238 ASSERT_EQ(rows.size(), 2); // 0th precomputed, tree-padding
239
240 EXPECT_THAT(rows[1],
241 AllOf(ROW_FIELD_EQ(tx_sel, 1),
242 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::TREE_PADDING)),
243 ROW_FIELD_EQ(tx_start_phase, 1),
244 ROW_FIELD_EQ(tx_end_phase, 1),
245 ROW_FIELD_EQ(tx_is_tree_padding, 1),
246 ROW_FIELD_EQ(tx_remaining_phase_counter, 1),
247 ROW_FIELD_EQ(tx_remaining_phase_inv, 1),
248 ROW_FIELD_EQ(tx_prev_note_hash_tree_root, 27),
249 ROW_FIELD_EQ(tx_prev_note_hash_tree_size, 65),
250 ROW_FIELD_EQ(tx_prev_num_note_hashes_emitted, 1),
251 ROW_FIELD_EQ(tx_next_note_hash_tree_root, 27),
252 ROW_FIELD_EQ(tx_next_note_hash_tree_size, 128),
253 ROW_FIELD_EQ(tx_prev_nullifier_tree_root, 28),
254 ROW_FIELD_EQ(tx_prev_nullifier_tree_size, 127),
255 ROW_FIELD_EQ(tx_prev_num_nullifiers_emitted, 63),
256 ROW_FIELD_EQ(tx_next_nullifier_tree_root, 28),
257 ROW_FIELD_EQ(tx_next_nullifier_tree_size, 128)));
258}
259
260TEST(TxTraceGenTest, CleanupEvent)
261{
262 TestTraceContainer trace;
263 TxTraceBuilder builder;
264
265 simulation::TxStartupEvent startup_event = {
266 .gas_used = { 500, 1000 },
267 .gas_limit = { 1000, 2000 },
268 .teardown_gas_limit = { 0, 0 },
269 };
270
271 simulation::TxPhaseEvent tx_event = { .phase = TransactionPhase::CLEANUP,
272 .state_before = {},
273 .state_after = {},
274 .reverted = false,
275 .event = simulation::CleanupEvent{} };
276
277 builder.process({ startup_event, tx_event }, trace);
278 auto rows = trace.as_rows();
279 ASSERT_EQ(rows.size(), 2); // 0th precomputed, cleanup
280
281 EXPECT_THAT(
282 rows[1],
283 AllOf(ROW_FIELD_EQ(tx_sel, 1),
284 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::CLEANUP)),
285 ROW_FIELD_EQ(tx_start_phase, 1),
286 ROW_FIELD_EQ(tx_end_phase, 1),
287 ROW_FIELD_EQ(tx_is_cleanup, 1),
288 ROW_FIELD_EQ(tx_remaining_phase_counter, 1),
289 ROW_FIELD_EQ(tx_remaining_phase_inv, 1),
291 ROW_FIELD_EQ(tx_sel_read_trees_and_gas_used, 1),
293 ROW_FIELD_EQ(tx_sel_read_trees_and_gas_used, 1),
297 ROW_FIELD_EQ(tx_reverted_pi_offset, AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX)));
298}
299
300TEST(TxTraceGenTest, CleanupRevertedEvent)
301{
302 TestTraceContainer trace;
303 TxTraceBuilder builder;
304
305 simulation::TxStartupEvent startup_event = {
306 .gas_used = { 500, 1000 },
307 .gas_limit = { 1000, 2000 },
308 .teardown_gas_limit = { 0, 0 },
309 };
310
311 simulation::TxPhaseEvent tx_event = { .phase = TransactionPhase::R_NOTE_INSERTION,
312 .state_before = {},
313 .state_after = {},
314 .reverted = true,
315 .event = simulation::PrivateAppendTreeEvent{} };
316
317 simulation::TxPhaseEvent cleanup_event = { .phase = TransactionPhase::CLEANUP,
318 .state_before = {},
319 .state_after = {},
320 .reverted = false,
321 .event = simulation::CleanupEvent{} };
322
323 builder.process({ startup_event, tx_event, cleanup_event }, trace);
324 auto rows = trace.as_rows();
325 ASSERT_EQ(rows.size(), 3); // 0th precomputed, tx, cleanup
326
327 // Note insertion:
328 EXPECT_THAT(rows[1],
329 AllOf(ROW_FIELD_EQ(tx_sel, 1),
330 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::R_NOTE_INSERTION)),
331 ROW_FIELD_EQ(tx_start_phase, 1),
332 ROW_FIELD_EQ(tx_end_phase, 1),
333 ROW_FIELD_EQ(tx_is_cleanup, 0),
334 ROW_FIELD_EQ(tx_reverted, 1),
335 ROW_FIELD_EQ(tx_tx_reverted, 1)));
336
337 // Cleanup:
338 EXPECT_THAT(
339 rows[2],
340 AllOf(ROW_FIELD_EQ(tx_sel, 1),
341 ROW_FIELD_EQ(tx_phase_value, static_cast<uint8_t>(TransactionPhase::CLEANUP)),
342 ROW_FIELD_EQ(tx_start_phase, 1),
343 ROW_FIELD_EQ(tx_end_phase, 1),
344 ROW_FIELD_EQ(tx_is_cleanup, 1),
345 ROW_FIELD_EQ(tx_reverted, 0),
346 ROW_FIELD_EQ(tx_tx_reverted, 1),
347 ROW_FIELD_EQ(tx_remaining_phase_counter, 1),
348 ROW_FIELD_EQ(tx_remaining_phase_inv, 1),
350 ROW_FIELD_EQ(tx_sel_read_trees_and_gas_used, 1),
355 ROW_FIELD_EQ(tx_reverted_pi_offset, AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX)));
356}
357
358} // namespace
359} // namespace bb::avm2::tracegen
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_L1_TO_L2_MESSAGE_TREE_ROW_IDX
#define AVM_PUBLIC_INPUTS_EFFECTIVE_GAS_FEES_ROW_IDX
#define AVM_PUBLIC_INPUTS_FEE_PAYER_ROW_IDX
#define AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_NULLIFIERS_ROW_IDX
#define AVM_PUBLIC_INPUTS_TRANSACTION_FEE_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_GAS_USED_ROW_IDX
#define AVM_PUBLIC_INPUTS_PUBLIC_SETUP_CALL_REQUESTS_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NULLIFIER_TREE_ROW_IDX
#define AVM_PUBLIC_INPUTS_PREVIOUS_NON_REVERTIBLE_ACCUMULATED_DATA_ARRAY_LENGTHS_NULLIFIERS_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_NOTE_HASH_TREE_ROW_IDX
#define AVM_PUBLIC_INPUTS_REVERTED_ROW_IDX
#define AVM_PUBLIC_INPUTS_PUBLIC_CALL_REQUEST_ARRAY_LENGTHS_SETUP_CALLS_ROW_IDX
#define AVM_PUBLIC_INPUTS_GAS_SETTINGS_GAS_LIMITS_ROW_IDX
#define AVM_PUBLIC_INPUTS_END_TREE_SNAPSHOTS_PUBLIC_DATA_TREE_ROW_IDX
void process(const simulation::EventEmitterInterface< simulation::AluEvent >::Container &events, TraceContainer &trace)
Process the ALU events and populate the ALU relevant columns in the trace.
std::vector< AvmFullRowConstRef > as_rows() const
AluTraceBuilder builder
Definition alu.test.cpp:124
TestTraceContainer trace
#define ROW_FIELD_EQ(field_name, expression)
Definition macros.hpp:15
AvmFlavorSettings::FF FF
Definition field.hpp:10
TEST(BoomerangMegaCircuitBuilder, BasicCircuit)
unsigned __int128 uint128_t
Definition serialize.hpp:44
static field random_element(numeric::RNG *engine=nullptr) noexcept