Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
gas_tracker.test.cpp
Go to the documentation of this file.
2
3#include <gmock/gmock.h>
4#include <gtest/gtest.h>
5
14
15using ::testing::Return;
16
17namespace bb::avm2::simulation {
18namespace {
19
20class GasTrackerTest : public ::testing::Test {
21 protected:
22 void SetUp() override
23 {
24 // Default context setup
25 ON_CALL(context, get_gas_used()).WillByDefault(Return(Gas{ 0, 0 }));
26 ON_CALL(context, get_gas_limit()).WillByDefault(Return(Gas{ 1000, 500 }));
27 }
28
29 InstructionInfoDB instruction_info_db;
30 testing::StrictMock<MockContext> context;
31 testing::StrictMock<MockRangeCheck> range_check;
33 GasEvent gas_event;
34};
35
36TEST_F(GasTrackerTest, BaseGasConsumption)
37{
40
41 // Test base gas consumption (no dynamic gas factor).
43 EXPECT_CALL(context, get_gas_used);
44 EXPECT_CALL(context, get_gas_limit);
45 EXPECT_CALL(context, set_gas_used(Gas{ l2_gas_used, 0 }));
46
47 EXPECT_CALL(range_check, assert_range(1000 - l2_gas_used, 64));
48 EXPECT_CALL(range_check, assert_range(500, 64));
49
50 tracker.consume_gas();
51
52 EXPECT_EQ(gas_event,
53 (GasEvent{
54 .addressing_gas = 0,
55 .dynamic_gas_factor = Gas{ 0, 0 },
56 .limit_used_l2_comparison_witness = 1000 - l2_gas_used,
57 .limit_used_da_comparison_witness = 500,
58 .oog_l2 = false,
59 .oog_da = false,
60 }));
61}
62
63TEST_F(GasTrackerTest, AddressingGasConsumption)
64{
66 // Indirect and relative
67 instruction.indirect = 0b11;
68 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
69
70 // Test base gas consumption
72 EXPECT_CALL(context, get_gas_used);
73 EXPECT_CALL(context, get_gas_limit);
74 EXPECT_CALL(context, set_gas_used(Gas{ l2_gas_used, 0 }));
75
76 EXPECT_CALL(range_check, assert_range(1000 - l2_gas_used, 64));
77 EXPECT_CALL(range_check, assert_range(500, 64));
78
79 tracker.consume_gas();
80
81 EXPECT_EQ(gas_event,
82 (GasEvent{
84 .dynamic_gas_factor = Gas{ 0, 0 },
85 .limit_used_l2_comparison_witness = 1000 - l2_gas_used,
86 .limit_used_da_comparison_witness = 500,
87 .oog_l2 = false,
88 .oog_da = false,
89 }));
90}
91
92TEST_F(GasTrackerTest, OutOfGasBase)
93{
95 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
96
97 // Set up context to be near gas limit
98 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ 999, 450 }));
99 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ 1000, 500 }));
101 // No call to set_gas_used in the tracker.
102
103 EXPECT_CALL(range_check, assert_range((999 + opcode_l2_gas) - 1000 - 1, 64));
104 EXPECT_CALL(range_check, assert_range(500 - 450, 64));
105
106 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(), "(base)");
107
108 EXPECT_EQ(gas_event,
109 (GasEvent{
110 .addressing_gas = 0,
111 .dynamic_gas_factor = Gas{ 0, 0 },
112 .limit_used_l2_comparison_witness = (999 + opcode_l2_gas) - 1000 - 1,
113 .limit_used_da_comparison_witness = 500 - 450,
114 .oog_l2 = true,
115 .oog_da = false,
116 }));
117}
118
119TEST_F(GasTrackerTest, DynamicGasConsumption)
120{
122 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
123
124 EXPECT_CALL(context, get_gas_used);
125 EXPECT_CALL(context, get_gas_limit);
127 uint32_t l2_dyn_computation = AVM_CALLDATACOPY_DYN_L2_GAS * 10;
128 EXPECT_CALL(context, set_gas_used(Gas{ l2_base_gas + l2_dyn_computation, 0 }));
129
130 EXPECT_CALL(range_check, assert_range(1000 - (l2_base_gas + l2_dyn_computation), 64));
131 EXPECT_CALL(range_check, assert_range(500, 64));
132
133 tracker.consume_gas(Gas{ 10, 0 });
134
135 EXPECT_EQ(gas_event,
136 (GasEvent{
138 .dynamic_gas_factor = Gas{ 10, 0 },
139 .limit_used_l2_comparison_witness = 1000 - (l2_base_gas + l2_dyn_computation),
140 .limit_used_da_comparison_witness = 500,
141 .oog_l2 = false,
142 .oog_da = false,
143 }));
144}
145
146TEST_F(GasTrackerTest, OutOfGasDynamicPhase)
147{
149 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
150
151 uint32_t l2_gas_limit = 1000;
152 uint32_t l2_gas_used_start = l2_gas_limit - AVM_CALLDATACOPY_BASE_L2_GAS - 50;
153 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ l2_gas_used_start, 0 }));
154 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ l2_gas_limit, 500 }));
155
157 uint32_t l2_dyn_computation = AVM_CALLDATACOPY_DYN_L2_GAS * 100;
158 EXPECT_CALL(range_check,
159 assert_range((l2_base_gas + l2_dyn_computation + l2_gas_used_start) - l2_gas_limit - 1, 64));
160 EXPECT_CALL(range_check, assert_range(500, 64));
161
162 // This should throw because total gas exceeds limit.
163 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(Gas{ 100, 0 }), "(dynamic)");
164
165 EXPECT_EQ(gas_event,
166 (GasEvent{
167 .addressing_gas = 0,
168 .dynamic_gas_factor = Gas{ 100, 0 },
169 .limit_used_l2_comparison_witness =
170 (l2_base_gas + l2_dyn_computation + l2_gas_used_start) - l2_gas_limit - 1,
171 .limit_used_da_comparison_witness = 500,
172 .oog_l2 = true,
173 .oog_da = false,
174 }));
175}
176
177TEST_F(GasTrackerTest, OutOfGasBothPhases)
178{
179 // The objective of this test is to check that the event is properly formed for the case
180 // where we would run out of gas due to base gas, but we would also run out of gas due to
181 // dynamic gas, independently, if we carried on.
183 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
184
185 uint32_t l2_gas_limit = 1000;
186 uint32_t l2_gas_used_start = l2_gas_limit - 1; // will be surpased by base gas.
187 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ l2_gas_used_start, 0 }));
188 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ l2_gas_limit, 500 }));
189
191 uint32_t l2_dyn_computation = AVM_CALLDATACOPY_DYN_L2_GAS * 100;
192 EXPECT_CALL(range_check,
193 assert_range((l2_base_gas + l2_dyn_computation + l2_gas_used_start) - l2_gas_limit - 1, 64));
194 EXPECT_CALL(range_check, assert_range(500, 64));
195
196 // This should throw because total gas exceeds limit.
197 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(Gas{ 100, 0 }), "(base)");
198
199 EXPECT_EQ(gas_event,
200 (GasEvent{
201 .addressing_gas = 0,
202 .dynamic_gas_factor = Gas{ 100, 0 },
203 .limit_used_l2_comparison_witness =
204 (l2_base_gas + l2_dyn_computation + l2_gas_used_start) - l2_gas_limit - 1,
205 .limit_used_da_comparison_witness = 500,
206 .oog_l2 = true,
207 .oog_da = false,
208 }));
209}
210
211TEST_F(GasTrackerTest, OutOfGasBasePhaseWithOverflow)
212{
214
215 constexpr uint32_t uint32_max = std::numeric_limits<uint32_t>::max();
216 constexpr uint32_t gas_limit = uint32_max;
217 constexpr uint32_t prev_gas_used = uint32_max;
218
219 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
220
221 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ prev_gas_used, 0 }));
222 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ gas_limit, gas_limit }));
223
225 EXPECT_CALL(range_check, assert_range(prev_gas_used + l2_opcode_gas - gas_limit - 1, 64)); // L2 OOG.
226 EXPECT_CALL(range_check, assert_range(gas_limit, 64)); // DA not OOG.
227
228 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(), "(base)");
229
230 EXPECT_EQ(gas_event,
231 (GasEvent{
232 .addressing_gas = 0,
233 .dynamic_gas_factor = Gas{ 0, 0 },
234 .limit_used_l2_comparison_witness = prev_gas_used + l2_opcode_gas - gas_limit - 1,
235 .limit_used_da_comparison_witness = gas_limit,
236 .oog_l2 = true,
237 .oog_da = false,
238 }));
239}
240
241TEST_F(GasTrackerTest, OutOfGasDynamicPhaseWithOverflow)
242{
244
245 constexpr uint32_t uint32_max = std::numeric_limits<uint32_t>::max();
246 uint32_t gas_limit = uint32_max;
247 uint32_t prev_gas_used = uint32_max - AVM_CALLDATACOPY_BASE_L2_GAS - /*some buffer*/ 50;
248 uint32_t gas_factor = uint32_max;
249
250 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
251
252 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ prev_gas_used, 0 }));
253 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ gas_limit, gas_limit }));
254
256 uint64_t l2_dyn_computation = static_cast<uint64_t>(AVM_CALLDATACOPY_DYN_L2_GAS) * gas_factor;
257 EXPECT_CALL(range_check,
258 assert_range(prev_gas_used + l2_base_opcode_gas + l2_dyn_computation - gas_limit - 1, 64)); // L2 OOG.
259 EXPECT_CALL(range_check, assert_range(gas_limit, 64)); // DA not OOG.
260
261 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(Gas{ gas_factor, 0 }), "(dynamic)");
262
263 EXPECT_EQ(
264 gas_event,
265 (GasEvent{
266 .addressing_gas = 0,
267 .dynamic_gas_factor = Gas{ gas_factor, 0 },
268 .limit_used_l2_comparison_witness = prev_gas_used + l2_base_opcode_gas + l2_dyn_computation - gas_limit - 1,
269 .limit_used_da_comparison_witness = gas_limit,
270 .oog_l2 = true,
271 .oog_da = false,
272 }));
273}
274
275TEST_F(GasTrackerTest, GasLimitForCall)
276{
278 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
279 Gas gas_left = Gas{ 500, 200 };
280 Gas allocated_gas = Gas{ 100, 150 };
281
282 EXPECT_CALL(context, gas_left()).WillOnce(Return(gas_left));
283
284 EXPECT_CALL(range_check, assert_range(gas_left.l2Gas - allocated_gas.l2Gas - 1, 32));
285 EXPECT_CALL(range_check, assert_range(gas_left.daGas - allocated_gas.daGas - 1, 32));
286 EXPECT_EQ(tracker.compute_gas_limit_for_call(allocated_gas), allocated_gas);
287}
288
289TEST_F(GasTrackerTest, GasLimitForCallClamping)
290{
292 GasTracker tracker(gas_event, instruction, instruction_info_db, context, range_check);
293 Gas gas_left = Gas{ 500, 200 };
294 Gas allocated_gas = Gas{ 1000, 100 };
295 Gas clamped_gas = Gas{ 500, 100 };
296
297 EXPECT_CALL(context, gas_left()).WillOnce(Return(gas_left));
298
299 EXPECT_CALL(range_check, assert_range(allocated_gas.l2Gas - gas_left.l2Gas, 32));
300 EXPECT_CALL(range_check, assert_range(gas_left.daGas - allocated_gas.daGas - 1, 32));
301 EXPECT_EQ(tracker.compute_gas_limit_for_call(allocated_gas), clamped_gas);
302}
303
304} // namespace
305} // namespace bb::avm2::simulation
#define AVM_CALLDATACOPY_DYN_L2_GAS
#define AVM_SET_BASE_L2_GAS
#define AVM_CALLDATACOPY_BASE_L2_GAS
RangeCheck range_check
StrictMock< MockContext > context
InstructionInfoDB instruction_info_db
GasEvent gas_event
Instruction instruction
#define EXPECT_THROW_WITH_MESSAGE(code, expectedMessage)
Definition macros.hpp:7
uint32_t compute_addressing_gas(uint16_t indirect_flag)
Definition gas.cpp:10
TEST_F(IPATest, ChallengesAreZero)
Definition ipa.test.cpp:123
Instruction
Enumeration of VM instructions that can be executed.