fuel_gas_price_algorithm/
v0.rs1use std::{
2 cmp::max,
3 num::NonZeroU64,
4};
5
6use crate::utils::cumulative_percentage_change;
7
8#[cfg(test)]
9mod tests;
10
11#[derive(Debug, thiserror::Error, PartialEq)]
12pub enum Error {
13 #[error("Skipped L2 block update: expected {expected:?}, got {got:?}")]
14 SkippedL2Block { expected: u32, got: u32 },
15}
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct AlgorithmV0 {
19 new_exec_price: u64,
21 for_height: u32,
23 percentage: u64,
25}
26
27impl AlgorithmV0 {
28 pub fn calculate(&self) -> u64 {
29 self.new_exec_price
30 }
31
32 pub fn worst_case(&self, height: u32) -> u64 {
33 cumulative_percentage_change(
34 self.new_exec_price,
35 self.for_height,
36 self.percentage,
37 height,
38 )
39 }
40}
41
42#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
53pub struct AlgorithmUpdaterV0 {
54 pub new_exec_price: u64,
56 pub min_exec_gas_price: u64,
59 pub exec_gas_price_change_percent: u64,
62 pub l2_block_height: u32,
64 pub l2_block_fullness_threshold_percent: u64,
67}
68
69impl AlgorithmUpdaterV0 {
70 pub fn new(
71 new_exec_price: u64,
72 min_exec_gas_price: u64,
73 exec_gas_price_change_percent: u64,
74 l2_block_height: u32,
75 l2_block_fullness_threshold_percent: u64,
76 ) -> Self {
77 let new_exec_price_corrected = max(new_exec_price, min_exec_gas_price);
78 Self {
79 new_exec_price: new_exec_price_corrected,
80 min_exec_gas_price,
81 exec_gas_price_change_percent,
82 l2_block_height,
83 l2_block_fullness_threshold_percent,
84 }
85 }
86
87 pub fn update_l2_block_data(
88 &mut self,
89 height: u32,
90 used: u64,
91 capacity: NonZeroU64,
92 ) -> Result<(), Error> {
93 let expected = self.l2_block_height.saturating_add(1);
94 if height != expected {
95 Err(Error::SkippedL2Block {
96 expected,
97 got: height,
98 })
99 } else {
100 self.l2_block_height = height;
101 self.update_exec_gas_price(used, capacity);
102 Ok(())
103 }
104 }
105
106 fn update_exec_gas_price(&mut self, used: u64, capacity: NonZeroU64) {
107 let mut exec_gas_price = self.new_exec_price;
108 let fullness_percent = used
109 .saturating_mul(100)
110 .checked_div(capacity.into())
111 .unwrap_or(self.l2_block_fullness_threshold_percent);
112
113 match fullness_percent.cmp(&self.l2_block_fullness_threshold_percent) {
114 std::cmp::Ordering::Greater | std::cmp::Ordering::Equal => {
115 let change_amount = self.change_amount(exec_gas_price);
116 exec_gas_price = exec_gas_price.saturating_add(change_amount);
117 }
118 std::cmp::Ordering::Less => {
119 let change_amount = self.change_amount(exec_gas_price);
120 exec_gas_price = exec_gas_price.saturating_sub(change_amount);
121 }
122 }
123 self.new_exec_price = max(self.min_exec_gas_price, exec_gas_price);
124 }
125
126 fn change_amount(&self, principle: u64) -> u64 {
127 principle
128 .saturating_mul(self.exec_gas_price_change_percent)
129 .saturating_div(100)
130 }
131
132 pub fn algorithm(&self) -> AlgorithmV0 {
133 AlgorithmV0 {
134 new_exec_price: self.new_exec_price,
135 for_height: self.l2_block_height,
136 percentage: self.exec_gas_price_change_percent,
137 }
138 }
139}