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 <cstdint>
4#include <gmock/gmock.h>
5#include <gtest/gtest.h>
6
15
16using ::testing::Return;
17
18namespace bb::avm2::simulation {
19namespace {
20
21class GasTrackerTest : public ::testing::Test {
22 protected:
23 void SetUp() override
24 {
25 // Default context setup
26 ON_CALL(context, get_gas_used()).WillByDefault(Return(Gas{ 0, 0 }));
27 ON_CALL(context, get_gas_limit()).WillByDefault(Return(Gas{ 1000, 500 }));
28 }
29
30 InstructionInfoDB instruction_info_db;
31 testing::StrictMock<MockContext> context;
32 testing::StrictMock<MockGreaterThan> greater_than;
34 GasEvent gas_event;
35};
36
37TEST_F(GasTrackerTest, BaseGasConsumption)
38{
41
42 // Test base gas consumption (no dynamic gas factor).
44 EXPECT_CALL(context, get_gas_used);
45 EXPECT_CALL(context, get_gas_limit);
46 EXPECT_CALL(context, set_gas_used(Gas{ l2_gas_used, 0 }));
47
48 EXPECT_CALL(greater_than, gt(l2_gas_used, 1000));
49 EXPECT_CALL(greater_than, gt(0, 500));
50
51 tracker.consume_gas();
52
53 EXPECT_EQ(gas_event,
54 (GasEvent{
55 .addressing_gas = 0,
56 .dynamic_gas_factor = Gas{ 0, 0 },
57 .total_gas_used_l2 = l2_gas_used,
58 .total_gas_used_da = 0,
59 .oog_l2 = false,
60 .oog_da = false,
61 }));
62}
63
64TEST_F(GasTrackerTest, AddressingGasConsumption)
65{
67 // Indirect and relative
68 instruction.indirect = 0b11;
69 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
70
71 // Test base gas consumption
73 EXPECT_CALL(context, get_gas_used);
74 EXPECT_CALL(context, get_gas_limit);
75 EXPECT_CALL(context, set_gas_used(Gas{ l2_gas_used, 0 }));
76
77 EXPECT_CALL(greater_than, gt(l2_gas_used, 1000));
78 EXPECT_CALL(greater_than, gt(0, 500));
79
80 tracker.consume_gas();
81
82 EXPECT_EQ(gas_event,
83 (GasEvent{
85 .dynamic_gas_factor = Gas{ 0, 0 },
86 .total_gas_used_l2 = l2_gas_used,
87 .total_gas_used_da = 0,
88 .oog_l2 = false,
89 .oog_da = false,
90 }));
91}
92
93TEST_F(GasTrackerTest, OutOfGasBase)
94{
96 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
97
98 // Set up context to be near gas limit
99 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ 999, 450 }));
100 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ 1000, 500 }));
102 // No call to set_gas_used in the tracker.
103
104 EXPECT_CALL(greater_than, gt(999 + opcode_l2_gas, 1000)).WillOnce(Return(true));
105 EXPECT_CALL(greater_than, gt(450, 500)).WillOnce(Return(false));
106
107 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(), "(base)");
108
109 EXPECT_EQ(gas_event,
110 (GasEvent{
111 .addressing_gas = 0,
112 .dynamic_gas_factor = Gas{ 0, 0 },
113 .total_gas_used_l2 = 999 + opcode_l2_gas,
114 .total_gas_used_da = 450,
115 .oog_l2 = true,
116 .oog_da = false,
117 }));
118}
119
120TEST_F(GasTrackerTest, DynamicGasConsumption)
121{
123 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
124
125 EXPECT_CALL(context, get_gas_used);
126 EXPECT_CALL(context, get_gas_limit);
128 uint32_t l2_dyn_computation = AVM_CALLDATACOPY_DYN_L2_GAS * 10;
129 EXPECT_CALL(context, set_gas_used(Gas{ l2_base_gas + l2_dyn_computation, 0 }));
130
131 EXPECT_CALL(greater_than, gt(l2_base_gas + l2_dyn_computation, 1000));
132 EXPECT_CALL(greater_than, gt(0, 500));
133
134 tracker.consume_gas(Gas{ 10, 0 });
135
136 EXPECT_EQ(gas_event,
137 (GasEvent{
139 .dynamic_gas_factor = Gas{ 10, 0 },
140 .total_gas_used_l2 = l2_base_gas + l2_dyn_computation,
141 .total_gas_used_da = 0,
142 .oog_l2 = false,
143 .oog_da = false,
144 }));
145}
146
147TEST_F(GasTrackerTest, OutOfGasDynamicPhase)
148{
150 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
151
152 uint32_t l2_gas_limit = 1000;
153 uint32_t l2_gas_used_start = l2_gas_limit - AVM_CALLDATACOPY_BASE_L2_GAS - 50;
154 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ l2_gas_used_start, 0 }));
155 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ l2_gas_limit, 500 }));
156
158 uint32_t l2_dyn_computation = AVM_CALLDATACOPY_DYN_L2_GAS * 100;
159 EXPECT_CALL(greater_than, gt(l2_base_gas + l2_dyn_computation + l2_gas_used_start, l2_gas_limit))
160 .WillOnce(Return(true));
161 EXPECT_CALL(greater_than, gt(0, 500)).WillOnce(Return(false));
162
163 // This should throw because total gas exceeds limit.
164 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(Gas{ 100, 0 }), "(dynamic)");
165
166 EXPECT_EQ(gas_event,
167 (GasEvent{
168 .addressing_gas = 0,
169 .dynamic_gas_factor = Gas{ 100, 0 },
170 .total_gas_used_l2 = l2_base_gas + l2_dyn_computation + l2_gas_used_start,
171 .total_gas_used_da = 0,
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, greater_than);
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(greater_than, gt(l2_base_gas + l2_dyn_computation + l2_gas_used_start, l2_gas_limit))
193 .WillOnce(Return(true));
194 EXPECT_CALL(greater_than, gt(0, 500)).WillOnce(Return(false));
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 .total_gas_used_l2 = l2_base_gas + l2_dyn_computation + l2_gas_used_start,
204 .total_gas_used_da = 0,
205 .oog_l2 = true,
206 .oog_da = false,
207 }));
208}
209
210TEST_F(GasTrackerTest, OutOfGasBasePhaseWithOverflow)
211{
213
214 constexpr uint32_t uint32_max = std::numeric_limits<uint32_t>::max();
215 constexpr uint32_t gas_limit = uint32_max;
216 constexpr uint32_t prev_gas_used = uint32_max;
217
218 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
219
220 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ prev_gas_used, 0 }));
221 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ gas_limit, gas_limit }));
222
224 EXPECT_CALL(greater_than,
225 gt(static_cast<uint64_t>(prev_gas_used) + static_cast<uint64_t>(l2_opcode_gas), gas_limit))
226 .WillOnce(Return(true)); // L2 OOG.
227 EXPECT_CALL(greater_than, gt(0, gas_limit)).WillOnce(Return(false)); // DA not OOG.
228
229 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(), "(base)");
230
231 EXPECT_EQ(gas_event,
232 (GasEvent{
233 .addressing_gas = 0,
234 .dynamic_gas_factor = Gas{ 0, 0 },
235 .total_gas_used_l2 = static_cast<uint64_t>(prev_gas_used) + static_cast<uint64_t>(l2_opcode_gas),
236 .total_gas_used_da = 0,
237 .oog_l2 = true,
238 .oog_da = false,
239 }));
240}
241
242TEST_F(GasTrackerTest, OutOfGasDynamicPhaseWithOverflow)
243{
245
246 constexpr uint32_t uint32_max = std::numeric_limits<uint32_t>::max();
247 uint32_t gas_limit = uint32_max;
248 uint32_t prev_gas_used = uint32_max - AVM_CALLDATACOPY_BASE_L2_GAS - /*some buffer*/ 50;
249 uint32_t gas_factor = uint32_max;
250
251 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
252
253 EXPECT_CALL(context, get_gas_used).WillOnce(Return(Gas{ prev_gas_used, 0 }));
254 EXPECT_CALL(context, get_gas_limit).WillOnce(Return(Gas{ gas_limit, gas_limit }));
255
257 uint64_t l2_dyn_computation = static_cast<uint64_t>(AVM_CALLDATACOPY_DYN_L2_GAS) * gas_factor;
258 EXPECT_CALL(
259 greater_than,
260 gt(static_cast<uint64_t>(prev_gas_used) + static_cast<uint64_t>(l2_base_opcode_gas) + l2_dyn_computation,
261 static_cast<uint64_t>(gas_limit)))
262 .WillOnce(Return(true)); // L2 OOG.
263 EXPECT_CALL(greater_than, gt(0, gas_limit)).WillOnce(Return(false)); // DA not OOG.
264
265 EXPECT_THROW_WITH_MESSAGE(tracker.consume_gas(Gas{ gas_factor, 0 }), "(dynamic)");
266
267 EXPECT_EQ(gas_event,
268 (GasEvent{
269 .addressing_gas = 0,
270 .dynamic_gas_factor = Gas{ gas_factor, 0 },
271 .total_gas_used_l2 = prev_gas_used + l2_base_opcode_gas + l2_dyn_computation,
272 .total_gas_used_da = 0,
273 .oog_l2 = true,
274 .oog_da = false,
275 }));
276}
277
278TEST_F(GasTrackerTest, GasLimitForCall)
279{
281 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
282 Gas gas_left = Gas{ 500, 200 };
283 Gas allocated_gas = Gas{ 100, 150 };
284
285 EXPECT_CALL(context, gas_left()).WillOnce(Return(gas_left));
286
287 EXPECT_CALL(greater_than, gt(gas_left.l2Gas, allocated_gas.l2Gas)).WillOnce(Return(true));
288 EXPECT_CALL(greater_than, gt(gas_left.daGas, allocated_gas.daGas)).WillOnce(Return(true));
289 EXPECT_EQ(tracker.compute_gas_limit_for_call(allocated_gas), allocated_gas);
290}
291
292TEST_F(GasTrackerTest, GasLimitForCallClamping)
293{
295 GasTracker tracker(gas_event, instruction, instruction_info_db, context, greater_than);
296 Gas gas_left = Gas{ 500, 200 };
297 Gas allocated_gas = Gas{ 1000, 100 };
298 Gas clamped_gas = Gas{ 500, 100 };
299
300 EXPECT_CALL(context, gas_left()).WillOnce(Return(gas_left));
301
302 EXPECT_CALL(greater_than, gt(gas_left.l2Gas, allocated_gas.l2Gas)).WillOnce(Return(false));
303 EXPECT_CALL(greater_than, gt(gas_left.daGas, allocated_gas.daGas)).WillOnce(Return(true));
304 EXPECT_EQ(tracker.compute_gas_limit_for_call(allocated_gas), clamped_gas);
305}
306
307} // namespace
308} // namespace bb::avm2::simulation
#define AVM_CALLDATACOPY_DYN_L2_GAS
#define AVM_SET_BASE_L2_GAS
#define AVM_CALLDATACOPY_BASE_L2_GAS
GreaterThan gt
StrictMock< MockContext > context
InstructionInfoDB instruction_info_db
GasEvent gas_event
Instruction instruction
testing::StrictMock< MockGreaterThan > greater_than
#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:188
Instruction
Enumeration of VM instructions that can be executed.