Skip to content

Commit

Permalink
Add activity concept with safety mode
Browse files Browse the repository at this point in the history
  • Loading branch information
MitchTurner committed Oct 16, 2024
1 parent 0fdd76f commit 54a9da8
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 19 deletions.
91 changes: 73 additions & 18 deletions crates/fuel-gas-price-algorithm/src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,38 +147,93 @@ pub struct AlgorithmUpdaterV1 {
/// The latest known cost per byte for recording blocks on the DA chain
pub latest_da_cost_per_byte: u128,
/// Activity of L2
pub l2_activity: Activity,
pub l2_activity: L2ActivityTracker,
/// The unrecorded blocks that are used to calculate the projected cost of recording blocks
pub unrecorded_blocks: BTreeMap<Height, Bytes>,
}

/// Because the DA gas price can increase even when no-one is using the network, there is a potential
/// for a negative feedback loop to occur where the gas price increases, further decreasing activity
/// and increasing the gas price. The `L2ActivityTracker` is used to moderate changes to the DA
/// gas price based on the activity of the L2 chain.
///
/// For each L2 block, the activity is calculated as a percentage of the block capacity used. If the
/// activity is below a certain threshold, the activity is decreased. The activity exists on a scale
/// between 0 and the sum of the increase, hold, and decrease buffers:
///
/// |<-- decrease range -->|<-- hold range -->|<-- increase range -->|
///
/// The current activity determines the behavior of the DA gas price.
///
/// For healthy behavior, the activity should be in the `increase` range.
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
pub struct Activity {
top: i16,
bottom: i16,
current: i16,
pub struct L2ActivityTracker {
/// The _size_ of the range of the activity buffer that will increase the gas price
increase_range_size: u16,
/// The _size_ of the range of the activity buffer that will hold the gas price
hold_range_size: u16,
/// The _size_ of the range of the activity buffer that will decrease the gas price
decrease_range_size: u16,
/// The current activity of the L2 chain
activity: u16,
/// The threshold of activity below which the activity will be decreased
block_activity_threshold: ClampedPercentage,
}

impl Activity {
pub fn new(top: i16, bottom: i16, current: i16) -> Self {
/// Designates the intended behavior of the DA gas price based on the activity of the L2 chain
pub enum DAGasPriceSafetyMode {
/// Should increase DA gas price freely
Increase,
/// Should not increase the DA gas price
Hold,
/// Should decrease the DA gas price always
Decrease,
}

impl L2ActivityTracker {
pub fn new_full(
increase_range_size: u16,
hold_range_size: u16,
decrease_range_size: u16,
block_activity_threshold: ClampedPercentage,
) -> Self {
let activity = decrease_range_size + hold_range_size + increase_range_size;
Self {
top,
bottom,
current,
increase_range_size,
hold_range_size,
decrease_range_size,
activity,
block_activity_threshold,
}
}
}

fn change_percent_with_activity(base: u16, activity: u8, max_change: u16) -> u16 {
let activity = activity as u16;
let max_change = max_change as u16;
let base = base as u16;
let change = activity.saturating_mul(max_change).saturating_div(100);
base.saturating_add(change)
pub fn new_always_increases() -> Self {
Self::new_full(1, 0, 0, ClampedPercentage::new(0))
}

pub fn safety_mode(&self) -> DAGasPriceSafetyMode {
if self.activity > self.decrease_range_size + self.hold_range_size {
DAGasPriceSafetyMode::Increase
} else if self.activity > self.decrease_range_size {
DAGasPriceSafetyMode::Hold
} else {
DAGasPriceSafetyMode::Decrease
}
}

pub fn update(&mut self, block_usage: ClampedPercentage) {
let cap =
self.decrease_range_size + self.hold_range_size + self.increase_range_size;
if block_usage < self.block_activity_threshold {
self.activity = self.activity.saturating_sub(1);
} else {
self.activity = self.activity.saturating_add(1).min(cap);
}
}
}

/// A value that represents a value between 0 and 100. Higher values are clamped to 100
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)]
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, PartialOrd)]
pub struct ClampedPercentage {
value: u8,
}
Expand Down
6 changes: 5 additions & 1 deletion crates/fuel-gas-price-algorithm/src/v1/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
#![allow(clippy::arithmetic_side_effects)]
#![allow(clippy::cast_possible_truncation)]

use crate::v1::AlgorithmUpdaterV1;
use crate::v1::{
AlgorithmUpdaterV1,
L2ActivityTracker,
};

#[cfg(test)]
mod algorithm_v1_tests;
Expand Down Expand Up @@ -190,6 +193,7 @@ impl UpdaterBuilder {
.da_gas_price_factor
.try_into()
.expect("Should never be non-zero"),
l2_activity: L2ActivityTracker::new_always_increases(),
}
}
}
Expand Down

0 comments on commit 54a9da8

Please sign in to comment.