Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
gas_tracker.cpp
Go to the documentation of this file.
2
3#include <cstddef>
4#include <cstdint>
5
7
8namespace bb::avm2::simulation {
9namespace {
10
11// Wider type used for intermediate gas calculations.
12struct IntermediateGas {
13 uint64_t l2Gas;
14 uint64_t daGas;
15
16 IntermediateGas operator+(const IntermediateGas& other) const
17 {
18 return IntermediateGas{ .l2Gas = l2Gas + other.l2Gas, .daGas = daGas + other.daGas };
19 }
20
21 IntermediateGas operator*(const IntermediateGas& other) const
22 {
23 return IntermediateGas{ .l2Gas = l2Gas * other.l2Gas, .daGas = daGas * other.daGas };
24 }
25
26 Gas to_gas() const
27 {
28 assert(l2Gas <= std::numeric_limits<uint32_t>::max());
29 assert(daGas <= std::numeric_limits<uint32_t>::max());
30 return Gas{ .l2Gas = static_cast<uint32_t>(l2Gas), .daGas = static_cast<uint32_t>(daGas) };
31 }
32};
33
34IntermediateGas to_intermediate_gas(const Gas& gas)
35{
36 return IntermediateGas{ .l2Gas = static_cast<uint64_t>(gas.l2Gas), .daGas = static_cast<uint64_t>(gas.daGas) };
37}
38
39} // namespace
40
53
54void GasTracker::consume_gas(const Gas& dynamic_gas_factor)
55{
56 // Base.
57 Gas prev_gas_used = context.get_gas_used();
58 const uint32_t base_da_gas = spec.gas_cost.base_da;
59
60 // Previous gas used can be up to 2**32 - 1
61 IntermediateGas base_actual_gas_used =
62 to_intermediate_gas(prev_gas_used) +
63 to_intermediate_gas({ gas_event.addressing_gas + spec.gas_cost.opcode_gas, base_da_gas });
64 IntermediateGas gas_limit = to_intermediate_gas(context.get_gas_limit());
65
66 bool oog_base_l2 = base_actual_gas_used.l2Gas > gas_limit.l2Gas;
67 bool oog_base_da = base_actual_gas_used.daGas > gas_limit.daGas;
68
69 // Dynamic.
70 gas_event.dynamic_gas_factor = dynamic_gas_factor;
71
72 const uint32_t dynamic_l2_gas = spec.gas_cost.dyn_l2;
73 const uint32_t dynamic_da_gas = spec.gas_cost.dyn_da;
74
75 IntermediateGas total_gas_used =
76 base_actual_gas_used +
77 (to_intermediate_gas(Gas{ dynamic_l2_gas, dynamic_da_gas }) * to_intermediate_gas(dynamic_gas_factor));
78
79 gas_event.oog_l2 = total_gas_used.l2Gas > gas_limit.l2Gas;
80 gas_event.oog_da = total_gas_used.daGas > gas_limit.daGas;
81
82 // This is a bit of an abstraction leak from the circuit. We have optimized the circuit so gas is
83 // checked against the limit only once. This means that we need to call the range check gadget
84 // on finish, since if gas is fine on base we won't call the range check gadget, and then we might
85 // not call consume_dynamic_gas.
87 gas_event.oog_l2 ? total_gas_used.l2Gas - gas_limit.l2Gas - 1 : gas_limit.l2Gas - total_gas_used.l2Gas;
89 gas_event.oog_da ? total_gas_used.daGas - gas_limit.daGas - 1 : gas_limit.daGas - total_gas_used.daGas;
90
93
94 if (oog_base_l2 || oog_base_da) {
95 throw OutOfGasException(format("Out of gas (base): L2 used ",
96 base_actual_gas_used.l2Gas,
97 " of ",
98 gas_limit.l2Gas,
99 ", DA used ",
100 base_actual_gas_used.daGas,
101 " of ",
102 gas_limit.daGas));
103 } else if (gas_event.oog_l2 || gas_event.oog_da) {
104 throw OutOfGasException(format("Out of gas (dynamic): L2 used ",
105 total_gas_used.l2Gas,
106 " of ",
107 gas_limit.l2Gas,
108 ", DA used ",
109 total_gas_used.daGas,
110 " of ",
111 gas_limit.daGas));
112 }
113
114 // Safe downcast since if we were over 32 bits, we would have OOG'd.
115 context.set_gas_used(total_gas_used.to_gas());
116}
117
118// Gas limit for call is the minimum between the gas allocated to the call by the user, and the gas left.
119// This applies to both gas dimensions independently.
120// This method does not emit a gas event.
122{
123 Gas gas_left = context.gas_left();
124
125 bool is_l2_gas_allocated_lt_left = allocated_gas.l2Gas < gas_left.l2Gas;
126 uint32_t l2_gas_comparison_witness =
127 is_l2_gas_allocated_lt_left ? gas_left.l2Gas - allocated_gas.l2Gas - 1 : allocated_gas.l2Gas - gas_left.l2Gas;
128
129 bool is_da_gas_allocated_lt_left = allocated_gas.daGas < gas_left.daGas;
130 uint32_t da_gas_comparison_witness =
131 is_da_gas_allocated_lt_left ? gas_left.daGas - allocated_gas.daGas - 1 : allocated_gas.daGas - gas_left.daGas;
132
133 range_check.assert_range(l2_gas_comparison_witness, 32);
134 range_check.assert_range(da_gas_comparison_witness, 32);
135
136 return {
137 .l2Gas = is_l2_gas_allocated_lt_left ? allocated_gas.l2Gas : gas_left.l2Gas,
138 .daGas = is_da_gas_allocated_lt_left ? allocated_gas.daGas : gas_left.daGas,
139 };
140}
141
142} // namespace bb::avm2::simulation
Gas compute_gas_limit_for_call(const Gas &allocated_gas) override
GasTracker(GasEvent &gas_event, const Instruction &instruction, const InstructionInfoDBInterface &instruction_info_db, ContextInterface &context, RangeCheckInterface &range_check)
const ExecInstructionSpec & spec
void consume_gas(const Gas &dynamic_gas_factor={ 0, 0 }) override
std::string format(Args... args)
Definition log.hpp:20
uint64_t l2Gas
uint64_t daGas
InstructionInfoDB instruction_info_db
GasEvent gas_event
Instruction instruction
uint32_t compute_addressing_gas(uint16_t indirect_flag)
Definition gas.cpp:10
Univariate< Fr, domain_end, domain_start, skip_count > operator+(const Fr &ff, const Univariate< Fr, domain_end, domain_start, skip_count > &uv)
Univariate< Fr, domain_end, domain_start, skip_count > operator*(const Fr &ff, const Univariate< Fr, domain_end, domain_start, skip_count > &uv)