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 "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_FAILURE_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);
72 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_FAILURE_MUST_DISCARD),
73 "FAILURE_MUST_DISCARD");
74}
75
76TEST(TxDiscardConstrainingTest, LastRowOfSetupCalculation)
77{
78 // Test LAST_ROW_OF_SETUP = (1 - is_revertible) * is_revertible'
79 TestTraceContainer trace({
80 { { C::precomputed_first_row, 1 } },
81 // Row 1: Not revertible (setup phase)
82 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
83 // Row 2: Still not revertible
84 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
85 // Row 3: Last row of setup (not revertible -> revertible transition)
86 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
87 // Row 4: First revertible row
88 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
89 // Row 5: Still revertible
90 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
91 { { C::tx_sel, 0 } },
92 });
93
94 // This should pass - the transition from non-revertible to revertible lifts propagation
95 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
96}
97
98TEST(TxDiscardConstrainingTest, DiscardPropagationNormal)
99{
100 // Test normal propagation of discard value
101 TestTraceContainer trace({
102 { { C::precomputed_first_row, 1 } },
103 // Row 1: discard=1, should propagate
104 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
105 // Row 2: discard=1 (propagated)
106 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
107 // Row 3: discard=1, reverted=1 (propagated, but failure now encountered)
108 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
109 // Row 4: discard=0 (reset to 0 because propagation lifted at failure)
110 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
111 { { C::tx_sel, 0 } },
112 });
113
114 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
115
116 // Negative test: discard doesn't propagate when it should
117 trace.set(C::tx_discard, 2, 0);
118 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION),
119 "DISCARD_PROPAGATION");
120 // reset discard to 1
121 trace.set(C::tx_discard, 2, 1);
122}
123
124TEST(TxDiscardConstrainingTest, DiscardPropagationLiftedAtSetupEnd)
125{
126 // Test propagation lifted at the last row of setup
127 TestTraceContainer trace({
128 { { C::precomputed_first_row, 1 } },
129 // Row 1: Setup phase (not revertible)
130 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
131 // Row 2: Last row of setup
132 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
133 // Row 3: First revertible row - discard can change
134 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
135 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
136 { { C::tx_sel, 0 } },
137 });
138
139 // This should pass because transition from non-revertible to revertible lifts propagation
140 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
141}
142
143TEST(TxDiscardConstrainingTest, DiscardPropagationLiftedOnFailure)
144{
145 // Test propagation lifted when reverted=1
146 TestTraceContainer trace({
147 { { C::precomputed_first_row, 1 } },
148 // Row 1: discard=1
149 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
150 // Row 2: discard=1 (propagated)
151 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } }, // Failure here
152 // Row 3: discard can be 0 (propagation lifted due to failure)
153 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
154 { { C::tx_sel, 0 } },
155 });
156
157 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION);
158}
159
160TEST(TxDiscardConstrainingTest, FailureOnlyInRevertibles)
161{
162 TestTraceContainer trace({
163 { { C::precomputed_first_row, 1 } },
164 // Non-revertibles and setup phases
165 // Discard must be 0 because setup phase is not revertible.
166 // Propagate discard=0 through non-revertibles and setup phases.
167 // Lift propagation of discard at end of setup.
168 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
169 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
170 // Start revertibles
171 // Discard=1 because revertibles fail later
172 // Propagate discard=1 through revertibles.
173 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
174 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
175 // Padding for app-logic
176 // Lift propagation of discard when revertibles fail. Discard=0 for padding row.
177 // Propagate discard=0 through app-logic padding to teardown.
178 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
179 // Teardown without failure
180 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
181 { { C::tx_sel, 0 } },
182 });
183
184 // Check all subrelations
185 check_relation<tx_discard_relation>(trace);
186}
187
188TEST(TxDiscardConstrainingTest, FailureOnlyInAppLogic)
189{
190 TestTraceContainer trace({
191 { { C::precomputed_first_row, 1 } },
192 // Non-revertibles and setup phases
193 // Discard must be 0 because setup phase is not revertible.
194 // Propagate discard=0 through non-revertibles and setup phases.
195 // Lift propagation of discard at end of setup.
196 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
197 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
198 // Start revertibles and app logic
199 // Discard=1 because app-logic fails later
200 // Propagate discard=1 through revertibles and app logic.
201 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
202 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
203 // Failure in app logic
204 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
205 // Teardown without failure
206 // Lift propagation of discard when app-logic failure is encountered.
207 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
208 { { C::tx_sel, 0 } },
209 });
210
211 // Check all subrelations
212 check_relation<tx_discard_relation>(trace);
213}
214
215TEST(TxDiscardConstrainingTest, FailureOnlyInTeardown)
216{
217 TestTraceContainer trace({
218 { { C::precomputed_first_row, 1 } },
219 // Non-revertibles and setup phases
220 // Discard must be 0 because setup phase is not revertible.
221 // Propagate discard=0 through non-revertibles and setup phases.
222 // Lift propagation of discard at end of setup.
223 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
224 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
225 // Start revertibles and app logic
226 // Discard=1 because later teardown fails
227 // Propagate discard=1 through revertibles, app logic, and teardown
228 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
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 // Teardown fails, discard=1
232 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
233 { { C::tx_sel, 0 } },
234 });
235
236 // Check all subrelations
237 check_relation<tx_discard_relation>(trace);
238
239 // Negative test: discard=0 somewhere in revertibles, but teardown fails
240 trace.set(C::tx_discard, 3, 0);
241 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION),
242 "DISCARD_PROPAGATION");
243 // reset discard to 1
244 trace.set(C::tx_discard, 3, 1);
245}
246
247TEST(TxDiscardConstrainingTest, FailureInRevertiblesAndTeardown)
248{
249 TestTraceContainer trace({
250 { { C::precomputed_first_row, 1 } },
251 // Non-revertibles and setup phases
252 // Discard must be 0 because setup phase is not revertible.
253 // Propagate discard=0 through non-revertibles and setup phases.
254 // Lift propagation of discard at end of setup.
255 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
256 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
257 // Start revertibles and app logic
258 // Discard=1 because revertibles fail later
259 // Propagate discard=1 through revertibles and app logic.
260 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
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, 1 } },
263 // Teardown fails too, discard=1
264 // Lift discard propagation, but teardown fails too, so discard remains 1.
265 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
266 { { C::tx_sel, 0 } },
267 });
268
269 // Check all subrelations
270 check_relation<tx_discard_relation>(trace);
271}
272
273TEST(TxDiscardConstrainingTest, DiscardButFailureNeverEncountered)
274{
275 TestTraceContainer trace({
276 { { C::precomputed_first_row, 1 } },
277 // Non-revertibles and setup phases
278 // Discard must be 0 because setup phase is not revertible.
279 // Propagate discard=0 through non-revertibles and setup phases.
280 // Lift propagation of discard at end of setup.
281 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
282 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
283 // Start revertibles and app logic
284 // Propagate discard=1 through revertibles, app logic, and teardown
285 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 0 } },
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 // Teardown, discard=1, and failure=1 lifts propagation.
289 // THIS WILL BE EDITED later so that failure doesn't happen.
290 { { C::tx_sel, 1 }, { C::tx_discard, 1 }, { C::tx_is_revertible, 1 }, { C::tx_reverted, 1 } },
291 // Tree-padding & cleanup phases
292 // These are non-revertible.
293 // THESE WILL BE EDITED later so that they get discard=1, which should fail.
294 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
295 { { C::tx_sel, 1 }, { C::tx_discard, 0 }, { C::tx_is_revertible, 0 }, { C::tx_reverted, 0 } },
296 { { C::tx_sel, 0 } },
297 });
298
299 // Check all subrelations
300 check_relation<tx_discard_relation>(trace);
301
302 // Negative test: no failure encountered in teardown, so propagation is never lifted.
303 trace.set(C::tx_reverted, 6, 0);
304 EXPECT_THROW_WITH_MESSAGE(check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_DISCARD_PROPAGATION),
305 "DISCARD_PROPAGATION");
306 // now set the tree-padding & cleanup rows to discard so that propagation works,
307 // but it should still fail because you cannot discard in non-revertible phases.
308 trace.set(C::tx_discard, 7, 1);
309 trace.set(C::tx_discard, 8, 1);
310
312 check_relation<tx_discard_relation>(trace, tx_discard_relation::SR_CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES),
313 "CAN_ONLY_DISCARD_IN_REVERTIBLE_PHASES");
314
315 // reset all
316 trace.set(C::tx_reverted, 6, 0);
317 trace.set(C::tx_discard, 7, 0);
318 trace.set(C::tx_discard, 8, 0);
319}
320
321} // namespace
322} // namespace bb::avm2::constraining
void set(Column col, uint32_t row, const FF &value)
TestTraceContainer trace
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
TEST(TxExecutionConstrainingTest, WriteTreeValue)
Definition tx.test.cpp:508
TestTraceContainer empty_trace()
Definition fixtures.cpp:153
typename Flavor::FF FF