Skip to content

Commit

Permalink
bug: fix algorithm overflow issues (#2173)
Browse files Browse the repository at this point in the history
## Linked Issues/PRs
Closes #2164
Closes #2147

## Description
The main change with this code is "normalizaing" the costs and rewards
instead of keeping a total over all time. i.e. every time we receive a
DA block, we see if the reward is greater than the costs, or vice versa.
If the reward is higher, we set the reward to the difference and set the
the last known cost to `0` and adjust the projected cost accordingly.

In addition, we were using a random set of types for the algorithm and
also used casts in many places. This PR should fix a lot of those
problems.

Bonus: This fix prompted me to run the optimization again. Since the set
is much bigger now, I decided to enable running the simulation in
parallel tasks to speed up the code.

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

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

---------

Co-authored-by: green <xgreenx9999@gmail.com>
Co-authored-by: Aaryamann Challani <43716372+rymnc@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 11, 2024
1 parent ce857cf commit f308bae
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 133 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
5 changes: 4 additions & 1 deletion crates/fuel-gas-price-algorithm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ name = "fuel_gas_price_algorithm"
path = "src/lib.rs"

[dependencies]
proptest = { workspace = true }
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }

[dev-dependencies]
proptest = { workspace = true }
rand = { workspace = true }
2 changes: 2 additions & 0 deletions crates/fuel-gas-price-algorithm/gas-price-analysis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ anyhow = "1.0.86"
clap = { version = "4.5.16", features = ["derive"] }
csv = "1.3.0"
fuel-gas-price-algorithm = { path = ".." }
futures = "0.3.30"
plotters = "0.3.5"
rand = "0.8.5"
rand_distr = "0.4.3"
serde = { version = "1.0.209", features = ["derive"] }
tokio = { version = "1.40.0", features = ["macros", "rt", "rt-multi-thread"] }
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ enum Source {
},
}

fn main() -> anyhow::Result<()> {
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Arg::parse();

const UPDATE_PERIOD: usize = 12;
Expand Down Expand Up @@ -103,7 +104,7 @@ fn main() -> anyhow::Result<()> {
);
let simulator = Simulator::new(da_cost_per_byte);
let (results, (p, d)) =
naive_optimisation(&simulator, iterations as usize, UPDATE_PERIOD);
naive_optimisation(&simulator, iterations as usize, UPDATE_PERIOD).await;
println!(
"Optimization results: P: {}, D: {}",
prettify_number(p),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
use futures::future::join_all;

fn da_pid_factors(size: usize) -> Vec<(i64, i64)> {
let mut rng = StdRng::seed_from_u64(10902);
Expand All @@ -11,19 +12,28 @@ fn da_pid_factors(size: usize) -> Vec<(i64, i64)> {
.collect()
}

pub fn naive_optimisation(
pub async fn naive_optimisation(
simulator: &Simulator,
iterations: usize,
da_recording_rate: usize,
) -> (SimulationResults, (i64, i64)) {
da_pid_factors(iterations)
.iter()
let tasks = da_pid_factors(iterations)
.into_iter()
.map(|(p, d)| {
(
simulator.run_simulation(*p, *d, da_recording_rate),
(*p, *d),
)
let new_simulator = simulator.clone();
let f = move || {
(
new_simulator.run_simulation(p, d, da_recording_rate),
(p, d),
)
};
tokio::task::spawn_blocking(f)
})
.collect::<Vec<_>>();
join_all(tasks)
.await
.into_iter()
.map(Result::unwrap)
.min_by_key(|(results, _)| {
let SimulationResults { actual_profit, .. } = results;
let err = actual_profit.iter().map(|p| p.abs()).sum::<i128>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,7 @@ use fuel_gas_price_algorithm::v1::{
AlgorithmUpdaterV1,
RecordedBlock,
};
use std::{
iter,
iter::{
Enumerate,
Zip,
},
num::NonZeroU64,
slice::Iter,
};
use std::num::NonZeroU64;

use super::*;

Expand All @@ -27,6 +19,7 @@ pub struct SimulationResults {
pub pessimistic_costs: Vec<u128>,
}

#[derive(Clone, Debug)]
pub struct Simulator {
da_cost_per_byte: Vec<u64>,
}
Expand Down Expand Up @@ -82,17 +75,17 @@ impl Simulator {
gas_price_factor: NonZeroU64::new(gas_price_factor).unwrap(),
l2_block_height: 0,
// Choose the ideal fullness percentage for the L2 block
l2_block_fullness_threshold_percent: 50,
l2_block_fullness_threshold_percent: 50u8.into(),
// Increase to make the exec price change faster
exec_gas_price_change_percent: 2,
// Increase to make the da price change faster
max_da_gas_price_change_percent: 10,
total_da_rewards: 0,
total_da_rewards_excess: 0,
da_recorded_block_height: 0,
// Change to adjust the cost per byte of the DA on block 0
latest_da_cost_per_byte: 0,
projected_total_da_cost: 0,
latest_known_total_da_cost: 0,
latest_known_total_da_cost_excess: 0,
unrecorded_blocks: vec![],
da_p_component,
da_d_component,
Expand Down Expand Up @@ -123,18 +116,6 @@ impl Simulator {
exec_gas_prices.push(updater.new_scaled_exec_price);
let gas_price = updater.algorithm().calculate(max_block_bytes);
gas_prices.push(gas_price);
// Update DA blocks on the occasion there is one

if let Some(mut da_blocks) = da_block.clone() {
let mut total_costs = updater.latest_known_total_da_cost;
for block in &mut da_blocks {
total_costs += block.block_cost as u128;
actual_costs.push(total_costs);
}
updater.update_da_record_data(da_blocks.to_owned()).unwrap();
assert_eq!(total_costs, updater.projected_total_da_cost);
assert_eq!(total_costs, updater.latest_known_total_da_cost);
}
updater
.update_l2_block_data(
height,
Expand All @@ -147,17 +128,26 @@ impl Simulator {
da_gas_prices.push(updater.last_da_gas_price);
pessimistic_costs
.push(max_block_bytes as u128 * updater.latest_da_cost_per_byte);
actual_reward_totals.push(updater.total_da_rewards);
actual_reward_totals.push(updater.total_da_rewards_excess);
projected_cost_totals.push(updater.projected_total_da_cost);
}

// Update DA blocks on the occasion there is one
if let Some(da_blocks) = &da_block {
let mut total_cost = updater.latest_known_total_da_cost_excess;
for block in da_blocks {
total_cost += block.block_cost as u128;
actual_costs.push(total_cost);
}
updater.update_da_record_data(&da_blocks).unwrap();
}
}
let (fullness_without_capacity, bytes): (Vec<_>, Vec<_>) =
fullness_and_bytes.iter().cloned().unzip();
let fullness = fullness_without_capacity
let fullness: Vec<_> = fullness_without_capacity
.iter()
.map(|&fullness| (fullness, capacity))
.collect();
let bytes_and_costs = bytes
let bytes_and_costs: Vec<_> = bytes
.iter()
.zip(self.da_cost_per_byte.iter())
.map(|(bytes, cost_per_byte)| (*bytes, (*bytes * cost_per_byte) as u64))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub fn get_da_cost_per_byte_from_source(
}
}

#[allow(dead_code)]
#[derive(Debug, serde::Deserialize)]
struct Record {
block_number: u64,
Expand Down
Loading

0 comments on commit f308bae

Please sign in to comment.