Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
tx_discard.test.cpp
Go to the documentation of this file.
1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
3
4#include <cstdint>
5
13
14namespace bb::avm2::constraining {
15namespace {
16
17using tracegen::TestTraceContainer;
19using C = Column;
20using tx_discard_relation = bb::avm2::tx_discard<FF>;
21
22TEST(TxDiscardConstrainingTest, EmptyRow)
23{
24 check_relation<tx_discard_relation>(testing::empty_trace());
25}
26
27TEST(TxDiscardConstrainingTest, CanOnlyDiscardInRevertiblePhases)
28{
29 // Test that discard=1 => is_revertible=1
30 TestTraceContainer trace({
31 { { C::precomputed_first_row, 1 } },
32 // Valid: discard=0, is_revertible=0
33 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
34 // Valid: discard=0, is_revertible=1
35 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
36 // Valid: discard=1, is_revertible=1
37 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
38 { { C::tx_sel, 0 } },
39 });
40
41 // Check subrelation 1 (discard requires revertible)
42 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES);
43
44 // Negative test: discard=1 but is_revertible=0
45 trace.set(C::tx_discard, 1, 1);
46 trace.set(C::tx_is_revertible, 1, 0);
48 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES),
49 tx_discard_relation::get_subrelation_label(tx_discard_relation::SR_CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES));
50}
51
52TEST(TxDiscardConstrainingTest, FailureMustDiscard)
53{
54 // Test that reverted=1 => discard=1
55 TestTraceContainer trace({
56 { { C::precomputed_first_row, 1 } },
57 // Valid: reverted=0, discard=0
58 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
59 // Valid: reverted=1, discard=1
60 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
61 // Valid: reverted=0, discard=1 (discard doesn't imply failure)
62 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
63 { { C::tx_sel, 0 } },
64 });
65
66 // Check FAILURE_MUST_DISCARD subrelation
67 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_REVERTED_MUST_DISCARD);
68
69 // Negative test: reverted=1 but discard=0
70 trace.set(C::tx_reverted, 1, 1);
71 trace.set(C::tx_discard, 1, 0);
73 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_REVERTED_MUST_DISCARD),
74 tx_discard_relation::get_subrelation_label(tx_discard_relation::SR_REVERTED_MUST_DISCARD));
75}
76
77TEST(TxDiscardConstrainingTest, LastRowOfSetupCalculation)
78{
79 // Test LAST_ROW_OF_SETUP = (1 - is_revertible) * is_revertible'
80 TestTraceContainer trace({
81 { { C::precomputed_first_row, 1 } },
82 // Row 1: Not revertible (setup phase)
83 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
84 // Row 2: Still not revertible
85 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
86 // Row 3: Last row of setup (not revertible -> revertible transition)
87 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
88 // Row 4: First revertible row
89 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
90 // Row 5: Still revertible
91 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
92 { { C::tx_sel, 0 } },
93 });
94
95 // This should pass - the transition from non-revertible to revertible lifts propagation
96 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
97}
98
99TEST(TxDiscardConstrainingTest, DiscardPropagationNormal)
100{
101 // Test normal propagation of discard value
102 TestTraceContainer trace({
103 { { C::precomputed_first_row, 1 } },
104 // Row 1: discard=1, should propagate
105 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
106 // Row 2: discard=1 (propagated)
107 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
108 // Row 3: discard=1, reverted=1 (propagated, but failure now encountered)
109 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
110 // Row 4: discard=0 (reset to 0 because propagation lifted at failure)
111 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
112 { { C::tx_sel, 0 } },
113 });
114
115 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
116
117 // Negative test: discard doesn't propagate when it should
118 trace.set(C::tx_discard, 2, 0);
119 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION),
120 tx_discard_relation::get_subrelation_label(tx_discard_relation::SR_DISCARD_PROPAGATION));
121 // reset discard to 1
122 trace.set(C::tx_discard, 2, 1);
123}
124
125TEST(TxDiscardConstrainingTest, DiscardPropagationLiftedAtSetupEnd)
126{
127 // Test propagation lifted at the last row of setup
128 TestTraceContainer trace({
129 { { C::precomputed_first_row, 1 } },
130 // Row 1: Setup phase (not revertible)
131 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
132 // Row 2: Last row of setup
133 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
134 // Row 3: First revertible row - discard can change
135 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
136 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
137 { { C::tx_sel, 0 } },
138 });
139
140 // This should pass because transition from non-revertible to revertible lifts propagation
141 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
142}
143
144TEST(TxDiscardConstrainingTest, DiscardPropagationLiftedOnFailure)
145{
146 // Test propagation lifted when reverted=1
147 TestTraceContainer trace({
148 { { C::precomputed_first_row, 1 } },
149 // Row 1: discard=1
150 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
151 // Row 2: discard=1 (propagated)
152 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } }, // Failure here
153 // Row 3: discard can be 0 (propagation lifted due to failure)
154 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
155 { { C::tx_sel, 0 } },
156 });
157
158 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
159}
160
161TEST(TxDiscardConstrainingTest, FailureOnlyInRevertibles)
162{
163 TestTraceContainer trace({
164 { { C::precomputed_first_row, 1 } },
165 // Non-revertibles and setup phases
166 // Discard must be 0 because setup phase is not revertible.
167 // Propagate discard=0 through non-revertibles and setup phases.
168 // Lift propagation of discard at end of setup.
169 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
170 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
171 // Start revertibles
172 // Discard=1 because revertibles fail later
173 // Propagate discard=1 through revertibles.
174 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
175 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
176 // Padding for app-logic
177 // Lift propagation of discard when revertibles fail. Discard=0 for padding row.
178 // Propagate discard=0 through app-logic padding to teardown.
179 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
180 // Teardown without failure
181 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
182 { { C::tx_sel, 0 } },
183 });
184
185 // Check all subrelations
186 check_relation<tx_discard_relation>(trace);
187}
188
189TEST(TxDiscardConstrainingTest, FailureOnlyInAppLogic)
190{
191 TestTraceContainer trace({
192 { { C::precomputed_first_row, 1 } },
193 // Non-revertibles and setup phases
194 // Discard must be 0 because setup phase is not revertible.
195 // Propagate discard=0 through non-revertibles and setup phases.
196 // Lift propagation of discard at end of setup.
197 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
198 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
199 // Start revertibles and app logic
200 // Discard=1 because app-logic fails later
201 // Propagate discard=1 through revertibles and app logic.
202 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
203 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
204 // Failure in app logic
205 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
206 // Teardown without failure
207 // Lift propagation of discard when app-logic failure is encountered.
208 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
209 { { C::tx_sel, 0 } },
210 });
211
212 // Check all subrelations
213 check_relation<tx_discard_relation>(trace);
214}
215
216TEST(TxDiscardConstrainingTest, FailureOnlyInTeardown)
217{
218 TestTraceContainer trace({
219 { { C::precomputed_first_row, 1 } },
220 // Non-revertibles and setup phases
221 // Discard must be 0 because setup phase is not revertible.
222 // Propagate discard=0 through non-revertibles and setup phases.
223 // Lift propagation of discard at end of setup.
224 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
225 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
226 // Start revertibles and app logic
227 // Discard=1 because later teardown fails
228 // Propagate discard=1 through revertibles, app logic, and teardown
229 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
230 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
231 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
232 // Teardown fails, discard=1
233 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
234 { { C::tx_sel, 0 } },
235 });
236
237 // Check all subrelations
238 check_relation<tx_discard_relation>(trace);
239
240 // Negative test: discard=0 somewhere in revertibles, but teardown fails
241 trace.set(C::tx_discard, 3, 0);
242 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION),
243 tx_discard_relation::get_subrelation_label(tx_discard_relation::SR_DISCARD_PROPAGATION));
244 // reset discard to 1
245 trace.set(C::tx_discard, 3, 1);
246}
247
248TEST(TxDiscardConstrainingTest, FailureInRevertiblesAndTeardown)
249{
250 TestTraceContainer trace({
251 { { C::precomputed_first_row, 1 } },
252 // Non-revertibles and setup phases
253 // Discard must be 0 because setup phase is not revertible.
254 // Propagate discard=0 through non-revertibles and setup phases.
255 // Lift propagation of discard at end of setup.
256 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
257 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
258 // Start revertibles and app logic
259 // Discard=1 because revertibles fail later
260 // Propagate discard=1 through revertibles and app logic.
261 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
262 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
263 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
264 // Teardown fails too, discard=1
265 // Lift discard propagation, but teardown fails too, so discard remains 1.
266 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
267 { { C::tx_sel, 0 } },
268 });
269
270 // Check all subrelations
271 check_relation<tx_discard_relation>(trace);
272}
273
274TEST(TxDiscardConstrainingTest, DiscardButFailureNeverEncountered)
275{
276 TestTraceContainer trace({
277 { { C::precomputed_first_row, 1 } },
278 // Non-revertibles and setup phases
279 // Discard must be 0 because setup phase is not revertible.
280 // Propagate discard=0 through non-revertibles and setup phases.
281 // Lift propagation of discard at end of setup.
282 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
283 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
284 // Start revertibles and app logic
285 // Propagate discard=1 through revertibles, app logic, and teardown
286 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
287 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
288 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
289 // Teardown, discard=1, and failure=1 lifts propagation.
290 // THIS WILL BE EDITED later so that failure doesn't happen.
291 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
292 // Tree-padding & cleanup phases
293 // These are non-revertible.
294 // THESE WILL BE EDITED later so that they get discard=1, which should fail.
295 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
296 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
297 { { C::tx_sel, 0 } },
298 });
299
300 // Check all subrelations
301 check_relation<tx_discard_relation>(trace);
302
303 // Negative test: no failure encountered in teardown, so propagation is never lifted.
304 trace.set(C::tx_reverted, 6, 0);
305 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION),
306 tx_discard_relation::get_subrelation_label(tx_discard_relation::SR_DISCARD_PROPAGATION));
307 // now set the tree-padding & cleanup rows to discard so that propagation works,
308 // but it should still fail because you cannot discard in non-revertible phases.
309 trace.set(C::tx_discard, 7, 1);
310 trace.set(C::tx_discard, 8, 1);
311
313 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES),
314 tx_discard_relation::get_subrelation_label(tx_discard_relation::SR_CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES));
315
316 // reset all
317 trace.set(C::tx_reverted, 6, 0);
318 trace.set(C::tx_discard, 7, 0);
319 trace.set(C::tx_discard, 8, 0);
320}
321
322} // namespace
323} // namespace bb::avm2::constraining
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessageRegex)
Definition assert.hpp:224
void set(Column col, uint32_t row, const FF &value, bool use_atomic_limbs=false)
TestTraceContainer trace
TEST(AvmFixedVKTests, FixedVKCommitments)
Test that the fixed VK commitments agree with the ones computed from precomputed columns.
TestTraceContainer empty_trace()
Definition fixtures.cpp:156