Skip to content

Commit

Permalink
Use fees to calculate DA reward and avoid issues with Gwei/Wei conver…
Browse files Browse the repository at this point in the history
…sions (#2229)

## Linked Issues/PRs
Closes #2165
Closes #2243

## Description
- Modify the calculation of rewards to use the block fee instead of
block gas.
- Update the charts to be displayed in Gwei rather than Wei to reduce
noise and more closely resemble what we will see as an outside observer
of the Fuel L2 gas prices.

## Checklist
- [x] New behavior is reflected in tests

### Before requesting review
- [x] I have reviewed the code myself

---------

Co-authored-by: Rafał Chabowski <rafal.chabowski@fuel.sh>
Co-authored-by: Aaryamann Challani <43716372+rymnc@users.noreply.github.com>
Co-authored-by: Andrea Cerone <andrea.cerone@gmail.com>
Co-authored-by: Green Baneling <XgreenX9999@gmail.com>
  • Loading branch information
5 people authored Sep 25, 2024
1 parent fcbb487 commit 1e2bcdc
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 63 deletions.
58 changes: 41 additions & 17 deletions crates/fuel-gas-price-algorithm/gas-price-analysis/src/charts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::{
path::PathBuf,
};

const ONE_GWEI: u64 = 1_000_000_000;

pub fn draw_chart(
results: SimulationResults,
p_comp: i64,
Expand Down Expand Up @@ -76,19 +78,24 @@ pub fn draw_gas_prices(
da_gas_prices: &[u64],
title: &str,
) -> anyhow::Result<()> {
let gas_prices_gwei: Vec<_> = gas_prices.into_iter().map(|x| x / ONE_GWEI).collect();
let _exec_gas_prices_gwei: Vec<_> =
_exec_gas_prices.into_iter().map(|x| x / ONE_GWEI).collect();
let da_gas_prices_gwei: Vec<_> =
da_gas_prices.into_iter().map(|x| x / ONE_GWEI).collect();
// const GAS_PRICE_COLOR: RGBColor = BLACK;
// const EXEC_GAS_PRICE_COLOR: RGBColor = RED;
const DA_GAS_PRICE_COLOR: RGBColor = BLUE;
let min = 0;
let max = *da_gas_prices.iter().max().unwrap();
let max = *da_gas_prices_gwei.iter().max().unwrap();

let mut chart = ChartBuilder::on(drawing_area)
.caption(title, ("sans-serif", 50).into_font())
.margin(5)
.x_label_area_size(40)
.y_label_area_size(100)
.right_y_label_area_size(100)
.build_cartesian_2d(0..gas_prices.len(), min..max)?;
.build_cartesian_2d(0..gas_prices_gwei.len(), min..max)?;

chart
.configure_mesh()
Expand Down Expand Up @@ -120,7 +127,7 @@ pub fn draw_gas_prices(
// Draw the da gas prices
chart
.draw_series(LineSeries::new(
da_gas_prices.iter().enumerate().map(|(x, y)| (x, *y)),
da_gas_prices_gwei.iter().enumerate().map(|(x, y)| (x, *y)),
DA_GAS_PRICE_COLOR,
))?
.label("DA Gas Price")
Expand Down Expand Up @@ -189,10 +196,11 @@ pub fn draw_bytes_and_cost_per_block(
const BYTES_PER_BLOCK_COLOR: RGBColor = BLACK;
let (bytes, costs): (Vec<u64>, Vec<u64>) =
bytes_and_costs_per_block.iter().cloned().unzip();
let costs_gwei: Vec<_> = costs.into_iter().map(|x| x / ONE_GWEI).collect();

let min = 0;
let max_left = *bytes.iter().max().unwrap();
let max_right = *costs.iter().max().unwrap();
let max_right = *costs_gwei.iter().max().unwrap();

let mut chart = ChartBuilder::on(drawing_area)
.caption(title, ("sans-serif", 50).into_font())
Expand Down Expand Up @@ -230,7 +238,7 @@ pub fn draw_bytes_and_cost_per_block(

chart
.draw_secondary_series(LineSeries::new(
costs.iter().enumerate().map(|(x, y)| (x, *y)),
costs_gwei.iter().enumerate().map(|(x, y)| (x, *y)),
RED,
))
.unwrap()
Expand All @@ -257,22 +265,35 @@ pub fn draw_profit(
const ACTUAL_PROFIT_COLOR: RGBColor = BLACK;
const PROJECTED_PROFIT_COLOR: RGBColor = RED;
const PESSIMISTIC_BLOCK_COST_COLOR: RGBColor = BLUE;
let actual_profit_gwei: Vec<_> = actual_profit
.into_iter()
.map(|x| x / ONE_GWEI as i128)
.collect();
let projected_profit_gwei: Vec<_> = projected_profit
.into_iter()
.map(|x| x / ONE_GWEI as i128)
.collect();
let pessimistic_block_costs_gwei: Vec<_> = pessimistic_block_costs
.into_iter()
.map(|x| x / ONE_GWEI as u128)
.collect();
let min = *std::cmp::min(
actual_profit
actual_profit_gwei
.iter()
.min()
.ok_or(anyhow::anyhow!("Path has no parent"))?,
projected_profit
projected_profit_gwei
.iter()
.min()
.ok_or(anyhow::anyhow!("Path has no parent"))?,
);

let max = *std::cmp::max(
actual_profit
actual_profit_gwei
.iter()
.max()
.ok_or(anyhow::anyhow!("Path has no parent"))?,
projected_profit
projected_profit_gwei
.iter()
.max()
.ok_or(anyhow::anyhow!("Path has no parent"))?,
Expand All @@ -284,27 +305,27 @@ pub fn draw_profit(
.x_label_area_size(40)
.y_label_area_size(100)
.right_y_label_area_size(100)
.build_cartesian_2d(0..actual_profit.len(), min..max)
.build_cartesian_2d(0..actual_profit_gwei.len(), min..max)
.unwrap()
.set_secondary_coord(
0..actual_profit.len(),
0..*pessimistic_block_costs.iter().max().unwrap(),
0..actual_profit_gwei.len(),
0..*pessimistic_block_costs_gwei.iter().max().unwrap(),
);

chart
.configure_mesh()
.y_desc("Profit")
.y_desc("Profit (Gwei)")
.x_desc("Block")
.draw()?;

chart
.configure_secondary_axes()
.y_desc("Pessimistic cost")
.y_desc("Pessimistic cost (Gwei)")
.draw()?;

chart
.draw_series(LineSeries::new(
actual_profit.iter().enumerate().map(|(x, y)| (x, *y)),
actual_profit_gwei.iter().enumerate().map(|(x, y)| (x, *y)),
ACTUAL_PROFIT_COLOR,
))?
.label("Actual Profit")
Expand All @@ -314,7 +335,10 @@ pub fn draw_profit(

chart
.draw_series(LineSeries::new(
projected_profit.iter().enumerate().map(|(x, y)| (x, *y)),
projected_profit_gwei
.iter()
.enumerate()
.map(|(x, y)| (x, *y)),
PROJECTED_PROFIT_COLOR,
))?
.label("Projected Profit")
Expand All @@ -325,7 +349,7 @@ pub fn draw_profit(
// draw the block bytes
chart
.draw_secondary_series(LineSeries::new(
pessimistic_block_costs
pessimistic_block_costs_gwei
.iter()
.enumerate()
.map(|(x, y)| (x, *y)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,14 @@ impl Simulator {
da_gas_prices.push(updater.new_scaled_da_gas_price);
let gas_price = updater.algorithm().calculate();
gas_prices.push(gas_price);
let total_fee = gas_price * fullness;
updater
.update_l2_block_data(
height,
fullness,
capacity.try_into().unwrap(),
bytes,
gas_price,
total_fee,
)
.unwrap();
pessimistic_costs
Expand Down
53 changes: 39 additions & 14 deletions crates/fuel-gas-price-algorithm/src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl AlgorithmUpdaterV1 {
used: u64,
capacity: NonZeroU64,
block_bytes: u64,
_gas_price: u64,
fee_wei: u64,
) -> Result<(), Error> {
let expected = self.l2_block_height.saturating_add(1);
if height != expected {
Expand All @@ -220,19 +220,12 @@ impl AlgorithmUpdaterV1 {
self.l2_block_height = height;

// rewards
let block_da_reward = used.saturating_mul(self.descaled_da_price());
self.total_da_rewards_excess = self
.total_da_rewards_excess
.saturating_add(block_da_reward.into());
let rewards = self.total_da_rewards_excess.try_into().unwrap_or(i128::MAX);
self.update_rewards(fee_wei);
let rewards = self.clamped_rewards_as_i128();

// costs
let block_projected_da_cost =
(block_bytes as u128).saturating_mul(self.latest_da_cost_per_byte);
self.projected_total_da_cost = self
.projected_total_da_cost
.saturating_add(block_projected_da_cost);
let projected_total_da_cost = self.projected_cost_as_i128();
self.update_projected_cost(block_bytes);
let projected_total_da_cost = self.clamped_projected_cost_as_i128();
let last_profit = rewards.saturating_sub(projected_total_da_cost);
self.update_last_profit(last_profit);

Expand All @@ -243,11 +236,43 @@ impl AlgorithmUpdaterV1 {
}
}

// We are assuming that the difference between u128::MAX and i128::MAX is negligible
fn projected_cost_as_i128(&self) -> i128 {
fn update_rewards(&mut self, fee_wei: u64) {
let block_da_reward = self.da_portion_of_fee(fee_wei);
self.total_da_rewards_excess = self
.total_da_rewards_excess
.saturating_add(block_da_reward.into());
}

fn update_projected_cost(&mut self, block_bytes: u64) {
let block_projected_da_cost =
(block_bytes as u128).saturating_mul(self.latest_da_cost_per_byte);
self.projected_total_da_cost = self
.projected_total_da_cost
.saturating_add(block_projected_da_cost);
}

// Take the `fee_wei` and return the portion of the fee that should be used for paying DA costs
fn da_portion_of_fee(&self, fee_wei: u64) -> u64 {
// fee_wei * (da_price / (exec_price + da_price))
let numerator = fee_wei.saturating_mul(self.descaled_da_price());
let denominator = self
.descaled_exec_price()
.saturating_add(self.descaled_da_price());
if denominator == 0 {
0
} else {
numerator.div_ceil(denominator)
}
}

fn clamped_projected_cost_as_i128(&self) -> i128 {
i128::try_from(self.projected_total_da_cost).unwrap_or(i128::MAX)
}

fn clamped_rewards_as_i128(&self) -> i128 {
i128::try_from(self.total_da_rewards_excess).unwrap_or(i128::MAX)
}

fn update_last_profit(&mut self, new_profit: i128) {
self.second_to_last_profit = self.last_profit;
self.last_profit = new_profit;
Expand Down
4 changes: 2 additions & 2 deletions crates/fuel-gas-price-algorithm/src/v1/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ impl UpdaterBuilder {
Self {
min_exec_gas_price: 0,
min_da_gas_price: 0,
starting_exec_gas_price: 0,
starting_da_gas_price: 0,
starting_exec_gas_price: 1,
starting_da_gas_price: 1,
exec_gas_price_change_percent: 0,
max_change_percent: u16::MAX,

Expand Down
Loading

0 comments on commit 1e2bcdc

Please sign in to comment.